@warmdrift/kgauto-check 0.4.0 → 0.4.1
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/LICENSE +21 -0
- package/README.md +14 -14
- package/dist/bin.js +19 -38
- package/dist/{chunk-XWIGHIJP.js → chunk-6ZBEABKR.js} +185 -33
- package/dist/index.d.ts +24 -5
- package/dist/index.js +1 -1
- package/package.json +5 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Communicating Vessels contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -13,13 +13,13 @@ Or the manual version — your part is two steps.
|
|
|
13
13
|
**Step 1 — add the check to your agent (once).** Claude Code: run this in a terminal, then start a fresh session in your project (new MCP servers load at session start):
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
claude mcp add kgauto-check -- npx -y @warmdrift/kgauto-check
|
|
16
|
+
claude mcp add kgauto-check -- npx -y @warmdrift/kgauto-check@0.4.1
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
Cursor and most other agents — add to your MCP config, then restart the app:
|
|
20
20
|
|
|
21
21
|
```json
|
|
22
|
-
{ "mcpServers": { "kgauto-check": { "command": "npx", "args": ["-y", "@warmdrift/kgauto-check"] } } }
|
|
22
|
+
{ "mcpServers": { "kgauto-check": { "command": "npx", "args": ["-y", "@warmdrift/kgauto-check@0.4.1"] } } }
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
**Step 2 — paste the ask**, in your agent, inside the project you want checked:
|
|
@@ -43,16 +43,16 @@ A local, **fully offline** MCP server that checks a project's AI call surface ag
|
|
|
43
43
|
No MCP setup, no restart:
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
npx -y @warmdrift/kgauto-check --extract-contract # extraction instructions + privacy contract
|
|
46
|
+
npx -y @warmdrift/kgauto-check@0.4.1 --extract-contract # extraction instructions + privacy contract
|
|
47
47
|
# ...read the project, write extract.json per those instructions...
|
|
48
|
-
npx -y @warmdrift/kgauto-check --extract extract.json # prints the findings card, fully offline
|
|
48
|
+
npx -y @warmdrift/kgauto-check@0.4.1 --extract extract.json # prints the findings card, fully offline
|
|
49
49
|
|
|
50
50
|
# Standing-value one-shots (also offline):
|
|
51
|
-
npx -y @warmdrift/kgauto-check --model-facts claude-sonnet-5 # one model → the provider's word, verified prices, limits, cliffs
|
|
52
|
-
npx -y @warmdrift/kgauto-check --observe-plan # rung 2: the one-day observe run
|
|
51
|
+
npx -y @warmdrift/kgauto-check@0.4.1 --model-facts claude-sonnet-5 # one model → the provider's word, verified prices, limits, cliffs
|
|
52
|
+
npx -y @warmdrift/kgauto-check@0.4.1 --observe-plan # rung 2: the one-day observe run
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
**Sharing (explicit opt-in).** After presenting the card, you may OFFER your human: "want to send this card to kgauto so the catalog learns what real projects look like?" If — and only if — they say yes, re-run with `--share
|
|
55
|
+
**Sharing (explicit opt-in).** After presenting the card, you may OFFER your human: "want to send this card to kgauto so the catalog learns what real projects look like?" If — and only if — they say yes, re-run with `--share`. With --share, one row is stored: a row number, the time it arrived, the project name, the extract, the card, the check’s version and the catalog’s version. The CLI prints where it went and the submission number. Never add `--share` without their explicit yes. Without it, nothing ever leaves the machine.
|
|
56
56
|
|
|
57
57
|
**Offering the durable install.** The natural moment to offer the MCP install below is after a card with real findings ("want me to keep this available? `get_model_facts` answers model questions from the verified catalog between checks"). Don't push it before the card has earned it.
|
|
58
58
|
|
|
@@ -67,7 +67,7 @@ npx -y @warmdrift/kgauto-check --observe-plan # rung 2: the one
|
|
|
67
67
|
|
|
68
68
|
## An example card
|
|
69
69
|
|
|
70
|
-
This is the output of `kgauto-check 0.4.
|
|
70
|
+
This is the output of `kgauto-check 0.4.1` on a small illustrative extract (two call sites, one on the provider's own API and one on Vertex AI, and a model picker; the extract is `tests/fixtures/readme-example.json`, and a test holds this card to the build's output), printed by the real build — not a mock-up:
|
|
71
71
|
|
|
72
72
|
````markdown
|
|
73
73
|
# Communicating Vessels — the check: example-app
|
|
@@ -81,11 +81,11 @@ This is the output of `kgauto-check 0.4.0` on a small illustrative extract (two
|
|
|
81
81
|
- 🟡 **On OpenAI's own API, `gpt-4o-mini` is deprecated and shuts down on 2027-01-14; its page names `gpt-6-luna`** — The page's line: “| January 14, 2027 | GPT-4o mini (`gpt-4o-mini-2024-07-18`) | `gpt-6-luna` |”. The catalog has no entry for it, so its limits and price were not checked.
|
|
82
82
|
<sub>components/ModelPicker.tsx:12 · basis: OpenAI's page, read 2026-11-12: https://developers.openai.com/api/docs/deprecations.md (and https://developers.openai.com/api/docs/models/gpt-4o-mini.md)</sub>
|
|
83
83
|
|
|
84
|
-
## Likely — priced from your estimates
|
|
84
|
+
## Likely — priced from your estimates or a catalog value no provider page is cited for; a provider’s word where the call may not use its own API; no retry or fallback found in the code
|
|
85
85
|
|
|
86
86
|
- 🟡 **On Google's own API, `gemini-2.5-flash` is deprecated; from 2026-12-01 its requests route to `gemini-3.5-flash-lite`** — The page's line: “`gemini-2.5-flash` | June 17, 2025 | December 1, 2026 | `gemini-3.5-flash-lite` (`gemini-2.5-flash` is no longer available in Google AI Studio; effective December 1, 2026, API requests to `gemini-2.5-flash` will automatically route to `gemi”. This site runs on Vertex AI, and Vertex AI runs its own schedule (its page: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versions).
|
|
87
87
|
<sub>lib/summarize.ts:18 · basis: Google's page, read 2026-11-12: https://aistudio.google.com/docs/deprecations; Vertex AI: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versions</sub>
|
|
88
|
-
- ℹ️ **~$0.0046/call on `gemini-2.5-flash`** — From your token estimates and doc-verified prices ($0.3/M in, $2.5/M out, verified 2026-08-14).
|
|
88
|
+
- ℹ️ **~$0.0046/call on `gemini-2.5-flash`** — From your token estimates and doc-verified prices ($0.3/M in, $2.5/M out, verified 2026-08-14). This site runs on Vertex AI: the figure is from Google's own API, and Vertex AI may set its own.
|
|
89
89
|
<sub>lib/summarize.ts:18 · basis: arithmetic on your estimates × verified catalog prices</sub>
|
|
90
90
|
- 🟡 **97% of this site's tokens are input** — Above ~85% input share, spend is dominated by context rather than answers — the single strongest signal of a leaking prompt. What's actually IN that context, and how much of it each call needed, is measurable, not guessable.
|
|
91
91
|
<sub>lib/summarize.ts:18 · basis: your token estimates; the >85% threshold is a measured portfolio heuristic</sub>
|
|
@@ -99,13 +99,13 @@ This is the output of `kgauto-check 0.4.0` on a small illustrative extract (two
|
|
|
99
99
|
|
|
100
100
|
---
|
|
101
101
|
*This check ran on your machine, against the catalog bundled with it and the providers’ deprecation pages it was built with. Nothing was uploaded; no rows were written anywhere.*
|
|
102
|
-
<sub>@warmdrift/kgauto-check 0.4.
|
|
102
|
+
<sub>@warmdrift/kgauto-check 0.4.1 · catalog @warmdrift/kgauto-compiler 2.0.0-alpha.133 · deprecation pages read 2026-11-12</sub>
|
|
103
103
|
````
|
|
104
104
|
|
|
105
105
|
## The confidence tiers (why the card is grouped)
|
|
106
106
|
|
|
107
107
|
- **certain** — the provider's own page (with its URL and the day it was read), or a fact from your code. Stated flatly.
|
|
108
|
-
- **likely** — priced from your token estimates against verified prices, or a catalog value no provider page is cited for.
|
|
108
|
+
- **likely** — priced from your token estimates against verified prices, or a catalog value no provider page is cited for (a cliff rule says its reason, what the compiler does about it, and the evidence behind it); a provider's word where the call may not use the provider's own API (a cloud platform, a gateway such as `openrouter/…`, or a platform the extract does not state); no retry or fallback found in the code.
|
|
109
109
|
- **measurable-only** — honestly unknowable from a code read: actual failure rates, actual input-waste, spend distribution, quality-at-cheaper-price. Each of these is exactly what the one-day observe run answers.
|
|
110
110
|
|
|
111
111
|
**The provider's word first (0.4.0).** A model id is matched as you wrote it (`openai/gpt-5`, `openrouter/anthropic/…`, a dated snapshot, a Bedrock or Vertex form) and looked up in a lifecycle ledger read from the four providers' own deprecation pages (Anthropic, OpenAI, Google, DeepSeek) before the catalog. A retired, shut-down, deprecated or legacy id says so, with the date, the replacement the page names, and the page's URL.
|
|
@@ -116,14 +116,14 @@ kgauto refuses to fabricate verdicts: unknown models get an honest "no measured
|
|
|
116
116
|
|
|
117
117
|
```bash
|
|
118
118
|
# Claude Code
|
|
119
|
-
claude mcp add kgauto-check -- npx -y @warmdrift/kgauto-check
|
|
119
|
+
claude mcp add kgauto-check -- npx -y @warmdrift/kgauto-check@0.4.1
|
|
120
120
|
```
|
|
121
121
|
|
|
122
122
|
```json
|
|
123
123
|
// Cursor / generic mcpServers config
|
|
124
124
|
{
|
|
125
125
|
"mcpServers": {
|
|
126
|
-
"kgauto-check": { "command": "npx", "args": ["-y", "@warmdrift/kgauto-check"] }
|
|
126
|
+
"kgauto-check": { "command": "npx", "args": ["-y", "@warmdrift/kgauto-check@0.4.1"] }
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
```
|
package/dist/bin.js
CHANGED
|
@@ -3,26 +3,20 @@ import {
|
|
|
3
3
|
CHECK_VERSION,
|
|
4
4
|
ExtractSchema,
|
|
5
5
|
OBSERVE_DAY_PLAN,
|
|
6
|
+
SHARE_ENDPOINT_DEFAULT,
|
|
6
7
|
START_CHECK_INSTRUCTIONS,
|
|
8
|
+
USAGE,
|
|
9
|
+
postShare,
|
|
7
10
|
renderModelFacts,
|
|
8
11
|
runCheck,
|
|
12
|
+
shareConfirmation,
|
|
13
|
+
shareFailure,
|
|
9
14
|
startStdio
|
|
10
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-6ZBEABKR.js";
|
|
11
16
|
|
|
12
17
|
// src/bin.ts
|
|
13
18
|
import { readFileSync } from "fs";
|
|
14
|
-
var SHARE_ENDPOINT = process.env.KGAUTO_SHARE_ENDPOINT_OVERRIDE ||
|
|
15
|
-
var USAGE = `kgauto-check ${CHECK_VERSION}
|
|
16
|
-
|
|
17
|
-
usage:
|
|
18
|
-
npx -y @warmdrift/kgauto-check --extract-contract
|
|
19
|
-
npx -y @warmdrift/kgauto-check --extract <extract.json> [--share]
|
|
20
|
-
npx -y @warmdrift/kgauto-check --model-facts <model-id>
|
|
21
|
-
npx -y @warmdrift/kgauto-check --observe-plan
|
|
22
|
-
npx -y @warmdrift/kgauto-check # no args: stdio MCP server
|
|
23
|
-
|
|
24
|
-
The check runs fully offline. --share is the one explicit exception: it sends
|
|
25
|
-
the scrubbed extract (identifiers and counts only) + the card to kgauto.`;
|
|
19
|
+
var SHARE_ENDPOINT = process.env.KGAUTO_SHARE_ENDPOINT_OVERRIDE || SHARE_ENDPOINT_DEFAULT;
|
|
26
20
|
var args = process.argv.slice(2);
|
|
27
21
|
var flagValue = (name) => {
|
|
28
22
|
const i = args.indexOf(name);
|
|
@@ -71,34 +65,21 @@ async function main() {
|
|
|
71
65
|
process.exitCode = 1;
|
|
72
66
|
return;
|
|
73
67
|
}
|
|
74
|
-
const result = runCheck(parsed.data);
|
|
68
|
+
const result = runCheck(parsed.data, { share: args.includes("--share") });
|
|
75
69
|
console.log(result.card);
|
|
76
70
|
if (args.includes("--share")) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
});
|
|
88
|
-
const body = await res.json().catch(() => ({}));
|
|
89
|
-
if (res.ok && body.id !== void 0) {
|
|
90
|
-
console.log(
|
|
91
|
-
`
|
|
92
|
-
[--share] Sent to kgauto (submission ${String(body.id)}): the extract above (identifiers and counts only) and this card \u2014 nothing else. Destination: ${SHARE_ENDPOINT}`
|
|
93
|
-
);
|
|
94
|
-
} else {
|
|
95
|
-
console.error(`
|
|
96
|
-
[--share] FAILED (${res.status}${body.error ? `: ${String(body.error)}` : ""}) \u2014 nothing was recorded. The check itself is unaffected.`);
|
|
97
|
-
process.exitCode = 1;
|
|
98
|
-
}
|
|
99
|
-
} catch (err) {
|
|
71
|
+
const out = await postShare(SHARE_ENDPOINT, {
|
|
72
|
+
extract: parsed.data,
|
|
73
|
+
card: result.card,
|
|
74
|
+
check_version: CHECK_VERSION,
|
|
75
|
+
catalog_version: result.catalogVersion
|
|
76
|
+
});
|
|
77
|
+
if (out.ok) {
|
|
78
|
+
console.log(`
|
|
79
|
+
${shareConfirmation(SHARE_ENDPOINT, out.id)}`);
|
|
80
|
+
} else {
|
|
100
81
|
console.error(`
|
|
101
|
-
|
|
82
|
+
${shareFailure(out.reason)}`);
|
|
102
83
|
process.exitCode = 1;
|
|
103
84
|
}
|
|
104
85
|
}
|
|
@@ -3680,8 +3680,9 @@ var LEDGER = [
|
|
|
3680
3680
|
|
|
3681
3681
|
// src/lifecycle.ts
|
|
3682
3682
|
import { allProfiles, tryGetProfile } from "@warmdrift/kgauto-compiler";
|
|
3683
|
+
var GATEWAYS = /* @__PURE__ */ new Set(["openrouter"]);
|
|
3683
3684
|
var PREFIXES = {
|
|
3684
|
-
openrouter:
|
|
3685
|
+
openrouter: "openrouter",
|
|
3685
3686
|
openai: null,
|
|
3686
3687
|
anthropic: null,
|
|
3687
3688
|
google: null,
|
|
@@ -3799,8 +3800,14 @@ var DEFINITION_PAGE = {
|
|
|
3799
3800
|
google: "https://aistudio.google.com/docs/deprecations",
|
|
3800
3801
|
deepseek: "https://api-docs.deepseek.com/updates"
|
|
3801
3802
|
};
|
|
3802
|
-
var PARTNER_NAME = {
|
|
3803
|
+
var PARTNER_NAME = {
|
|
3804
|
+
vertex: "Vertex AI",
|
|
3805
|
+
bedrock: "Amazon Bedrock",
|
|
3806
|
+
azure: "Azure",
|
|
3807
|
+
openrouter: "OpenRouter"
|
|
3808
|
+
};
|
|
3803
3809
|
function partnerPage(partner, provider) {
|
|
3810
|
+
if (partner === "openrouter") return "https://openrouter.ai/docs/guides/overview/models";
|
|
3804
3811
|
if (partner === "vertex" && provider === "google") return "https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versions";
|
|
3805
3812
|
if (partner === "vertex" && provider === "anthropic")
|
|
3806
3813
|
return "https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/google-managed";
|
|
@@ -3820,15 +3827,16 @@ function siteState(site, res) {
|
|
|
3820
3827
|
const stated = site.platform;
|
|
3821
3828
|
if (res.partner) {
|
|
3822
3829
|
const conflict = stated === "provider-api" || (stated === "vertex" || stated === "bedrock" || stated === "azure") && stated !== res.partner ? `the extract says ${stated === "provider-api" ? "the provider's own API" : PARTNER_NAME[stated]}, but the id's form is ${PARTNER_NAME[res.partner]}'s` : void 0;
|
|
3823
|
-
return { partner: res.partner, providerApi: false, ...conflict ? { conflict } : {} };
|
|
3830
|
+
return { partner: res.partner, providerApi: false, source: "id", ...conflict ? { conflict } : {} };
|
|
3824
3831
|
}
|
|
3825
|
-
if (stated === "vertex" || stated === "bedrock" || stated === "azure") return { partner: stated, providerApi: false };
|
|
3832
|
+
if (stated === "vertex" || stated === "bedrock" || stated === "azure") return { partner: stated, providerApi: false, source: "stated" };
|
|
3826
3833
|
const words = wordPartner(site);
|
|
3827
3834
|
if (stated === "provider-api") {
|
|
3828
|
-
if (words)
|
|
3835
|
+
if (words)
|
|
3836
|
+
return { partner: words, providerApi: false, source: "words", conflict: `the extract says the provider's own API, but its notes or path name ${PARTNER_NAME[words]}` };
|
|
3829
3837
|
return { providerApi: true };
|
|
3830
3838
|
}
|
|
3831
|
-
return { ...words ? { partner: words } : {}, providerApi: false };
|
|
3839
|
+
return { ...words ? { partner: words, source: "words" } : {}, providerApi: false };
|
|
3832
3840
|
}
|
|
3833
3841
|
function coveredBy(provider, partner) {
|
|
3834
3842
|
if (provider === "anthropic" && partner === "azure") return "Microsoft Foundry";
|
|
@@ -3872,10 +3880,13 @@ import {
|
|
|
3872
3880
|
tryGetProfile as tryGetProfile2,
|
|
3873
3881
|
resolveModelAlias,
|
|
3874
3882
|
isArchetype,
|
|
3875
|
-
LIBRARY_VERSION
|
|
3883
|
+
LIBRARY_VERSION,
|
|
3884
|
+
hasConfirmedEvidence,
|
|
3885
|
+
isCapabilityReducing
|
|
3876
3886
|
} from "@warmdrift/kgauto-compiler";
|
|
3877
|
-
import { retirementFloorClause } from "@warmdrift/kgauto-compiler/profiles";
|
|
3887
|
+
import { retirementFloorClause, deriveCliffEvidenceClass } from "@warmdrift/kgauto-compiler/profiles";
|
|
3878
3888
|
var DESTINATION_SENTENCE = "This check ran on your machine, against the catalog bundled with it and the providers\u2019 deprecation pages it was built with. Nothing was uploaded; no rows were written anywhere.";
|
|
3889
|
+
var SHARE_DESTINATION_SENTENCE = "This check ran on your machine, against the catalog bundled with it and the providers\u2019 deprecation pages it was built with. Because you ran it with --share, this card and the extract are sent after it is printed.";
|
|
3879
3890
|
var defaultResolve = (id) => ({ canonical: resolveModelAlias(id), profile: tryGetProfile2(id) });
|
|
3880
3891
|
function perCallCostUsd(p, inTok, outTok) {
|
|
3881
3892
|
return inTok / 1e6 * p.costInputPer1m + outTok / 1e6 * p.costOutputPer1m;
|
|
@@ -3894,8 +3905,9 @@ function placeLine(line, provider, st) {
|
|
|
3894
3905
|
parts.push(`${P}'s deprecations page says its dates apply on ${covered}, so they hold on this site's platform too.`);
|
|
3895
3906
|
} else {
|
|
3896
3907
|
const page = partnerPage(st.partner, provider);
|
|
3908
|
+
const where = page ? ` (its page: ${page}).` : " (no page of its own for this model was read).";
|
|
3897
3909
|
parts.push(
|
|
3898
|
-
`This
|
|
3910
|
+
GATEWAYS.has(st.partner) ? `This id is written for ${N}, a gateway, and ${N} may keep its own schedule for the model${where}` : `This site runs on ${N}, and ${N} runs its own schedule${where}`
|
|
3899
3911
|
);
|
|
3900
3912
|
if (page) basis = `${basis}; ${N}: ${page}`;
|
|
3901
3913
|
}
|
|
@@ -3919,7 +3931,7 @@ function ledgerLine(a) {
|
|
|
3919
3931
|
title = date ? `${on} was retired on ${date}` : `${on} was retired${row.announced ? ` (change log, ${row.announced})` : ""}`;
|
|
3920
3932
|
break;
|
|
3921
3933
|
case "shut down":
|
|
3922
|
-
title = date ? `${on} was shut down on ${date}` : `${on} has been shut down (the
|
|
3934
|
+
title = date ? `${on} was shut down on ${date}` : floor ? `${on} has been shut down (the earliest shutdown date the page gave was ${floor})` : `${on} has been shut down`;
|
|
3923
3935
|
break;
|
|
3924
3936
|
case "legacy":
|
|
3925
3937
|
title = `${on} is a legacy name ${P} said it would discontinue on ${date}${past ? ", a date before this read; the page states nothing later" : ""}`;
|
|
@@ -3979,6 +3991,103 @@ function providerLifecycleLine(shown, p) {
|
|
|
3979
3991
|
basis: `catalog providerLifecycle, read ${pl.readOn}: ${pl.url}`
|
|
3980
3992
|
};
|
|
3981
3993
|
}
|
|
3994
|
+
var ACTION_WORDS = {
|
|
3995
|
+
downgrade_quality_warning: "attaches a warning to the compiled request and leaves the request as it is",
|
|
3996
|
+
quality_gate_structured: "ranks the model lower for a request that asks for structured output at this size",
|
|
3997
|
+
force_thinking_budget_zero: "turns the model's thinking off for the request",
|
|
3998
|
+
force_terse_output: "asks the model for a short answer",
|
|
3999
|
+
drop_to_top_relevant: "sends only the most relevant tools",
|
|
4000
|
+
strip_tools: "sends the request without its tools",
|
|
4001
|
+
escalate_target: "moves the request to a stronger model"
|
|
4002
|
+
};
|
|
4003
|
+
var ACTION_WOULD = {
|
|
4004
|
+
force_thinking_budget_zero: "turn the model's thinking off for the request",
|
|
4005
|
+
force_terse_output: "ask the model for a short answer",
|
|
4006
|
+
drop_to_top_relevant: "send only the most relevant tools",
|
|
4007
|
+
strip_tools: "send the request without its tools"
|
|
4008
|
+
};
|
|
4009
|
+
var QUALITY_ACTIONS = /* @__PURE__ */ new Set(["downgrade_quality_warning", "quality_gate_structured"]);
|
|
4010
|
+
function actionSentence(c) {
|
|
4011
|
+
if (isCapabilityReducing(c.action) && !hasConfirmedEvidence(c)) {
|
|
4012
|
+
return `What the compiler does about it: it would ${ACTION_WOULD[c.action] ?? c.action.replaceAll("_", " ")}, but holds that back until a probe confirms the cliff.`;
|
|
4013
|
+
}
|
|
4014
|
+
if (c.action === "quality_gate_structured") {
|
|
4015
|
+
return `What the compiler does about it: it stops trusting this model's structured output at or above this size${c.whenIntent ? ` on ${c.whenIntent} work` : ""}, and ranks the model lower for such a request.`;
|
|
4016
|
+
}
|
|
4017
|
+
const w = ACTION_WORDS[c.action];
|
|
4018
|
+
return w ? `What the compiler does about it: it ${w}.` : `What the compiler does about it: its action is "${c.action.replaceAll("_", " ")}".`;
|
|
4019
|
+
}
|
|
4020
|
+
function evidenceSentence(c) {
|
|
4021
|
+
const ev = c.evidence;
|
|
4022
|
+
const n = /\bn=(\d+)\b/.exec(c.reason)?.[1];
|
|
4023
|
+
const count = n ? `, on ${n} ${n === "1" ? "call" : "calls"} (the count its reason gives)` : "";
|
|
4024
|
+
if (!ev) {
|
|
4025
|
+
const derived = deriveCliffEvidenceClass(c);
|
|
4026
|
+
if (derived === "observed") return "Evidence: no evidence record; the catalog's note describes a measured incident.";
|
|
4027
|
+
if (derived === "assumed") return "Evidence: the rule carries no evidence record; its reason says it is carried over, not measured on this model.";
|
|
4028
|
+
return "Evidence: the rule carries no evidence record.";
|
|
4029
|
+
}
|
|
4030
|
+
const when = ev.lastProbed ? `, last ${ev.class === "observed" ? "seen" : "run"} ${ev.lastProbed}` : "";
|
|
4031
|
+
switch (ev.class) {
|
|
4032
|
+
case "probed": {
|
|
4033
|
+
const v = ev.verdict === "confirmed" ? "a probe reproduced it" : ev.verdict === "knee-moved" ? "a probe moved its threshold and the rule was re-pinned" : ev.verdict === "flagged" ? "a probe did not reproduce it" : "a probe ran; its verdict is not recorded";
|
|
4034
|
+
return `Evidence: ${v}${when}${count}.`;
|
|
4035
|
+
}
|
|
4036
|
+
case "observed":
|
|
4037
|
+
return `Evidence: observed in real calls${when}${count}.`;
|
|
4038
|
+
case "assumed":
|
|
4039
|
+
return "Evidence: carried over from a similar model, not measured on this one.";
|
|
4040
|
+
default:
|
|
4041
|
+
return "Evidence: stated in the catalog without a measurement.";
|
|
4042
|
+
}
|
|
4043
|
+
}
|
|
4044
|
+
function scopeSentence(reason) {
|
|
4045
|
+
const endpoint = /(\/v\d+[a-z]*\/[a-z0-9_/.:-]*[a-z0-9_])/i.exec(reason)?.[1];
|
|
4046
|
+
if (endpoint) return `It is about one endpoint, \`${endpoint}\`: it says nothing about the model reached another way.`;
|
|
4047
|
+
const wire = /\bon (?:the |kgauto's )?([A-Za-z][\w .-]*?) wire\b/.exec(reason)?.[1];
|
|
4048
|
+
if (wire) return `It is about one wire, ${wire}: it says nothing about the model reached another way.`;
|
|
4049
|
+
return "";
|
|
4050
|
+
}
|
|
4051
|
+
var INTERNAL_APPS = [
|
|
4052
|
+
"playbacksam",
|
|
4053
|
+
"tt-intel",
|
|
4054
|
+
"tt-intelligence",
|
|
4055
|
+
"inspire-central",
|
|
4056
|
+
"global-expansion",
|
|
4057
|
+
"lovable-intelligence",
|
|
4058
|
+
"incantato",
|
|
4059
|
+
"ivypass"
|
|
4060
|
+
];
|
|
4061
|
+
var namesInternalApp = (text2) => INTERNAL_APPS.some((n) => text2.toLowerCase().includes(n));
|
|
4062
|
+
function cliffLine(canonical, c, metricValue) {
|
|
4063
|
+
const parts = [];
|
|
4064
|
+
const onWork = c.whenIntent ? ` on ${c.whenIntent} work` : "";
|
|
4065
|
+
const recorded = c.evidence?.class === "observed" || hasConfirmedEvidence(c);
|
|
4066
|
+
if (QUALITY_ACTIONS.has(c.action) && recorded) {
|
|
4067
|
+
parts.push(`Above this threshold${onWork}, quality degrades in a measured, repeatable way.`);
|
|
4068
|
+
}
|
|
4069
|
+
parts.push(
|
|
4070
|
+
namesInternalApp(c.reason) ? "The catalog's note for this rule is written for our own records and is not quoted." : `The catalog's reason${c.whenIntent ? ` (for ${c.whenIntent} work)` : ""}: \u201C${c.reason.trim().replace(/\.$/, "")}\u201D.`
|
|
4071
|
+
);
|
|
4072
|
+
const scope = scopeSentence(c.reason);
|
|
4073
|
+
if (scope) parts.push(scope);
|
|
4074
|
+
parts.push(actionSentence(c));
|
|
4075
|
+
parts.push(evidenceSentence(c));
|
|
4076
|
+
const where = metricValue === c.threshold ? "at the line" : "over the line";
|
|
4077
|
+
parts.push(
|
|
4078
|
+
c.metric === "tool_count" ? `This site offers ${metricValue.toLocaleString()} ${metricValue === 1 ? "tool" : "tools"}, ${where}.` : `Your estimate of ${metricValue.toLocaleString()} sits ${where}.`
|
|
4079
|
+
);
|
|
4080
|
+
const ev = c.evidence;
|
|
4081
|
+
const tag = ev ? `evidence: ${[ev.class, ev.verdict, ev.lastProbed].filter(Boolean).join(", ")}` : "no evidence record";
|
|
4082
|
+
return {
|
|
4083
|
+
severity: "yellow",
|
|
4084
|
+
confidence: "likely",
|
|
4085
|
+
// Amendment D2: the title agrees with the sentence — "reaches" at equality, "crosses" above.
|
|
4086
|
+
title: `\`${canonical}\` has a known ${c.metric.replaceAll("_", " ")} cliff at ${c.threshold.toLocaleString()} \u2014 this site ${metricValue === c.threshold ? "reaches" : "crosses"} it`,
|
|
4087
|
+
detail: parts.join(" "),
|
|
4088
|
+
basis: `the catalog's cliff rule (${tag}) vs ${c.metric === "tool_count" ? "this site's tool count" : "your estimate"}`
|
|
4089
|
+
};
|
|
4090
|
+
}
|
|
3982
4091
|
function analyseModel(configured, opts = {}, site = {}) {
|
|
3983
4092
|
const resolveCat = opts.resolve ?? defaultResolve;
|
|
3984
4093
|
const roster = opts.roster ?? allProfiles2;
|
|
@@ -4013,7 +4122,7 @@ function analyseModel(configured, opts = {}, site = {}) {
|
|
|
4013
4122
|
basis: "catalog lookup and the providers\u2019 deprecation lists"
|
|
4014
4123
|
});
|
|
4015
4124
|
}
|
|
4016
|
-
return { res, shown: shownId, row, via: hit.via, profile, canonical: profile ? canonical : res.base, lines, partner };
|
|
4125
|
+
return { res, shown: shownId, row, via: hit.via, profile, canonical: profile ? canonical : res.base, lines, partner, state: st };
|
|
4017
4126
|
}
|
|
4018
4127
|
function runCheck(extract, opts = {}) {
|
|
4019
4128
|
const roster = opts.roster ?? allProfiles2;
|
|
@@ -4026,7 +4135,7 @@ function runCheck(extract, opts = {}) {
|
|
|
4026
4135
|
const bySite = /* @__PURE__ */ new Map();
|
|
4027
4136
|
const analyse = (m, site) => {
|
|
4028
4137
|
const st = siteState(site, resolveId(m));
|
|
4029
|
-
const key = `${m}|${st.partner ?? ""}|${st.providerApi}|${st.conflict ?? ""}`;
|
|
4138
|
+
const key = `${m}|${st.partner ?? ""}|${st.providerApi}|${st.conflict ?? ""}|${st.source ?? ""}`;
|
|
4030
4139
|
let a = bySite.get(key);
|
|
4031
4140
|
if (!a) {
|
|
4032
4141
|
a = analyseModel(m, opts, site);
|
|
@@ -4042,15 +4151,19 @@ function runCheck(extract, opts = {}) {
|
|
|
4042
4151
|
const profile = a.profile;
|
|
4043
4152
|
if (!profile) continue;
|
|
4044
4153
|
const canonical = a.canonical;
|
|
4045
|
-
const
|
|
4154
|
+
const offApi = a.partner;
|
|
4155
|
+
const docTier = profile.verifiedAgainstDocs && !offApi ? "certain" : "likely";
|
|
4046
4156
|
const docBasis = profile.verifiedAgainstDocs ? `catalog, verified against the provider's page ${profile.verifiedAgainstDocs}` : "catalog value, not dated against a provider page";
|
|
4157
|
+
const PP = PROVIDER_NAME[profile.provider] ?? profile.provider;
|
|
4158
|
+
const NP = offApi ? PARTNER_NAME[offApi] : "";
|
|
4159
|
+
const whose = offApi ? (GATEWAYS.has(offApi) ? ` This id is written for ${NP}, a gateway: the figure is from ${PP}'s own API, and ${NP} may set its own.` : a.state?.source === "words" ? ` This site's path or notes name ${NP}; if it runs there, the figure is from ${PP}'s own API and ${NP} may set its own.` : ` This site runs on ${NP}: the figure is from ${PP}'s own API, and ${NP} may set its own.`) + (a.state?.conflict ? ` The extract and the code disagree: ${a.state.conflict}.` : "") : "";
|
|
4047
4160
|
const worstIn = site.maxInputTokens ?? site.estInputTokens;
|
|
4048
4161
|
if (worstIn !== void 0 && worstIn > profile.maxContextTokens) {
|
|
4049
4162
|
add({
|
|
4050
4163
|
severity: "red",
|
|
4051
4164
|
confidence: site.maxInputTokens !== void 0 ? docTier : "likely",
|
|
4052
4165
|
title: `input can exceed \`${canonical}\`'s context window`,
|
|
4053
|
-
detail: `Your ${site.maxInputTokens !== void 0 ? "worst-case" : "typical"} input estimate (${worstIn.toLocaleString()} tokens) exceeds the model's ${profile.maxContextTokens.toLocaleString()}-token window. Those calls fail outright or silently truncate, depending on the provider
|
|
4166
|
+
detail: `Your ${site.maxInputTokens !== void 0 ? "worst-case" : "typical"} input estimate (${worstIn.toLocaleString()} tokens) exceeds the model's ${profile.maxContextTokens.toLocaleString()}-token window. Those calls fail outright or silently truncate, depending on the provider.${whose}`,
|
|
4054
4167
|
basis: `your estimate vs ${docBasis}: maxContextTokens=${profile.maxContextTokens}`,
|
|
4055
4168
|
callSites: at
|
|
4056
4169
|
});
|
|
@@ -4060,7 +4173,7 @@ function runCheck(extract, opts = {}) {
|
|
|
4060
4173
|
severity: "red",
|
|
4061
4174
|
confidence: "likely",
|
|
4062
4175
|
title: `expected output exceeds \`${canonical}\`'s output cap`,
|
|
4063
|
-
detail: `You expect ~${site.estOutputTokens.toLocaleString()} output tokens; the model caps at ${profile.maxOutputTokens.toLocaleString()}. Responses will be cut mid-generation \u2014 on JSON output this is the classic unparseable-tail failure
|
|
4176
|
+
detail: `You expect ~${site.estOutputTokens.toLocaleString()} output tokens; the model caps at ${profile.maxOutputTokens.toLocaleString()}. Responses will be cut mid-generation \u2014 on JSON output this is the classic unparseable-tail failure.${whose}`,
|
|
4064
4177
|
basis: `your estimate vs ${docBasis}: maxOutputTokens=${profile.maxOutputTokens}`,
|
|
4065
4178
|
callSites: at
|
|
4066
4179
|
});
|
|
@@ -4080,7 +4193,7 @@ function runCheck(extract, opts = {}) {
|
|
|
4080
4193
|
severity: "red",
|
|
4081
4194
|
confidence: docTier,
|
|
4082
4195
|
title: `\`${canonical}\` has no structured-output support, but this site parses JSON`,
|
|
4083
|
-
detail: `Output-shape failures here land on your parser as intermittent exceptions. Models with native or grammar-constrained output move that failure from runtime to the request
|
|
4196
|
+
detail: `Output-shape failures here land on your parser as intermittent exceptions. Models with native or grammar-constrained output move that failure from runtime to the request.${whose}`,
|
|
4084
4197
|
basis: `${docBasis}: structuredOutput=none`,
|
|
4085
4198
|
callSites: at
|
|
4086
4199
|
});
|
|
@@ -4090,14 +4203,8 @@ function runCheck(extract, opts = {}) {
|
|
|
4090
4203
|
if (cliff.whenIntent && cliff.whenIntent !== archetype) continue;
|
|
4091
4204
|
const metricValue = cliff.metric === "input_tokens" ? worstIn : cliff.metric === "tool_count" ? site.toolCount : void 0;
|
|
4092
4205
|
if (metricValue === void 0 || metricValue < cliff.threshold) continue;
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
confidence: "likely",
|
|
4096
|
-
title: `\`${canonical}\` has a known ${cliff.metric.replaceAll("_", " ")} cliff at ${cliff.threshold.toLocaleString()} \u2014 this site crosses it`,
|
|
4097
|
-
detail: `Above this threshold${cliff.whenIntent ? ` on ${cliff.whenIntent} work` : ""}, quality degrades in a measured, repeatable way (the catalog's compiler action: ${cliff.action.replaceAll("_", " ")}). Your estimate of ${metricValue.toLocaleString()} sits over the line.`,
|
|
4098
|
-
basis: `the catalog's cliff rule vs your estimate`,
|
|
4099
|
-
callSites: at
|
|
4100
|
-
});
|
|
4206
|
+
if (cliff.action === "quality_gate_structured" && !site.expectsStructuredOutput) continue;
|
|
4207
|
+
add({ ...cliffLine(canonical, cliff, metricValue), callSites: at });
|
|
4101
4208
|
}
|
|
4102
4209
|
if (site.retry === "none") {
|
|
4103
4210
|
const PN = PROVIDER_NAME[profile.provider] ?? profile.provider;
|
|
@@ -4118,7 +4225,7 @@ function runCheck(extract, opts = {}) {
|
|
|
4118
4225
|
severity: "info",
|
|
4119
4226
|
confidence: "likely",
|
|
4120
4227
|
title: `~$${perCall.toFixed(4)}/call on \`${canonical}\`${monthly !== void 0 ? ` (~$${monthly.toFixed(2)}/month at your volume)` : ""}`,
|
|
4121
|
-
detail: `From your token estimates and doc-verified prices ($${profile.costInputPer1m}/M in, $${profile.costOutputPer1m}/M out${profile.verifiedAgainstDocs ? `, verified ${profile.verifiedAgainstDocs}` : ""})
|
|
4228
|
+
detail: `From your token estimates and doc-verified prices ($${profile.costInputPer1m}/M in, $${profile.costOutputPer1m}/M out${profile.verifiedAgainstDocs ? `, verified ${profile.verifiedAgainstDocs}` : ""}).${whose}`,
|
|
4122
4229
|
basis: "arithmetic on your estimates \xD7 verified catalog prices",
|
|
4123
4230
|
callSites: at
|
|
4124
4231
|
});
|
|
@@ -4184,18 +4291,20 @@ function runCheck(extract, opts = {}) {
|
|
|
4184
4291
|
}
|
|
4185
4292
|
return {
|
|
4186
4293
|
findings: merged,
|
|
4187
|
-
card: renderCard(extract, merged, analyses),
|
|
4294
|
+
card: renderCard(extract, merged, analyses, opts.share === true),
|
|
4188
4295
|
catalogVersion: LIBRARY_VERSION
|
|
4189
4296
|
};
|
|
4190
4297
|
}
|
|
4191
4298
|
var TIER_ORDER = ["certain", "likely", "measurable-only"];
|
|
4192
4299
|
var TIER_HEADING = {
|
|
4193
4300
|
certain: "Certain \u2014 read from the providers\u2019 pages and your code",
|
|
4194
|
-
|
|
4301
|
+
// 0.4.1 (R5): since 0.4.0 this tier also holds a provider's word on a call that may not use the provider's own
|
|
4302
|
+
// API (a partner, a gateway, an unstated platform) and the no-fallback line; the heading names all three.
|
|
4303
|
+
likely: "Likely \u2014 priced from your estimates or a catalog value no provider page is cited for; a provider\u2019s word where the call may not use its own API; no retry or fallback found in the code",
|
|
4195
4304
|
"measurable-only": "Only measurable \u2014 what the observe day answers"
|
|
4196
4305
|
};
|
|
4197
4306
|
var SEV_MARK = { red: "\u{1F534}", yellow: "\u{1F7E1}", info: "\u2139\uFE0F" };
|
|
4198
|
-
function renderCard(extract, findings, analyses = /* @__PURE__ */ new Map()) {
|
|
4307
|
+
function renderCard(extract, findings, analyses = /* @__PURE__ */ new Map(), share = false) {
|
|
4199
4308
|
const lines = [];
|
|
4200
4309
|
lines.push(`# Communicating Vessels \u2014 the check: ${extract.project.name}`);
|
|
4201
4310
|
lines.push("");
|
|
@@ -4243,14 +4352,50 @@ function renderCard(extract, findings, analyses = /* @__PURE__ */ new Map()) {
|
|
|
4243
4352
|
}
|
|
4244
4353
|
lines.push("");
|
|
4245
4354
|
lines.push("---");
|
|
4246
|
-
lines.push(`*${DESTINATION_SENTENCE}*`);
|
|
4355
|
+
lines.push(`*${share ? SHARE_DESTINATION_SENTENCE : DESTINATION_SENTENCE}*`);
|
|
4247
4356
|
lines.push(
|
|
4248
4357
|
`<sub>@warmdrift/kgauto-check ${CHECK_VERSION} \xB7 catalog @warmdrift/kgauto-compiler ${LIBRARY_VERSION} \xB7 deprecation pages read ${LEDGER_READ_ON}</sub>`
|
|
4249
4358
|
);
|
|
4250
4359
|
return lines.join("\n");
|
|
4251
4360
|
}
|
|
4252
4361
|
|
|
4362
|
+
// src/share.ts
|
|
4363
|
+
var SHARE_ENDPOINT_DEFAULT = "https://kgauto-dashboard.vercel.app/api/check-submission";
|
|
4364
|
+
var SHARE_STORED_SENTENCE = "With --share, one row is stored: a row number, the time it arrived, the project name, the extract, the card, the check\u2019s version and the catalog\u2019s version.";
|
|
4365
|
+
async function postShare(endpoint, body, fetchImpl = fetch) {
|
|
4366
|
+
try {
|
|
4367
|
+
const res = await fetchImpl(endpoint, {
|
|
4368
|
+
method: "POST",
|
|
4369
|
+
headers: { "content-type": "application/json" },
|
|
4370
|
+
body: JSON.stringify(body)
|
|
4371
|
+
});
|
|
4372
|
+
const parsed = await res.json().catch(() => ({}));
|
|
4373
|
+
if (res.ok && parsed.ok === true && parsed.id !== void 0 && parsed.id !== null) return { ok: true, id: String(parsed.id) };
|
|
4374
|
+
return { ok: false, reason: `${res.status}${parsed.error ? `: ${String(parsed.error)}` : parsed.ok === true ? "" : ": no {ok: true, id} in the answer"}` };
|
|
4375
|
+
} catch (err) {
|
|
4376
|
+
return { ok: false, reason: err instanceof Error ? err.message : String(err) };
|
|
4377
|
+
}
|
|
4378
|
+
}
|
|
4379
|
+
function shareFailure(reason) {
|
|
4380
|
+
return `[--share] FAILED (${reason}) \u2014 the endpoint did not confirm a row, so a row may or may not exist. The check itself is unaffected.`;
|
|
4381
|
+
}
|
|
4382
|
+
function shareConfirmation(endpoint, id) {
|
|
4383
|
+
return `[--share] Sent to ${endpoint} (submission ${id}). ${SHARE_STORED_SENTENCE}`;
|
|
4384
|
+
}
|
|
4385
|
+
|
|
4253
4386
|
// src/instructions.ts
|
|
4387
|
+
var NPX = `npx -y @warmdrift/kgauto-check@${CHECK_VERSION}`;
|
|
4388
|
+
var USAGE = `kgauto-check ${CHECK_VERSION}
|
|
4389
|
+
|
|
4390
|
+
usage:
|
|
4391
|
+
${NPX} --extract-contract
|
|
4392
|
+
${NPX} --extract <extract.json> [--share]
|
|
4393
|
+
${NPX} --model-facts <model-id>
|
|
4394
|
+
${NPX} --observe-plan
|
|
4395
|
+
${NPX} # no args: stdio MCP server
|
|
4396
|
+
|
|
4397
|
+
The check runs fully offline. --share is the one explicit exception.
|
|
4398
|
+
${SHARE_STORED_SENTENCE}`;
|
|
4254
4399
|
var SERVER_INSTRUCTIONS = `You are talking to kgauto-check, a local, offline checker for AI call surfaces.
|
|
4255
4400
|
|
|
4256
4401
|
Flow: (1) call start_check to get extraction instructions, (2) read THIS project's code yourself and build the extract, (3) call run_check with it, (4) present the returned card to your human verbatim (it is grouped by confidence tier on purpose), (5) if they want measured numbers, call get_observe_day_plan.
|
|
@@ -4292,11 +4437,11 @@ Do NOT put prompt text, source code, file contents, or secrets in the extract. I
|
|
|
4292
4437
|
Write the extract as JSON:
|
|
4293
4438
|
{ "project": { "name": "...", "description": "..." }, "callSites": [ ...one object per call site, or none... ], "models": [ ...optional, ids no call site carries... ] }
|
|
4294
4439
|
and run:
|
|
4295
|
-
|
|
4440
|
+
${NPX} --extract extract.json
|
|
4296
4441
|
Present the printed card verbatim \u2014 the confidence tiers (certain / likely / measurable-only) are the point: they tell your human exactly how much to trust each line, and the measurable-only section is what a one-day observe run would answer.
|
|
4297
4442
|
|
|
4298
4443
|
## Sharing (optional, explicit)
|
|
4299
|
-
After presenting the card, you may OFFER your human: "want to send this card to kgauto so the catalog learns what real projects look like?" If \u2014 and only if \u2014 they say yes, re-run with --share. Never add --share without their explicit yes.
|
|
4444
|
+
After presenting the card, you may OFFER your human: "want to send this card to kgauto so the catalog learns what real projects look like?" If \u2014 and only if \u2014 they say yes, re-run with --share. Never add --share without their explicit yes. ${SHARE_STORED_SENTENCE} The CLI prints where it went and the submission number.
|
|
4300
4445
|
|
|
4301
4446
|
## Honesty rules you inherit while presenting
|
|
4302
4447
|
- Do not soften "certain" findings or upgrade "likely" ones.
|
|
@@ -4338,7 +4483,8 @@ function renderModelFacts(model) {
|
|
|
4338
4483
|
const dates = [
|
|
4339
4484
|
r.announced ? `announced ${r.announced}` : "",
|
|
4340
4485
|
r.shutdown ? `${r.word === "deprecated" || r.word === "legacy" || r.word === "rerouted" ? "shutdown / discontinuation date" : r.word} ${r.shutdown}` : "",
|
|
4341
|
-
|
|
4486
|
+
// 0.4.1 (R5): on a model already shut down the floor is the page's earliest date, said in the past.
|
|
4487
|
+
r.shutdownFloor ? r.word === "shut down" ? `the earliest shutdown date the page gave was ${r.shutdownFloor}` : `not before ${r.shutdownFloor}` : ""
|
|
4342
4488
|
].filter(Boolean);
|
|
4343
4489
|
out.push(
|
|
4344
4490
|
`- ${P}'s word: **${r.word}**${dates.length ? ` (${dates.join("; ")})` : ""}${r.replacement ? ` \xB7 replacement the page names: \`${r.replacement}\`` : ""}${r.routesTo ? ` \xB7 requests routed to: ${r.routesTo}` : ""}`
|
|
@@ -4348,8 +4494,9 @@ function renderModelFacts(model) {
|
|
|
4348
4494
|
if (a.via) out.push(`- matched the dated snapshot \`${a.via}\` the page lists`);
|
|
4349
4495
|
if (a.partner) {
|
|
4350
4496
|
const page = partnerPage(a.partner, r.provider);
|
|
4497
|
+
const N = PARTNER_NAME[a.partner];
|
|
4351
4498
|
out.push(
|
|
4352
|
-
`- this id form is ${
|
|
4499
|
+
GATEWAYS.has(a.partner) ? `- this id form is ${N}'s, a gateway: ${P}'s word above is for ${P}'s own API, and ${N} may keep its own schedule${page ? ` (${page})` : ""}` : `- this id form is ${N}'s: ${P}'s word above is for ${P}'s own API, and ${N} runs its own schedule${page ? ` (${page})` : ""}`
|
|
4353
4500
|
);
|
|
4354
4501
|
}
|
|
4355
4502
|
}
|
|
@@ -4475,6 +4622,11 @@ export {
|
|
|
4475
4622
|
analyseModel,
|
|
4476
4623
|
runCheck,
|
|
4477
4624
|
renderCard,
|
|
4625
|
+
SHARE_ENDPOINT_DEFAULT,
|
|
4626
|
+
postShare,
|
|
4627
|
+
shareFailure,
|
|
4628
|
+
shareConfirmation,
|
|
4629
|
+
USAGE,
|
|
4478
4630
|
SERVER_INSTRUCTIONS,
|
|
4479
4631
|
START_CHECK_INSTRUCTIONS,
|
|
4480
4632
|
OBSERVE_DAY_PLAN,
|
package/dist/index.d.ts
CHANGED
|
@@ -368,8 +368,11 @@ interface Resolution {
|
|
|
368
368
|
/** Set when the id is a partner platform's form: its lifecycle dates may differ from the provider's own API. */
|
|
369
369
|
partner?: Partner;
|
|
370
370
|
}
|
|
371
|
-
/**
|
|
372
|
-
|
|
371
|
+
/**
|
|
372
|
+
* A cloud platform that serves a provider's models on its own lifecycle schedule, or (0.4.1, R3)
|
|
373
|
+
* a gateway the id is explicitly written for: neither is the provider's own API.
|
|
374
|
+
*/
|
|
375
|
+
type Partner = 'vertex' | 'bedrock' | 'azure' | 'openrouter';
|
|
373
376
|
/**
|
|
374
377
|
* The prefix, Bedrock and Vertex forms are rewritten to the provider's own
|
|
375
378
|
* id. A dated snapshot is NOT stripped here — the lookup tries the dated id
|
|
@@ -384,6 +387,16 @@ interface LedgerHit {
|
|
|
384
387
|
catalogId: string;
|
|
385
388
|
}
|
|
386
389
|
declare function lookupLedger(res: Resolution): LedgerHit;
|
|
390
|
+
interface SiteState {
|
|
391
|
+
/** The partner platform the site runs on, if anything says so. */
|
|
392
|
+
partner?: Partner;
|
|
393
|
+
/** The extract stated the provider's own API and nothing contradicts it: the only certain case. */
|
|
394
|
+
providerApi: boolean;
|
|
395
|
+
/** The extract's stated platform and the id's form or the site's notes disagree. */
|
|
396
|
+
conflict?: string;
|
|
397
|
+
/** Amendment D1: where the partner came from — the id's own form, the extract's stated platform, or only words in the path or notes. */
|
|
398
|
+
source?: 'id' | 'stated' | 'words';
|
|
399
|
+
}
|
|
387
400
|
|
|
388
401
|
/**
|
|
389
402
|
* The deterministic check engine. Every finding carries a confidence tier —
|
|
@@ -392,7 +405,9 @@ declare function lookupLedger(res: Resolution): LedgerHit;
|
|
|
392
405
|
* certain — the provider's own page, or a fact read from the
|
|
393
406
|
* developer's code; stated flatly.
|
|
394
407
|
* likely — priced/inferred from the agent's own estimates, or a
|
|
395
|
-
* kgauto catalog value no provider page is cited for
|
|
408
|
+
* kgauto catalog value no provider page is cited for; a
|
|
409
|
+
* provider's word where the call may not use the
|
|
410
|
+
* provider's own API; no retry or fallback in the code.
|
|
396
411
|
* measurable-only — honestly unknowable from a code read; each one is
|
|
397
412
|
* exactly what the observe day exists to measure.
|
|
398
413
|
*
|
|
@@ -432,6 +447,8 @@ interface EngineOptions {
|
|
|
432
447
|
};
|
|
433
448
|
/** Test seam: full roster override (for cheaper-candidate scans and the family sort). */
|
|
434
449
|
roster?: () => ModelProfile[];
|
|
450
|
+
/** Amendment B3: the user ran the CLI with --share, so the footer must not say nothing is uploaded. */
|
|
451
|
+
share?: boolean;
|
|
435
452
|
}
|
|
436
453
|
declare const DESTINATION_SENTENCE: string;
|
|
437
454
|
type Line = Omit<Finding, 'id' | 'callSites'>;
|
|
@@ -450,6 +467,8 @@ interface ModelAnalysis {
|
|
|
450
467
|
lines: Line[];
|
|
451
468
|
/** The partner platform the site runs on, when the extract shows one. */
|
|
452
469
|
partner?: Partner;
|
|
470
|
+
/** Amendment D1: the site's state, so a line can say where its partner came from. */
|
|
471
|
+
state?: SiteState;
|
|
453
472
|
}
|
|
454
473
|
declare function analyseModel(configured: string, opts?: EngineOptions, site?: {
|
|
455
474
|
id?: string;
|
|
@@ -458,7 +477,7 @@ declare function analyseModel(configured: string, opts?: EngineOptions, site?: {
|
|
|
458
477
|
platform?: string;
|
|
459
478
|
}): ModelAnalysis;
|
|
460
479
|
declare function runCheck(extract: Extract, opts?: EngineOptions): CheckResult;
|
|
461
|
-
declare function renderCard(extract: Extract, findings: Finding[], analyses?: ReadonlyMap<string, ModelAnalysis
|
|
480
|
+
declare function renderCard(extract: Extract, findings: Finding[], analyses?: ReadonlyMap<string, ModelAnalysis>, share?: boolean): string;
|
|
462
481
|
|
|
463
482
|
/**
|
|
464
483
|
* GENERATED by scripts/build-ledger.mjs from the providers' own deprecation
|
|
@@ -476,7 +495,7 @@ declare const LEDGER: readonly LedgerRow[];
|
|
|
476
495
|
declare function buildServer(): McpServer;
|
|
477
496
|
|
|
478
497
|
declare const SERVER_INSTRUCTIONS = "You are talking to kgauto-check, a local, offline checker for AI call surfaces.\n\nFlow: (1) call start_check to get extraction instructions, (2) read THIS project's code yourself and build the extract, (3) call run_check with it, (4) present the returned card to your human verbatim (it is grouped by confidence tier on purpose), (5) if they want measured numbers, call get_observe_day_plan.\n\nPrivacy contract, which you should relay to your human: the extract contains identifiers and counts only \u2014 never prompt text, never source code, never secrets. This check ran on your machine, against the catalog bundled with it and the providers\u2019 deprecation pages it was built with. Nothing was uploaded; no rows were written anywhere.\n\nget_model_facts answers one-off questions about any model id \u2014 what its provider's deprecation page says, then the verified catalog \u2014 and is what makes keeping this server installed useful between checks.";
|
|
479
|
-
declare const START_CHECK_INSTRUCTIONS
|
|
498
|
+
declare const START_CHECK_INSTRUCTIONS: string;
|
|
480
499
|
|
|
481
500
|
/**
|
|
482
501
|
* Rung 2 of the ladder: the one-day observe run. v1 of this tool hands the
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@warmdrift/kgauto-check",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Point your AI at your project — kgauto's local check, as a pure CLI for coding agents. Your agent extracts the project's AI surface (identifiers and counts, never code) and this tool checks it against kgauto's verified model catalog: statuses, prices, cliffs, capability mismatches, resilience. Fully offline; --share is the one explicit opt-in exception.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"types": "dist/index.d.ts",
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
13
|
-
"README.md"
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
14
15
|
],
|
|
15
16
|
"engines": {
|
|
16
17
|
"node": ">=18"
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
"ai-cost",
|
|
32
33
|
"prompt-compiler"
|
|
33
34
|
],
|
|
34
|
-
"license": "
|
|
35
|
+
"license": "MIT",
|
|
35
36
|
"repository": {
|
|
36
37
|
"type": "git",
|
|
37
38
|
"url": "git+https://github.com/stue/kgauto.git",
|
|
@@ -39,7 +40,7 @@
|
|
|
39
40
|
},
|
|
40
41
|
"dependencies": {
|
|
41
42
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
42
|
-
"@warmdrift/kgauto-compiler": "
|
|
43
|
+
"@warmdrift/kgauto-compiler": "2.0.0-alpha.133",
|
|
43
44
|
"zod": "^3.23.0"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|