specguard-mcp 0.1.2 → 0.1.4
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 +183 -17
- package/dist/bin/specguard-mcp.js +5 -0
- package/dist/bin/specguard-mcp.js.map +1 -1
- package/dist/src/support/run-command.d.ts +42 -0
- package/dist/src/support/run-command.js +124 -8
- package/dist/src/support/run-command.js.map +1 -1
- package/dist/src/support/specguard-api.d.ts +50 -0
- package/dist/src/support/specguard-api.js +148 -8
- package/dist/src/support/specguard-api.js.map +1 -1
- package/dist/src/support/teardown.d.ts +33 -0
- package/dist/src/support/teardown.js +56 -0
- package/dist/src/support/teardown.js.map +1 -0
- package/dist/src/tools/add-repository.d.ts +55 -0
- package/dist/src/tools/add-repository.js +114 -0
- package/dist/src/tools/add-repository.js.map +1 -0
- package/dist/src/tools/args.d.ts +20 -0
- package/dist/src/tools/args.js +30 -0
- package/dist/src/tools/args.js.map +1 -1
- package/dist/src/tools/create-repository-api-key.d.ts +26 -0
- package/dist/src/tools/create-repository-api-key.js +83 -0
- package/dist/src/tools/create-repository-api-key.js.map +1 -0
- package/dist/src/tools/index.d.ts +61 -7
- package/dist/src/tools/index.js +71 -7
- package/dist/src/tools/index.js.map +1 -1
- package/dist/src/tools/list-repositories.d.ts +14 -7
- package/dist/src/tools/list-repositories.js +14 -7
- package/dist/src/tools/list-repositories.js.map +1 -1
- package/dist/src/tools/registrable-repositories.d.ts +51 -0
- package/dist/src/tools/registrable-repositories.js +92 -0
- package/dist/src/tools/registrable-repositories.js.map +1 -0
- package/dist/src/tools/remove-repository.d.ts +33 -0
- package/dist/src/tools/remove-repository.js +81 -0
- package/dist/src/tools/remove-repository.js.map +1 -0
- package/dist/src/tools/repository-overview.js +33 -8
- package/dist/src/tools/repository-overview.js.map +1 -1
- package/dist/src/tools/revoke-repository-api-key.d.ts +29 -0
- package/dist/src/tools/revoke-repository-api-key.js +85 -0
- package/dist/src/tools/revoke-repository-api-key.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { postJsonObject, requireUserApiConfig } from "../support/specguard-api.js";
|
|
2
|
+
import { optionalString, requireString } from "./args.js";
|
|
3
|
+
/**
|
|
4
|
+
* `POST /api/v1/repositories/:repository_id/api_keys` as a tool — shipped in
|
|
5
|
+
* the platform (`specguard/config/routes.rb:158`,
|
|
6
|
+
* `user_repository_api_keys_controller#create`, SPGD-754).
|
|
7
|
+
*
|
|
8
|
+
* == Reveal-once, again
|
|
9
|
+
*
|
|
10
|
+
* The 201 body carries `api_key.token` — the raw key, the only time it exists
|
|
11
|
+
* anywhere — exactly as `add_repository`'s does. The body is therefore passed
|
|
12
|
+
* through UNRESHAPED in both `text` and `structured` for the same reason that
|
|
13
|
+
* tool states: any reshaping on this hop is a value that cannot be recovered
|
|
14
|
+
* rather than a field that can be re-fetched. Recovery for a dropped token is
|
|
15
|
+
* minting another key — this same tool — because the platform ships no
|
|
16
|
+
* `#regenerate` and no re-serve.
|
|
17
|
+
*
|
|
18
|
+
* == The name is top-level and optional
|
|
19
|
+
*
|
|
20
|
+
* `params[:name]` defaults to `ApiKey::DEFAULT_NAME` server-side; `undefined`
|
|
21
|
+
* here means "let the server name it" and simply omits the key from the POST
|
|
22
|
+
* body. Not re-validated here for the reason `add_repository` states: a second
|
|
23
|
+
* format rule on this side is a rule with no owner, free to drift from the one
|
|
24
|
+
* that actually decides.
|
|
25
|
+
*/
|
|
26
|
+
const createRepositoryApiKey = {
|
|
27
|
+
name: "create_repository_api_key",
|
|
28
|
+
title: "Create repository API key",
|
|
29
|
+
description: "Mints a new CI API key (an sgk_… key) for a SpecGuard repository, and returns it " +
|
|
30
|
+
"alongside the repository's existing keys. " +
|
|
31
|
+
"⚠️ `api_key.token` is shown THIS ONCE AND NEVER AGAIN — nothing stores it and no " +
|
|
32
|
+
"endpoint can re-serve it, so hand it to the user in your reply rather than assuming " +
|
|
33
|
+
"it can be fetched later. If it is dropped, the recovery is minting another key with " +
|
|
34
|
+
"this same tool (the platform has no regenerate), then revoking the orphaned one. " +
|
|
35
|
+
"On success the response carries an `api_key` block (`name`, `token`, `hint`, " +
|
|
36
|
+
"`created_at`) — the same reveal-once shape `add_repository` serves. " +
|
|
37
|
+
"Minting does not disturb existing keys: each key on a repository authenticates " +
|
|
38
|
+
"independently until revoked. " +
|
|
39
|
+
"Takes `repository_id` (the numeric id `list_repositories` reports) and an optional " +
|
|
40
|
+
"`name`, which the server defaults when omitted. " +
|
|
41
|
+
"Authorization is the `keys_manage` capability — a member without it is refused 403 " +
|
|
42
|
+
"in SpecGuard's own words. " +
|
|
43
|
+
"Needs SPECGUARD_USER_API_KEY (an sgu_… key), the same credential `add_repository` " +
|
|
44
|
+
"writes with and a DIFFERENT one from the sgk_… repository key " +
|
|
45
|
+
"`get_repository_overview` uses.",
|
|
46
|
+
inputSchema: {
|
|
47
|
+
type: "object",
|
|
48
|
+
properties: {
|
|
49
|
+
repository_id: {
|
|
50
|
+
type: "string",
|
|
51
|
+
description: "The repository to mint the key for — its numeric id, as `add_repository` " +
|
|
52
|
+
"returns and `list_repositories` reports, not the `org/repo` handle.",
|
|
53
|
+
},
|
|
54
|
+
name: {
|
|
55
|
+
type: "string",
|
|
56
|
+
description: "An optional label for the key. Omit it to let SpecGuard use its default name. " +
|
|
57
|
+
"The server validates the name and refuses an unusable one in its own words.",
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
required: ["repository_id"],
|
|
61
|
+
// Closed for the reason every tool here states — and on a WRITE, a silently
|
|
62
|
+
// dropped misspelled argument still mints something, just possibly mislabeled.
|
|
63
|
+
additionalProperties: false,
|
|
64
|
+
},
|
|
65
|
+
async run(args, context) {
|
|
66
|
+
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
67
|
+
const name = optionalString(args["name"], "name");
|
|
68
|
+
const api = requireUserApiConfig(context.config);
|
|
69
|
+
// `name` omitted when absent rather than sent as null, so the server's own
|
|
70
|
+
// `ApiKey::DEFAULT_NAME` default applies — this bridge expresses "no
|
|
71
|
+
// preference", it does not choose on the server's behalf.
|
|
72
|
+
const created = await postJsonObject(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/api_keys`, name === undefined ? {} : { name }, context.fetch);
|
|
73
|
+
// Unreshaped, for the reason `add_repository` states at its own return:
|
|
74
|
+
// `api_key.token` exists nowhere else, so any reshaping on this hop is a
|
|
75
|
+
// value that cannot be recovered.
|
|
76
|
+
return {
|
|
77
|
+
text: JSON.stringify(created, null, 2),
|
|
78
|
+
structured: created,
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
export default createRepositoryApiKey;
|
|
83
|
+
//# sourceMappingURL=create-repository-api-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-repository-api-key.js","sourceRoot":"","sources":["../../../src/tools/create-repository-api-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,sBAAsB,GAAmB;IAC7C,IAAI,EAAE,2BAA2B;IACjC,KAAK,EAAE,2BAA2B;IAClC,WAAW,EACT,mFAAmF;QACnF,4CAA4C;QAC5C,mFAAmF;QACnF,sFAAsF;QACtF,sFAAsF;QACtF,mFAAmF;QACnF,+EAA+E;QAC/E,sEAAsE;QACtE,iFAAiF;QACjF,+BAA+B;QAC/B,qFAAqF;QACrF,kDAAkD;QAClD,qFAAqF;QACrF,4BAA4B;QAC5B,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,2EAA2E;oBAC3E,qEAAqE;aACxE;YACD,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,gFAAgF;oBAChF,6EAA6E;aAChF;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,CAAC;QAC3B,4EAA4E;QAC5E,+EAA+E;QAC/E,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,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;QAElD,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,2EAA2E;QAC3E,qEAAqE;QACrE,0DAA0D;QAC1D,MAAM,OAAO,GAAG,MAAM,cAAc,CAClC,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,WAAW,EACnE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAClC,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,wEAAwE;QACxE,yEAAyE;QACzE,kCAAkC;QAClC,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACtC,UAAU,EAAE,OAAO;SACpB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -41,13 +41,67 @@ import type { ToolDefinition } from "./types.js";
|
|
|
41
41
|
* and fails on use, which is worse than not offering the tool, because the
|
|
42
42
|
* agent has already committed to a plan by the time it finds out.
|
|
43
43
|
*
|
|
44
|
-
* The
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
44
|
+
* == The fourth: the first tool that WRITES
|
|
45
|
+
*
|
|
46
|
+
* - `add_repository` wraps `POST /api/v1/repositories` (shipped:
|
|
47
|
+
* `specguard/config/routes.rb`, `Api::V1::UserRepositoriesController#create`).
|
|
48
|
+
*
|
|
49
|
+
* The endpoint had shipped for a while; what this bridge lacked was a way to
|
|
50
|
+
* CALL it — `support/specguard-api.ts` offered only `getJson`, which hardcoded
|
|
51
|
+
* `method: "GET"` and took no body. The reservation recorded here was that the
|
|
52
|
+
* write transport should land WITH the first write tool, designed against a real
|
|
53
|
+
* request body and a real 4xx surface rather than invented for a caller that did
|
|
54
|
+
* not exist. That is what happened: `postJson`/`postJsonObject` arrived with
|
|
55
|
+
* this entry, sharing `fetchWithTimeout` with the read path rather than standing
|
|
56
|
+
* beside it, and `describeFailure` grew the `400` branch that surfaces
|
|
57
|
+
* SpecGuard's own refusal sentence — the modal answer this endpoint gives.
|
|
58
|
+
*
|
|
59
|
+
* The standing rule is unchanged and still binding. What once kept `DELETE
|
|
60
|
+
* /api/v1/repositories/:id` and the API-key endpoints out under it — "not on
|
|
61
|
+
* `origin/main`, so they may not be wrapped" — stopped being true when SPGD-754
|
|
62
|
+
* shipped them, and the sixth-through-eighth section below records their
|
|
63
|
+
* wrapping. What moved was the platform, not the bar.
|
|
64
|
+
*
|
|
65
|
+
* == The fifth: the read half of the registration gate
|
|
66
|
+
*
|
|
67
|
+
* - `registrable_repositories` wraps `GET /api/v1/repositories/registrable`
|
|
68
|
+
* (shipped: `specguard/config/routes.rb:117`,
|
|
69
|
+
* `Api::V1::UserRepositoriesController#registrable`).
|
|
70
|
+
*
|
|
71
|
+
* `list_repositories` says what IS registered; this says what COULD be — the
|
|
72
|
+
* set the gate would consult, read out in advance, so an agent can pick a
|
|
73
|
+
* `full_name` for `add_repository` from a real answer. Landing it also
|
|
74
|
+
* generalised the 400 branch in `describeFailure` into a status-parameterised
|
|
75
|
+
* extractor, because this endpoint's modal first answer is a 403 (`not_granted`)
|
|
76
|
+
* carrying the same `{error, message}` contract — the identical defect, given
|
|
77
|
+
* the identical remedy.
|
|
78
|
+
*
|
|
79
|
+
* The user-scoped surface as it now stands is therefore three tools: read the
|
|
80
|
+
* list, read the gate's answer, write a registration. The standing rule is
|
|
81
|
+
* unchanged and still binding, which is what keeps the rest out:
|
|
82
|
+
* `DELETE /api/v1/repositories/:id` and the API-key endpoints (SPGD-754) are
|
|
83
|
+
* NOT on `origin/main`, so they may not be wrapped here however useful a tool
|
|
84
|
+
* for them would be. What moved was the platform, not the bar.
|
|
85
|
+
*
|
|
86
|
+
* == The sixth through eighth: removal and the key lifecycle
|
|
87
|
+
*
|
|
88
|
+
* - `remove_repository` wraps `DELETE /api/v1/repositories/:id`, and
|
|
89
|
+
* `create_repository_api_key` / `revoke_repository_api_key` wrap the two
|
|
90
|
+
* `api_keys` endpoints (all shipped: SPGD-754, `specguard@origin/main`).
|
|
91
|
+
*
|
|
92
|
+
* The closing fence the two paragraphs above share — "the DELETE and API-key
|
|
93
|
+
* endpoints are NOT on `origin/main`, so they may not be wrapped" — stopped
|
|
94
|
+
* being true when SPGD-754 landed, and these three entries are what became
|
|
95
|
+
* wrappable the moment it did. They also forced the transport's third verb:
|
|
96
|
+
* both DELETE endpoints answer `204` with NO body, the one response in the
|
|
97
|
+
* `sgu_` surface that is deliberately not JSON, which is why `deleteJson`
|
|
98
|
+
* returns the raw body text instead of routing an empty 204 through
|
|
99
|
+
* `requestJson`'s JSON parse.
|
|
100
|
+
*
|
|
101
|
+
* The standing rule itself is unchanged and still binding — which still keeps
|
|
102
|
+
* out `/check-intent`, duplicate clustering, member management and rename: none
|
|
103
|
+
* of their backing endpoints has shipped, and a tool advertised in `tools/list`
|
|
104
|
+
* remains a promise an agent will act on.
|
|
51
105
|
*/
|
|
52
106
|
export declare const TOOLS: readonly ToolDefinition[];
|
|
53
107
|
export type { ToolContext, ToolDefinition, ToolResult } from "./types.js";
|
package/dist/src/tools/index.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import addRepository from "./add-repository.js";
|
|
2
|
+
import createRepositoryApiKey from "./create-repository-api-key.js";
|
|
1
3
|
import lintIntentAnnotations from "./lint-intent-annotations.js";
|
|
2
4
|
import listRepositories from "./list-repositories.js";
|
|
3
5
|
import getRepositoryOverview from "./repository-overview.js";
|
|
6
|
+
import registrableRepositories from "./registrable-repositories.js";
|
|
7
|
+
import removeRepository from "./remove-repository.js";
|
|
8
|
+
import revokeRepositoryApiKey from "./revoke-repository-api-key.js";
|
|
4
9
|
/**
|
|
5
10
|
* THE REGISTRY — the one file that changes when the toolset grows.
|
|
6
11
|
*
|
|
@@ -43,17 +48,76 @@ import getRepositoryOverview from "./repository-overview.js";
|
|
|
43
48
|
* and fails on use, which is worse than not offering the tool, because the
|
|
44
49
|
* agent has already committed to a plan by the time it finds out.
|
|
45
50
|
*
|
|
46
|
-
* The
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
51
|
+
* == The fourth: the first tool that WRITES
|
|
52
|
+
*
|
|
53
|
+
* - `add_repository` wraps `POST /api/v1/repositories` (shipped:
|
|
54
|
+
* `specguard/config/routes.rb`, `Api::V1::UserRepositoriesController#create`).
|
|
55
|
+
*
|
|
56
|
+
* The endpoint had shipped for a while; what this bridge lacked was a way to
|
|
57
|
+
* CALL it — `support/specguard-api.ts` offered only `getJson`, which hardcoded
|
|
58
|
+
* `method: "GET"` and took no body. The reservation recorded here was that the
|
|
59
|
+
* write transport should land WITH the first write tool, designed against a real
|
|
60
|
+
* request body and a real 4xx surface rather than invented for a caller that did
|
|
61
|
+
* not exist. That is what happened: `postJson`/`postJsonObject` arrived with
|
|
62
|
+
* this entry, sharing `fetchWithTimeout` with the read path rather than standing
|
|
63
|
+
* beside it, and `describeFailure` grew the `400` branch that surfaces
|
|
64
|
+
* SpecGuard's own refusal sentence — the modal answer this endpoint gives.
|
|
65
|
+
*
|
|
66
|
+
* The standing rule is unchanged and still binding. What once kept `DELETE
|
|
67
|
+
* /api/v1/repositories/:id` and the API-key endpoints out under it — "not on
|
|
68
|
+
* `origin/main`, so they may not be wrapped" — stopped being true when SPGD-754
|
|
69
|
+
* shipped them, and the sixth-through-eighth section below records their
|
|
70
|
+
* wrapping. What moved was the platform, not the bar.
|
|
71
|
+
*
|
|
72
|
+
* == The fifth: the read half of the registration gate
|
|
73
|
+
*
|
|
74
|
+
* - `registrable_repositories` wraps `GET /api/v1/repositories/registrable`
|
|
75
|
+
* (shipped: `specguard/config/routes.rb:117`,
|
|
76
|
+
* `Api::V1::UserRepositoriesController#registrable`).
|
|
77
|
+
*
|
|
78
|
+
* `list_repositories` says what IS registered; this says what COULD be — the
|
|
79
|
+
* set the gate would consult, read out in advance, so an agent can pick a
|
|
80
|
+
* `full_name` for `add_repository` from a real answer. Landing it also
|
|
81
|
+
* generalised the 400 branch in `describeFailure` into a status-parameterised
|
|
82
|
+
* extractor, because this endpoint's modal first answer is a 403 (`not_granted`)
|
|
83
|
+
* carrying the same `{error, message}` contract — the identical defect, given
|
|
84
|
+
* the identical remedy.
|
|
85
|
+
*
|
|
86
|
+
* The user-scoped surface as it now stands is therefore three tools: read the
|
|
87
|
+
* list, read the gate's answer, write a registration. The standing rule is
|
|
88
|
+
* unchanged and still binding, which is what keeps the rest out:
|
|
89
|
+
* `DELETE /api/v1/repositories/:id` and the API-key endpoints (SPGD-754) are
|
|
90
|
+
* NOT on `origin/main`, so they may not be wrapped here however useful a tool
|
|
91
|
+
* for them would be. What moved was the platform, not the bar.
|
|
92
|
+
*
|
|
93
|
+
* == The sixth through eighth: removal and the key lifecycle
|
|
94
|
+
*
|
|
95
|
+
* - `remove_repository` wraps `DELETE /api/v1/repositories/:id`, and
|
|
96
|
+
* `create_repository_api_key` / `revoke_repository_api_key` wrap the two
|
|
97
|
+
* `api_keys` endpoints (all shipped: SPGD-754, `specguard@origin/main`).
|
|
98
|
+
*
|
|
99
|
+
* The closing fence the two paragraphs above share — "the DELETE and API-key
|
|
100
|
+
* endpoints are NOT on `origin/main`, so they may not be wrapped" — stopped
|
|
101
|
+
* being true when SPGD-754 landed, and these three entries are what became
|
|
102
|
+
* wrappable the moment it did. They also forced the transport's third verb:
|
|
103
|
+
* both DELETE endpoints answer `204` with NO body, the one response in the
|
|
104
|
+
* `sgu_` surface that is deliberately not JSON, which is why `deleteJson`
|
|
105
|
+
* returns the raw body text instead of routing an empty 204 through
|
|
106
|
+
* `requestJson`'s JSON parse.
|
|
107
|
+
*
|
|
108
|
+
* The standing rule itself is unchanged and still binding — which still keeps
|
|
109
|
+
* out `/check-intent`, duplicate clustering, member management and rename: none
|
|
110
|
+
* of their backing endpoints has shipped, and a tool advertised in `tools/list`
|
|
111
|
+
* remains a promise an agent will act on.
|
|
53
112
|
*/
|
|
54
113
|
export const TOOLS = [
|
|
55
114
|
lintIntentAnnotations,
|
|
56
115
|
getRepositoryOverview,
|
|
57
116
|
listRepositories,
|
|
117
|
+
addRepository,
|
|
118
|
+
registrableRepositories,
|
|
119
|
+
removeRepository,
|
|
120
|
+
createRepositoryApiKey,
|
|
121
|
+
revokeRepositoryApiKey,
|
|
58
122
|
];
|
|
59
123
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,qBAAqB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,qBAAqB,MAAM,0BAA0B,CAAC;AAC7D,OAAO,uBAAuB,MAAM,+BAA+B,CAAC;AACpE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AAGpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuGG;AACH,MAAM,CAAC,MAAM,KAAK,GAA8B;IAC9C,qBAAqB;IACrB,qBAAqB;IACrB,gBAAgB;IAChB,aAAa;IACb,uBAAuB;IACvB,gBAAgB;IAChB,sBAAsB;IACtB,sBAAsB;CACvB,CAAC"}
|
|
@@ -13,13 +13,20 @@ import type { ToolDefinition } from "./types.js";
|
|
|
13
13
|
* answer, and it is the whole of what this tool does.
|
|
14
14
|
*
|
|
15
15
|
* It is also the tool that proves the second credential slot works end to end,
|
|
16
|
-
* which is why it
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
16
|
+
* which is why it shipped alone. It no longer IS alone: `add_repository`
|
|
17
|
+
* (SPGD-764) reads the same `sgu_` key and wraps `POST /api/v1/repositories`,
|
|
18
|
+
* which arrived once this bridge had a write transport to call it with —
|
|
19
|
+
* `postJson`/`postJsonObject` in `support/specguard-api.ts`, landed with that
|
|
20
|
+
* tool and designed against a real request body and a real 4xx surface, exactly
|
|
21
|
+
* as the reservation recorded here asked. The registry's standing rule
|
|
22
|
+
* (`tools/index.ts`) is unchanged and still binding: a tool in `tools/list` is a
|
|
23
|
+
* promise an agent acts on, so the REST of the user-scoped surface — removing a
|
|
24
|
+
* repository, minting or revoking keys — stays out until those endpoints ship.
|
|
25
|
+
*
|
|
26
|
+
* What this tool still uniquely answers is the question above: which
|
|
27
|
+
* repositories there ARE. `add_repository` extends that surface rather than
|
|
28
|
+
* replacing it, and the two share a handle — the `full_name` reported here is
|
|
29
|
+
* the `full_name` that one takes.
|
|
23
30
|
*
|
|
24
31
|
* == It reads the OTHER key, and that is the point
|
|
25
32
|
*
|
|
@@ -13,13 +13,20 @@ import { getJsonObject, requireUserApiConfig } from "../support/specguard-api.js
|
|
|
13
13
|
* answer, and it is the whole of what this tool does.
|
|
14
14
|
*
|
|
15
15
|
* It is also the tool that proves the second credential slot works end to end,
|
|
16
|
-
* which is why it
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
16
|
+
* which is why it shipped alone. It no longer IS alone: `add_repository`
|
|
17
|
+
* (SPGD-764) reads the same `sgu_` key and wraps `POST /api/v1/repositories`,
|
|
18
|
+
* which arrived once this bridge had a write transport to call it with —
|
|
19
|
+
* `postJson`/`postJsonObject` in `support/specguard-api.ts`, landed with that
|
|
20
|
+
* tool and designed against a real request body and a real 4xx surface, exactly
|
|
21
|
+
* as the reservation recorded here asked. The registry's standing rule
|
|
22
|
+
* (`tools/index.ts`) is unchanged and still binding: a tool in `tools/list` is a
|
|
23
|
+
* promise an agent acts on, so the REST of the user-scoped surface — removing a
|
|
24
|
+
* repository, minting or revoking keys — stays out until those endpoints ship.
|
|
25
|
+
*
|
|
26
|
+
* What this tool still uniquely answers is the question above: which
|
|
27
|
+
* repositories there ARE. `add_repository` extends that surface rather than
|
|
28
|
+
* replacing it, and the two share a handle — the `full_name` reported here is
|
|
29
|
+
* the `full_name` that one takes.
|
|
23
30
|
*
|
|
24
31
|
* == It reads the OTHER key, and that is the point
|
|
25
32
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-repositories.js","sourceRoot":"","sources":["../../../src/tools/list-repositories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGlF
|
|
1
|
+
{"version":3,"file":"list-repositories.js","sourceRoot":"","sources":["../../../src/tools/list-repositories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGlF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,MAAM,gBAAgB,GAAmB;IACvC,IAAI,EAAE,mBAAmB;IACzB,KAAK,EAAE,mBAAmB;IAC1B,WAAW,EACT,2FAA2F;QAC3F,2FAA2F;QAC3F,6DAA6D;QAC7D,6FAA6F;QAC7F,wDAAwD;QACxD,mFAAmF;QACnF,2FAA2F;QAC3F,uDAAuD;QACvD,kEAAkE;QAClE,6FAA6F;QAC7F,8FAA8F;QAC9F,wFAAwF;QACxF,4FAA4F;QAC5F,QAAQ;IACV,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,4EAA4E;QAC5E,oEAAoE;QACpE,wEAAwE;QACxE,sEAAsE;QACtE,2EAA2E;QAC3E,uEAAuE;QACvE,uCAAuC;QACvC,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO;QACtB,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,sBAAsB,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAEpF,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACtC,UAAU,EAAE,OAAO;SACpB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ToolDefinition } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* `GET /api/v1/repositories/registrable` as a tool — shipped today in the
|
|
4
|
+
* platform (`specguard/config/routes.rb:117`, served by
|
|
5
|
+
* `Api::V1::UserRepositoriesController#registrable`).
|
|
6
|
+
*
|
|
7
|
+
* == What it answers, and why `list_repositories` does not
|
|
8
|
+
*
|
|
9
|
+
* `list_repositories` reports what is already registered; this reports what
|
|
10
|
+
* COULD be — the repositories the registration gate would consult, read out
|
|
11
|
+
* loud in advance. It exists so an agent can pick a `full_name` for
|
|
12
|
+
* `add_repository` from a real answer rather than by guessing, and so a
|
|
13
|
+
* `has already been taken` refusal can be explained rather than merely
|
|
14
|
+
* retried.
|
|
15
|
+
*
|
|
16
|
+
* == Two controller decisions the description carries, because both are
|
|
17
|
+
* counter-intuitive and both are stated in the controller's own comments
|
|
18
|
+
*
|
|
19
|
+
* `registered` is asked of `Repository` GLOBALLY, not of what this person can
|
|
20
|
+
* open. The controller says why: a repository somebody ELSE registered still
|
|
21
|
+
* refuses this person's POST with `has already been taken`, so a reading
|
|
22
|
+
* scoped to what they can see would mark it `registered: false` and send them
|
|
23
|
+
* at a name that cannot be registered by anyone. An entry is therefore
|
|
24
|
+
* MARKED, not excluded — `registered: true` is the answer to "why did my POST
|
|
25
|
+
* say has already been taken".
|
|
26
|
+
*
|
|
27
|
+
* And a name appearing here is NOT a promise the write will succeed. This is
|
|
28
|
+
* the set the gate would consult at the moment of the read; the repository may
|
|
29
|
+
* be registered by someone else between the two calls.
|
|
30
|
+
*
|
|
31
|
+
* == The modal first answer is a 403, and that is why `describeFailure` grew
|
|
32
|
+
*
|
|
33
|
+
* `#registrable` fails closed on the two states `GrantVerifier` refuses on and
|
|
34
|
+
* renders `status: :forbidden` — NOT the 400 path the other refusals use. A
|
|
35
|
+
* nil grant is, in the controller's own words, "an ordinary state and not an
|
|
36
|
+
* error: it is every person who has not opened SpecGuard in a browser since
|
|
37
|
+
* this shipped" — so the 403 is the modal first answer this tool gives, and
|
|
38
|
+
* the sentence it carries (sign in, reconnect GitHub, retry) reaches the agent
|
|
39
|
+
* through the 403 branch in `specguard-api.ts`, which this tool is the reason
|
|
40
|
+
* for. On refusal the body still carries `grant`: `null` when there never was
|
|
41
|
+
* one, populated with `stale: true` when it lapsed — "yours lapsed four days
|
|
42
|
+
* ago" is a different fact from "you never had one", and the tool description
|
|
43
|
+
* is where an agent learns to branch on it.
|
|
44
|
+
*
|
|
45
|
+
* == No arguments, for the same reason `list_repositories` has none
|
|
46
|
+
*
|
|
47
|
+
* The credential is the whole of the scope. The endpoint takes no parameters,
|
|
48
|
+
* and nothing an argument could select reaches this answer.
|
|
49
|
+
*/
|
|
50
|
+
declare const registrableRepositories: ToolDefinition;
|
|
51
|
+
export default registrableRepositories;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { getJsonObject, requireUserApiConfig } from "../support/specguard-api.js";
|
|
2
|
+
/**
|
|
3
|
+
* `GET /api/v1/repositories/registrable` as a tool — shipped today in the
|
|
4
|
+
* platform (`specguard/config/routes.rb:117`, served by
|
|
5
|
+
* `Api::V1::UserRepositoriesController#registrable`).
|
|
6
|
+
*
|
|
7
|
+
* == What it answers, and why `list_repositories` does not
|
|
8
|
+
*
|
|
9
|
+
* `list_repositories` reports what is already registered; this reports what
|
|
10
|
+
* COULD be — the repositories the registration gate would consult, read out
|
|
11
|
+
* loud in advance. It exists so an agent can pick a `full_name` for
|
|
12
|
+
* `add_repository` from a real answer rather than by guessing, and so a
|
|
13
|
+
* `has already been taken` refusal can be explained rather than merely
|
|
14
|
+
* retried.
|
|
15
|
+
*
|
|
16
|
+
* == Two controller decisions the description carries, because both are
|
|
17
|
+
* counter-intuitive and both are stated in the controller's own comments
|
|
18
|
+
*
|
|
19
|
+
* `registered` is asked of `Repository` GLOBALLY, not of what this person can
|
|
20
|
+
* open. The controller says why: a repository somebody ELSE registered still
|
|
21
|
+
* refuses this person's POST with `has already been taken`, so a reading
|
|
22
|
+
* scoped to what they can see would mark it `registered: false` and send them
|
|
23
|
+
* at a name that cannot be registered by anyone. An entry is therefore
|
|
24
|
+
* MARKED, not excluded — `registered: true` is the answer to "why did my POST
|
|
25
|
+
* say has already been taken".
|
|
26
|
+
*
|
|
27
|
+
* And a name appearing here is NOT a promise the write will succeed. This is
|
|
28
|
+
* the set the gate would consult at the moment of the read; the repository may
|
|
29
|
+
* be registered by someone else between the two calls.
|
|
30
|
+
*
|
|
31
|
+
* == The modal first answer is a 403, and that is why `describeFailure` grew
|
|
32
|
+
*
|
|
33
|
+
* `#registrable` fails closed on the two states `GrantVerifier` refuses on and
|
|
34
|
+
* renders `status: :forbidden` — NOT the 400 path the other refusals use. A
|
|
35
|
+
* nil grant is, in the controller's own words, "an ordinary state and not an
|
|
36
|
+
* error: it is every person who has not opened SpecGuard in a browser since
|
|
37
|
+
* this shipped" — so the 403 is the modal first answer this tool gives, and
|
|
38
|
+
* the sentence it carries (sign in, reconnect GitHub, retry) reaches the agent
|
|
39
|
+
* through the 403 branch in `specguard-api.ts`, which this tool is the reason
|
|
40
|
+
* for. On refusal the body still carries `grant`: `null` when there never was
|
|
41
|
+
* one, populated with `stale: true` when it lapsed — "yours lapsed four days
|
|
42
|
+
* ago" is a different fact from "you never had one", and the tool description
|
|
43
|
+
* is where an agent learns to branch on it.
|
|
44
|
+
*
|
|
45
|
+
* == No arguments, for the same reason `list_repositories` has none
|
|
46
|
+
*
|
|
47
|
+
* The credential is the whole of the scope. The endpoint takes no parameters,
|
|
48
|
+
* and nothing an argument could select reaches this answer.
|
|
49
|
+
*/
|
|
50
|
+
const registrableRepositories = {
|
|
51
|
+
name: "registrable_repositories",
|
|
52
|
+
title: "Registrable repositories",
|
|
53
|
+
description: "Lists the GitHub repositories the person behind this server's user API key could register " +
|
|
54
|
+
"with SpecGuard — the set the registration gate would consult, read out in advance, so an " +
|
|
55
|
+
"agent can pick a `full_name` for `add_repository` from a real answer rather than by " +
|
|
56
|
+
"guessing. Each entry carries `full_name` and `registered`. `registered` is asked GLOBALLY, " +
|
|
57
|
+
"not just of this person's own repositories: an entry marked `registered: true` was " +
|
|
58
|
+
"registered by SOMEBODY — possibly someone else — and a POST naming it will be refused with " +
|
|
59
|
+
"`has already been taken`, which is exactly the question this flag answers. Entries are " +
|
|
60
|
+
"marked, not excluded, for that reason. The response also carries a `grant` block " +
|
|
61
|
+
"(`captured_at`, `expires_at`, `stale`) describing the stored record of this person's GitHub " +
|
|
62
|
+
"permissions. A MISSING or STALE grant is not an error — it is every person who has not " +
|
|
63
|
+
"opened SpecGuard in a browser recently — and the call then answers 403 with SpecGuard's own " +
|
|
64
|
+
"sentence naming the fix: sign in to SpecGuard in a browser and reconnect GitHub, then try " +
|
|
65
|
+
"again. On that refusal the body's `grant` distinguishes the two cases: `grant: null` means " +
|
|
66
|
+
"there never was one (first-time setup), a populated grant with `stale: true` means an " +
|
|
67
|
+
"existing connection lapsed (same remedy, likely faster to complete) — branch on it before " +
|
|
68
|
+
"telling the person what to do. A name appearing in the list is not a promise the write " +
|
|
69
|
+
"will succeed: someone may register it between this read and the POST. Ordered by " +
|
|
70
|
+
"`full_name` ascending, which is stable across calls. Needs SPECGUARD_USER_API_KEY (an " +
|
|
71
|
+
"sgu_… key), the same credential `list_repositories` and `add_repository` read and a " +
|
|
72
|
+
"DIFFERENT one from the sgk_… repository key `get_repository_overview` uses.",
|
|
73
|
+
inputSchema: {
|
|
74
|
+
type: "object",
|
|
75
|
+
// No properties, deliberately — see this file's header. Still CLOSED rather
|
|
76
|
+
// than merely empty, for the reason `list-repositories.ts` gives inline:
|
|
77
|
+
// `server.ts` forwards `arguments` unvalidated and `run` ignores them, so
|
|
78
|
+
// an open schema would have an invented argument silently dropped and the
|
|
79
|
+
// call answered as if it had been honoured.
|
|
80
|
+
additionalProperties: false,
|
|
81
|
+
},
|
|
82
|
+
async run(_args, context) {
|
|
83
|
+
const api = requireUserApiConfig(context.config);
|
|
84
|
+
const listing = await getJsonObject(api, "/api/v1/repositories/registrable", {}, context.fetch);
|
|
85
|
+
return {
|
|
86
|
+
text: JSON.stringify(listing, null, 2),
|
|
87
|
+
structured: listing,
|
|
88
|
+
};
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
export default registrableRepositories;
|
|
92
|
+
//# sourceMappingURL=registrable-repositories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registrable-repositories.js","sourceRoot":"","sources":["../../../src/tools/registrable-repositories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGlF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,uBAAuB,GAAmB;IAC9C,IAAI,EAAE,0BAA0B;IAChC,KAAK,EAAE,0BAA0B;IACjC,WAAW,EACT,4FAA4F;QAC5F,2FAA2F;QAC3F,sFAAsF;QACtF,6FAA6F;QAC7F,qFAAqF;QACrF,6FAA6F;QAC7F,yFAAyF;QACzF,mFAAmF;QACnF,8FAA8F;QAC9F,yFAAyF;QACzF,8FAA8F;QAC9F,4FAA4F;QAC5F,6FAA6F;QAC7F,wFAAwF;QACxF,4FAA4F;QAC5F,yFAAyF;QACzF,mFAAmF;QACnF,wFAAwF;QACxF,sFAAsF;QACtF,6EAA6E;IAC/E,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,4EAA4E;QAC5E,yEAAyE;QACzE,0EAA0E;QAC1E,0EAA0E;QAC1E,4CAA4C;QAC5C,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO;QACtB,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,MAAM,OAAO,GAAG,MAAM,aAAa,CACjC,GAAG,EACH,kCAAkC,EAClC,EAAE,EACF,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACtC,UAAU,EAAE,OAAO;SACpB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ToolDefinition } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* `DELETE /api/v1/repositories/:id` as a tool — shipped in the platform
|
|
4
|
+
* (`specguard/config/routes.rb:152`, `Api::V1::UserRepositoriesController#destroy`,
|
|
5
|
+
* SPGD-754).
|
|
6
|
+
*
|
|
7
|
+
* == The destructive gesture in the whole surface
|
|
8
|
+
*
|
|
9
|
+
* Everything else here reads, registers, or mints. This one removes a
|
|
10
|
+
* repository AND every key, run and intent on it (`memberships_helper.rb`:
|
|
11
|
+
* "Delete the repository, and every key, run and intent on it"), and there is no
|
|
12
|
+
* undo. The description therefore carries the hazard BEFORE the call: it is
|
|
13
|
+
* prompt material, read when the agent is deciding whether to act, not a
|
|
14
|
+
* footnote discovered after.
|
|
15
|
+
*
|
|
16
|
+
* == Authorization is `repo.delete` at either surface
|
|
17
|
+
*
|
|
18
|
+
* The controller authorizes through `RepositoryAuthorization`'s `:repo_delete`
|
|
19
|
+
* fork — deliberately NOT `:owner` — so a member granted `repo.delete` may
|
|
20
|
+
* remove the repository from either surface. The tool does not probe for the
|
|
21
|
+
* capability client-side: the server is the gate, and a member without it
|
|
22
|
+
* receives a 403 whose sentence arrives verbatim through the landed
|
|
23
|
+
* `refusalMessage` branch in `describeFailure`.
|
|
24
|
+
*
|
|
25
|
+
* == 204 with no body
|
|
26
|
+
*
|
|
27
|
+
* This is the one response in the `sgu_` surface that is deliberately not a
|
|
28
|
+
* JSON body — which is why `deleteJson` exists: routing an empty-body 204
|
|
29
|
+
* through `requestJson`'s JSON parse would turn a successful delete into
|
|
30
|
+
* "the body was not JSON". Here, no body IS the success.
|
|
31
|
+
*/
|
|
32
|
+
declare const removeRepository: ToolDefinition;
|
|
33
|
+
export default removeRepository;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { deleteJson, requireUserApiConfig } from "../support/specguard-api.js";
|
|
2
|
+
import { requireString } from "./args.js";
|
|
3
|
+
/**
|
|
4
|
+
* `DELETE /api/v1/repositories/:id` as a tool — shipped in the platform
|
|
5
|
+
* (`specguard/config/routes.rb:152`, `Api::V1::UserRepositoriesController#destroy`,
|
|
6
|
+
* SPGD-754).
|
|
7
|
+
*
|
|
8
|
+
* == The destructive gesture in the whole surface
|
|
9
|
+
*
|
|
10
|
+
* Everything else here reads, registers, or mints. This one removes a
|
|
11
|
+
* repository AND every key, run and intent on it (`memberships_helper.rb`:
|
|
12
|
+
* "Delete the repository, and every key, run and intent on it"), and there is no
|
|
13
|
+
* undo. The description therefore carries the hazard BEFORE the call: it is
|
|
14
|
+
* prompt material, read when the agent is deciding whether to act, not a
|
|
15
|
+
* footnote discovered after.
|
|
16
|
+
*
|
|
17
|
+
* == Authorization is `repo.delete` at either surface
|
|
18
|
+
*
|
|
19
|
+
* The controller authorizes through `RepositoryAuthorization`'s `:repo_delete`
|
|
20
|
+
* fork — deliberately NOT `:owner` — so a member granted `repo.delete` may
|
|
21
|
+
* remove the repository from either surface. The tool does not probe for the
|
|
22
|
+
* capability client-side: the server is the gate, and a member without it
|
|
23
|
+
* receives a 403 whose sentence arrives verbatim through the landed
|
|
24
|
+
* `refusalMessage` branch in `describeFailure`.
|
|
25
|
+
*
|
|
26
|
+
* == 204 with no body
|
|
27
|
+
*
|
|
28
|
+
* This is the one response in the `sgu_` surface that is deliberately not a
|
|
29
|
+
* JSON body — which is why `deleteJson` exists: routing an empty-body 204
|
|
30
|
+
* through `requestJson`'s JSON parse would turn a successful delete into
|
|
31
|
+
* "the body was not JSON". Here, no body IS the success.
|
|
32
|
+
*/
|
|
33
|
+
const removeRepository = {
|
|
34
|
+
name: "remove_repository",
|
|
35
|
+
title: "Remove repository",
|
|
36
|
+
description: "Removes a repository from SpecGuard, DELETING every key, run and intent on it. " +
|
|
37
|
+
"This is IRREVERSIBLE: the repository's CI keys stop authenticating and its recorded " +
|
|
38
|
+
"runs and intents are gone, with no undo and no way to recover them short of " +
|
|
39
|
+
"re-registering from scratch. A 204 means it is deleted. " +
|
|
40
|
+
"Authorization is the `repo.delete` capability at either surface — an owner, or a " +
|
|
41
|
+
"member granted it, may remove the repository; a member without it is refused 403 in " +
|
|
42
|
+
"SpecGuard's own words. Confirm with the user before calling: this is the destructive " +
|
|
43
|
+
"gesture in this toolset, and once it returns 204 the repository and its history " +
|
|
44
|
+
"cannot be brought back. " +
|
|
45
|
+
"Takes `repository_id` — the numeric id `add_repository` and `list_repositories` " +
|
|
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.",
|
|
50
|
+
inputSchema: {
|
|
51
|
+
type: "object",
|
|
52
|
+
properties: {
|
|
53
|
+
repository_id: {
|
|
54
|
+
type: "string",
|
|
55
|
+
description: "The id of the repository to remove — the numeric id `add_repository` returns " +
|
|
56
|
+
"and `list_repositories` reports, not the `org/repo` handle. SpecGuard scopes " +
|
|
57
|
+
"the lookup to repositories you may act on and answers 404 otherwise.",
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
required: ["repository_id"],
|
|
61
|
+
// Closed for the reason every tool here states: `server.ts` forwards
|
|
62
|
+
// `arguments` unvalidated, and on the DESTRUCTIVE path a silently-dropped
|
|
63
|
+
// argument is the worst case of the write-path argument — the call still
|
|
64
|
+
// deletes something, just not what the agent believed it named.
|
|
65
|
+
additionalProperties: false,
|
|
66
|
+
},
|
|
67
|
+
async run(args, context) {
|
|
68
|
+
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
69
|
+
const api = requireUserApiConfig(context.config);
|
|
70
|
+
const body = await deleteJson(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}`, context.fetch);
|
|
71
|
+
// 204 with no body. Nothing upstream to pass through, so the result says
|
|
72
|
+
// what the verb did — in the tool's own words, because the deployment's
|
|
73
|
+
// whole answer was "no content".
|
|
74
|
+
return {
|
|
75
|
+
text: body === "" ? "Repository removed (204). Every key, run and intent on it is deleted." : body,
|
|
76
|
+
structured: { repository_id: repositoryId, deleted: true },
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
export default removeRepository;
|
|
81
|
+
//# sourceMappingURL=remove-repository.js.map
|
|
@@ -0,0 +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"}
|