@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 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`: it sends the scrubbed extract (identifiers and counts only, by contract) and the card, says exactly where they went, and nothing else. Never add `--share` without their explicit yes. Without it, nothing ever leaves the machine.
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.0` on a small illustrative extract (two call sites, one on the provider's own API and one on Vertex AI, and a model picker), printed by the real build — not a mock-up:
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, or a catalog value no provider page is cited for
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.0 · catalog @warmdrift/kgauto-compiler 2.0.0-alpha.132 · deprecation pages read 2026-11-12</sub>
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-XWIGHIJP.js";
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 || "https://kgauto-dashboard.vercel.app/api/check-submission";
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
- try {
78
- const res = await fetch(SHARE_ENDPOINT, {
79
- method: "POST",
80
- headers: { "content-type": "application/json" },
81
- body: JSON.stringify({
82
- extract: parsed.data,
83
- card: result.card,
84
- check_version: CHECK_VERSION,
85
- catalog_version: result.catalogVersion
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
- [--share] FAILED (${err instanceof Error ? err.message : String(err)}) \u2014 nothing was recorded. The check itself is unaffected.`);
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: null,
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 = { vertex: "Vertex AI", bedrock: "Amazon Bedrock", azure: "Azure" };
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) return { partner: words, providerApi: false, conflict: `the extract says the provider's own API, but its notes or path name ${PARTNER_NAME[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 site runs on ${N}, and ${N} runs its own schedule` + (page ? ` (its page: ${page}).` : " (no page of its own for this model was read).")
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 page's date: not before ${floor})`;
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 docTier = profile.verifiedAgainstDocs ? "certain" : "likely";
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
- add({
4094
- severity: "yellow",
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
- likely: "Likely \u2014 priced from your estimates, or a catalog value no provider page is cited for",
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
- npx -y @warmdrift/kgauto-check --extract extract.json
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. It sends the scrubbed extract and the card, nothing else, and says exactly where they went.
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
- r.shutdownFloor ? `not before ${r.shutdownFloor}` : ""
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 ${PARTNER_NAME[a.partner]}'s: ${P}'s word above is for ${P}'s own API, and ${PARTNER_NAME[a.partner]} runs its own schedule${page ? ` (${page})` : ""}`
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
- /** A cloud platform that serves a provider's models on its own lifecycle schedule. */
372
- type Partner = 'vertex' | 'bedrock' | 'azure';
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>): string;
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 = "# kgauto check \u2014 extraction instructions (for you, the agent)\n\nYour job: read this project's code and build an extract of its AI call surface. You have repo access; kgauto does not, by design.\n\n## What to find\nScan for LLM API usage: provider SDK imports (anthropic, openai, @google/generative-ai / @google/genai, ai-sdk, litellm, langchain, ...), raw HTTPS calls to provider endpoints, and any internal wrapper around them. Each distinct place the project sends a prompt to a model is one call site.\n\n## What to collect per call site (identifiers and counts ONLY)\n- id: a stable label you choose, e.g. \"api/summarize.ts:42\"\n- model: the model id exactly as configured (a provider or gateway prefix such as openai/ or openrouter/anthropic/ is fine; the check says what it looked the id up as)\n- modelSelection: hardcoded | config | env | dynamic\n- platform: state it for EVERY call site \u2014 where the request is served: provider-api (the provider's own API), vertex, bedrock, azure, or other (a gateway or another host). Tell it from the SDK imported (e.g. @anthropic-ai/sdk vs @anthropic-ai/vertex-sdk or @aws-sdk/client-bedrock-runtime; google-genai vs google.cloud.aiplatform / @google-cloud/aiplatform), the base URL (api.openai.com vs *.openai.azure.com; generativelanguage.googleapis.com vs *-aiplatform.googleapis.com), and the credentials used (a provider API key vs cloud credentials, a project and location). A lifecycle line is stated as certain only for provider-api; a cloud platform keeps its own schedule. If you truly cannot tell, write other and say why in notes.\n- archetype: your best guess at the work's intent \u2014 one of: ask, classify, critique, extract, generate, hunt, plan, summarize, transform\n- estInputTokens / maxInputTokens / estOutputTokens: estimate from the code (what gets concatenated into the prompt; ~4 chars per token). Worst case matters \u2014 find the biggest thing that can flow in.\n- toolCount, usesParallelToolCalls: from the tools array and how results are consumed\n- expectsStructuredOutput: true if the response is JSON.parse'd or schema-validated\n- streaming, retry (none | same-model | fallback-chain | unknown), fallbackModels\n- estCallsPerMonth: only if genuinely inferable (cron cadence, obvious traffic); omit rather than invent\n\n## Model ids with no call site\nIf the project holds model ids that no call site above carries \u2014 a model picker, a config or environment default, a list of supported models \u2014 list each once under \"models\" (identifiers only):\n- model: the id exactly as written\n- where: file:line where it is written\n- modelSelection: hardcoded | config | env | dynamic (optional)\n- platform: provider-api | vertex | bedrock | azure | other (as above)\nIf you find no call site at all (the project spawns a CLI, or takes the model as a run-time argument), \"callSites\" may be an empty array: the check still prints a card, about the ids in \"models\", and says no call site was found to check a request shape against. Never invent a model id to fill a call site.\n\n## Privacy contract (relay this to your human)\nDo NOT put prompt text, source code, file contents, or secrets in the extract. Identifiers and counts only. 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\n## Then\nWrite the extract as JSON:\n{ \"project\": { \"name\": \"...\", \"description\": \"...\" }, \"callSites\": [ ...one object per call site, or none... ], \"models\": [ ...optional, ids no call site carries... ] }\nand run:\n npx -y @warmdrift/kgauto-check --extract extract.json\nPresent 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.\n\n## Sharing (optional, explicit)\nAfter 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. It sends the scrubbed extract and the card, nothing else, and says exactly where they went.\n\n## Honesty rules you inherit while presenting\n- Do not soften \"certain\" findings or upgrade \"likely\" ones.\n- If a model was unknown to the catalog, say so \u2014 kgauto refuses to fabricate verdicts, and so should you.\n- A line that names a provider's word (retired, shut down, deprecated, legacy) carries the page it was read on: quote it as written.\n- Estimates you made are estimates: if a finding hinges on your token guess, say it can be firmed up by measuring.";
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
@@ -16,7 +16,7 @@ import {
16
16
  renderModelFacts,
17
17
  resolveId,
18
18
  runCheck
19
- } from "./chunk-XWIGHIJP.js";
19
+ } from "./chunk-6ZBEABKR.js";
20
20
  export {
21
21
  CHECK_VERSION,
22
22
  CallSiteSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warmdrift/kgauto-check",
3
- "version": "0.4.0",
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": "UNLICENSED",
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": "^2.0.0-alpha.132",
43
+ "@warmdrift/kgauto-compiler": "2.0.0-alpha.133",
43
44
  "zod": "^3.23.0"
44
45
  },
45
46
  "devDependencies": {