specguard-mcp 0.1.38 → 0.1.40
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 +62 -7
- package/dist/src/config.d.ts +2 -2
- package/dist/src/config.js +1 -1
- package/dist/src/support/specguard-api.js +1 -1
- package/dist/src/tools/args.d.ts +11 -0
- package/dist/src/tools/args.js +20 -0
- package/dist/src/tools/args.js.map +1 -1
- package/dist/src/tools/find-tests-near-behavior.d.ts +40 -0
- package/dist/src/tools/find-tests-near-behavior.js +160 -0
- package/dist/src/tools/find-tests-near-behavior.js.map +1 -0
- package/dist/src/tools/index.d.ts +19 -1
- package/dist/src/tools/index.js +21 -1
- package/dist/src/tools/index.js.map +1 -1
- package/dist/src/tools/list-repositories.d.ts +5 -3
- package/dist/src/tools/list-repositories.js +17 -9
- package/dist/src/tools/list-repositories.js.map +1 -1
- package/dist/src/tools/list-repository-api-keys.js +4 -0
- package/dist/src/tools/list-repository-api-keys.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,14 +33,14 @@ refuses to boot and takes the tools that needed no configuration down with it.
|
|
|
33
33
|
| Variable | Needed by | Default | What it is |
|
|
34
34
|
| --- | --- | --- | --- |
|
|
35
35
|
| `SPECGUARD_ENDPOINT` | `get_repository_overview`, `get_intent_schema`, `get_server_version`, `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. `get_server_version` and `get_intent_schema` need only this variable — they send no API key, because the routes they read are unauthenticated by design |
|
|
36
|
-
| `SPECGUARD_API_KEY` | `get_repository_overview`, `near_duplicate_clusters` (default calls) | — | an agent/CI API key (`sgk_…`) issued by that deployment — a **per-repository** key, which is the single repository those tools answer about by default |
|
|
37
|
-
| `SPECGUARD_USER_API_KEY` | `list_repositories` (fallback), `add_repository`, `registrable_repositories`, `remove_repository` (fallback), `create_repository_api_key` (fallback), `revoke_repository_api_key` (fallback), `list_repository_api_keys` (fallback), `list_repository_agent_keys` (fallback), `revoke_repository_agent_key` (fallback), `list_repository_agent_keys_presented_revoked` (fallback), `list_repository_members` (fallback), `add_repository_member` (fallback), `update_repository_member_permissions` (fallback), `remove_repository_member` (fallback), `get_repository_overview` / `near_duplicate_clusters` **with** `repository` (fallback), `rename_repository` | — | a **user** API key (`sgu_…`), minted from that deployment's account page. A different credential from the one above, not a second place to put the same value: SpecGuard decides which of them a request may use from the token's prefix, before it reads anything, and answers `401` for the other one. Set whichever your tools need — both, if you use both |
|
|
38
|
-
| `SPECGUARD_AGENT_API_KEY` | `list_repositories` (preferred), `remove_repository` (preferred), `create_repository_api_key` (preferred), `revoke_repository_api_key` (preferred), `list_repository_api_keys` (preferred), `list_repository_agent_keys` (preferred), `revoke_repository_agent_key` (preferred), `list_repository_agent_keys_presented_revoked` (preferred), `list_repository_members` (preferred), `add_repository_member` (preferred), `update_repository_member_permissions` (preferred), `remove_repository_member` (preferred), `get_repository_overview` / `near_duplicate_clusters` **with** `repository` (preferred) | — | an **agent** API key (`sga_…`), minted from that deployment's account page (Agent keys panel) with an explicit set of repositories and permissions. It speaks for nobody: its reach is exactly the set granted onto it, fixed at mint time, and every read is bounded by that set server-side. This is the credential to give an automated agent — one key, many repositories, none of a person's rights. When it and `SPECGUARD_USER_API_KEY` are both set, every tool that answers either key — `list_repositories`, `remove_repository`, the members tools, the key-lifecycle tools, and `get_repository_overview` / `near_duplicate_clusters` **with** `repository` — uses **this** one, so discovery stays inside the set the other tools can reach |
|
|
36
|
+
| `SPECGUARD_API_KEY` | `get_repository_overview`, `near_duplicate_clusters`, `find_tests_near_behavior` (default calls) | — | an agent/CI API key (`sgk_…`) issued by that deployment — a **per-repository** key, which is the single repository those tools answer about by default |
|
|
37
|
+
| `SPECGUARD_USER_API_KEY` | `list_repositories` (fallback), `add_repository`, `registrable_repositories`, `remove_repository` (fallback), `create_repository_api_key` (fallback), `revoke_repository_api_key` (fallback), `list_repository_api_keys` (fallback), `list_repository_agent_keys` (fallback), `revoke_repository_agent_key` (fallback), `list_repository_agent_keys_presented_revoked` (fallback), `list_repository_members` (fallback), `add_repository_member` (fallback), `update_repository_member_permissions` (fallback), `remove_repository_member` (fallback), `get_repository_overview` / `near_duplicate_clusters` / `find_tests_near_behavior` **with** `repository` (fallback), `rename_repository` | — | a **user** API key (`sgu_…`), minted from that deployment's account page. A different credential from the one above, not a second place to put the same value: SpecGuard decides which of them a request may use from the token's prefix, before it reads anything, and answers `401` for the other one. Set whichever your tools need — both, if you use both |
|
|
38
|
+
| `SPECGUARD_AGENT_API_KEY` | `list_repositories` (preferred), `remove_repository` (preferred), `create_repository_api_key` (preferred), `revoke_repository_api_key` (preferred), `list_repository_api_keys` (preferred), `list_repository_agent_keys` (preferred), `revoke_repository_agent_key` (preferred), `list_repository_agent_keys_presented_revoked` (preferred), `list_repository_members` (preferred), `add_repository_member` (preferred), `update_repository_member_permissions` (preferred), `remove_repository_member` (preferred), `get_repository_overview` / `near_duplicate_clusters` / `find_tests_near_behavior` **with** `repository` (preferred) | — | an **agent** API key (`sga_…`), minted from that deployment's account page (Agent keys panel) with an explicit set of repositories and permissions. It speaks for nobody: its reach is exactly the set granted onto it, fixed at mint time, and every read is bounded by that set server-side. This is the credential to give an automated agent — one key, many repositories, none of a person's rights. When it and `SPECGUARD_USER_API_KEY` are both set, every tool that answers either key — `list_repositories`, `remove_repository`, the members tools, the key-lifecycle tools, and `get_repository_overview` / `near_duplicate_clusters` / `find_tests_near_behavior` **with** `repository` — uses **this** one, so discovery stays inside the set the other tools can reach |
|
|
39
39
|
| `SPECGUARD_LINT_COMMAND` | `lint_intent_annotations` | `specguard-lint` | the command that runs the linter — the one switch between the Ruby and the JS/TS client. Most Ruby projects need `bundle exec specguard-lint`; a JS/TS project sets `npx -p @yatfa/specguard specguard lint` (and needs the validator backend: a `validate-intent` binary whose path `SPECGUARD_VALIDATE_INTENT` names — today the only way to supply it) |
|
|
40
40
|
| `SPECGUARD_TIMEOUT_MS` | HTTP tools | `30000` | how long a call to SpecGuard may take |
|
|
41
41
|
|
|
42
42
|
`SPECGUARD_ENDPOINT` and `SPECGUARD_API_KEY` are the same variables
|
|
43
|
-
[`specguard-
|
|
43
|
+
[`specguard-ruby`](https://github.com/yatfa-ai/specguard-ruby) uses to ship a run, so a repository
|
|
44
44
|
that already posts telemetry to SpecGuard already has them. `SPECGUARD_USER_API_KEY` is **not** one
|
|
45
45
|
of them — the gem has no notion of a user key — so that one is minted and set here for the first
|
|
46
46
|
time.
|
|
@@ -500,7 +500,7 @@ blank value is no ask: passing an empty string and omitting the argument make th
|
|
|
500
500
|
| --- | --- |
|
|
501
501
|
| `q` | keep only repositories whose `full_name` (`org/repo`) contains this substring, case-insensitively. A plain substring, not a pattern — the LIKE wildcards `%`/`_` are escaped server-side, so `org/my_repo` matches itself. A match-less ask is an empty list, not an error |
|
|
502
502
|
| `role` | `"owned"` or `"shared"` — one half of the list's mix: the repositories this person owns, or the ones shared with them. Mind the spelling: the *ask* values are `owned`/`shared`, while each entry's `role` field reads `owner`/`member` — `role: "owner"` is not a valid ask and settles to no ask (full list, no error). Under the `sga_…` agent key the ask settles to no ask for every value: ownership is a person fact and the key speaks for nobody, so the full granted list is served |
|
|
503
|
-
| `sort` | `"stale"` — re-order stalest-first: repositories CI has never ingested a run for first, then least-recently-ingested, with `full_name` breaking ties so two calls agree element for element. The same entries, a different order; the default order stays `full_name` ascending |
|
|
503
|
+
| `sort` | `"stale"` — re-order stalest-first: repositories CI has never ingested a run for first, then least-recently-ingested, with `full_name` breaking ties so two calls agree element for element. `"annotated"` — re-order least-annotated share first: a suite measured at 0-of-N leads, repositories with no run or an unmeasured suite come last (never ranked as 0%), and `full_name` breaks ties. The same entries, a different order; the default order stays `full_name` ascending |
|
|
504
504
|
|
|
505
505
|
The body comes back as SpecGuard serves it — `{"repositories": […]}`, each entry carrying `id`,
|
|
506
506
|
`full_name`, `name`, `registered_at`, `role`, `delivery_health` and `latest_run`, ordered by
|
|
@@ -714,6 +714,57 @@ path's one deliberate omission: `api_key` is **absent** from the plural body rat
|
|
|
714
714
|
because the block describes the credential that made the request and no member credential is a
|
|
715
715
|
repository key (an absent key there is the surface's shape, never a dropped block).
|
|
716
716
|
|
|
717
|
+
### `find_tests_near_behavior`
|
|
718
|
+
|
|
719
|
+
Asks a repository's stored test suite map which tests are **nearest a behavior phrase** you give
|
|
720
|
+
it. The server embeds the phrase and ranks the repository's stored test identities by similarity,
|
|
721
|
+
returning the top hits in the `near` block (`GET /api/v1/repository?near=<phrase>`, or the plural
|
|
722
|
+
`GET /api/v1/repositories/:id?near=<phrase>`) — each hit with its similarity, its `signal_source`,
|
|
723
|
+
its last-known path and the weight the latest run measured.
|
|
724
|
+
|
|
725
|
+
| argument | |
|
|
726
|
+
| --- | --- |
|
|
727
|
+
| `behavior` | **required** — the behavior phrase, in plain words (e.g. "rejects an expired password reset token"). Trimmed and sent as `near`. Blank or whitespace-only is refused before any request, and so is a phrase containing a NUL (`\u0000`) character: the server would read either as no ask and answer the whole overview with `near: null`, which would look like an answered ask |
|
|
728
|
+
| `repository` | ask THIS repository (its numeric id from `list_repositories`) under the **agent key** (`SPECGUARD_AGENT_API_KEY`, `sga_…`), or — when no agent key is set — the **user key** (`SPECGUARD_USER_API_KEY`, `sgu_…`), instead of the one the `sgk_…` key resolves to — omit it for the default, `sgk_`-keyed ask |
|
|
729
|
+
| `limit` | optional integer page size, **1–50** — omit it for the default page of 10. Sent as `&limit=<n>` only when supplied, so an ask without it is the same request as before. The server clamps the ask to 50 and reports the value it applied as `limit` in the `near` block; a non-integer, zero or negative value is refused before any request |
|
|
730
|
+
|
|
731
|
+
**The answer is a page, not the set.** Read `truncated` and `limit` in the returned `near` block:
|
|
732
|
+
`limit` is the page size the server applied, and `truncated: true` means **more matches exist than
|
|
733
|
+
were returned** — a full page of 10 may be "10 of 37". When `truncated` is true, re-ask the **same
|
|
734
|
+
phrase** with a larger `limit` (max 50) before paraphrasing it: a repeated phrase is cache-served and
|
|
735
|
+
free, while each paraphrase is a novel phrase and one billed embed.
|
|
736
|
+
|
|
737
|
+
**What the answer is not.** It ranks *stored* tests nearest the phrase and **never answers "is this
|
|
738
|
+
already tested?"** — it never gates a write and never issues a verdict. A hit near the phrase is not
|
|
739
|
+
coverage, and an empty answer is not proof of absence. `similarity_floor` is the near-duplicate
|
|
740
|
+
census's redundancy bar, **not** the 0.95 matching threshold that decides whether two tests are the
|
|
741
|
+
same test. Read `similarity_basis` and `similarity_floor` before any figure.
|
|
742
|
+
|
|
743
|
+
**The three silences differ** — never collapse them, and `null` is never `[]`:
|
|
744
|
+
|
|
745
|
+
- `status` of `provider_unconfigured` or `embedding_failed` with `ranked: null` — no ranking was
|
|
746
|
+
attempted, or the provider refused (`error` carries its reason). This says nothing about the suite.
|
|
747
|
+
- `identity_count: 0` with `ranked: []` — the repository holds no identities; nothing has been
|
|
748
|
+
ingested.
|
|
749
|
+
- `ranked: []` with `identity_count` above zero and `best_below_floor_similarity` — identities exist,
|
|
750
|
+
the search ran, and none is near the phrase; the nearest one's similarity is served so "nothing
|
|
751
|
+
near" is a finding you can check.
|
|
752
|
+
|
|
753
|
+
`signal_sources` (the composition of the served page) and each hit's `signal_source` (matched on
|
|
754
|
+
declared intent, or on name) are different evidence — read the source before leaning on a hit.
|
|
755
|
+
|
|
756
|
+
**Cost.** Each *novel* phrase costs **one billed embedding call** at the provider; a repeated phrase
|
|
757
|
+
is served from the cache and costs nothing (`cache_served` says which happened). The ask is live —
|
|
758
|
+
computed on the request — unlike the stored census `near_duplicate_clusters` returns, and it is a
|
|
759
|
+
tool of its own so that a `get_repository_overview` call never pays an embed by accident.
|
|
760
|
+
|
|
761
|
+
Same endpoints and credentials as `get_repository_overview`: without `repository`, an `sgk_…`
|
|
762
|
+
repository key on `GET /api/v1/repository`; with `repository`, either member credential on the
|
|
763
|
+
plural endpoint — the agent key preferred, the user key when no agent key is set. A repository
|
|
764
|
+
outside the presented credential's grant answers 404 at the server. The response is that body with
|
|
765
|
+
the `near` block opened, passed through unmodified; on the plural path `api_key` is **absent** from
|
|
766
|
+
the body rather than nulled (the surface's shape, never a dropped block).
|
|
767
|
+
|
|
717
768
|
### `remove_repository`
|
|
718
769
|
|
|
719
770
|
Removes a repository from SpecGuard — and with it **every key, run and intent on it**. This is the
|
|
@@ -780,7 +831,11 @@ serves live rows only). One row per key: `id`, `name`, `token_hint`, `created_at
|
|
|
780
831
|
omitted — `rotated_at`, and `rotated_and_unused` (live-scoped: the stranded shape
|
|
781
832
|
`get_repository_overview`'s `credential_health` reports, at row grain). `status` is
|
|
782
833
|
`live`/`revoked`, with `revoked_at` present only on revoked rows — a revoked `sgk_` row is not a
|
|
783
|
-
credential either, but the rotation's story lives in the population.
|
|
834
|
+
credential either, but the rotation's story lives in the population. A **revoked** row also
|
|
835
|
+
serves `last_refused_at`: `null` means offboarding took (nothing has presented the dead token
|
|
836
|
+
since the cut), a timestamp means the dead token is still arriving and that row's `token_hint`
|
|
837
|
+
is what to hunt in the secret stores that may still hold it. Live rows carry no
|
|
838
|
+
`last_refused_at` key.
|
|
784
839
|
|
|
785
840
|
| argument | |
|
|
786
841
|
| --- | --- |
|
|
@@ -1146,7 +1201,7 @@ npm run typecheck # types only
|
|
|
1146
1201
|
## Related repositories
|
|
1147
1202
|
|
|
1148
1203
|
- [`specguard`](https://github.com/yatfa-ai/specguard) — the platform: ingest API + Hotwire dashboard
|
|
1149
|
-
- [`specguard-
|
|
1204
|
+
- [`specguard-ruby`](https://github.com/yatfa-ai/specguard-ruby) — Ruby client (RSpec formatter, Minitest reporter + `@intent` linter)
|
|
1150
1205
|
- [`open-test-intent`](https://github.com/yatfa-ai/open-test-intent) — the annotation protocol SpecGuard consumes
|
|
1151
1206
|
|
|
1152
1207
|
## License
|
package/dist/src/config.d.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
* == SPECGUARD_ENDPOINT, with SPECGUARD_URL as an accepted alias
|
|
21
21
|
*
|
|
22
|
-
* `SPECGUARD_ENDPOINT` is the name the shipped `specguard-
|
|
22
|
+
* `SPECGUARD_ENDPOINT` is the name the shipped `specguard-ruby` gem already
|
|
23
23
|
* reads, so a repository whose CI posts runs to SpecGuard has it set — that is
|
|
24
24
|
* the whole reason this server borrows the name rather than coining one. The
|
|
25
25
|
* SPGD-310 brief writes it as `SPECGUARD_URL`, so that spelling is accepted
|
|
@@ -222,7 +222,7 @@ export declare const REPOSITORY_CREDENTIAL: Credential;
|
|
|
222
222
|
/**
|
|
223
223
|
* The `sgu_` key: a person, and a variable nothing else in the toolchain reads.
|
|
224
224
|
*
|
|
225
|
-
* `specguard-
|
|
225
|
+
* `specguard-ruby` ships runs with an `sgk_` key and has no notion of this one,
|
|
226
226
|
* so an operator who already has CI reporting to SpecGuard does NOT already
|
|
227
227
|
* have this variable — which is why the message says where to mint one rather
|
|
228
228
|
* than assuming it is lying around.
|
package/dist/src/config.js
CHANGED
|
@@ -47,7 +47,7 @@ export const REPOSITORY_CREDENTIAL = {
|
|
|
47
47
|
/**
|
|
48
48
|
* The `sgu_` key: a person, and a variable nothing else in the toolchain reads.
|
|
49
49
|
*
|
|
50
|
-
* `specguard-
|
|
50
|
+
* `specguard-ruby` ships runs with an `sgk_` key and has no notion of this one,
|
|
51
51
|
* so an operator who already has CI reporting to SpecGuard does NOT already
|
|
52
52
|
* have this variable — which is why the message says where to mint one rather
|
|
53
53
|
* than assuming it is lying around.
|
|
@@ -272,7 +272,7 @@ async function requestUserAgent() {
|
|
|
272
272
|
* ONE TOTAL BUDGET, not one per phase. `requestTimeoutMs` bounds the whole call:
|
|
273
273
|
* headers and body share it, so a response whose headers took 29s of a 30s
|
|
274
274
|
* budget has 1s left in which to deliver its body. The sibling transport in
|
|
275
|
-
* `specguard-
|
|
275
|
+
* `specguard-ruby` (`lib/specguard/client/transport.rb`) gives each phase its own
|
|
276
276
|
* full `@timeout` because `Net::HTTP` exposes exactly that knob and no other;
|
|
277
277
|
* here the deadline is ours to place, and a single total is both stricter and
|
|
278
278
|
* the thing an operator who set one number actually meant.
|
package/dist/src/tools/args.d.ts
CHANGED
|
@@ -66,6 +66,17 @@ 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
|
+
* A positive integer, or nothing.
|
|
71
|
+
*
|
|
72
|
+
* Accepts only a finite JSON number with no fractional part that is >= 1. A
|
|
73
|
+
* numeric string ("10"), a float (2.5), zero, a negative, NaN and Infinity all
|
|
74
|
+
* throw `ArgumentError` — the same class every other shape check here throws.
|
|
75
|
+
* No upper bound is applied: a ceiling is the callee's to own (the server
|
|
76
|
+
* clamps and reports the value it applied), and the one a tool's schema
|
|
77
|
+
* advertises is the schema's to declare, not this helper's to duplicate.
|
|
78
|
+
*/
|
|
79
|
+
export declare function optionalPositiveInteger(value: unknown, field: string): number | undefined;
|
|
69
80
|
/**
|
|
70
81
|
* An optional array of non-blank strings, or nothing.
|
|
71
82
|
*
|
package/dist/src/tools/args.js
CHANGED
|
@@ -93,6 +93,26 @@ export function optionalBoolean(value, field) {
|
|
|
93
93
|
throw new ArgumentError(`\`${field}\` must be a boolean.`);
|
|
94
94
|
return value;
|
|
95
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* A positive integer, or nothing.
|
|
98
|
+
*
|
|
99
|
+
* Accepts only a finite JSON number with no fractional part that is >= 1. A
|
|
100
|
+
* numeric string ("10"), a float (2.5), zero, a negative, NaN and Infinity all
|
|
101
|
+
* throw `ArgumentError` — the same class every other shape check here throws.
|
|
102
|
+
* No upper bound is applied: a ceiling is the callee's to own (the server
|
|
103
|
+
* clamps and reports the value it applied), and the one a tool's schema
|
|
104
|
+
* advertises is the schema's to declare, not this helper's to duplicate.
|
|
105
|
+
*/
|
|
106
|
+
export function optionalPositiveInteger(value, field) {
|
|
107
|
+
if (value === undefined || value === null)
|
|
108
|
+
return undefined;
|
|
109
|
+
if (typeof value !== "number" || !Number.isInteger(value)) {
|
|
110
|
+
throw new ArgumentError(`\`${field}\` must be an integer.`);
|
|
111
|
+
}
|
|
112
|
+
if (value < 1)
|
|
113
|
+
throw new ArgumentError(`\`${field}\` must be at least 1.`);
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
96
116
|
/**
|
|
97
117
|
* An optional array of non-blank strings, or nothing.
|
|
98
118
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../../src/tools/args.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../../src/tools/args.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ToolDefinition } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* `GET /api/v1/repository?near=<behavior phrase>` as a tool — the bridge half
|
|
4
|
+
* of roadmap SPGD-1102 ("Ask the suite map"), slice 3. The platform half
|
|
5
|
+
* shipped first: `RequestedNearParam` guards the ask and `NearProbe` answers
|
|
6
|
+
* it, behind the `near` block of `RepositoryOverview`, on both overview doors
|
|
7
|
+
* (the singular `GET /api/v1/repository` under an `sgk_` key, the plural
|
|
8
|
+
* `GET /api/v1/repositories/:id` under an agent or user key).
|
|
9
|
+
*
|
|
10
|
+
* == Why a SEPARATE tool, and not a parameter on `get_repository_overview`
|
|
11
|
+
*
|
|
12
|
+
* Every other ask on the overview is free or stored. This one is LIVE and
|
|
13
|
+
* BILLED: a novel phrase costs one embedding call at the provider (a repeated
|
|
14
|
+
* phrase is served from the embedding cache and buys nothing). An agent
|
|
15
|
+
* calling the overview must never pay an embed by accident, and an agent
|
|
16
|
+
* calling this tool has asked for nothing else — the same line
|
|
17
|
+
* `near_duplicate_clusters` draws for the census, drawn here for a cost that
|
|
18
|
+
* is per-call rather than per-ingest.
|
|
19
|
+
*
|
|
20
|
+
* == The phrase is sent trimmed, and a NUL is refused HERE
|
|
21
|
+
*
|
|
22
|
+
* `requireString` trims and refuses blank. The NUL refusal is the bridge's to
|
|
23
|
+
* make, because the server's guard treats a NUL-containing, blank or
|
|
24
|
+
* non-String `near` as NO ASK and answers the plain overview with `near:
|
|
25
|
+
* null` — a 200 that would read, to an agent that sent a phrase, as an
|
|
26
|
+
* answered ask. Refusing client-side keeps "asked, nothing came back" and
|
|
27
|
+
* "never asked" from sharing one wire shape.
|
|
28
|
+
*
|
|
29
|
+
* == The response is passed through, not re-modelled
|
|
30
|
+
*
|
|
31
|
+
* Same rule as `near-duplicate-clusters.ts`. The `near` block's shape carries
|
|
32
|
+
* distinctions the serializer spent care on — `ranked: null` (no ranking was
|
|
33
|
+
* attempted: `provider_unconfigured` / `embedding_failed`) versus `ranked: []`
|
|
34
|
+
* (the search ran and found nothing near), and, inside the latter,
|
|
35
|
+
* `identity_count: 0` versus `identity_count > 0` with
|
|
36
|
+
* `best_below_floor_similarity`. Coalescing any of them would turn three
|
|
37
|
+
* different silences into one. The body goes back as it arrived.
|
|
38
|
+
*/
|
|
39
|
+
declare const findTestsNearBehavior: ToolDefinition;
|
|
40
|
+
export default findTestsNearBehavior;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { ArgumentError } from "../errors.js";
|
|
2
|
+
import { getJsonObject, repositoryTarget } from "../support/specguard-api.js";
|
|
3
|
+
import { optionalPositiveInteger, optionalString, requireString } from "./args.js";
|
|
4
|
+
/**
|
|
5
|
+
* `GET /api/v1/repository?near=<behavior phrase>` as a tool — the bridge half
|
|
6
|
+
* of roadmap SPGD-1102 ("Ask the suite map"), slice 3. The platform half
|
|
7
|
+
* shipped first: `RequestedNearParam` guards the ask and `NearProbe` answers
|
|
8
|
+
* it, behind the `near` block of `RepositoryOverview`, on both overview doors
|
|
9
|
+
* (the singular `GET /api/v1/repository` under an `sgk_` key, the plural
|
|
10
|
+
* `GET /api/v1/repositories/:id` under an agent or user key).
|
|
11
|
+
*
|
|
12
|
+
* == Why a SEPARATE tool, and not a parameter on `get_repository_overview`
|
|
13
|
+
*
|
|
14
|
+
* Every other ask on the overview is free or stored. This one is LIVE and
|
|
15
|
+
* BILLED: a novel phrase costs one embedding call at the provider (a repeated
|
|
16
|
+
* phrase is served from the embedding cache and buys nothing). An agent
|
|
17
|
+
* calling the overview must never pay an embed by accident, and an agent
|
|
18
|
+
* calling this tool has asked for nothing else — the same line
|
|
19
|
+
* `near_duplicate_clusters` draws for the census, drawn here for a cost that
|
|
20
|
+
* is per-call rather than per-ingest.
|
|
21
|
+
*
|
|
22
|
+
* == The phrase is sent trimmed, and a NUL is refused HERE
|
|
23
|
+
*
|
|
24
|
+
* `requireString` trims and refuses blank. The NUL refusal is the bridge's to
|
|
25
|
+
* make, because the server's guard treats a NUL-containing, blank or
|
|
26
|
+
* non-String `near` as NO ASK and answers the plain overview with `near:
|
|
27
|
+
* null` — a 200 that would read, to an agent that sent a phrase, as an
|
|
28
|
+
* answered ask. Refusing client-side keeps "asked, nothing came back" and
|
|
29
|
+
* "never asked" from sharing one wire shape.
|
|
30
|
+
*
|
|
31
|
+
* == The response is passed through, not re-modelled
|
|
32
|
+
*
|
|
33
|
+
* Same rule as `near-duplicate-clusters.ts`. The `near` block's shape carries
|
|
34
|
+
* distinctions the serializer spent care on — `ranked: null` (no ranking was
|
|
35
|
+
* attempted: `provider_unconfigured` / `embedding_failed`) versus `ranked: []`
|
|
36
|
+
* (the search ran and found nothing near), and, inside the latter,
|
|
37
|
+
* `identity_count: 0` versus `identity_count > 0` with
|
|
38
|
+
* `best_below_floor_similarity`. Coalescing any of them would turn three
|
|
39
|
+
* different silences into one. The body goes back as it arrived.
|
|
40
|
+
*/
|
|
41
|
+
const findTestsNearBehavior = {
|
|
42
|
+
name: "find_tests_near_behavior",
|
|
43
|
+
title: "Find tests near a behavior",
|
|
44
|
+
description: "Ask a repository's stored test suite map: which tests are nearest a behavior phrase you give it? " +
|
|
45
|
+
"The server embeds your phrase and ranks the repository's stored test identities by similarity, " +
|
|
46
|
+
"returning the top hits in the `near` block — each with its similarity, `signal_source`, last-known " +
|
|
47
|
+
"path and the weight the latest run measured. " +
|
|
48
|
+
"THE ANSWER IS A PAGE, NOT THE SET: the default page is 10 hits. READ `truncated` AND `limit` in the " +
|
|
49
|
+
"returned `near` block — `limit` is the page size the server APPLIED (it clamps your ask to 50) and " +
|
|
50
|
+
"`truncated: true` means MORE matches exist than were returned, so a full page of 10 may be \"10 of " +
|
|
51
|
+
"37\". When `truncated` is true, re-ask the SAME phrase with a larger optional `limit` (max 50) " +
|
|
52
|
+
"BEFORE paraphrasing it: a repeated phrase is cache-served and free, while each paraphrase is a " +
|
|
53
|
+
"novel phrase and one billed embed. " +
|
|
54
|
+
"WHAT THE ANSWER IS NOT: it ranks STORED tests nearest the phrase and NEVER answers \"is this " +
|
|
55
|
+
"already tested?\". It never gates a write and never issues a verdict — a hit near the phrase is not " +
|
|
56
|
+
"coverage, and an empty answer is not proof of absence. `similarity_floor` is the near-duplicate " +
|
|
57
|
+
"census's redundancy bar (how alike two tests must read for the census to pair them), NOT the 0.95 " +
|
|
58
|
+
"matching threshold that decides whether two tests are the same test; do not read it as a pass mark. " +
|
|
59
|
+
"READ `similarity_basis` AND `similarity_floor` BEFORE ANY FIGURE: a similarity without the statement " +
|
|
60
|
+
"of what it measures is a confident number over nothing. " +
|
|
61
|
+
"THE THREE SILENCES ARE DIFFERENT AND MUST NOT BE COLLAPSED: (1) `status` of `provider_unconfigured` " +
|
|
62
|
+
"or `embedding_failed` with `ranked: null` — no ranking was attempted or the provider refused (an " +
|
|
63
|
+
"`error` carries the provider's own reason); this says NOTHING about the suite. (2) `identity_count: " +
|
|
64
|
+
"0` with `ranked: []` — the repository holds no identities, nothing has been ingested. (3) `ranked: " +
|
|
65
|
+
"[]` with `identity_count` above zero and `best_below_floor_similarity` — identities exist and the " +
|
|
66
|
+
"search ran, and none is near the phrase; the nearest one's similarity is served so that \"nothing " +
|
|
67
|
+
"near\" is a finding you can check. `null` and `[]` are never interchangeable here. " +
|
|
68
|
+
"`signal_sources` (the composition of the served page) and each hit's `signal_source` (whether the " +
|
|
69
|
+
"hit matched on declared intent or on its name) are DIFFERENT EVIDENCE: a name match and an intent " +
|
|
70
|
+
"match are not the same claim, so read the source before leaning on a hit. " +
|
|
71
|
+
"COST: each NOVEL phrase costs ONE BILLED EMBEDDING CALL at the provider; repeating a phrase is " +
|
|
72
|
+
"served from the cache and costs nothing (`cache_served` says which happened). The ask is LIVE — " +
|
|
73
|
+
"computed on the request — unlike the stored census `near_duplicate_clusters` returns; it is its " +
|
|
74
|
+
"own tool so that an overview call never pays an embed by accident. Send a considered phrase, not " +
|
|
75
|
+
"a sweep of guesses. " +
|
|
76
|
+
"`behavior` is REQUIRED: a behavior phrase in plain words (trimmed; blank is refused here before " +
|
|
77
|
+
"any request, and so is a NUL character — the server would read it as no ask and answer the whole " +
|
|
78
|
+
"overview with `near: null`, which would look like an answered ask). " +
|
|
79
|
+
"WHICH repository is asked is optional: pass `repository` (a numeric id from `list_repositories`) " +
|
|
80
|
+
"to ask that named repository under either member credential — the agent key preferred, the person " +
|
|
81
|
+
"key when no agent key is set — or omit it to ask the repository the configured sgk_… key resolves " +
|
|
82
|
+
"to. Same endpoints and credentials as `get_repository_overview`: without `repository`, an `sgk_` " +
|
|
83
|
+
"repository key (SPECGUARD_API_KEY) on `GET /api/v1/repository`; with `repository`, EITHER member " +
|
|
84
|
+
"credential on `GET /api/v1/repositories/:id` — SPECGUARD_AGENT_API_KEY (an sga_… agent key) " +
|
|
85
|
+
"preferred, and, when that is not set, SPECGUARD_USER_API_KEY (an sgu_… person key); with both set " +
|
|
86
|
+
"the agent key wins. The server owns the refusals on that path: a repository outside the presented " +
|
|
87
|
+
"credential's grant answers 404, person and agent alike. " +
|
|
88
|
+
"The response is the endpoint's full body with the `near` block OPENED, passed through unmodified — " +
|
|
89
|
+
"with the one surface difference `get_repository_overview` documents for its own `repository` ask: " +
|
|
90
|
+
"on the plural path the `api_key` block is ABSENT from the body rather than nulled.",
|
|
91
|
+
inputSchema: {
|
|
92
|
+
type: "object",
|
|
93
|
+
properties: {
|
|
94
|
+
behavior: {
|
|
95
|
+
type: "string",
|
|
96
|
+
description: "REQUIRED. The behavior phrase to look for — plain words describing what a test would " +
|
|
97
|
+
"check, e.g. \"rejects an expired password reset token\". Trimmed and sent as `near`. " +
|
|
98
|
+
"Blank or whitespace-only is refused before any request, and so is a phrase containing a " +
|
|
99
|
+
"NUL character (U+0000): the server reads those shapes as no ask at all and would answer " +
|
|
100
|
+
"the whole overview with `near: null`. NOTE: every NOVEL phrase costs one billed " +
|
|
101
|
+
"embedding call; a repeated phrase is cache-served.",
|
|
102
|
+
},
|
|
103
|
+
repository: {
|
|
104
|
+
type: "string",
|
|
105
|
+
description: "Ask THIS repository instead of the one the configured sgk_… key resolves to. The " +
|
|
106
|
+
"value is the repository's NUMERIC ID, exactly as served in `list_repositories` " +
|
|
107
|
+
"entries' `id` — not the `org/repo` handle. " +
|
|
108
|
+
"The credential changes with it: the call authenticates with EITHER member credential, " +
|
|
109
|
+
"whichever is set — SPECGUARD_AGENT_API_KEY (an sga_… agent key; the set of " +
|
|
110
|
+
"repositories granted onto it at mint time is the boundary the id is resolved " +
|
|
111
|
+
"inside) and, when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key — a PERSON " +
|
|
112
|
+
"key, whose accessible set is the boundary instead); with both set the agent key " +
|
|
113
|
+
"wins. A repository outside the presented credential's grant answers 404, " +
|
|
114
|
+
"indistinguishable from one that does not exist. " +
|
|
115
|
+
"Omit it — or pass a blank — and the call is the singular one under SPECGUARD_API_KEY.",
|
|
116
|
+
},
|
|
117
|
+
limit: {
|
|
118
|
+
type: "integer",
|
|
119
|
+
minimum: 1,
|
|
120
|
+
maximum: 50,
|
|
121
|
+
description: "OPTIONAL page size: how many hits to return in the `near` block. Omit it for the " +
|
|
122
|
+
"default page of 10. The server clamps the ask to 50 and reports the value it applied " +
|
|
123
|
+
"as `limit` in the `near` block, beside `truncated` — read both: `truncated: true` " +
|
|
124
|
+
"means more matches exist than were returned, and asking again with a larger `limit` " +
|
|
125
|
+
"(same phrase, so cache-served and free) is cheaper than paraphrasing it (a novel " +
|
|
126
|
+
"phrase, one billed embed). Must be an integer >= 1; anything else is refused before " +
|
|
127
|
+
"any request.",
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
required: ["behavior"],
|
|
131
|
+
additionalProperties: false,
|
|
132
|
+
},
|
|
133
|
+
async run(args, context) {
|
|
134
|
+
// Argument checks come FIRST, before config resolution or any request:
|
|
135
|
+
// a malformed phrase must not cost a credential lookup, let alone a
|
|
136
|
+
// billed embed.
|
|
137
|
+
const behavior = requireString(args["behavior"], "behavior");
|
|
138
|
+
if (behavior.includes("\u0000")) {
|
|
139
|
+
throw new ArgumentError("`behavior` must not contain a NUL (\\u0000) character: the server reads a NUL-containing " +
|
|
140
|
+
"`near` as no ask and would answer the whole overview with `near: null`, which would look " +
|
|
141
|
+
"like an answered ask. Remove the character and send the phrase again.");
|
|
142
|
+
}
|
|
143
|
+
const repository = optionalString(args["repository"], "repository");
|
|
144
|
+
const limit = optionalPositiveInteger(args["limit"], "limit");
|
|
145
|
+
const { api, path } = repositoryTarget(context.config, repository);
|
|
146
|
+
// `limit` rides the wire only when supplied, so an ask without it is
|
|
147
|
+
// byte-identical to the request this tool made before `limit` existed. The
|
|
148
|
+
// server owns the clamp (50) and reports the applied value in `near.limit`.
|
|
149
|
+
const query = { near: behavior };
|
|
150
|
+
if (limit !== undefined)
|
|
151
|
+
query["limit"] = String(limit);
|
|
152
|
+
const overview = await getJsonObject(api, path, query, context.fetch);
|
|
153
|
+
return {
|
|
154
|
+
text: JSON.stringify(overview, null, 2),
|
|
155
|
+
structured: overview,
|
|
156
|
+
};
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
export default findTestsNearBehavior;
|
|
160
|
+
//# sourceMappingURL=find-tests-near-behavior.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-tests-near-behavior.js","sourceRoot":"","sources":["../../../src/tools/find-tests-near-behavior.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,7 +12,7 @@ import type { ToolDefinition } from "./types.js";
|
|
|
12
12
|
* == What is in the bootstrap, and why only these two
|
|
13
13
|
*
|
|
14
14
|
* - `lint_intent_annotations` wraps `specguard-lint` (shipped:
|
|
15
|
-
* `specguard-
|
|
15
|
+
* `specguard-ruby/bin/specguard-lint`, SPGD-12 §1).
|
|
16
16
|
* - `get_repository_overview` wraps `GET /api/v1/repository` (shipped:
|
|
17
17
|
* `specguard/config/routes.rb`).
|
|
18
18
|
*
|
|
@@ -231,6 +231,24 @@ import type { ToolDefinition } from "./types.js";
|
|
|
231
231
|
* is unchanged and still binding — the route was verified-shipped, spec-covered
|
|
232
232
|
* and root-level before this entry wrapped it, and `/check-intent` (a comment
|
|
233
233
|
* in `routes.rb`) stays out.
|
|
234
|
+
*
|
|
235
|
+
* == Ask the suite map
|
|
236
|
+
*
|
|
237
|
+
* - `find_tests_near_behavior` wraps `GET /api/v1/repository?near=<phrase>`
|
|
238
|
+
* (and the plural `GET /api/v1/repositories/:id?near=`), serving the
|
|
239
|
+
* `near` block `RepositoryOverview#serialized_near` builds through
|
|
240
|
+
* `NearProbe` (shipped: roadmap SPGD-1102 slices 1–2, specguard
|
|
241
|
+
* `2e18377` and `59b0d19`).
|
|
242
|
+
*
|
|
243
|
+
* The first tool here whose ask is LIVE and BILLED — each novel phrase costs
|
|
244
|
+
* one embedding call — which is why it is a tool of its own rather than a
|
|
245
|
+
* parameter on `get_repository_overview`: an overview call must never pay an
|
|
246
|
+
* embed by accident. It ranks stored tests nearest a phrase and never answers
|
|
247
|
+
* "is this already tested?"; the tool description carries that and the three
|
|
248
|
+
* silences the block keeps apart. The standing rule is unchanged and still
|
|
249
|
+
* binding — `/check-intent` stays out: it has no backing endpoint, and this
|
|
250
|
+
* tool is deliberately not a stand-in for one (the platform's floor discloses
|
|
251
|
+
* and filters a ranked read; it never gates a write and issues no verdict).
|
|
234
252
|
*/
|
|
235
253
|
export declare const TOOLS: readonly ToolDefinition[];
|
|
236
254
|
export type { ToolContext, ToolDefinition, ToolResult } from "./types.js";
|
package/dist/src/tools/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import addRepository from "./add-repository.js";
|
|
2
2
|
import addRepositoryMember from "./add-repository-member.js";
|
|
3
3
|
import createRepositoryApiKey from "./create-repository-api-key.js";
|
|
4
|
+
import findTestsNearBehavior from "./find-tests-near-behavior.js";
|
|
4
5
|
import getIntentSchema from "./get-intent-schema.js";
|
|
5
6
|
import getServerVersion from "./get-server-version.js";
|
|
6
7
|
import lintIntentAnnotations from "./lint-intent-annotations.js";
|
|
@@ -31,7 +32,7 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
|
|
|
31
32
|
* == What is in the bootstrap, and why only these two
|
|
32
33
|
*
|
|
33
34
|
* - `lint_intent_annotations` wraps `specguard-lint` (shipped:
|
|
34
|
-
* `specguard-
|
|
35
|
+
* `specguard-ruby/bin/specguard-lint`, SPGD-12 §1).
|
|
35
36
|
* - `get_repository_overview` wraps `GET /api/v1/repository` (shipped:
|
|
36
37
|
* `specguard/config/routes.rb`).
|
|
37
38
|
*
|
|
@@ -250,6 +251,24 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
|
|
|
250
251
|
* is unchanged and still binding — the route was verified-shipped, spec-covered
|
|
251
252
|
* and root-level before this entry wrapped it, and `/check-intent` (a comment
|
|
252
253
|
* in `routes.rb`) stays out.
|
|
254
|
+
*
|
|
255
|
+
* == Ask the suite map
|
|
256
|
+
*
|
|
257
|
+
* - `find_tests_near_behavior` wraps `GET /api/v1/repository?near=<phrase>`
|
|
258
|
+
* (and the plural `GET /api/v1/repositories/:id?near=`), serving the
|
|
259
|
+
* `near` block `RepositoryOverview#serialized_near` builds through
|
|
260
|
+
* `NearProbe` (shipped: roadmap SPGD-1102 slices 1–2, specguard
|
|
261
|
+
* `2e18377` and `59b0d19`).
|
|
262
|
+
*
|
|
263
|
+
* The first tool here whose ask is LIVE and BILLED — each novel phrase costs
|
|
264
|
+
* one embedding call — which is why it is a tool of its own rather than a
|
|
265
|
+
* parameter on `get_repository_overview`: an overview call must never pay an
|
|
266
|
+
* embed by accident. It ranks stored tests nearest a phrase and never answers
|
|
267
|
+
* "is this already tested?"; the tool description carries that and the three
|
|
268
|
+
* silences the block keeps apart. The standing rule is unchanged and still
|
|
269
|
+
* binding — `/check-intent` stays out: it has no backing endpoint, and this
|
|
270
|
+
* tool is deliberately not a stand-in for one (the platform's floor discloses
|
|
271
|
+
* and filters a ranked read; it never gates a write and issues no verdict).
|
|
253
272
|
*/
|
|
254
273
|
export const TOOLS = [
|
|
255
274
|
lintIntentAnnotations,
|
|
@@ -272,5 +291,6 @@ export const TOOLS = [
|
|
|
272
291
|
listRepositoryAgentKeys,
|
|
273
292
|
listRepositoryAgentKeysPresentedRevoked,
|
|
274
293
|
revokeRepositoryAgentKey,
|
|
294
|
+
findTestsNearBehavior,
|
|
275
295
|
];
|
|
276
296
|
//# 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,eAAe,MAAM,wBAAwB,CAAC;AACrD,OAAO,gBAAgB,MAAM,yBAAyB,CAAC;AACvD,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,+BAA+B,CAAC;AAClE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,qBAAqB,MAAM,0BAA0B,CAAC;AAC7D,OAAO,uBAAuB,MAAM,+BAA+B,CAAC;AACpE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,sBAAsB,MAAM,+BAA+B,CAAC;AACnE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,wBAAwB,MAAM,kCAAkC,CAAC;AACxE,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,iCAAiC,MAAM,2CAA2C,CAAC;AAG1F
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,qBAAqB,MAAM,+BAA+B,CAAC;AAClE,OAAO,eAAe,MAAM,wBAAwB,CAAC;AACrD,OAAO,gBAAgB,MAAM,yBAAyB,CAAC;AACvD,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,+BAA+B,CAAC;AAClE,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0PG;AACH,MAAM,CAAC,MAAM,KAAK,GAA8B;IAC9C,qBAAqB;IACrB,eAAe;IACf,qBAAqB;IACrB,gBAAgB;IAChB,gBAAgB;IAChB,aAAa;IACb,uBAAuB;IACvB,gBAAgB;IAChB,sBAAsB;IACtB,sBAAsB;IACtB,qBAAqB;IACrB,qBAAqB;IACrB,qBAAqB;IACrB,mBAAmB;IACnB,iCAAiC;IACjC,sBAAsB;IACtB,gBAAgB;IAChB,uBAAuB;IACvB,uCAAuC;IACvC,wBAAwB;IACxB,qBAAqB;CACtB,CAAC"}
|
|
@@ -61,7 +61,9 @@ import type { ToolDefinition } from "./types.js";
|
|
|
61
61
|
* and `?role=shared` (the exact partition of the accessible set into owned and
|
|
62
62
|
* shared halves), and `?sort=stale` (never-ingested repositories first, then
|
|
63
63
|
* least-recently-ingested, `github_full_name` breaking ties so the order is
|
|
64
|
-
* deterministic)
|
|
64
|
+
* deterministic) or `?sort=annotated` (least-annotated share first; a
|
|
65
|
+
* repository with no run or an unmeasured suite last, never ranked as 0%; a
|
|
66
|
+
* suite measured at 0-of-N first; `github_full_name` breaking ties). The concern's own comment says the endpoint reads them "for
|
|
65
67
|
* a machine" — and this bridge IS that machine, so they are forwarded here
|
|
66
68
|
* rather than re-invented.
|
|
67
69
|
*
|
|
@@ -159,8 +161,8 @@ import type { ToolDefinition } from "./types.js";
|
|
|
159
161
|
* The order is `full_name` ascending, which the controller picks as the only
|
|
160
162
|
* column a client can page or diff against without SpecGuard promising an id
|
|
161
163
|
* ordering it has not designed — and `?sort=stale` re-sequences exactly that
|
|
162
|
-
* loaded set rather than issuing a different query
|
|
163
|
-
* change, only their order does. It is stated here for the same reason the
|
|
164
|
+
* loaded set rather than issuing a different query (as does `?sort=annotated`),
|
|
165
|
+
* so the entries never change, only their order does. It is stated here for the same reason the
|
|
164
166
|
* other tool states its orders: a list whose order is a coincidence and a list
|
|
165
167
|
* whose order is a contract look identical in a response body.
|
|
166
168
|
*/
|
|
@@ -62,7 +62,9 @@ import { optionalString } from "./args.js";
|
|
|
62
62
|
* and `?role=shared` (the exact partition of the accessible set into owned and
|
|
63
63
|
* shared halves), and `?sort=stale` (never-ingested repositories first, then
|
|
64
64
|
* least-recently-ingested, `github_full_name` breaking ties so the order is
|
|
65
|
-
* deterministic)
|
|
65
|
+
* deterministic) or `?sort=annotated` (least-annotated share first; a
|
|
66
|
+
* repository with no run or an unmeasured suite last, never ranked as 0%; a
|
|
67
|
+
* suite measured at 0-of-N first; `github_full_name` breaking ties). The concern's own comment says the endpoint reads them "for
|
|
66
68
|
* a machine" — and this bridge IS that machine, so they are forwarded here
|
|
67
69
|
* rather than re-invented.
|
|
68
70
|
*
|
|
@@ -160,8 +162,8 @@ import { optionalString } from "./args.js";
|
|
|
160
162
|
* The order is `full_name` ascending, which the controller picks as the only
|
|
161
163
|
* column a client can page or diff against without SpecGuard promising an id
|
|
162
164
|
* ordering it has not designed — and `?sort=stale` re-sequences exactly that
|
|
163
|
-
* loaded set rather than issuing a different query
|
|
164
|
-
* change, only their order does. It is stated here for the same reason the
|
|
165
|
+
* loaded set rather than issuing a different query (as does `?sort=annotated`),
|
|
166
|
+
* so the entries never change, only their order does. It is stated here for the same reason the
|
|
165
167
|
* other tool states its orders: a list whose order is a coincidence and a list
|
|
166
168
|
* whose order is a contract look identical in a response body.
|
|
167
169
|
*/
|
|
@@ -198,9 +200,11 @@ const listRepositories = {
|
|
|
198
200
|
"`role: \"owned\"` or `\"shared\"` (one half of the owned/shared mix — note the ask is " +
|
|
199
201
|
"spelled `owned`, not the response field's `owner`; under the AGENT key this ask settles " +
|
|
200
202
|
"to the no-ask, because ownership is a person fact and the key speaks for nobody), and " +
|
|
201
|
-
"`sort
|
|
203
|
+
"`sort` (`\"stale\"`: repositories " +
|
|
202
204
|
"CI has never ingested a run for first, then least-recently-ingested, `full_name` " +
|
|
203
|
-
"breaking ties
|
|
205
|
+
"breaking ties; `\"annotated\"`: least-annotated share first, repositories with no run " +
|
|
206
|
+
"or an unmeasured suite last — never ranked as 0% — a suite measured at 0-of-N first, " +
|
|
207
|
+
"`full_name` breaking ties). Omit them all and the request is the plain full list. " +
|
|
204
208
|
"Ordered by `full_name` ascending unless `sort` asks otherwise, and stable across calls " +
|
|
205
209
|
"either way. " +
|
|
206
210
|
"The set is exactly what the key behind it may see — a repository outside the credential's " +
|
|
@@ -252,16 +256,20 @@ const listRepositories = {
|
|
|
252
256
|
},
|
|
253
257
|
sort: {
|
|
254
258
|
type: "string",
|
|
255
|
-
enum: ["stale"],
|
|
256
|
-
description: "Re-order the list
|
|
259
|
+
enum: ["stale", "annotated"],
|
|
260
|
+
description: "Re-order the list. The default order is `full_name` ascending, which " +
|
|
257
261
|
"is stable across calls but says nothing about what needs attention; `stale` puts " +
|
|
258
262
|
"the repositories CI has NEVER ingested a run for FIRST (never-ingested is the " +
|
|
259
263
|
"stalest state on this list, not a zero), then least-recently-ingested, newest last, " +
|
|
260
264
|
"with `github_full_name` breaking ties so two calls with the same data agree element " +
|
|
261
265
|
"for element. " +
|
|
266
|
+
"`annotated` puts the LEAST-annotated suites first (annotated share of the latest " +
|
|
267
|
+
"run, ascending): a suite measured at 0-of-N leads, and repositories CI has never " +
|
|
268
|
+
"reported a run for, or whose suite was not measured, come LAST — an unmeasured suite " +
|
|
269
|
+
"is never ranked as 0% — with `github_full_name` breaking ties. " +
|
|
262
270
|
"It re-sequences the loaded set rather than issuing a different query: the same " +
|
|
263
|
-
"entries, a different order. `stale`
|
|
264
|
-
"is deliberately no word for the default, because omitting the argument already " +
|
|
271
|
+
"entries, a different order. `stale` and `annotated` are the sole sort words the endpoint " +
|
|
272
|
+
"names — there is deliberately no word for the default, because omitting the argument already " +
|
|
265
273
|
"means it. " +
|
|
266
274
|
"Any other value a schema-bypassing client sends settles to the server's no-ask clamp " +
|
|
267
275
|
"(default order, no error); blank (or null) is no ask, byte-identical to omitting the " +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-repositories.js","sourceRoot":"","sources":["../../../src/tools/list-repositories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AACzF,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C
|
|
1
|
+
{"version":3,"file":"list-repositories.js","sourceRoot":"","sources":["../../../src/tools/list-repositories.ts"],"names":[],"mappings":"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"}
|
|
@@ -75,6 +75,10 @@ const listRepositoryApiKeys = {
|
|
|
75
75
|
"`get_repository_overview`'s `credential_health` reports, at row grain. " +
|
|
76
76
|
"`token_hint` is a hint, never the token — the plaintext existed for exactly one response " +
|
|
77
77
|
"at mint time and nothing persisted it. " +
|
|
78
|
+
"The post-cut verify: a REVOKED row also serves `last_refused_at`. `null` means offboarding " +
|
|
79
|
+
"took — nothing has presented the dead token since the cut; a timestamp means the dead " +
|
|
80
|
+
"token is still arriving, and that row's `token_hint` is what to hunt in the secret stores " +
|
|
81
|
+
"that may still hold it. Live rows carry no `last_refused_at` key. " +
|
|
78
82
|
"Takes `repository_id` (the numeric id `list_repositories` reports, not the `org/repo` handle). " +
|
|
79
83
|
"It authenticates with EITHER of this server's two key-administration credentials, whichever " +
|
|
80
84
|
"is set: SPECGUARD_AGENT_API_KEY (an sga_… key — the call then reaches only the repositories " +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-repository-api-keys.js","sourceRoot":"","sources":["../../../src/tools/list-repository-api-keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AACzF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,MAAM,qBAAqB,GAAmB;IAC5C,IAAI,EAAE,0BAA0B;IAChC,KAAK,EAAE,0BAA0B;IACjC,WAAW,EACT,qFAAqF;QACrF,0FAA0F;QAC1F,6FAA6F;QAC7F,4FAA4F;QAC5F,uEAAuE;QACvE,uFAAuF;QACvF,uFAAuF;QACvF,yFAAyF;QACzF,+BAA+B;QAC/B,oFAAoF;QACpF,4FAA4F;QAC5F,2FAA2F;QAC3F,uFAAuF;QACvF,2FAA2F;QAC3F,wFAAwF;QACxF,yEAAyE;QACzE,2FAA2F;QAC3F,yCAAyC;QACzC,iGAAiG;QACjG,8FAA8F;QAC9F,8FAA8F;QAC9F,+FAA+F;QAC/F,4FAA4F;QAC5F,wEAAwE;QACxE,4FAA4F;QAC5F,wFAAwF;QACxF,mDAAmD;QACnD,kGAAkG;QAClG,oDAAoD;IACtD,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,8EAA8E;oBAC9E,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,2BAA2B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAExD,MAAM,IAAI,GAAG,MAAM,aAAa,CAC9B,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,WAAW,EACnE,EAAE,EACF,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,2EAA2E;QAC3E,2EAA2E;QAC3E,yEAAyE;QACzE,0DAA0D;QAC1D,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,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"list-repository-api-keys.js","sourceRoot":"","sources":["../../../src/tools/list-repository-api-keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AACzF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,MAAM,qBAAqB,GAAmB;IAC5C,IAAI,EAAE,0BAA0B;IAChC,KAAK,EAAE,0BAA0B;IACjC,WAAW,EACT,qFAAqF;QACrF,0FAA0F;QAC1F,6FAA6F;QAC7F,4FAA4F;QAC5F,uEAAuE;QACvE,uFAAuF;QACvF,uFAAuF;QACvF,yFAAyF;QACzF,+BAA+B;QAC/B,oFAAoF;QACpF,4FAA4F;QAC5F,2FAA2F;QAC3F,uFAAuF;QACvF,2FAA2F;QAC3F,wFAAwF;QACxF,yEAAyE;QACzE,2FAA2F;QAC3F,yCAAyC;QACzC,6FAA6F;QAC7F,wFAAwF;QACxF,4FAA4F;QAC5F,oEAAoE;QACpE,iGAAiG;QACjG,8FAA8F;QAC9F,8FAA8F;QAC9F,+FAA+F;QAC/F,4FAA4F;QAC5F,wEAAwE;QACxE,4FAA4F;QAC5F,wFAAwF;QACxF,mDAAmD;QACnD,kGAAkG;QAClG,oDAAoD;IACtD,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,8EAA8E;oBAC9E,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,2BAA2B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAExD,MAAM,IAAI,GAAG,MAAM,aAAa,CAC9B,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,WAAW,EACnE,EAAE,EACF,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,2EAA2E;QAC3E,2EAA2E;QAC3E,yEAAyE;QACzE,0DAA0D;QAC1D,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,qBAAqB,CAAC"}
|