specguard-mcp 0.1.37 → 0.1.39
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 +60 -10
- package/dist/src/tools/find-tests-near-behavior.d.ts +40 -0
- package/dist/src/tools/find-tests-near-behavior.js +135 -0
- package/dist/src/tools/find-tests-near-behavior.js.map +1 -0
- package/dist/src/tools/index.d.ts +18 -0
- package/dist/src/tools/index.js +20 -0
- package/dist/src/tools/index.js.map +1 -1
- package/dist/src/tools/lint-intent-annotations.js +6 -3
- package/dist/src/tools/lint-intent-annotations.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,10 +33,10 @@ 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 |
|
|
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: `SPECGUARD_VALIDATE_INTENT
|
|
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
|
+
| `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
|
|
@@ -73,9 +73,10 @@ Validates the `@intent:` annotations in a project's test files against the
|
|
|
73
73
|
[OpenTestIntent](https://github.com/yatfa-ai/open-test-intent) schema, by running that project's own
|
|
74
74
|
linter with `--json` — `specguard-lint` (Ruby/RSpec, `*_spec.rb`) or `specguard lint` (JS/TS,
|
|
75
75
|
`@yatfa/specguard`; `.ts`/`.tsx`/`.js`/`.jsx`/`.mjs`/`.cjs`). `SPECGUARD_LINT_COMMAND` selects which;
|
|
76
|
-
the server does not auto-detect it. A JS/TS run needs the validator backend
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
the server does not auto-detect it. A JS/TS run needs the validator backend: a `validate-intent` binary
|
|
77
|
+
whose path `SPECGUARD_VALIDATE_INTENT` names (install it with open-test-intent's `scripts/install.sh`). That variable is
|
|
78
|
+
today the only way to supply it — the npm package's auto-resolution is a seam that resolves nothing yet — and without a
|
|
79
|
+
binary the linter exits `2` and says why (see the specguard-ts README, "The validate-intent binary"). Findings come back as data — file, line, failure kind, every violated rule
|
|
79
80
|
— rather than as a prose report to regex.
|
|
80
81
|
|
|
81
82
|
| argument | |
|
|
@@ -87,8 +88,9 @@ the server does not auto-detect it. A JS/TS run needs the validator backend
|
|
|
87
88
|
|
|
88
89
|
The report is the linter's own document, echoed untouched, so its `summary` keys and finding kinds
|
|
89
90
|
differ per client — Ruby reports `files`/`annotations`/`failed`; JS/TS reports
|
|
90
|
-
`files`/`annotations`/`malformed`/`unreadable
|
|
91
|
-
|
|
91
|
+
`files`/`annotations`/`malformed`/`unreadable`. Both clients can emit an `unreachable` finding kind (an
|
|
92
|
+
annotation extraction can never claim: stacked, separated, shadowed, or trailing on a group line); JS/TS
|
|
93
|
+
additionally emits `no-match`, which Ruby folds into `read` — read the report rather than assuming one shape.
|
|
92
94
|
|
|
93
95
|
Needs no SpecGuard deployment and no API key. A **missing** annotation is never a failure: adoption
|
|
94
96
|
is gradual by design, so a suite with no annotations lints clean.
|
|
@@ -712,6 +714,50 @@ path's one deliberate omission: `api_key` is **absent** from the plural body rat
|
|
|
712
714
|
because the block describes the credential that made the request and no member credential is a
|
|
713
715
|
repository key (an absent key there is the surface's shape, never a dropped block).
|
|
714
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
|
+
|
|
730
|
+
**What the answer is not.** It ranks *stored* tests nearest the phrase and **never answers "is this
|
|
731
|
+
already tested?"** — it never gates a write and never issues a verdict. A hit near the phrase is not
|
|
732
|
+
coverage, and an empty answer is not proof of absence. `similarity_floor` is the near-duplicate
|
|
733
|
+
census's redundancy bar, **not** the 0.95 matching threshold that decides whether two tests are the
|
|
734
|
+
same test. Read `similarity_basis` and `similarity_floor` before any figure.
|
|
735
|
+
|
|
736
|
+
**The three silences differ** — never collapse them, and `null` is never `[]`:
|
|
737
|
+
|
|
738
|
+
- `status` of `provider_unconfigured` or `embedding_failed` with `ranked: null` — no ranking was
|
|
739
|
+
attempted, or the provider refused (`error` carries its reason). This says nothing about the suite.
|
|
740
|
+
- `identity_count: 0` with `ranked: []` — the repository holds no identities; nothing has been
|
|
741
|
+
ingested.
|
|
742
|
+
- `ranked: []` with `identity_count` above zero and `best_below_floor_similarity` — identities exist,
|
|
743
|
+
the search ran, and none is near the phrase; the nearest one's similarity is served so "nothing
|
|
744
|
+
near" is a finding you can check.
|
|
745
|
+
|
|
746
|
+
`signal_sources` (the composition of the served page) and each hit's `signal_source` (matched on
|
|
747
|
+
declared intent, or on name) are different evidence — read the source before leaning on a hit.
|
|
748
|
+
|
|
749
|
+
**Cost.** Each *novel* phrase costs **one billed embedding call** at the provider; a repeated phrase
|
|
750
|
+
is served from the cache and costs nothing (`cache_served` says which happened). The ask is live —
|
|
751
|
+
computed on the request — unlike the stored census `near_duplicate_clusters` returns, and it is a
|
|
752
|
+
tool of its own so that a `get_repository_overview` call never pays an embed by accident.
|
|
753
|
+
|
|
754
|
+
Same endpoints and credentials as `get_repository_overview`: without `repository`, an `sgk_…`
|
|
755
|
+
repository key on `GET /api/v1/repository`; with `repository`, either member credential on the
|
|
756
|
+
plural endpoint — the agent key preferred, the user key when no agent key is set. A repository
|
|
757
|
+
outside the presented credential's grant answers 404 at the server. The response is that body with
|
|
758
|
+
the `near` block opened, passed through unmodified; on the plural path `api_key` is **absent** from
|
|
759
|
+
the body rather than nulled (the surface's shape, never a dropped block).
|
|
760
|
+
|
|
715
761
|
### `remove_repository`
|
|
716
762
|
|
|
717
763
|
Removes a repository from SpecGuard — and with it **every key, run and intent on it**. This is the
|
|
@@ -778,7 +824,11 @@ serves live rows only). One row per key: `id`, `name`, `token_hint`, `created_at
|
|
|
778
824
|
omitted — `rotated_at`, and `rotated_and_unused` (live-scoped: the stranded shape
|
|
779
825
|
`get_repository_overview`'s `credential_health` reports, at row grain). `status` is
|
|
780
826
|
`live`/`revoked`, with `revoked_at` present only on revoked rows — a revoked `sgk_` row is not a
|
|
781
|
-
credential either, but the rotation's story lives in the population.
|
|
827
|
+
credential either, but the rotation's story lives in the population. A **revoked** row also
|
|
828
|
+
serves `last_refused_at`: `null` means offboarding took (nothing has presented the dead token
|
|
829
|
+
since the cut), a timestamp means the dead token is still arriving and that row's `token_hint`
|
|
830
|
+
is what to hunt in the secret stores that may still hold it. Live rows carry no
|
|
831
|
+
`last_refused_at` key.
|
|
782
832
|
|
|
783
833
|
| argument | |
|
|
784
834
|
| --- | --- |
|
|
@@ -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,135 @@
|
|
|
1
|
+
import { ArgumentError } from "../errors.js";
|
|
2
|
+
import { getJsonObject, repositoryTarget } from "../support/specguard-api.js";
|
|
3
|
+
import { 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
|
+
"WHAT THE ANSWER IS NOT: it ranks STORED tests nearest the phrase and NEVER answers \"is this " +
|
|
49
|
+
"already tested?\". It never gates a write and never issues a verdict — a hit near the phrase is not " +
|
|
50
|
+
"coverage, and an empty answer is not proof of absence. `similarity_floor` is the near-duplicate " +
|
|
51
|
+
"census's redundancy bar (how alike two tests must read for the census to pair them), NOT the 0.95 " +
|
|
52
|
+
"matching threshold that decides whether two tests are the same test; do not read it as a pass mark. " +
|
|
53
|
+
"READ `similarity_basis` AND `similarity_floor` BEFORE ANY FIGURE: a similarity without the statement " +
|
|
54
|
+
"of what it measures is a confident number over nothing. " +
|
|
55
|
+
"THE THREE SILENCES ARE DIFFERENT AND MUST NOT BE COLLAPSED: (1) `status` of `provider_unconfigured` " +
|
|
56
|
+
"or `embedding_failed` with `ranked: null` — no ranking was attempted or the provider refused (an " +
|
|
57
|
+
"`error` carries the provider's own reason); this says NOTHING about the suite. (2) `identity_count: " +
|
|
58
|
+
"0` with `ranked: []` — the repository holds no identities, nothing has been ingested. (3) `ranked: " +
|
|
59
|
+
"[]` with `identity_count` above zero and `best_below_floor_similarity` — identities exist and the " +
|
|
60
|
+
"search ran, and none is near the phrase; the nearest one's similarity is served so that \"nothing " +
|
|
61
|
+
"near\" is a finding you can check. `null` and `[]` are never interchangeable here. " +
|
|
62
|
+
"`signal_sources` (the composition of the served page) and each hit's `signal_source` (whether the " +
|
|
63
|
+
"hit matched on declared intent or on its name) are DIFFERENT EVIDENCE: a name match and an intent " +
|
|
64
|
+
"match are not the same claim, so read the source before leaning on a hit. " +
|
|
65
|
+
"COST: each NOVEL phrase costs ONE BILLED EMBEDDING CALL at the provider; repeating a phrase is " +
|
|
66
|
+
"served from the cache and costs nothing (`cache_served` says which happened). The ask is LIVE — " +
|
|
67
|
+
"computed on the request — unlike the stored census `near_duplicate_clusters` returns; it is its " +
|
|
68
|
+
"own tool so that an overview call never pays an embed by accident. Send a considered phrase, not " +
|
|
69
|
+
"a sweep of guesses. " +
|
|
70
|
+
"`behavior` is REQUIRED: a behavior phrase in plain words (trimmed; blank is refused here before " +
|
|
71
|
+
"any request, and so is a NUL character — the server would read it as no ask and answer the whole " +
|
|
72
|
+
"overview with `near: null`, which would look like an answered ask). " +
|
|
73
|
+
"WHICH repository is asked is optional: pass `repository` (a numeric id from `list_repositories`) " +
|
|
74
|
+
"to ask that named repository under either member credential — the agent key preferred, the person " +
|
|
75
|
+
"key when no agent key is set — or omit it to ask the repository the configured sgk_… key resolves " +
|
|
76
|
+
"to. Same endpoints and credentials as `get_repository_overview`: without `repository`, an `sgk_` " +
|
|
77
|
+
"repository key (SPECGUARD_API_KEY) on `GET /api/v1/repository`; with `repository`, EITHER member " +
|
|
78
|
+
"credential on `GET /api/v1/repositories/:id` — SPECGUARD_AGENT_API_KEY (an sga_… agent key) " +
|
|
79
|
+
"preferred, and, when that is not set, SPECGUARD_USER_API_KEY (an sgu_… person key); with both set " +
|
|
80
|
+
"the agent key wins. The server owns the refusals on that path: a repository outside the presented " +
|
|
81
|
+
"credential's grant answers 404, person and agent alike. " +
|
|
82
|
+
"The response is the endpoint's full body with the `near` block OPENED, passed through unmodified — " +
|
|
83
|
+
"with the one surface difference `get_repository_overview` documents for its own `repository` ask: " +
|
|
84
|
+
"on the plural path the `api_key` block is ABSENT from the body rather than nulled.",
|
|
85
|
+
inputSchema: {
|
|
86
|
+
type: "object",
|
|
87
|
+
properties: {
|
|
88
|
+
behavior: {
|
|
89
|
+
type: "string",
|
|
90
|
+
description: "REQUIRED. The behavior phrase to look for — plain words describing what a test would " +
|
|
91
|
+
"check, e.g. \"rejects an expired password reset token\". Trimmed and sent as `near`. " +
|
|
92
|
+
"Blank or whitespace-only is refused before any request, and so is a phrase containing a " +
|
|
93
|
+
"NUL character (U+0000): the server reads those shapes as no ask at all and would answer " +
|
|
94
|
+
"the whole overview with `near: null`. NOTE: every NOVEL phrase costs one billed " +
|
|
95
|
+
"embedding call; a repeated phrase is cache-served.",
|
|
96
|
+
},
|
|
97
|
+
repository: {
|
|
98
|
+
type: "string",
|
|
99
|
+
description: "Ask THIS repository instead of the one the configured sgk_… key resolves to. The " +
|
|
100
|
+
"value is the repository's NUMERIC ID, exactly as served in `list_repositories` " +
|
|
101
|
+
"entries' `id` — not the `org/repo` handle. " +
|
|
102
|
+
"The credential changes with it: the call authenticates with EITHER member credential, " +
|
|
103
|
+
"whichever is set — SPECGUARD_AGENT_API_KEY (an sga_… agent key; the set of " +
|
|
104
|
+
"repositories granted onto it at mint time is the boundary the id is resolved " +
|
|
105
|
+
"inside) and, when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key — a PERSON " +
|
|
106
|
+
"key, whose accessible set is the boundary instead); with both set the agent key " +
|
|
107
|
+
"wins. A repository outside the presented credential's grant answers 404, " +
|
|
108
|
+
"indistinguishable from one that does not exist. " +
|
|
109
|
+
"Omit it — or pass a blank — and the call is the singular one under SPECGUARD_API_KEY.",
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
required: ["behavior"],
|
|
113
|
+
additionalProperties: false,
|
|
114
|
+
},
|
|
115
|
+
async run(args, context) {
|
|
116
|
+
// Argument checks come FIRST, before config resolution or any request:
|
|
117
|
+
// a malformed phrase must not cost a credential lookup, let alone a
|
|
118
|
+
// billed embed.
|
|
119
|
+
const behavior = requireString(args["behavior"], "behavior");
|
|
120
|
+
if (behavior.includes("\u0000")) {
|
|
121
|
+
throw new ArgumentError("`behavior` must not contain a NUL (\\u0000) character: the server reads a NUL-containing " +
|
|
122
|
+
"`near` as no ask and would answer the whole overview with `near: null`, which would look " +
|
|
123
|
+
"like an answered ask. Remove the character and send the phrase again.");
|
|
124
|
+
}
|
|
125
|
+
const repository = optionalString(args["repository"], "repository");
|
|
126
|
+
const { api, path } = repositoryTarget(context.config, repository);
|
|
127
|
+
const overview = await getJsonObject(api, path, { near: behavior }, context.fetch);
|
|
128
|
+
return {
|
|
129
|
+
text: JSON.stringify(overview, null, 2),
|
|
130
|
+
structured: overview,
|
|
131
|
+
};
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
export default findTestsNearBehavior;
|
|
135
|
+
//# 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":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,qBAAqB,GAAmB;IAC5C,IAAI,EAAE,0BAA0B;IAEhC,KAAK,EAAE,4BAA4B;IAEnC,WAAW,EACT,mGAAmG;QACnG,iGAAiG;QACjG,qGAAqG;QACrG,+CAA+C;QAC/C,+FAA+F;QAC/F,sGAAsG;QACtG,kGAAkG;QAClG,oGAAoG;QACpG,sGAAsG;QACtG,uGAAuG;QACvG,0DAA0D;QAC1D,sGAAsG;QACtG,mGAAmG;QACnG,sGAAsG;QACtG,qGAAqG;QACrG,oGAAoG;QACpG,oGAAoG;QACpG,qFAAqF;QACrF,oGAAoG;QACpG,oGAAoG;QACpG,4EAA4E;QAC5E,iGAAiG;QACjG,kGAAkG;QAClG,kGAAkG;QAClG,mGAAmG;QACnG,sBAAsB;QACtB,kGAAkG;QAClG,mGAAmG;QACnG,sEAAsE;QACtE,mGAAmG;QACnG,oGAAoG;QACpG,oGAAoG;QACpG,mGAAmG;QACnG,mGAAmG;QACnG,8FAA8F;QAC9F,oGAAoG;QACpG,oGAAoG;QACpG,0DAA0D;QAC1D,qGAAqG;QACrG,oGAAoG;QACpG,oFAAoF;IAEtF,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,QAAQ,EAAE;gBACR,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,uFAAuF;oBACvF,uFAAuF;oBACvF,0FAA0F;oBAC1F,0FAA0F;oBAC1F,kFAAkF;oBAClF,oDAAoD;aACvD;YACD,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,mFAAmF;oBACnF,iFAAiF;oBACjF,6CAA6C;oBAC7C,wFAAwF;oBACxF,6EAA6E;oBAC7E,+EAA+E;oBAC/E,qFAAqF;oBACrF,kFAAkF;oBAClF,2EAA2E;oBAC3E,kDAAkD;oBAClD,uFAAuF;aAC1F;SACF;QACD,QAAQ,EAAE,CAAC,UAAU,CAAC;QACtB,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO;QACrB,uEAAuE;QACvE,oEAAoE;QACpE,gBAAgB;QAChB,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,CAAC;QAC7D,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,aAAa,CACrB,2FAA2F;gBACzF,2FAA2F;gBAC3F,uEAAuE,CAC1E,CAAC;QACJ,CAAC;QACD,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC;QACpE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAEnE,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAEnF,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YACvC,UAAU,EAAE,QAAQ;SACrB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -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";
|
|
@@ -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"}
|
|
@@ -53,10 +53,13 @@ const lintIntentAnnotations = {
|
|
|
53
53
|
description: "Validate the `@intent:` annotations in a project's test files against the " +
|
|
54
54
|
"OpenTestIntent schema, using that project's own SpecGuard linter: `specguard-lint` for Ruby " +
|
|
55
55
|
"(RSpec, *_spec.rb) or `specguard lint` for JS/TS (@yatfa/specguard; .ts/.tsx/.js/.jsx/.mjs/.cjs). " +
|
|
56
|
-
"SPECGUARD_LINT_COMMAND picks which one runs; a JS/TS run also needs the validator backend " +
|
|
57
|
-
"
|
|
56
|
+
"SPECGUARD_LINT_COMMAND picks which one runs; a JS/TS run also needs the validator backend, " +
|
|
57
|
+
"a validate-intent binary whose path SPECGUARD_VALIDATE_INTENT names (today the only way to supply it; " +
|
|
58
|
+
"there is no prebuilt auto-resolution yet), otherwise the linter exits 2 and says why. " +
|
|
58
59
|
"Returns each finding as " +
|
|
59
|
-
"structured data — file, line, failure kind (schema / extraction / parse / read
|
|
60
|
+
"structured data — file, line, failure kind (schema / extraction / parse / read / unreachable, " +
|
|
61
|
+
"the last being an annotation extraction can never claim — stacked, separated, shadowed, or " +
|
|
62
|
+
"trailing on a group line — which both clients can report; JS/TS also reports no-match), and every " +
|
|
60
63
|
"violated rule — so a malformed annotation can be fixed without reading a CI log. " +
|
|
61
64
|
"Use it after writing or editing `@intent:` annotations, or to audit a suite. " +
|
|
62
65
|
"A MISSING annotation is never a failure: adoption is gradual by design, so a suite with no " +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint-intent-annotations.js","sourceRoot":"","sources":["../../../src/tools/lint-intent-annotations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAsB,MAAM,2BAA2B,CAAC;AACtG,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,MAAM,qBAAqB,GAAmB;IAC5C,IAAI,EAAE,yBAAyB;IAE/B,KAAK,EAAE,0BAA0B;IAEjC,WAAW,EACT,4EAA4E;QAC5E,8FAA8F;QAC9F,oGAAoG;QACpG,
|
|
1
|
+
{"version":3,"file":"lint-intent-annotations.js","sourceRoot":"","sources":["../../../src/tools/lint-intent-annotations.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"}
|