specguard-mcp 0.1.4 → 0.1.5
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 +150 -1
- package/dist/src/support/specguard-api.d.ts +19 -0
- package/dist/src/support/specguard-api.js +26 -0
- package/dist/src/support/specguard-api.js.map +1 -1
- package/dist/src/tools/add-repository-member.d.ts +31 -0
- package/dist/src/tools/add-repository-member.js +105 -0
- package/dist/src/tools/add-repository-member.js.map +1 -0
- package/dist/src/tools/args.d.ts +26 -0
- package/dist/src/tools/args.js +52 -0
- package/dist/src/tools/args.js.map +1 -1
- package/dist/src/tools/index.d.ts +53 -9
- package/dist/src/tools/index.js +65 -9
- package/dist/src/tools/index.js.map +1 -1
- package/dist/src/tools/list-repository-members.d.ts +32 -0
- package/dist/src/tools/list-repository-members.js +76 -0
- package/dist/src/tools/list-repository-members.js.map +1 -0
- package/dist/src/tools/near-duplicate-clusters.d.ts +58 -0
- package/dist/src/tools/near-duplicate-clusters.js +116 -0
- package/dist/src/tools/near-duplicate-clusters.js.map +1 -0
- package/dist/src/tools/remove-repository-member.d.ts +30 -0
- package/dist/src/tools/remove-repository-member.js +93 -0
- package/dist/src/tools/remove-repository-member.js.map +1 -0
- package/dist/src/tools/rename-repository.d.ts +44 -0
- package/dist/src/tools/rename-repository.js +99 -0
- package/dist/src/tools/rename-repository.js.map +1 -0
- package/dist/src/tools/update-repository-member-permissions.d.ts +30 -0
- package/dist/src/tools/update-repository-member-permissions.js +97 -0
- package/dist/src/tools/update-repository-member-permissions.js.map +1 -0
- package/package.json +2 -1
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` | — | 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_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
|
|
|
@@ -434,6 +434,47 @@ speaks for.
|
|
|
434
434
|
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
435
435
|
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
436
436
|
|
|
437
|
+
### `near_duplicate_clusters`
|
|
438
|
+
|
|
439
|
+
Runs SpecGuard's near-duplicate census over a repository's tests — which tests *read alike* (same
|
|
440
|
+
body text, whatever file they sit in), clustered by similarity. Answers the refactoring question
|
|
441
|
+
the overview's per-run rankings cannot: where the same test is written twice, before you delete or
|
|
442
|
+
merge anything.
|
|
443
|
+
|
|
444
|
+
**This is the expensive read in this toolset.** The census is linear but measured in seconds —
|
|
445
|
+
seven queries at every size, tens of seconds extrapolated at the 20,000-test design point — which
|
|
446
|
+
is why the platform serves it only to a client that asks (`?near_duplicates=`, shipped by SPGD-703)
|
|
447
|
+
and answers `near_duplicates: null` on the plain overview. Calling this tool **is** the ask;
|
|
448
|
+
`get_repository_overview` never sends it, so an agent reading the overview cannot pay the census by
|
|
449
|
+
accident.
|
|
450
|
+
|
|
451
|
+
**This tool takes no arguments** — nothing about the census is choosable. The clusters are the
|
|
452
|
+
repository's, computed over every run; one call returns them all. (The server reads only that the
|
|
453
|
+
`near_duplicates` key is *present* — `=false` would open it too — so there is no value for an
|
|
454
|
+
argument to carry.)
|
|
455
|
+
|
|
456
|
+
Read the response with its own rules in mind:
|
|
457
|
+
|
|
458
|
+
- `similarity_floor` and `similarity_basis` sit **first** in the block and qualify every figure
|
|
459
|
+
below them — a cluster count without what "similar" meant is a count you cannot act on.
|
|
460
|
+
- `member_count` (texts in the repository, across every run) and `example_count` (examples in the
|
|
461
|
+
one run `weighed_run_id` names) are **different grains**: a three-example table-driven loop is
|
|
462
|
+
one member and three examples. Never fold them.
|
|
463
|
+
- `truncated: true` means the `clusters` list was cut at the cap while the counts above it
|
|
464
|
+
(`cluster_count`, `identity_count`, `clustered_*`) describe the whole census.
|
|
465
|
+
- `unobserved_members: true` on a cluster says a member identity the weighed run did not observe
|
|
466
|
+
(deleted, renamed, deselected) is still listed — do not reconcile the member list against that
|
|
467
|
+
run's examples.
|
|
468
|
+
- `similarity_range` is `[strongest, weakest]`: membership is transitive, similarity is not.
|
|
469
|
+
- `total_seconds` is `null` where nothing was timed — never a zero that would read as free.
|
|
470
|
+
- `clusters: []` with a real `identity_count` is the **success** state (nothing reads alike); the
|
|
471
|
+
three silences — nothing ingested, nothing embedded, nothing alike — are kept distinguishable by
|
|
472
|
+
`recorded_count` / `identity_count` / the list itself.
|
|
473
|
+
|
|
474
|
+
Same credential and endpoint as `get_repository_overview` (`sgk_…` repository key on
|
|
475
|
+
`GET /api/v1/repository`); the response is that endpoint's full body with the `near_duplicates`
|
|
476
|
+
block opened, passed through unmodified.
|
|
477
|
+
|
|
437
478
|
### `remove_repository`
|
|
438
479
|
|
|
439
480
|
Removes a repository from SpecGuard — and with it **every key, run and intent on it**. This is the
|
|
@@ -498,6 +539,114 @@ means the key is revoked.
|
|
|
498
539
|
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
499
540
|
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
500
541
|
|
|
542
|
+
### `list_repository_members`
|
|
543
|
+
|
|
544
|
+
Lists who has access to a SpecGuard repository: one row per member with their `handle`,
|
|
545
|
+
`permissions`, `granted_by` (who last set them) and `created_at`, ordered by handle.
|
|
546
|
+
|
|
547
|
+
| argument | |
|
|
548
|
+
| --- | --- |
|
|
549
|
+
| `repository_id` | the repository — its numeric `id`, as `add_repository` returns and `list_repositories` reports, not the `org/repo` handle |
|
|
550
|
+
|
|
551
|
+
The list answers **memberships only** and never reports how many CI keys a member has minted
|
|
552
|
+
(`keys_minted`) — that is a separate `keys.manage` disclosure this endpoint deliberately withholds;
|
|
553
|
+
the API-keys tools are the surface for it. The response carries **no membership id**, by design.
|
|
554
|
+
|
|
555
|
+
Authorization is the `members.manage` capability: a caller who is not a member is refused `404`
|
|
556
|
+
(the repository's existence stays hidden), and a member without `members.manage` is refused `403`
|
|
557
|
+
with SpecGuard's own sentence, verbatim.
|
|
558
|
+
|
|
559
|
+
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
560
|
+
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
561
|
+
|
|
562
|
+
### `add_repository_member`
|
|
563
|
+
|
|
564
|
+
Grants a person access to a SpecGuard repository by their GitHub handle, with an optional list of
|
|
565
|
+
permissions.
|
|
566
|
+
|
|
567
|
+
| argument | |
|
|
568
|
+
| --- | --- |
|
|
569
|
+
| `repository_id` | the repository to grant access to — its numeric `id`, as `add_repository` returns and `list_repositories` reports, not the `org/repo` handle |
|
|
570
|
+
| `handle` | the person's GitHub **login** — `octocat`, not a profile URL and not a display name; SpecGuard refuses both with its own sentence |
|
|
571
|
+
| `permissions` | an optional list of permission strings (`view`, `keys.manage`, `members.manage`, `repo.delete`); omit it to grant access with no additional permissions |
|
|
572
|
+
|
|
573
|
+
Each resolution failure — nobody has signed in as that handle yet, the account is archived, the
|
|
574
|
+
handle is ambiguous, the handle is not a login — arrives as a **distinguishable** 400 message
|
|
575
|
+
naming the exact next move. The grantor recorded on the membership is always the person behind
|
|
576
|
+
`SPECGUARD_USER_API_KEY`; no argument can name a different one.
|
|
577
|
+
|
|
578
|
+
On success (`201`) the response carries a `member` block (`handle`, `permissions`, `granted_by`,
|
|
579
|
+
`created_at`) — and **no membership id**, by design. Authorization is the `members.manage`
|
|
580
|
+
capability; a member without it is refused `403` with SpecGuard's own sentence, verbatim.
|
|
581
|
+
|
|
582
|
+
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
583
|
+
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
584
|
+
|
|
585
|
+
### `update_repository_member_permissions`
|
|
586
|
+
|
|
587
|
+
Replaces one member's permission set on a SpecGuard repository.
|
|
588
|
+
|
|
589
|
+
| argument | |
|
|
590
|
+
| --- | --- |
|
|
591
|
+
| `repository_id` | the repository the membership belongs to — its numeric `id`, as `add_repository` returns and `list_repositories` reports, not the `org/repo` handle |
|
|
592
|
+
| `member_id` | the id of the **membership** row to edit — not a user id, not the handle. Scoped to `repository_id`: a foreign membership id is refused `404` |
|
|
593
|
+
| `permissions` | the member's **complete new** permission set (`view`, `keys.manage`, `members.manage`, `repo.delete`) — it replaces what they hold today, it is not merged |
|
|
594
|
+
|
|
595
|
+
**`permissions` replaces the whole set** — name every permission the member should end with.
|
|
596
|
+
Values are validated by SpecGuard; an unknown value is refused with its own sentence, verbatim.
|
|
597
|
+
|
|
598
|
+
**Known limitation:** no API endpoint serves the membership id — the member list and the
|
|
599
|
+
add-member response both omit it by design — so the id must be obtained from the platform (today
|
|
600
|
+
via the repository's web members page). There is no name-based lookup. Authorization is the
|
|
601
|
+
`members.manage` capability; a member without it is refused `403` with SpecGuard's own sentence,
|
|
602
|
+
verbatim.
|
|
603
|
+
|
|
604
|
+
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
605
|
+
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
606
|
+
|
|
607
|
+
### `remove_repository_member`
|
|
608
|
+
|
|
609
|
+
Revokes one person's access to a SpecGuard repository by removing their membership. A `204` means
|
|
610
|
+
it is revoked.
|
|
611
|
+
|
|
612
|
+
| argument | |
|
|
613
|
+
| --- | --- |
|
|
614
|
+
| `repository_id` | the repository the membership belongs to — its numeric `id`, as `add_repository` returns and `list_repositories` reports, not the `org/repo` handle |
|
|
615
|
+
| `member_id` | the id of the **membership** row to revoke — not a user id, not the handle. Scoped to `repository_id`: a foreign membership id is refused `404` |
|
|
616
|
+
|
|
617
|
+
**Revoking does NOT revoke that member's minted CI keys.** Any `sgk_…` keys they created on the
|
|
618
|
+
repository keep authenticating by design; the lever for those is the API-keys surface
|
|
619
|
+
(`revoke_repository_api_key`), not this one. Self-revocation is permitted — after it, the caller's
|
|
620
|
+
next request to the member routes answers `404`, not `403`. The repository owner's membership
|
|
621
|
+
cannot be removed at all. The same known limitation as the edit tool applies to `member_id`: no
|
|
622
|
+
endpoint serves it, so it comes from the platform's web members page today. Authorization is the
|
|
623
|
+
`members.manage` capability; a member without it is refused `403` with SpecGuard's own sentence,
|
|
624
|
+
verbatim.
|
|
625
|
+
|
|
626
|
+
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
627
|
+
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
628
|
+
|
|
629
|
+
### `rename_repository`
|
|
630
|
+
|
|
631
|
+
Renames a SpecGuard repository — changes the `org/repo` GitHub full name it is registered under —
|
|
632
|
+
keeping every API key, run and intent on it.
|
|
633
|
+
|
|
634
|
+
| argument | |
|
|
635
|
+
| --- | --- |
|
|
636
|
+
| `repository_id` | the id of the repository to rename — its numeric `id`, as `add_repository` returns and `list_repositories` reports, not the `org/repo` handle |
|
|
637
|
+
| `github_full_name` | the new GitHub full name, `org/repo` — sent top-level in the body, not nested under `repository` |
|
|
638
|
+
|
|
639
|
+
This is the alternative to the remove-and-re-register path: that one **deletes every API key, run
|
|
640
|
+
and intent** on the repository (`remove_repository`), while this keeps all of them. **Authorization
|
|
641
|
+
is owner-only** — deliberately narrower than removal: a member granted `repo.delete` may destroy
|
|
642
|
+
the repository but may not rename it. The owner check also redeems a browser-issued grant valid for
|
|
643
|
+
7 days; a nil or stale one is refused `403` with SpecGuard's own sentence naming the fix
|
|
644
|
+
(re-grant via the browser). A name another repository already holds is refused `400` — `taken`, not
|
|
645
|
+
`409` — verbatim. The `200` body is `{repository: …}` in the same shape `list_repositories` serves.
|
|
646
|
+
|
|
647
|
+
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
648
|
+
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
649
|
+
|
|
501
650
|
## How it works
|
|
502
651
|
|
|
503
652
|
```
|
|
@@ -25,6 +25,18 @@ export declare function getJson(api: ApiConfig, path: string, query: Record<stri
|
|
|
25
25
|
* send a body whose `Content-Type` says JSON and whose bytes are not.
|
|
26
26
|
*/
|
|
27
27
|
export declare function postJson(api: ApiConfig, path: string, body: Record<string, unknown>, fetchImpl: typeof globalThis.fetch): Promise<unknown>;
|
|
28
|
+
/**
|
|
29
|
+
* `PATCH` with a JSON body — the mutating-without-replacing half of the
|
|
30
|
+
* transport, and deliberately the SAME function underneath `postJson`, for the
|
|
31
|
+
* reason that header states: everything expensive about this module is about
|
|
32
|
+
* the deadline, not the verb.
|
|
33
|
+
*
|
|
34
|
+
* Routed through `requestJson` rather than `deleteJson`'s raw-body handling,
|
|
35
|
+
* because every PATCH this surface serves answers `200` WITH a JSON body —
|
|
36
|
+
* `requestJson`'s parse is correct here, and re-deriving success handling would
|
|
37
|
+
* be a third copy of the one status check.
|
|
38
|
+
*/
|
|
39
|
+
export declare function patchJson(api: ApiConfig, path: string, body: Record<string, unknown>, fetchImpl: typeof globalThis.fetch): Promise<unknown>;
|
|
28
40
|
/**
|
|
29
41
|
* `DELETE` — the destructive half of the transport, and deliberately the SAME
|
|
30
42
|
* function underneath `postJson` rather than beside it, for the reason
|
|
@@ -58,6 +70,13 @@ export declare function deleteJson(api: ApiConfig, path: string, fetchImpl: type
|
|
|
58
70
|
* answers with an array.
|
|
59
71
|
*/
|
|
60
72
|
export declare function postJsonObject(api: ApiConfig, path: string, body: Record<string, unknown>, fetchImpl: typeof globalThis.fetch): Promise<Record<string, unknown>>;
|
|
73
|
+
/**
|
|
74
|
+
* `patchJson`, narrowed exactly as `postJsonObject` narrows `postJson` — same
|
|
75
|
+
* guard, same sentence, same reason: `ToolResult.structured` is a
|
|
76
|
+
* `Record<string, unknown>`, so no tool should re-type the three-clause check
|
|
77
|
+
* on this verb either.
|
|
78
|
+
*/
|
|
79
|
+
export declare function patchJsonObject(api: ApiConfig, path: string, body: Record<string, unknown>, fetchImpl: typeof globalThis.fetch): Promise<Record<string, unknown>>;
|
|
61
80
|
/**
|
|
62
81
|
* `getJson`, narrowed to the object every tool here actually asks it for.
|
|
63
82
|
*
|
|
@@ -38,6 +38,23 @@ export async function postJson(api, path, body, fetchImpl) {
|
|
|
38
38
|
body: JSON.stringify(body),
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* `PATCH` with a JSON body — the mutating-without-replacing half of the
|
|
43
|
+
* transport, and deliberately the SAME function underneath `postJson`, for the
|
|
44
|
+
* reason that header states: everything expensive about this module is about
|
|
45
|
+
* the deadline, not the verb.
|
|
46
|
+
*
|
|
47
|
+
* Routed through `requestJson` rather than `deleteJson`'s raw-body handling,
|
|
48
|
+
* because every PATCH this surface serves answers `200` WITH a JSON body —
|
|
49
|
+
* `requestJson`'s parse is correct here, and re-deriving success handling would
|
|
50
|
+
* be a third copy of the one status check.
|
|
51
|
+
*/
|
|
52
|
+
export async function patchJson(api, path, body, fetchImpl) {
|
|
53
|
+
return requestJson(new URL(`${api.endpoint}${path}`), api, fetchImpl, {
|
|
54
|
+
method: "PATCH",
|
|
55
|
+
body: JSON.stringify(body),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
41
58
|
/**
|
|
42
59
|
* `DELETE` — the destructive half of the transport, and deliberately the SAME
|
|
43
60
|
* function underneath `postJson` rather than beside it, for the reason
|
|
@@ -78,6 +95,15 @@ export async function deleteJson(api, path, fetchImpl) {
|
|
|
78
95
|
export async function postJsonObject(api, path, body, fetchImpl) {
|
|
79
96
|
return asJsonObject(await postJson(api, path, body, fetchImpl));
|
|
80
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* `patchJson`, narrowed exactly as `postJsonObject` narrows `postJson` — same
|
|
100
|
+
* guard, same sentence, same reason: `ToolResult.structured` is a
|
|
101
|
+
* `Record<string, unknown>`, so no tool should re-type the three-clause check
|
|
102
|
+
* on this verb either.
|
|
103
|
+
*/
|
|
104
|
+
export async function patchJsonObject(api, path, body, fetchImpl) {
|
|
105
|
+
return asJsonObject(await patchJson(api, path, body, fetchImpl));
|
|
106
|
+
}
|
|
81
107
|
/**
|
|
82
108
|
* Everything both verbs do with a response, in one place.
|
|
83
109
|
*
|
|
@@ -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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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ToolDefinition } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* `POST /api/v1/repositories/:repository_id/members` as a tool — shipped in the
|
|
4
|
+
* platform (`specguard/config/routes.rb`,
|
|
5
|
+
* `Api::V1::UserRepositoryMembersController#create`, SPGD-875).
|
|
6
|
+
*
|
|
7
|
+
* == The handle is the LOGIN itself
|
|
8
|
+
*
|
|
9
|
+
* `User.resolve_by_handle` refuses a profile URL and a display name with its
|
|
10
|
+
* own sentence ("Send the login itself — octocat, not a profile URL or a
|
|
11
|
+
* display name"), and each non-`:found` resolution — never-signed-in,
|
|
12
|
+
* archived, ambiguous, malformed — arrives as a distinguishable 400 sentence
|
|
13
|
+
* through the landed `refusalMessage` branch. This bridge does not re-derive
|
|
14
|
+
* that vocabulary: a client-side copy is a rule with no owner, free to drift
|
|
15
|
+
* from the one that actually decides.
|
|
16
|
+
*
|
|
17
|
+
* == The grantor is always the authenticated principal
|
|
18
|
+
*
|
|
19
|
+
* `granted_by_user` is stamped server-side from the `sgu_` credential and is
|
|
20
|
+
* deliberately absent from the permitted params. The tool therefore takes no
|
|
21
|
+
* grantor argument, and no caller can name one.
|
|
22
|
+
*
|
|
23
|
+
* == The 201 body omits the membership id, by server design
|
|
24
|
+
*
|
|
25
|
+
* `#serialize` serves `handle`, `permissions`, `granted_by`, `created_at` —
|
|
26
|
+
* and no id, because ids are not portable between repositories and serving
|
|
27
|
+
* one invites treating it as portable. See
|
|
28
|
+
* `update_repository_member_permissions` for where the id comes from today.
|
|
29
|
+
*/
|
|
30
|
+
declare const addRepositoryMember: ToolDefinition;
|
|
31
|
+
export default addRepositoryMember;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { postJsonObject, requireUserApiConfig } from "../support/specguard-api.js";
|
|
2
|
+
import { optionalStringArray, requireString } from "./args.js";
|
|
3
|
+
/**
|
|
4
|
+
* `POST /api/v1/repositories/:repository_id/members` as a tool — shipped in the
|
|
5
|
+
* platform (`specguard/config/routes.rb`,
|
|
6
|
+
* `Api::V1::UserRepositoryMembersController#create`, SPGD-875).
|
|
7
|
+
*
|
|
8
|
+
* == The handle is the LOGIN itself
|
|
9
|
+
*
|
|
10
|
+
* `User.resolve_by_handle` refuses a profile URL and a display name with its
|
|
11
|
+
* own sentence ("Send the login itself — octocat, not a profile URL or a
|
|
12
|
+
* display name"), and each non-`:found` resolution — never-signed-in,
|
|
13
|
+
* archived, ambiguous, malformed — arrives as a distinguishable 400 sentence
|
|
14
|
+
* through the landed `refusalMessage` branch. This bridge does not re-derive
|
|
15
|
+
* that vocabulary: a client-side copy is a rule with no owner, free to drift
|
|
16
|
+
* from the one that actually decides.
|
|
17
|
+
*
|
|
18
|
+
* == The grantor is always the authenticated principal
|
|
19
|
+
*
|
|
20
|
+
* `granted_by_user` is stamped server-side from the `sgu_` credential and is
|
|
21
|
+
* deliberately absent from the permitted params. The tool therefore takes no
|
|
22
|
+
* grantor argument, and no caller can name one.
|
|
23
|
+
*
|
|
24
|
+
* == The 201 body omits the membership id, by server design
|
|
25
|
+
*
|
|
26
|
+
* `#serialize` serves `handle`, `permissions`, `granted_by`, `created_at` —
|
|
27
|
+
* and no id, because ids are not portable between repositories and serving
|
|
28
|
+
* one invites treating it as portable. See
|
|
29
|
+
* `update_repository_member_permissions` for where the id comes from today.
|
|
30
|
+
*/
|
|
31
|
+
const addRepositoryMember = {
|
|
32
|
+
name: "add_repository_member",
|
|
33
|
+
title: "Add repository member",
|
|
34
|
+
description: "Grants a person access to a SpecGuard repository by their GitHub handle, with an optional " +
|
|
35
|
+
"list of permissions. " +
|
|
36
|
+
"The `handle` is the LOGIN itself — `octocat`, not a profile URL and not a display name: " +
|
|
37
|
+
"SpecGuard refuses each of those with its own sentence, and every other resolution failure " +
|
|
38
|
+
"(nobody has signed in as that handle yet, the account is archived, the handle is ambiguous) " +
|
|
39
|
+
"arrives as a distinguishable 400 message naming the exact next move. " +
|
|
40
|
+
"The grantor recorded on the membership is always the person behind this server's user API " +
|
|
41
|
+
"key — the server stamps it, and no argument can name a different one. " +
|
|
42
|
+
"On success (201) the response carries a `member` block (`handle`, `permissions`, " +
|
|
43
|
+
"`granted_by`, `created_at`). It carries NO membership id, by design: ids are not portable " +
|
|
44
|
+
"between repositories, and editing or revoking a membership names a membership id obtained " +
|
|
45
|
+
"from the platform (today only via the web members page) — see the edit/revoke tools. " +
|
|
46
|
+
"Permissions are strings from SpecGuard's own set (`view`, `keys.manage`, `members.manage`, " +
|
|
47
|
+
"`repo.delete`); an unknown value is refused in SpecGuard's own words, and omitting the " +
|
|
48
|
+
"list grants access with no additional permissions. The repository owner cannot be added " +
|
|
49
|
+
"(they hold everything by construction). " +
|
|
50
|
+
"Authorization is the `members.manage` capability — a member without it is refused 403 in " +
|
|
51
|
+
"SpecGuard's own words. " +
|
|
52
|
+
"Takes `repository_id` — the numeric id `list_repositories` reports, not the `org/repo` " +
|
|
53
|
+
"handle. " +
|
|
54
|
+
"Needs SPECGUARD_USER_API_KEY (an sgu_… key), the same credential `add_repository` " +
|
|
55
|
+
"writes with 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 to grant access to — its numeric id, as `add_repository` " +
|
|
62
|
+
"returns and `list_repositories` reports, not the `org/repo` handle.",
|
|
63
|
+
},
|
|
64
|
+
handle: {
|
|
65
|
+
type: "string",
|
|
66
|
+
description: "The GitHub login of the person to add, e.g. `octocat` — not a profile URL and not a " +
|
|
67
|
+
"display name; SpecGuard refuses both with its own sentence. The person must have " +
|
|
68
|
+
"signed in to SpecGuard at least once.",
|
|
69
|
+
},
|
|
70
|
+
permissions: {
|
|
71
|
+
type: "array",
|
|
72
|
+
items: { type: "string" },
|
|
73
|
+
description: "An optional list of permission strings from SpecGuard's own set (`view`, " +
|
|
74
|
+
"`keys.manage`, `members.manage`, `repo.delete`). Omit it to grant access with no " +
|
|
75
|
+
"additional permissions. SpecGuard validates the values and refuses an unknown one " +
|
|
76
|
+
"in its own words.",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
required: ["repository_id", "handle"],
|
|
80
|
+
// Closed for the reason every tool here states — and on a WRITE, a silently
|
|
81
|
+
// dropped misspelled argument still grants something, just not what the
|
|
82
|
+
// agent believed it was asking for.
|
|
83
|
+
additionalProperties: false,
|
|
84
|
+
},
|
|
85
|
+
async run(args, context) {
|
|
86
|
+
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
87
|
+
const handle = requireString(args["handle"], "handle");
|
|
88
|
+
const permissions = optionalStringArray(args["permissions"], "permissions");
|
|
89
|
+
const api = requireUserApiConfig(context.config);
|
|
90
|
+
// Top-level `{handle, permissions}` — the shape the controller permits,
|
|
91
|
+
// matching `add_repository`'s stated rule: this is JSON an agent writes,
|
|
92
|
+
// not a Rails form. `permissions` omitted when absent so the server's own
|
|
93
|
+
// default applies; passed through as an ARRAY when present (the column is
|
|
94
|
+
// `text[]`, and a scalar on the wire is silently dropped server-side).
|
|
95
|
+
const created = await postJsonObject(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/members`, permissions === undefined ? { handle } : { handle, permissions }, context.fetch);
|
|
96
|
+
// Unreshaped, the standing rule — and the 201 body is the only answer this
|
|
97
|
+
// verb gives; nothing here exists to re-fetch elsewhere.
|
|
98
|
+
return {
|
|
99
|
+
text: JSON.stringify(created, null, 2),
|
|
100
|
+
structured: created,
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
export default addRepositoryMember;
|
|
105
|
+
//# sourceMappingURL=add-repository-member.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-repository-member.js","sourceRoot":"","sources":["../../../src/tools/add-repository-member.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG/D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,mBAAmB,GAAmB;IAC1C,IAAI,EAAE,uBAAuB;IAC7B,KAAK,EAAE,uBAAuB;IAC9B,WAAW,EACT,4FAA4F;QAC5F,uBAAuB;QACvB,0FAA0F;QAC1F,4FAA4F;QAC5F,8FAA8F;QAC9F,uEAAuE;QACvE,4FAA4F;QAC5F,wEAAwE;QACxE,mFAAmF;QACnF,4FAA4F;QAC5F,4FAA4F;QAC5F,uFAAuF;QACvF,6FAA6F;QAC7F,yFAAyF;QACzF,0FAA0F;QAC1F,0CAA0C;QAC1C,2FAA2F;QAC3F,yBAAyB;QACzB,yFAAyF;QACzF,UAAU;QACV,oFAAoF;QACpF,+FAA+F;IACjG,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,0EAA0E;oBAC1E,qEAAqE;aACxE;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,sFAAsF;oBACtF,mFAAmF;oBACnF,uCAAuC;aAC1C;YACD,WAAW,EAAE;gBACX,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACzB,WAAW,EACT,2EAA2E;oBAC3E,mFAAmF;oBACnF,oFAAoF;oBACpF,mBAAmB;aACtB;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,EAAE,QAAQ,CAAC;QACrC,4EAA4E;QAC5E,wEAAwE;QACxE,oCAAoC;QACpC,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,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,CAAC;QAE5E,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,wEAAwE;QACxE,yEAAyE;QACzE,0EAA0E;QAC1E,0EAA0E;QAC1E,uEAAuE;QACvE,MAAM,OAAO,GAAG,MAAM,cAAc,CAClC,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,UAAU,EAClE,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAChE,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,2EAA2E;QAC3E,yDAAyD;QACzD,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,mBAAmB,CAAC"}
|
package/dist/src/tools/args.d.ts
CHANGED
|
@@ -66,3 +66,29 @@ export declare function optionalString(value: unknown, field: string): string |
|
|
|
66
66
|
*/
|
|
67
67
|
export declare function requireString(value: unknown, field: string): string;
|
|
68
68
|
export declare function optionalBoolean(value: unknown, field: string): boolean | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* An optional array of non-blank strings, or nothing.
|
|
71
|
+
*
|
|
72
|
+
* The SHAPE-ONLY sibling of the linter's `optionalStringArray` (which stays in
|
|
73
|
+
* `lint-intent-annotations.ts` because its refusals — empty list, leading dash
|
|
74
|
+
* — are about the linter's own argument grammar and throw `CommandError`). This
|
|
75
|
+
* one answers only "is it an array of strings" and always throws
|
|
76
|
+
* `ArgumentError`, which is what a pass-through array of permission names
|
|
77
|
+
* needs: the platform is the authority on which strings are legal, and a
|
|
78
|
+
* client-side copy of that rule is a rule with no owner, free to drift from the
|
|
79
|
+
* one that actually decides.
|
|
80
|
+
*/
|
|
81
|
+
export declare function optionalStringArray(value: unknown, field: string): string[] | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* A mandatory array of non-blank strings, and nothing else will do.
|
|
84
|
+
*
|
|
85
|
+
* The mandatory counterpart of `optionalStringArray`, added with
|
|
86
|
+
* `update_repository_member_permissions` (SPGD-885): the server column behind
|
|
87
|
+
* that call is `text[]`, and a scalar on the wire is silently dropped
|
|
88
|
+
* server-side — so the array shape is checked HERE, before a write, rather
|
|
89
|
+
* than persisted as a member holding nothing. Blank entries are dropped rather
|
|
90
|
+
* than refused: the server's own normalisation does the same, so refusing here
|
|
91
|
+
* would be a second vocabulary the caller must satisfy before the one that
|
|
92
|
+
* decides even sees the request.
|
|
93
|
+
*/
|
|
94
|
+
export declare function requireStringArray(value: unknown, field: string): string[];
|
package/dist/src/tools/args.js
CHANGED
|
@@ -93,4 +93,56 @@ export function optionalBoolean(value, field) {
|
|
|
93
93
|
throw new ArgumentError(`\`${field}\` must be a boolean.`);
|
|
94
94
|
return value;
|
|
95
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* An optional array of non-blank strings, or nothing.
|
|
98
|
+
*
|
|
99
|
+
* The SHAPE-ONLY sibling of the linter's `optionalStringArray` (which stays in
|
|
100
|
+
* `lint-intent-annotations.ts` because its refusals — empty list, leading dash
|
|
101
|
+
* — are about the linter's own argument grammar and throw `CommandError`). This
|
|
102
|
+
* one answers only "is it an array of strings" and always throws
|
|
103
|
+
* `ArgumentError`, which is what a pass-through array of permission names
|
|
104
|
+
* needs: the platform is the authority on which strings are legal, and a
|
|
105
|
+
* client-side copy of that rule is a rule with no owner, free to drift from the
|
|
106
|
+
* one that actually decides.
|
|
107
|
+
*/
|
|
108
|
+
export function optionalStringArray(value, field) {
|
|
109
|
+
if (value === undefined || value === null)
|
|
110
|
+
return undefined;
|
|
111
|
+
if (!Array.isArray(value))
|
|
112
|
+
throw new ArgumentError(`\`${field}\` must be an array of strings.`);
|
|
113
|
+
const entries = value.map((entry) => {
|
|
114
|
+
if (typeof entry !== "string")
|
|
115
|
+
throw new ArgumentError(`\`${field}\` must contain only strings.`);
|
|
116
|
+
// Trimmed like its scalar siblings: a value an agent produced by
|
|
117
|
+
// concatenating strings arrives with whitespace that is not part of what it
|
|
118
|
+
// meant to send.
|
|
119
|
+
return entry.trim();
|
|
120
|
+
});
|
|
121
|
+
return entries;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* A mandatory array of non-blank strings, and nothing else will do.
|
|
125
|
+
*
|
|
126
|
+
* The mandatory counterpart of `optionalStringArray`, added with
|
|
127
|
+
* `update_repository_member_permissions` (SPGD-885): the server column behind
|
|
128
|
+
* that call is `text[]`, and a scalar on the wire is silently dropped
|
|
129
|
+
* server-side — so the array shape is checked HERE, before a write, rather
|
|
130
|
+
* than persisted as a member holding nothing. Blank entries are dropped rather
|
|
131
|
+
* than refused: the server's own normalisation does the same, so refusing here
|
|
132
|
+
* would be a second vocabulary the caller must satisfy before the one that
|
|
133
|
+
* decides even sees the request.
|
|
134
|
+
*/
|
|
135
|
+
export function requireStringArray(value, field) {
|
|
136
|
+
if (value === undefined || value === null) {
|
|
137
|
+
throw new ArgumentError(`\`${field}\` is required.`);
|
|
138
|
+
}
|
|
139
|
+
if (!Array.isArray(value))
|
|
140
|
+
throw new ArgumentError(`\`${field}\` must be an array of strings.`);
|
|
141
|
+
const entries = value.map((entry) => {
|
|
142
|
+
if (typeof entry !== "string")
|
|
143
|
+
throw new ArgumentError(`\`${field}\` must contain only strings.`);
|
|
144
|
+
return entry.trim();
|
|
145
|
+
});
|
|
146
|
+
return entries.filter((entry) => entry !== "");
|
|
147
|
+
}
|
|
96
148
|
//# sourceMappingURL=args.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../../src/tools/args.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc,EAAE,KAAa;IAC1D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,MAAM,IAAI,aAAa,CAAC,KAAK,KAAK,sBAAsB,CAAC,CAAC;IACzF,8EAA8E;IAC9E,gFAAgF;IAChF,2EAA2E;IAC3E,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,OAAO,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc,EAAE,KAAa;IACzD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,MAAM,IAAI,aAAa,CAAC,KAAK,KAAK,iBAAiB,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,MAAM,IAAI,aAAa,CAAC,KAAK,KAAK,sBAAsB,CAAC,CAAC;IAEzF,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,KAAK,EAAE;QAAE,MAAM,IAAI,aAAa,CAAC,KAAK,KAAK,uBAAuB,CAAC,CAAC;IAE/E,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAc,EAAE,KAAa;IAC3D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5D,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,MAAM,IAAI,aAAa,CAAC,KAAK,KAAK,uBAAuB,CAAC,CAAC;IAC3F,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../../src/tools/args.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,12 +34,21 @@ import type { ToolDefinition } from "./types.js";
|
|
|
34
34
|
*
|
|
35
35
|
* == What is deliberately absent
|
|
36
36
|
*
|
|
37
|
-
* `/check-intent`
|
|
38
|
-
*
|
|
39
|
-
* advertised in `tools/list` is a
|
|
40
|
-
*
|
|
41
|
-
* and fails on use, which is worse than
|
|
42
|
-
* agent has already committed to a plan by
|
|
37
|
+
* `/check-intent` is NOT here and must not be added until its backing endpoint
|
|
38
|
+
* exists — `specguard/config/routes.rb:113` carries it as a comment only, which
|
|
39
|
+
* is the evidence this forbid rests on. A tool advertised in `tools/list` is a
|
|
40
|
+
* promise an agent will act on: wrapping an endpoint that does not exist would
|
|
41
|
+
* produce a server that discovers cleanly and fails on use, which is worse than
|
|
42
|
+
* not offering the tool, because the agent has already committed to a plan by
|
|
43
|
+
* the time it finds out.
|
|
44
|
+
*
|
|
45
|
+
* Duplicate clustering was once under this same forbid, on the same standing
|
|
46
|
+
* rule — no tool may wrap what has not shipped. That half retired when the
|
|
47
|
+
* platform moved: SPGD-703 (`specguard` `c43dc19`, 2026-08-28) shipped
|
|
48
|
+
* `GET /api/v1/repository?near_duplicates=`, serving
|
|
49
|
+
* `RepositoryOverview#serialized_near_duplicates` behind an opt-in ask, and
|
|
50
|
+
* `near_duplicate_clusters` below wraps it. What moved was the platform, not
|
|
51
|
+
* the bar.
|
|
43
52
|
*
|
|
44
53
|
* == The fourth: the first tool that WRITES
|
|
45
54
|
*
|
|
@@ -99,9 +108,44 @@ import type { ToolDefinition } from "./types.js";
|
|
|
99
108
|
* `requestJson`'s JSON parse.
|
|
100
109
|
*
|
|
101
110
|
* The standing rule itself is unchanged and still binding — which still keeps
|
|
102
|
-
* out `/check-intent
|
|
103
|
-
*
|
|
104
|
-
*
|
|
111
|
+
* out `/check-intent`: it has no backing endpoint (`routes.rb:113` mounts it
|
|
112
|
+
* as a comment only). A tool advertised in `tools/list` remains a promise an
|
|
113
|
+
* agent will act on.
|
|
114
|
+
*
|
|
115
|
+
* == The ninth through twelfth: member management
|
|
116
|
+
*
|
|
117
|
+
* - `list_repository_members`, `add_repository_member`,
|
|
118
|
+
* `update_repository_member_permissions` and `remove_repository_member`
|
|
119
|
+
* wrap the four `user_repository_members` endpoints (all shipped: SPGD-875,
|
|
120
|
+
* specguard@origin/main).
|
|
121
|
+
*
|
|
122
|
+
* They also forced the transport's fourth verb: `update` is a PATCH, which
|
|
123
|
+
* arrived with `patchJson` in this same slice — 200 with a JSON body, so it
|
|
124
|
+
* routes through `requestJson` like `postJson` rather than `deleteJson`'s
|
|
125
|
+
* raw-body handling.
|
|
126
|
+
*
|
|
127
|
+
* A known limitation rides with them and is stated in the edit/revoke tool
|
|
128
|
+
* descriptions rather than papered over: PATCH and DELETE name a membership by
|
|
129
|
+
* id, but no endpoint serves that id (the platform's `#serialize` deliberately
|
|
130
|
+
* omits it), so the id comes from the platform's web members page today. That
|
|
131
|
+
* is a platform-side follow-up, not a client-side workaround — there is no
|
|
132
|
+
* name-based lookup.
|
|
133
|
+
*
|
|
134
|
+
* == The thirteenth: rename
|
|
135
|
+
*
|
|
136
|
+
* - `rename_repository` wraps `PATCH /api/v1/repositories/:id` (shipped:
|
|
137
|
+
* SPGD-878, `specguard@origin/main` e026793, PR #266).
|
|
138
|
+
*
|
|
139
|
+
* This is the entry the forbid above once named as "the natural next slice" —
|
|
140
|
+
* the platform moved (SPGD-878 shipped the endpoint), so the forbid retired
|
|
141
|
+
* exactly as the duplicate-clustering one did. It reuses `patchJson` landed
|
|
142
|
+
* with the member-management slice rather than minting a transport of its own.
|
|
143
|
+
* The verb's one asymmetry is carried in the tool description rather than
|
|
144
|
+
* papered over: rename authorizes OWNER-ONLY, while removal authorizes the
|
|
145
|
+
* BROADER `repo.delete` capability — a member who may destroy the repository
|
|
146
|
+
* may not rename it. Before this tool the bridge's only rename path was
|
|
147
|
+
* remove-and-re-register, which destroys every key, run and intent; this one
|
|
148
|
+
* keeps them.
|
|
105
149
|
*/
|
|
106
150
|
export declare const TOOLS: readonly ToolDefinition[];
|
|
107
151
|
export type { ToolContext, ToolDefinition, ToolResult } from "./types.js";
|