specguard-mcp 0.1.39 → 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 CHANGED
@@ -40,7 +40,7 @@ refuses to boot and takes the tools that needed no configuration down with 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-rspec`](https://github.com/yatfa-ai/specguard-rspec) uses to ship a run, so a repository
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
@@ -726,6 +726,13 @@ its last-known path and the weight the latest run measured.
726
726
  | --- | --- |
727
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
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.
729
736
 
730
737
  **What the answer is not.** It ranks *stored* tests nearest the phrase and **never answers "is this
731
738
  already tested?"** — it never gates a write and never issues a verdict. A hit near the phrase is not
@@ -1194,7 +1201,7 @@ npm run typecheck # types only
1194
1201
  ## Related repositories
1195
1202
 
1196
1203
  - [`specguard`](https://github.com/yatfa-ai/specguard) — the platform: ingest API + Hotwire dashboard
1197
- - [`specguard-rspec`](https://github.com/yatfa-ai/specguard-rspec) — Ruby client (RSpec formatter + `@intent` linter)
1204
+ - [`specguard-ruby`](https://github.com/yatfa-ai/specguard-ruby) — Ruby client (RSpec formatter, Minitest reporter + `@intent` linter)
1198
1205
  - [`open-test-intent`](https://github.com/yatfa-ai/open-test-intent) — the annotation protocol SpecGuard consumes
1199
1206
 
1200
1207
  ## License
@@ -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-rspec` gem already
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-rspec` ships runs with an `sgk_` key and has no notion of this one,
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.
@@ -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-rspec` ships runs with an `sgk_` key and has no notion of this one,
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-rspec` (`lib/specguard/rspec/transport.rb`) gives each phase its own
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.
@@ -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
  *
@@ -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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"}
@@ -1,6 +1,6 @@
1
1
  import { ArgumentError } from "../errors.js";
2
2
  import { getJsonObject, repositoryTarget } from "../support/specguard-api.js";
3
- import { optionalString, requireString } from "./args.js";
3
+ import { optionalPositiveInteger, optionalString, requireString } from "./args.js";
4
4
  /**
5
5
  * `GET /api/v1/repository?near=<behavior phrase>` as a tool — the bridge half
6
6
  * of roadmap SPGD-1102 ("Ask the suite map"), slice 3. The platform half
@@ -45,6 +45,12 @@ const findTestsNearBehavior = {
45
45
  "The server embeds your phrase and ranks the repository's stored test identities by similarity, " +
46
46
  "returning the top hits in the `near` block — each with its similarity, `signal_source`, last-known " +
47
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. " +
48
54
  "WHAT THE ANSWER IS NOT: it ranks STORED tests nearest the phrase and NEVER answers \"is this " +
49
55
  "already tested?\". It never gates a write and never issues a verdict — a hit near the phrase is not " +
50
56
  "coverage, and an empty answer is not proof of absence. `similarity_floor` is the near-duplicate " +
@@ -108,6 +114,18 @@ const findTestsNearBehavior = {
108
114
  "indistinguishable from one that does not exist. " +
109
115
  "Omit it — or pass a blank — and the call is the singular one under SPECGUARD_API_KEY.",
110
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
+ },
111
129
  },
112
130
  required: ["behavior"],
113
131
  additionalProperties: false,
@@ -123,8 +141,15 @@ const findTestsNearBehavior = {
123
141
  "like an answered ask. Remove the character and send the phrase again.");
124
142
  }
125
143
  const repository = optionalString(args["repository"], "repository");
144
+ const limit = optionalPositiveInteger(args["limit"], "limit");
126
145
  const { api, path } = repositoryTarget(context.config, repository);
127
- const overview = await getJsonObject(api, path, { near: behavior }, context.fetch);
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);
128
153
  return {
129
154
  text: JSON.stringify(overview, null, 2),
130
155
  structured: overview,
@@ -1 +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"}
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-rspec/bin/specguard-lint`, SPGD-12 §1).
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
  *
@@ -32,7 +32,7 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
32
32
  * == What is in the bootstrap, and why only these two
33
33
  *
34
34
  * - `lint_intent_annotations` wraps `specguard-lint` (shipped:
35
- * `specguard-rspec/bin/specguard-lint`, SPGD-12 §1).
35
+ * `specguard-ruby/bin/specguard-lint`, SPGD-12 §1).
36
36
  * - `get_repository_overview` wraps `GET /api/v1/repository` (shipped:
37
37
  * `specguard/config/routes.rb`).
38
38
  *
@@ -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). The concern's own comment says the endpoint reads them "for
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, so the entries never
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). The concern's own comment says the endpoint reads them "for
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, so the entries never
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: \"stale\"` (repositories " +
203
+ "`sort` (`\"stale\"`: repositories " +
202
204
  "CI has never ingested a run for first, then least-recently-ingested, `full_name` " +
203
- "breaking ties). Omit them all and the request is the plain full list. " +
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 stalest-first. The default order is `full_name` ascending, which " +
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` is the only ordering the endpoint names — there " +
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":"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"}
1
+ {"version":3,"file":"list-repositories.js","sourceRoot":"","sources":["../../../src/tools/list-repositories.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specguard-mcp",
3
- "version": "0.1.39",
3
+ "version": "0.1.40",
4
4
  "description": "MCP server exposing SpecGuard suite intelligence to AI coding agents",
5
5
  "license": "ISC",
6
6
  "type": "module",