@everfur/cli 0.9.1 → 0.9.2

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.
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  /*! @everfur/cli. Copyright (c) 2026 Strand Health Inc. dba Everfur. All rights reserved. Use is subject to the Everfur SDK License: https://docs.everfur.com/license */
3
- import { hostnameOf, listen, close, writeJson, serveStatelessMcp } from './chunk-JURZYOMH.js';
4
- import { createHostedTokenVerifier, tokenBucketOf, isAccessTokenShaped, buildServer, MCP_SCOPE, tenantContextOf, sendTestUserRef, hostedVerifyUserRef, REVOKED_AUTHORIZATION_REMEDY, SYNTHETIC_USER_REF_PREFIX } from './chunk-FLW4ZANY.js';
5
- import { BASE_URL_ENV_VAR, resolveEndpoint, fetchTransport, systemClock, createApiClient, withPrefix, ephemeralCredential, validateContractText, isJsonObject, describeFailure } from './chunk-VUXILRME.js';
3
+ import { hostnameOf, listen, close, writeJson, serveStatelessMcp } from './chunk-LH4AWYCB.js';
4
+ import { createHostedTokenVerifier, tokenBucketOf, isAccessTokenShaped, buildServer, MCP_SCOPE, tenantContextOf, sendTestUserRef, hostedVerifyUserRef, REVOKED_AUTHORIZATION_REMEDY, SYNTHETIC_USER_REF_PREFIX } from './chunk-G7CJK7Z5.js';
5
+ import { BASE_URL_ENV_VAR, resolveEndpoint, fetchTransport, systemClock, createApiClient, withPrefix, ephemeralCredential, validateContractText, isJsonObject, describeFailure } from './chunk-VSZ4RPKA.js';
6
6
  import { createServer } from 'http';
7
7
  import { InvalidTokenError, TooManyRequestsError, TemporarilyUnavailableError } from '@modelcontextprotocol/sdk/server/auth/errors.js';
8
8
  import { isIP } from 'net';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /*! @everfur/cli. Copyright (c) 2026 Strand Health Inc. dba Everfur. All rights reserved. Use is subject to the Everfur SDK License: https://docs.everfur.com/license */
3
- import { ENVIRONMENTS, ENVELOPE_SHAPE, SURFACES, VERIFY_IDENTITY_MODES, digestOfProjection, ephemeralCredential, refusal, API_BASE_URL_BY_ENVIRONMENT, fetchContract, NO_CONTRACT_CACHE, systemClock, fetchTransport, describeFailure, loadDecisionSpaceFromContract, uuidFromKey, resolveEndpoint, createApiClient, createContractProvider, nodeContractCache, CLI_VERSION, withPrefix, isJsonObject, REFUSAL_POLICY, error_explanation_v1_schema_default, verification_v1_schema_default, diagnosis_v1_schema_default, plan_v1_schema_default, NEXT_ACTIONS, IDENTITY_QUESTION, IDENTITY_TREE, CAPABILITY_QUESTION, CAPABILITIES_TREE, WEB_EMBEDDING_QUESTION, PLATFORM_TREE, loadDecisionSpace, nodeFileSystem, expandCapabilities, detectThemeFromText, planIntegration, parseOrigin, parseLoaderUrl, isEverfurLoaderHost, EVERFUR_LOADER_HOSTS, resolveCredential, PARTNER_KEY, runVerification, themePropFromSource, normalizeSurfaces, failedResult, buildSupportBundle, chooseWidgetAuth, DIAGNOSTICS_PATH, diagnoseFailure, parseDiagnostics, buildDiagnosisDocument, toolCodeExplanation, resolveOffline, resolveWithoutRegistry, knownCodes, loadErrorRegistryFromContract, loadErrorRegistry, resolveAfterRegistryMiss, TOOL_CODES, registryAlsoIn, buildExplanationDocument, nextActionFor, CLAIMS_INBOUND_SECRET, WEBHOOK_SIGNING_SECRET, detectProject, BASE_URL_ENV_VAR, checkTenantMode, isWorkspaceRootEvidence, plannableCapabilities, blockedCapabilities, offlineDocument, toolCodeMeaning, SESSION_TOKEN, PLAN_DOCUMENT_KIND, PLAN_SCHEMA_VERSION, secretKeyHostProblem, ALLOW_CUSTOM_API_HOST_ENV_VAR, PARTNER_SECRET_KEY, SESSION_MINT_TREE, BACKEND_LANGUAGE_QUESTION, ALL_CAPABILITIES, WEBHOOK_PUBLIC_PATH, WEBHOOK_RECEIVER_PATH, TransportError, webhookRouteFile, importPath, hmacSha256, hmacSha256Hex, API_BASE_URL_PLACEHOLDER } from './chunk-VUXILRME.js';
3
+ import { ENVIRONMENTS, ENVELOPE_SHAPE, SURFACES, VERIFY_IDENTITY_MODES, digestOfProjection, ephemeralCredential, refusal, API_BASE_URL_BY_ENVIRONMENT, fetchContract, NO_CONTRACT_CACHE, systemClock, fetchTransport, describeFailure, loadDecisionSpaceFromContract, uuidFromKey, resolveEndpoint, createApiClient, createContractProvider, nodeContractCache, CLI_VERSION, withPrefix, isJsonObject, REFUSAL_POLICY, error_explanation_v1_schema_default, verification_v1_schema_default, diagnosis_v1_schema_default, plan_v1_schema_default, NEXT_ACTIONS, IDENTITY_QUESTION, IDENTITY_TREE, CAPABILITY_QUESTION, CAPABILITIES_TREE, WEB_EMBEDDING_QUESTION, PLATFORM_TREE, loadDecisionSpace, nodeFileSystem, expandCapabilities, detectThemeFromText, planIntegration, parseOrigin, parseLoaderUrl, isEverfurLoaderHost, EVERFUR_LOADER_HOSTS, resolveCredential, PARTNER_KEY, runVerification, themePropFromSource, normalizeSurfaces, failedResult, buildSupportBundle, chooseWidgetAuth, DIAGNOSTICS_PATH, diagnoseFailure, parseDiagnostics, buildDiagnosisDocument, toolCodeExplanation, resolveOffline, resolveWithoutRegistry, knownCodes, loadErrorRegistryFromContract, loadErrorRegistry, resolveAfterRegistryMiss, TOOL_CODES, registryAlsoIn, buildExplanationDocument, nextActionFor, CLAIMS_INBOUND_SECRET, WEBHOOK_SIGNING_SECRET, detectProject, BASE_URL_ENV_VAR, checkTenantMode, isWorkspaceRootEvidence, plannableCapabilities, blockedCapabilities, offlineDocument, toolCodeMeaning, SESSION_TOKEN, PLAN_DOCUMENT_KIND, PLAN_SCHEMA_VERSION, errorCodeOf, secretKeyHostProblem, ALLOW_CUSTOM_API_HOST_ENV_VAR, PARTNER_SECRET_KEY, SESSION_MINT_TREE, BACKEND_LANGUAGE_QUESTION, ALL_CAPABILITIES, WEBHOOK_PUBLIC_PATH, WEBHOOK_RECEIVER_PATH, TransportError, webhookRouteFile, importPath, hmacSha256, hmacSha256Hex, API_BASE_URL_PLACEHOLDER } from './chunk-VSZ4RPKA.js';
4
4
  import { z } from 'zod';
5
5
  import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
6
6
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
@@ -588,7 +588,7 @@ var PLAN_INPUT_SHAPE = {
588
588
  "For a remote MCP: the text of the project's tailwind.config.{js,ts}, the CSS that declares its theme (a Tailwind v4 @theme block or :root custom properties), or a React Native theme or colours file, so the plan can match the generated surface to the project's own theme. Read statically and never executed. With project_root the project is read from disk instead; this argument, when given, wins. The plan refuses to guess a theme it cannot read and names the missing facts in its match-theme step."
589
589
  ),
590
590
  capabilities: z.array(CAPABILITY).optional().describe(
591
- 'Which Everfur capabilities this integration uses, as the contract names them. The ids the contract can plan today are "chat", "entitlements", "events", "notifications", "photo", "records", "records-clinic" and "televet"; "animations", "health-plan", "records-push", "records-transfer", "server-pets", "texting" and "video" are blocked today and a plan refuses them with the reason. Pass ["all"] for every plannable capability. The loaded contract is the authority: an UNKNOWN_OPTION refusal lists its exact ids. The plan holds no credential, so everfur_verify_integration (not this tool) is the fail-closed check of what the tenant actually has. The native setup an in-app vet call needs (the Daily modules, an Expo config plugin, a clean prebuild, camera and microphone declarations, and a warning naming the missing-native-module error Expo Go produces) is planned only when the generated React Native file mounts that call; a plan whose file mounts only the vet visit button installs none of it. Omit if unknown; the tool will refuse and list the ids.'
591
+ 'Which Everfur capabilities this integration uses, as the contract names them. The ids the contract can plan today are "chat", "entitlements", "events", "notifications", "photo", "records", "records-clinic" and "televet"; "animations", "claims", "health-plan", "records-push", "records-transfer", "server-pets", "texting" and "video" are blocked today and a plan refuses them with the reason. Pass ["all"] for every plannable capability. The loaded contract is the authority: an UNKNOWN_OPTION refusal lists its exact ids. The plan holds no credential, so everfur_verify_integration (not this tool) is the fail-closed check of what the tenant actually has. The native setup an in-app vet call needs (the Daily modules, an Expo config plugin, a clean prebuild, camera and microphone declarations, and a warning naming the missing-native-module error Expo Go produces) is planned only when the generated React Native file mounts that call; a plan whose file mounts only the vet visit button installs none of it. Omit if unknown; the tool will refuse and list the ids.'
592
592
  ),
593
593
  identity_mode: IDENTITY_MODE.optional().describe('anonymous = no backend, scoped to the device. partner-user-ref = your backend mints a session against your own user id. shopify-app-proxy = a Shopify storefront, where Shopify vouches for the signed-in customer and no partner backend mints. "personalized" is accepted as an alias for partner-user-ref.'),
594
594
  session_mint_language: MINT_LANGUAGE.optional().describe("Backend language that will mint sessions. Only meaningful when identity_mode is partner-user-ref."),
@@ -800,10 +800,11 @@ async function planIntegrationTool(args, context, ports = {}) {
800
800
  );
801
801
  }
802
802
  if (plan.status === "blocked") {
803
+ const claims = (args.capabilities ?? []).some((value) => /claim/i.test(value));
803
804
  return refusal(
804
805
  "CAPABILITIES_BLOCKED",
805
- "Everything this integration asked for is blocked by the contract, so nothing can be built today. Each reason and who owns it are below; no plan works around a blocked surface.",
806
- { blocked: plan.blocked, warnings: plan.warnings, plan, next_call: null }
806
+ "Everything this integration asked for is blocked by the contract, so nothing can be built today. Each reason and who owns it are below; no plan works around a blocked surface." + (claims ? " A claims integration is planned by everfur_plan_claims_integration, which needs no project." : ""),
807
+ { blocked: plan.blocked, warnings: plan.warnings, plan, next_call: null, ...claims ? { see_also: "everfur_plan_claims_integration" } : {} }
807
808
  );
808
809
  }
809
810
  const ready = mode.warning === null ? plan : { ...plan, warnings: [...plan.warnings, mode.warning] };
@@ -1187,9 +1188,9 @@ var EXPLAIN_ERROR_OUTPUT_SHAPE = {
1187
1188
  };
1188
1189
  var INBOUND_DOOR_PREFIX = "/partners/claims/inbound/";
1189
1190
  var INBOUND_SANDBOX_ROUTE = "/partners/sandbox/claims-inbound";
1190
- var RESERVED_CLAIM_IDS = Object.freeze(["inbound"]);
1191
+ var RESERVED_CLAIM_IDS = Object.freeze(["inbound", "batches", "profiles", "pets", "outcomes"]);
1191
1192
  function isReservedClaimId(value) {
1192
- return RESERVED_CLAIM_IDS.includes(value);
1193
+ return RESERVED_CLAIM_IDS.includes(value.toLowerCase());
1193
1194
  }
1194
1195
  var INBOUND_TOKEN_PATTERN = /^[A-Za-z0-9_-]{43}$/;
1195
1196
  var INBOUND_SECRET_ENV = "EVERFUR_CLAIMS_INBOUND_SECRET";
@@ -1385,6 +1386,38 @@ var PII_KEY_PATTERNS = Object.freeze([
1385
1386
  function foldKey(key) {
1386
1387
  return key.toLowerCase().replace(/[^a-z0-9]/g, "");
1387
1388
  }
1389
+ var OWNER_CONTEXT_WORDS = Object.freeze([
1390
+ "owner",
1391
+ "holder",
1392
+ "policyholder",
1393
+ "customer",
1394
+ "member",
1395
+ "insured",
1396
+ "client",
1397
+ "parent",
1398
+ "guardian",
1399
+ "contact",
1400
+ "billing",
1401
+ "payer",
1402
+ "payee",
1403
+ "account"
1404
+ ]);
1405
+ var OWNER_SUFFIXES = Object.freeze(["s", "info", "details", "data", "profile"]);
1406
+ function isOwnerContextKey(key) {
1407
+ const folded = foldKey(key);
1408
+ if (OWNER_CONTEXT_WORDS.includes(folded)) return true;
1409
+ return OWNER_SUFFIXES.some((suffix) => folded.endsWith(suffix) && OWNER_CONTEXT_WORDS.includes(folded.slice(0, -suffix.length)));
1410
+ }
1411
+ function isRefKey(key) {
1412
+ const lowered = key.toLowerCase();
1413
+ if (lowered === "id" || lowered === "ref" || /^.+[_.-](?:id|ref)$/.test(lowered)) return true;
1414
+ return /^.*[a-z0-9](?:Id|ID|Ref|REF)$/.test(key);
1415
+ }
1416
+ function ownerPathProblem(keys) {
1417
+ if (!keys.some(isOwnerContextKey)) return null;
1418
+ const last = keys[keys.length - 1];
1419
+ return last !== void 0 && isRefKey(last) ? null : "a source path under an owner key (owner, holder, customer, contact, ...) may only read an id or ref key";
1420
+ }
1388
1421
  function isPiiKey(key) {
1389
1422
  const folded = foldKey(key);
1390
1423
  return folded.length > 0 && PII_KEY_PATTERNS.some((pattern) => pattern.test(folded));
@@ -1965,7 +1998,7 @@ var INBOUND_CODES = Object.freeze([
1965
1998
  409,
1966
1999
  "stop",
1967
2000
  "The sandbox tenant already has its inbound endpoint, and it has one at most. Its URL and secret were shown once, when it was created. Nothing was created.",
1968
- `Set ${INBOUND_URL_ENV} from where it was saved. For a new secret call ${SETUP} with rotate_secret: true, for a new URL with rotate_token: true. No route deletes a sandbox endpoint.`
2001
+ `Set ${INBOUND_URL_ENV} from where it was saved. For a new secret call ${SETUP} with rotate_secret: true, for a new URL with rotate_token: true. To start over on a sandbox tenant, delete_endpoint: true and create again.`
1969
2002
  ),
1970
2003
  inbound(
1971
2004
  "events_invalid",
@@ -4574,7 +4607,7 @@ function rotateDetail() {
4574
4607
  return `Secret rotation with no downtime: after a rotation the previous secret keeps verifying for previous_valid_seconds (default ${DEFAULT_PREVIOUS_VALID_SECONDS}, at most ${MAX_PREVIOUS_VALID_SECONDS}), so both are accepted while the claims system switches. Sandbox: ${SETUP2} with rotate_secret: true and secret_env_file ${LOCAL_ONLY} writes the new ${INBOUND_SECRET_ENV} to that file (never returned) and answers previous_secret_expires_at; put the new secret in the claims system's secrets store and switch the webhook to it before that time, then confirm with ${SAMPLES2}. previous_valid_seconds 0 cuts the old secret at once: only for a leak. A planned rotation while the previous secret of an earlier one is still valid answers 409 rotation_in_progress: wait for previous_secret_expires_at, or rotate with 0. URL token rotation: if the inbound URL leaks (a log line, a ticket, the chat), rotate its token with ${SETUP2} with rotate_token: true and secret_env_file ${LOCAL_ONLY}; it writes the new ${INBOUND_URL_ENV} to that file (never returned). The old URL answers 404 at once, with no overlap, so put the new URL in the claims system right away; the secret and the signing are unchanged. Live: ask Everfur for a secret rotation with the window wanted, or a token rotation; the new secret or URL is handed over once through a secure channel, and the same switch-over applies.`;
4575
4608
  }
4576
4609
  function goLiveDetail() {
4577
- return `Live setup is done by Everfur; the MCP never touches the live account. (1) Ask Everfur for the live endpoint, with the same signing config as the sandbox one, which must be hmac with signed_payload timestamp_body (a live endpoint refuses any other signing: 422 signing_mode_sandbox_only), and for the reviewed sandbox mapping (its active version) to be made active on the live account. (2) Everfur hands over the live URL and shared secret once, through a secure channel: put them in the claims system's secrets store for its production environment, never in an MCP configuration, an env file in a repository or the chat. (3) Everfur switches the inbound webhook on for the live account; until then the live URL answers a plain 404. (4) Point the production webhook at the live URL with the same event types, signing and retry settings as the sandbox. (5) Watch the first real events: the claims system's delivery log shows 202 (or 200 duplicate) for each; any other status is explained by ${EXPLAIN}. A 202 is received, not yet applied, and the live account has no event log route of its own, so ask Everfur to read the live event log for the first events, and check the claims appear in the claims portal. (6) Tell Everfur before changing the event format, so the mapping changes with it.`;
4610
+ return `Live setup is done by Everfur; the MCP never touches the live account. (1) Ask Everfur for the live endpoint, with the same signing config as the sandbox one, which must be hmac with signed_payload timestamp_body (a live endpoint refuses any other signing: 422 signing_mode_sandbox_only), and for the reviewed sandbox mapping (its active version) to be made active on the live account. (2) Everfur hands over the live URL and shared secret once, through a secure channel: put them in the claims system's secrets store for its production environment, never in an MCP configuration, an env file in a repository or the chat. (3) Everfur switches the inbound webhook on for the live account; until then the live URL answers a plain 404. (4) Point the production webhook at the live URL with the same event types, signing and retry settings as the sandbox. (5) Watch the first real events: the claims system's delivery log shows 202 (or 200 duplicate) for each; any other status is explained by ${EXPLAIN}. A 202 is received, not yet applied: the claims system's own servers read the live event log with the live secret key (GET /api/v1/partners/claims/inbound/events, the same view read_event_log shows for the sandbox; never through the MCP), so watch the first events reach applied there and the claims appear in the claims portal. (6) Tell Everfur before changing the event format, so the mapping changes with it.`;
4578
4611
  }
4579
4612
  function portalDetail() {
4580
4613
  return `Every claim the events file lands in the Everfur claims portal for the insurer's adjusters; ask Everfur for the adjusters' portal access. Evidence carries its sources (document, page and quoted text), with invoice lines, coverage gaps and the pre-existing check against past claims from profile events. Opening a claim moves it to in_review; asking for more records moves it to records_requested, answered by a documents_added event with packet_complete true. The adjuster records the decision (${list(DECISIONS)}), the amount paid in cents and a reason; Everfur never decides a claim. In the sandbox every claim runs straight to evidence_ready. Results can also be sent back to the insurer's own systems by the optional outbound webhooks (the optional section).`;
@@ -5021,7 +5054,7 @@ function checkMappingDocument(document) {
5021
5054
  extraKeys(kind, ["path", "values"], "kind", at);
5022
5055
  const path = kind["path"];
5023
5056
  if (typeof path !== "string") at("kind.path", "kind.path is required");
5024
- else pathProblem(path, "forbidden", "kind.path", at);
5057
+ else sourcePathProblem(path, "forbidden", [], "kind.path", at);
5025
5058
  const values = kind["values"];
5026
5059
  if (!isObject(values) || Object.keys(values).length === 0 || Object.keys(values).length > MAX_KIND_VALUES) {
5027
5060
  at("kind.values", `kind.values maps 1 to ${MAX_KIND_VALUES} native values to a kind`);
@@ -5086,6 +5119,8 @@ function checkMappingDocument(document) {
5086
5119
  extraKeys(listed, ["path", "fields"], `kinds.${name}.${list2}`, at);
5087
5120
  if (typeof listed["path"] !== "string") at(`kinds.${name}.${list2}.path`, "a list's path is required");
5088
5121
  else pathProblem(listed["path"], "required", `kinds.${name}.${list2}.path`, at);
5122
+ const listSteps = typeof listed["path"] === "string" ? parsePath(listed["path"], "required") : "not a path";
5123
+ const listKeys = typeof listSteps === "string" ? null : keysOf(listSteps);
5089
5124
  const listFields = listed["fields"];
5090
5125
  if (!isObject(listFields) || Object.keys(listFields).length === 0 || Object.keys(listFields).length > MAX_LIST_FIELDS) {
5091
5126
  at(`kinds.${name}.${list2}.fields`, `a list maps 1 to ${MAX_LIST_FIELDS} targets`);
@@ -5093,7 +5128,7 @@ function checkMappingDocument(document) {
5093
5128
  }
5094
5129
  for (const [target, field] of Object.entries(listFields)) {
5095
5130
  if (!allowed.includes(target)) at(`kinds.${name}.${list2}.fields.${target}`, `${list2} has no target ${target.slice(0, 64)}; targets: ${allowed.join(", ")}`);
5096
- checkField(field, `kinds.${name}.${list2}.fields.${target}`, at);
5131
+ checkField(field, `kinds.${name}.${list2}.fields.${target}`, at, listKeys);
5097
5132
  }
5098
5133
  }
5099
5134
  }
@@ -5111,7 +5146,19 @@ function pathProblem(text, star, where, at) {
5111
5146
  const parsed = parsePath(text, star);
5112
5147
  if (typeof parsed === "string") at(where, parsed);
5113
5148
  }
5114
- function checkField(field, where, at) {
5149
+ function keysOf(steps) {
5150
+ return steps.flatMap((step3) => step3.kind === "key" ? [step3.key] : []);
5151
+ }
5152
+ function sourcePathProblem(text, star, prefix, where, at) {
5153
+ const parsed = parsePath(text, star);
5154
+ if (typeof parsed === "string") {
5155
+ at(where, parsed);
5156
+ return;
5157
+ }
5158
+ const problem = ownerPathProblem([...prefix, ...keysOf(parsed)]);
5159
+ if (problem !== null) at(where, problem);
5160
+ }
5161
+ function checkField(field, where, at, prefix = []) {
5115
5162
  if (!isObject(field)) {
5116
5163
  at(where, "a field is an object: {path} or {paths}, with optional transforms");
5117
5164
  return;
@@ -5132,7 +5179,8 @@ function checkField(field, where, at) {
5132
5179
  if (path === void 0 && paths === void 0 && !constant) at(where, "a field needs a path, paths or a leading constant transform");
5133
5180
  if (path !== void 0) {
5134
5181
  if (typeof path !== "string") at(`${where}.path`, "a path is a string");
5135
- else pathProblem(path, "forbidden", `${where}.path`, at);
5182
+ else if (prefix === null) pathProblem(path, "forbidden", `${where}.path`, at);
5183
+ else sourcePathProblem(path, "forbidden", prefix, `${where}.path`, at);
5136
5184
  }
5137
5185
  if (paths !== void 0) {
5138
5186
  if (!Array.isArray(paths) || paths.length === 0 || paths.length > MAX_FIELD_PATHS) {
@@ -5140,7 +5188,8 @@ function checkField(field, where, at) {
5140
5188
  } else {
5141
5189
  paths.forEach((text, index) => {
5142
5190
  if (typeof text !== "string") at(`${where}.paths[${index}]`, "a path is a string");
5143
- else pathProblem(text, "forbidden", `${where}.paths[${index}]`, at);
5191
+ else if (prefix === null) pathProblem(text, "forbidden", `${where}.paths[${index}]`, at);
5192
+ else sourcePathProblem(text, "forbidden", prefix, `${where}.paths[${index}]`, at);
5144
5193
  });
5145
5194
  }
5146
5195
  }
@@ -5327,7 +5376,7 @@ var CLAIM_RULES = Object.freeze([
5327
5376
  { target: "amount_claimed_cents", scope: "claim", names: ["amountclaimed", "claimedamount", "claimamount", "requestedamount", "amountrequested", "claimed", "requested"], shape: "money", unscoped: true },
5328
5377
  { target: "billed_cents", scope: "claim", names: ["billedamount", "billed", "total", "totalamount", "invoicetotal", "invoiceamount", "amount", "totalbilled", "cost", "charges"], shape: "money", unscoped: true },
5329
5378
  { target: "clinic_name", scope: "clinic", names: ["name", "clinicname", "clinic", "vetname", "hospitalname", "practicename", "providername", "vet", "hospital", "practice", "provider"], shape: "text" },
5330
- { target: "packet_complete", scope: "claim", names: ["packetcomplete", "complete", "iscomplete", "final", "isfinal", "finalized", "finalised", "ready", "documentscomplete", "docscomplete"], shape: "bool", unscoped: true },
5379
+ { target: "packet_complete", scope: "claim", names: ["packetcomplete", "complete", "iscomplete", "final", "isfinal", "finalized", "finalised", "ready", "documentscomplete", "docscomplete", "alldocumentsreceived", "alldocsreceived", "documentsreceived", "docsreceived", "allreceived", "allfilesreceived", "filescomplete", "packetready", "readyforreview", "submissioncomplete"], shape: "bool", unscoped: true },
5331
5380
  { target: "pet.pet_ref", scope: "pet", names: ["petid", "petref", "petnumber", "animalid", "patientid", ...ID_NAMES], shape: "ref" },
5332
5381
  { target: "pet.name", scope: "pet", names: ["name", "petname", "animalname", "patientname", "callname"], shape: "text" },
5333
5382
  { target: "pet.species", scope: "pet", names: ["species", "speciescode", "kind", "type", "animaltype", "pettype", "animalkind"], shape: "species" },
@@ -5364,7 +5413,7 @@ function rulesFor(kind) {
5364
5413
  return Object.entries(PROFILE_FROM_CLAIM).map(([target, from]) => ({ ...byTarget.get(from), target }));
5365
5414
  }
5366
5415
  var DOCUMENT_RULES = Object.freeze([
5367
- { target: "base64", scope: null, names: ["base64", "content", "contents", "data", "body", "bytes", "file", "filedata", "blob", "payload", "encoded", "filecontent"], shape: "base64", unscoped: true },
5416
+ { target: "base64", scope: null, names: ["base64", "contentbase64", "base64content", "filebase64", "base64data", "database64", "documentbase64", "base64file", "content", "contents", "data", "body", "bytes", "file", "filedata", "blob", "payload", "encoded", "filecontent"], shape: "base64", unscoped: true },
5368
5417
  { target: "url", scope: null, names: ["url", "link", "href", "uri", "downloadurl", "fileurl", "location", "signedurl", "presignedurl", "download"], shape: "url", unscoped: true },
5369
5418
  { target: "file_name", scope: null, names: ["filename", "name", "title", "documentname", "originalname", "originalfilename", "label"], shape: "file_name", unscoped: true },
5370
5419
  { target: "kind", scope: null, names: ["kind", "category", "type", "documenttype", "doctype", "documentkind", "doccategory", "class"], shape: "doc_kind", unscoped: true },
@@ -5385,6 +5434,8 @@ var SPECIES_SYNONYMS = Object.freeze({
5385
5434
  d: "dog",
5386
5435
  puppy: "dog",
5387
5436
  canin: "dog",
5437
+ can: "dog",
5438
+ cn: "dog",
5388
5439
  cat: "cat",
5389
5440
  cats: "cat",
5390
5441
  feline: "cat",
@@ -5466,7 +5517,7 @@ function shapeFits(shape, leaf) {
5466
5517
  case "content_type":
5467
5518
  return only("ref", "text", "int", "bool");
5468
5519
  case "base64":
5469
- return only("base64");
5520
+ return only("base64") || foldKey(leaf.keys[leaf.keys.length - 1] ?? "").includes("base64") && only("base64", "ref", "text") && present(leaf.values).every((value) => BASE64.test(String(value).replace(/\s+/g, "")));
5470
5521
  case "url":
5471
5522
  return only("url");
5472
5523
  }
@@ -5731,11 +5782,12 @@ function transformsFor(shape, leaf, order, target, orderDecided = false) {
5731
5782
  }
5732
5783
  return { transforms, why, confidence, reviewNote, untrustedCodes };
5733
5784
  }
5734
- function pick(rule, leaves, used, parentKeys, documentElement = false) {
5785
+ function pick(rule, leaves, used, parentKeys, documentElement = false, ownerRule = true) {
5735
5786
  let best = null;
5736
5787
  let bestScore = 0;
5737
5788
  for (const leaf of leaves) {
5738
5789
  if (used.has(leaf.path)) continue;
5790
+ if (ownerRule && ownerPathProblem([...parentKeys, ...leaf.keys]) !== null) continue;
5739
5791
  if (rule.target !== "member_ref" && personalData(leaf, parentKeys, documentElement) !== null) continue;
5740
5792
  if (rule.target === "member_ref" && (isPiiKey(leaf.keys[leaf.keys.length - 1] ?? "") || leaf.shapes.has("email") || leaf.shapes.has("phone"))) continue;
5741
5793
  if (!shapeFits(rule.shape, leaf)) continue;
@@ -5942,8 +5994,26 @@ function proposeMapping(input) {
5942
5994
  const pinnedPath = pinned[rule.target];
5943
5995
  const leaf = pinnedPath !== void 0 ? flat.leaves.get(pinnedPath) ?? { path: pinnedPath, keys: pinnedPath.split("."), values: [], shapes: /* @__PURE__ */ new Set(["text"]) } : pick(rule, flat.leaves.values(), used, []);
5944
5996
  const required = REQUIRED_TARGETS[kind].includes(rule.target);
5997
+ const refused = leaf === null && pinnedPath === void 0 ? pick(rule, flat.leaves.values(), used, [], false, false) : null;
5998
+ if (refused !== null) {
5999
+ const where = echoCode(refused.path, "[a path not shown]");
6000
+ addGap({
6001
+ kind,
6002
+ target: rule.target,
6003
+ required,
6004
+ code: "unfilled",
6005
+ why: `${rule.target} reads like ${where}, but that key sits under an owner object (owner, holder, member, customer, ...) and is not named like an id or ref. The door's scrub drops it before mapping, and the API refuses a mapping that reads it (mapping_invalid).`,
6006
+ fix: "Have the claims system also send the value under a key named like an id or ref inside that object (memberId, member_id, memberRef, id), or outside the owner object; then pin it with hints.field_paths."
6007
+ });
6008
+ continue;
6009
+ }
6010
+ if (pinnedPath !== void 0 && ownerPathProblem(pinnedPath.split(".").map((part) => part.replace(/\[.*$/, ""))) !== null) {
6011
+ addGap({ kind, target: rule.target, required, code: "unfilled", why: "the pinned path passes through an owner object and its last key is not named like an id or ref; the scrub drops it and the API refuses the mapping (mapping_invalid)", fix: "Pin a key named like an id or ref (memberId, member_id, id), or one outside the owner object." });
6012
+ continue;
6013
+ }
5945
6014
  if (leaf === null) {
5946
6015
  if (required) addGap({ kind, target: rule.target, required, code: "unfilled", why: `no field in the ${kind} samples reads like ${rule.target}`, fix: `Pass hints.field_paths.${kind}["${rule.target}"] with the path that holds it, or make the insurer system send it.` });
6016
+ else if (rule.target === "packet_complete") addGap({ kind, target: rule.target, required: false, code: "needs_review", why: 'no field reads like "all documents are in". packet_complete is false when unmapped, and only an event with packet_complete true sends the claim to review, so with none mapped no claim ever leaves intake.', fix: `Map packet_complete to the claims system's own "documents complete" flag (hints.field_paths.${kind}["packet_complete"], a bool), or to a constant true when every ${kind} event carries the whole packet.` });
5947
6017
  continue;
5948
6018
  }
5949
6019
  if (pinnedPath !== void 0 && personalData(leaf) !== null && rule.target !== "member_ref") {
@@ -6430,7 +6500,7 @@ function inboundFailure(failure, action, notFound) {
6430
6500
  }
6431
6501
  return sandboxFailure(failure, action);
6432
6502
  }
6433
- var CREATE_ONCE = `The sandbox key can create the sandbox inbound endpoint once, with ${SETUP3} (create_endpoint: true, signing, secret_env_file and confirm: true from a person): its inbound URL (with the token) and first secret are shown once, in that answer, and are written to secret_env_file as ${INBOUND_URL_ENV} and ${INBOUND_SECRET_ENV}. Live inbound endpoints are set up by Everfur.`;
6503
+ var CREATE_ONCE = `The sandbox key can create the sandbox inbound endpoint (one per tenant) with ${SETUP3} (create_endpoint: true, signing, secret_env_file and confirm: true from a person): its inbound URL (with the token) and first secret are shown once, in that answer, and are written to secret_env_file as ${INBOUND_URL_ENV} and ${INBOUND_SECRET_ENV}. Live inbound endpoints are set up by Everfur.`;
6434
6504
  var URL_SHOWN_ONCE = `The inbound URL was shown once, when the endpoint was created: set ${INBOUND_URL_ENV} from where it was saved (the env file the create wrote, or the claims system's config). No route shows it again: rotate_secret gives a new secret, and rotate_token a new URL (the old one stops at once).`;
6435
6505
  var ENDPOINT_404 = `The sandbox claims-inbound routes answered 404: the inbound webhook is not switched on for this deployment or this sandbox tenant, the tenant has no claims portal, or no inbound endpoint exists for it yet. The first two are settings Everfur holds. ${CREATE_ONCE}`;
6436
6506
  var CREATE_404 = "The create answered 404: the sandbox claims-inbound routes are not switched on for this deployment or this sandbox tenant, or the tenant has no claims portal. Both are settings Everfur holds. Nothing was created.";
@@ -6481,21 +6551,28 @@ function mappingSummary(view) {
6481
6551
  }
6482
6552
  function validationErrors(body) {
6483
6553
  if (typeof body !== "object" || body === null) return [];
6484
- const errors = body["errors"];
6554
+ const record = body;
6555
+ const detail = record["detail"];
6556
+ const errors = !Array.isArray(record["errors"]) && typeof detail === "object" && detail !== null ? detail["errors"] : record["errors"];
6485
6557
  if (!Array.isArray(errors)) return [];
6486
6558
  return errors.slice(0, 20).flatMap((item) => {
6487
6559
  if (typeof item !== "object" || item === null) return [];
6488
- const record = item;
6489
- const loc = Array.isArray(record["loc"]) ? record["loc"].map(String).join(".") : String(record["loc"] ?? "");
6490
- const msg = typeof record["msg"] === "string" ? record["msg"] : "";
6560
+ const record2 = item;
6561
+ const loc = Array.isArray(record2["loc"]) ? record2["loc"].map(String).join(".") : String(record2["loc"] ?? "");
6562
+ const msg = typeof record2["msg"] === "string" ? record2["msg"] : "";
6491
6563
  return [{ loc: loc.slice(0, 200), msg: msg.slice(0, 300) }];
6492
6564
  });
6493
6565
  }
6494
6566
  function bodyCode(body) {
6495
- if (typeof body !== "object" || body === null) return null;
6496
- const record = body;
6497
- const code = record["error"] ?? record["code"];
6498
- return typeof code === "string" ? code : null;
6567
+ return errorCodeOf(body).code;
6568
+ }
6569
+ function unexpectedRefusal(answer, action, nothing) {
6570
+ const code = bodyCode(answer.value);
6571
+ return refusal(
6572
+ "CLAIMS_SANDBOX_CALL_FAILED",
6573
+ `The API answered ${answer.status} ${code === null ? "(no code)" : relayedReason(code)}, which this action does not expect. ${nothing}` + (code === null ? "" : " everfur_explain_claims_error explains the code."),
6574
+ { action, status: answer.status, code: code === null ? null : relayedReason(code), request_id: answer.requestId }
6575
+ );
6499
6576
  }
6500
6577
  var SAMPLE_EVENT = z.record(z.string(), z.unknown());
6501
6578
  function loadSamples(samples, files, scope) {
@@ -6580,7 +6657,16 @@ var PREVIEW_RESULT = z.object({
6580
6657
  });
6581
6658
  async function preview(sandbox, mapping, events, action) {
6582
6659
  const body = { ...mapping === void 0 ? {} : { mapping }, events };
6583
- const answer = await sandbox.client.request({ method: "POST", path: `${INBOUND_SANDBOX_ROUTE}/mapping/preview`, credentials: sandbox.credentials, body });
6660
+ const answer = await sandbox.client.request({ method: "POST", path: `${INBOUND_SANDBOX_ROUTE}/mapping/preview`, credentials: sandbox.credentials, body, acceptStatuses: [422] });
6661
+ if (answer.ok && answer.status === 422) {
6662
+ const code = bodyCode(answer.value);
6663
+ const problems = bodyInvalidErrors(answer.value);
6664
+ return refusal(
6665
+ code === "mapping_invalid" ? "CLAIMS_MAPPING_INVALID" : "CLAIMS_ARGUMENTS_INVALID",
6666
+ `The preview answered 422 ${code === null ? "(no code)" : relayedReason(code)}: ${problems.length > 0 ? problems.join("; ") : "the API named no field"}. Nothing was stored.`,
6667
+ { action, status: 422, code: code === null ? null : relayedReason(code), problems, request_id: answer.requestId }
6668
+ );
6669
+ }
6584
6670
  if (!answer.ok) {
6585
6671
  return inboundFailure(answer, action, mapping === void 0 ? `The preview answered 404: no mapping was passed and there is no draft to preview (an activated draft is no longer a draft). ${MAPPING_ROUTES_404}` : MAPPING_ROUTES_404);
6586
6672
  }
@@ -6657,7 +6743,9 @@ async function proposeClaimsMappingTool(args, context, ports = {}, options = {})
6657
6743
  } else {
6658
6744
  const results = await preview(sandbox, proposal.mapping, loaded.samples, "preview");
6659
6745
  if (!Array.isArray(results)) {
6660
- document["server_preview"] = { skipped: true, why: results.document["message"] ?? "the preview failed", code: results.document["error"]?.code ?? null };
6746
+ const error = results.document["error"];
6747
+ const problems = Array.isArray(error?.details?.problems) ? error.details.problems : results.document["problems"] ?? void 0;
6748
+ document["server_preview"] = { skipped: true, why: results.document["message"] ?? "the preview failed", code: error?.code ?? null, ...problems === void 0 ? {} : { problems } };
6661
6749
  } else {
6662
6750
  const relayed = results.map((item, index) => relayPreview(item, index));
6663
6751
  document["server_preview"] = { passed: relayed.every((item) => item["gaps"].length === 0), results: relayed };
@@ -6732,6 +6820,7 @@ async function saveClaimsMappingTool(args, context, ports = {}) {
6732
6820
  });
6733
6821
  if (!answer2.ok) return inboundFailure(answer2, action, MAPPING_ROUTES_404);
6734
6822
  if (answer2.status === 422) {
6823
+ if (bodyCode(answer2.value) !== "mapping_invalid") return unexpectedRefusal(answer2, action, "Nothing was saved.");
6735
6824
  return refusal("CLAIMS_MAPPING_INVALID", "The API refused the mapping (mapping_invalid); nothing was saved.", {
6736
6825
  action,
6737
6826
  problems: validationErrors(answer2.value).map((item) => `${item.loc}: ${item.msg}`),
@@ -6803,11 +6892,12 @@ async function saveClaimsMappingTool(args, context, ports = {}) {
6803
6892
  );
6804
6893
  }
6805
6894
  if (answer.status === 409 || answer.status === 422) {
6806
- const code = bodyCode(answer.value) ?? "";
6895
+ const code = bodyCode(answer.value);
6896
+ if (code !== "event_time_mapping_required" && code !== "mapping_invalid") return unexpectedRefusal(answer, action, "Nothing was activated.");
6807
6897
  return refusal(
6808
6898
  "CLAIMS_MAPPING_INVALID",
6809
6899
  code === "event_time_mapping_required" ? "The endpoint's signing signs no time (a body-only signature or a secret header), so the mapping must name event_time before it can be activated. Nothing was activated." : "The API refused to activate the draft (mapping_invalid). Nothing was activated.",
6810
- { action, code: code === "" ? null : code, problems: validationErrors(answer.value).map((item) => `${item.loc}: ${item.msg}`), request_id: answer.requestId }
6900
+ { action, code, problems: validationErrors(answer.value).map((item) => `${item.loc}: ${item.msg}`), request_id: answer.requestId }
6811
6901
  );
6812
6902
  }
6813
6903
  const view = MAPPING_VIEW.safeParse(answer.value);
@@ -6821,7 +6911,9 @@ function describeSigning(signing) {
6821
6911
  var CLAIMS_INBOUND_SIGNING_SETUP_INPUT_SHAPE = {
6822
6912
  create_endpoint: z.boolean().optional().describe(`Create the sandbox inbound endpoint, once, with signing, and write its inbound URL and first secret to secret_env_file as ${INBOUND_URL_ENV} and ${INBOUND_SECRET_ENV}. Needs confirm: true. The API shows the URL and secret only in that answer; neither is returned. Default false.`),
6823
6913
  signing: SIGNING_CONFIG.optional().describe("create_endpoint: the signing config the claims system will use. Use hmac with signed_payload timestamp_body: it is the only signing a live endpoint accepts. hmac over the body alone and secret_header are sandbox only (a live endpoint refuses them with 422 signing_mode_sandbox_only)."),
6824
- confirm: z.boolean().optional().describe("create_endpoint: true only when a human has read the signing config and asked for the endpoint to be created. It is a one-time action: no route deletes a sandbox endpoint. Never set it on your own."),
6914
+ confirm: z.boolean().optional().describe("create_endpoint: true only when a human has read the signing config and asked for the endpoint to be created, changed (set_signing) or deleted (delete_endpoint). Never set it on your own."),
6915
+ set_signing: z.boolean().optional().describe("Change the sandbox endpoint's signing config to signing (the header names, the prefix, the encoding, the mode). The URL and secret stay the same. Needs signing and confirm: true. Default false."),
6916
+ delete_endpoint: z.boolean().optional().describe("Delete the sandbox inbound endpoint: its URL answers 404 at once, and the event log and mappings stay, so create_endpoint can make a new one (a new URL and secret). Needs confirm: true. Live endpoints are kept by Everfur. Default false."),
6825
6917
  rotate_secret: z.boolean().optional().describe("Rotate the sandbox endpoint's shared secret and write the new one to secret_env_file. Default false: only read."),
6826
6918
  rotate_token: z.boolean().optional().describe(`Rotate the sandbox endpoint's URL token, after the inbound URL leaked, and write the new inbound URL to secret_env_file as ${INBOUND_URL_ENV}. The old URL answers 404 at once, with no overlap; the secret and the signing are unchanged. The new URL is never returned. Default false: only read.`),
6827
6919
  secret_env_file: z.string().min(1).max(1024).optional().describe(`create_endpoint, rotate_secret and rotate_token: absolute path of a local env file the secret is written to as ${INBOUND_SECRET_ENV}=... (on create also, and on rotate_token only, the inbound URL as ${INBOUND_URL_ENV}=...), replacing a line that already sets it, created with mode 600 when missing. Neither value is ever returned. It must be named .env or .env.<name>, inside the project this server runs in or ~/.config/everfur, ignored by git, and not a symlink.`),
@@ -6875,8 +6967,7 @@ function stripUndefined(env) {
6875
6967
  return out;
6876
6968
  }
6877
6969
  function bodyInvalidErrors(body) {
6878
- const detail = typeof body === "object" && body !== null ? body["detail"] ?? body : body;
6879
- return validationErrors(detail).map((item) => `${item.loc}: ${item.msg}`);
6970
+ return validationErrors(body).map((item) => `${item.loc}: ${item.msg}`);
6880
6971
  }
6881
6972
  function doorTokenOf(urlPath) {
6882
6973
  if (typeof urlPath !== "string") return null;
@@ -6897,7 +6988,7 @@ async function createEndpoint(args, context, ports) {
6897
6988
  if (args.confirm !== true) {
6898
6989
  return refusal(
6899
6990
  "CLAIMS_INBOUND_CREATE_CONFIRMATION_REQUIRED",
6900
- "create_endpoint needs confirm: true, set only when a person has read the signing config and asked for the sandbox endpoint to be created. It is a one-time action: the URL and secret are shown once, and no route deletes a sandbox endpoint. Nothing was created.",
6991
+ "create_endpoint needs confirm: true, set only when a person has read the signing config and asked for the sandbox endpoint to be created. The URL and secret are shown once, and a tenant has one endpoint (delete_endpoint removes it). Nothing was created.",
6901
6992
  { action, arguments: ["confirm"] }
6902
6993
  );
6903
6994
  }
@@ -6913,7 +7004,7 @@ async function createEndpoint(args, context, ports) {
6913
7004
  const gate = await humanGate(context, ports, {
6914
7005
  action: "create_endpoint",
6915
7006
  subject: JSON.stringify([signing, file]),
6916
- summary: `Create the sandbox inbound claims endpoint, once, with ${describeSigning(signing)}, and write its inbound URL and first secret to ${file}. No route deletes it.`,
7007
+ summary: `Create the sandbox inbound claims endpoint with ${describeSigning(signing)}, and write its inbound URL and first secret to ${file}.`,
6917
7008
  code: args.confirmation_code
6918
7009
  }, "Nothing was created.");
6919
7010
  if (gate !== null) return gate;
@@ -6941,28 +7032,31 @@ async function createEndpoint(args, context, ports) {
6941
7032
  }
6942
7033
  return inboundFailure(answer, action, CREATE_404);
6943
7034
  }
6944
- if (answer.status === 409 && bodyCode(answer.value) === "event_time_mapping_required") {
7035
+ const refusedCode = answer.status >= 400 ? bodyCode(answer.value) : null;
7036
+ if (refusedCode === "event_time_mapping_required") {
6945
7037
  return refusal(
6946
7038
  "CLAIMS_MAPPING_INVALID",
6947
7039
  "The signing config signs no time (a body-only signature or a secret header), and the active mapping names no event_time, so the API refused it (event_time_mapping_required). Nothing was created. Sign over a timestamp (hmac with signed_payload timestamp_body), or add event_time to the mapping and activate it first.",
6948
7040
  { action, status: 409, code: "event_time_mapping_required", request_id: answer.requestId }
6949
7041
  );
6950
7042
  }
6951
- if (answer.status === 409) {
7043
+ if (refusedCode === "endpoint_exists") {
6952
7044
  return refusal(
6953
7045
  "CLAIMS_INBOUND_ENDPOINT_EXISTS",
6954
- `This sandbox tenant already has an inbound endpoint (endpoint_exists), and it has one at most. Nothing was created. Its inbound URL was shown once, when it was created: set ${INBOUND_URL_ENV} from where it was saved. For a new secret, call ${SETUP3} with rotate_secret: true and secret_env_file. No route deletes a sandbox endpoint.`,
6955
- { action, status: 409, code: bodyCode(answer.value), request_id: answer.requestId }
7046
+ `This sandbox tenant already has an inbound endpoint (endpoint_exists), and it has one at most. Nothing was created. Its inbound URL was shown once, when it was created: set ${INBOUND_URL_ENV} from where it was saved. For a new secret, call ${SETUP3} with rotate_secret: true and secret_env_file; to start over, delete_endpoint: true (a person confirms) and create again.`,
7047
+ { action, status: 409, code: "endpoint_exists", request_id: answer.requestId }
6956
7048
  );
6957
7049
  }
6958
- if (answer.status === 422) {
6959
- return refusal("CLAIMS_ARGUMENTS_INVALID", "The API refused the signing config (body_invalid). Nothing was created.", {
7050
+ if (refusedCode === "body_invalid" || refusedCode === "signing_mode_sandbox_only") {
7051
+ return refusal("CLAIMS_ARGUMENTS_INVALID", refusedCode === "body_invalid" ? "The API refused the signing config (body_invalid). Nothing was created." : "The API refused the signing config (signing_mode_sandbox_only): this tenant is not a sandbox tenant, so it signs only with hmac and signed_payload timestamp_body. Nothing was created.", {
6960
7052
  action,
6961
7053
  arguments: ["signing"],
7054
+ code: refusedCode,
6962
7055
  problems: bodyInvalidErrors(answer.value),
6963
7056
  request_id: answer.requestId
6964
7057
  });
6965
7058
  }
7059
+ if (answer.status === 409 || answer.status === 422) return unexpectedRefusal(answer, action, "Nothing was created.");
6966
7060
  const created = typeof answer.value === "object" && answer.value !== null ? answer.value : {};
6967
7061
  const token = doorTokenOf(created["url_path"]);
6968
7062
  const secret = typeof created["secret"] === "string" && SECRET_SHAPE.test(created["secret"]) ? created["secret"] : null;
@@ -6976,7 +7070,7 @@ async function createEndpoint(args, context, ports) {
6976
7070
  const why = token === null || secret === null ? "came back in an unexpected shape and" : `could not be written to secret_env_file (${failure?.why ?? "unknown"}), and`;
6977
7071
  return refusal(
6978
7072
  "CLAIMS_INBOUND_CREDENTIALS_NOT_WRITTEN",
6979
- `The sandbox inbound endpoint now exists, but ${lost} ${why} the API shows them only once. ` + (secretWritten ? "" : "The secret is lost: rotate_secret: true with a writable secret_env_file recovers a new one. ") + (urlWritten ? "" : "The inbound URL is lost and no route shows it again: rotate_token: true with a writable secret_env_file gives a new one. ") + "No route deletes a sandbox endpoint, and creating again answers 409.",
7073
+ `The sandbox inbound endpoint now exists, but ${lost} ${why} the API shows them only once. ` + (secretWritten ? "" : "The secret is lost: rotate_secret: true with a writable secret_env_file recovers a new one. ") + (urlWritten ? "" : "The inbound URL is lost and no route shows it again: rotate_token: true with a writable secret_env_file gives a new one. ") + "Creating again answers 409 while this endpoint exists; delete_endpoint removes it first.",
6980
7074
  { action, written_to: file, url_written: urlWritten, secret_written: secretWritten, ...failure === void 0 ? {} : { why: failure.why }, request_id: answer.requestId }
6981
7075
  );
6982
7076
  }
@@ -6997,7 +7091,7 @@ async function createEndpoint(args, context, ports) {
6997
7091
  steps: [
6998
7092
  ...signingSteps(finalSigning),
6999
7093
  `The inbound URL and secret were written to ${file}; set the same two in the claims system's config. Neither is shown again.`,
7000
- "Changing the signing config itself (the header names, the prefix, the encoding) is a setting Everfur holds."
7094
+ `To change the signing config (the header names, the prefix, the encoding), call ${SETUP3} with set_signing: true and the new signing; on a live endpoint Everfur changes it.`
7001
7095
  ],
7002
7096
  needs_event_time: needsEventTime(finalSigning),
7003
7097
  local: localState(context, file, scope),
@@ -7012,15 +7106,16 @@ async function createEndpoint(args, context, ports) {
7012
7106
  }
7013
7107
  async function claimsInboundSigningSetupTool(args, context, ports = {}) {
7014
7108
  if (isHosted(context)) return notHosted(SETUP3, "it reads the sandbox endpoint with the sandbox tenant's secret key from a local shell only.");
7015
- const actions = ["create_endpoint", "rotate_secret", "rotate_token"].filter((name) => args[name] === true);
7109
+ const actions = ["create_endpoint", "rotate_secret", "rotate_token", "set_signing", "delete_endpoint"].filter((name) => args[name] === true);
7016
7110
  if (actions.length > 1) {
7017
7111
  return refusal(
7018
7112
  "CLAIMS_ARGUMENTS_INVALID",
7019
- `Pass one of create_endpoint, rotate_secret and rotate_token, not ${actions.join(" and ")}: a new endpoint already comes with its first URL and secret, and each rotation is its own confirmed action. Nothing was done.`,
7113
+ `Pass one of create_endpoint, rotate_secret, rotate_token, set_signing and delete_endpoint, not ${actions.join(" and ")}: each is its own confirmed action. Nothing was done.`,
7020
7114
  { arguments: [...actions] }
7021
7115
  );
7022
7116
  }
7023
7117
  if (args.create_endpoint === true) return createEndpoint(args, context, ports);
7118
+ if (args.set_signing === true || args.delete_endpoint === true) return changeEndpoint(args, context, ports);
7024
7119
  const scope = localScope(context.env, context.cwd);
7025
7120
  const rotation = args.rotate_secret === true ? { name: "rotate_secret", envVar: INBOUND_SECRET_ENV, what: "the new secret", value: "secret" } : args.rotate_token === true ? { name: "rotate_token", envVar: INBOUND_URL_ENV, what: "the new inbound URL", value: "URL" } : null;
7026
7121
  if (rotation !== null) {
@@ -7049,7 +7144,7 @@ async function claimsInboundSigningSetupTool(args, context, ports = {}) {
7049
7144
  steps: [
7050
7145
  ...signingSteps(signing),
7051
7146
  `${URL_SHOWN_ONCE} Keep it in the claims system's config too.`,
7052
- "Changing the signing config itself (the header names, the prefix, the encoding) is a setting Everfur holds."
7147
+ `To change the signing config (the header names, the prefix, the encoding), call ${SETUP3} with set_signing: true and the new signing; on a live endpoint Everfur changes it.`
7053
7148
  ],
7054
7149
  needs_event_time: needsEventTime(signing),
7055
7150
  local: localState(context, args.secret_env_file, scope)
@@ -7100,6 +7195,95 @@ async function claimsInboundSigningSetupTool(args, context, ports = {}) {
7100
7195
  }
7101
7196
  };
7102
7197
  }
7198
+ async function changeEndpoint(args, context, ports) {
7199
+ const action = args.set_signing === true ? "set_signing" : "delete_endpoint";
7200
+ const nothing = action === "set_signing" ? "Nothing was changed." : "Nothing was deleted.";
7201
+ const missing = [action === "set_signing" && args.signing === void 0 ? "signing" : null, args.confirm !== true ? "confirm" : null].filter((name) => name !== null);
7202
+ if (missing.length > 0) {
7203
+ return refusal(
7204
+ "CLAIMS_ARGUMENTS_INVALID",
7205
+ `${action} needs ${missing.join(" and ")}: confirm: true is set only when a person has asked for it. ${nothing}`,
7206
+ { action, arguments: missing }
7207
+ );
7208
+ }
7209
+ const sandbox = sandboxClient(context, ports);
7210
+ if (!isSandbox(sandbox)) return sandbox;
7211
+ const read = await readEndpoint(sandbox, action);
7212
+ if ("isError" in read) return read;
7213
+ const signing = args.signing;
7214
+ const gate = await humanGate(context, ports, action === "set_signing" ? {
7215
+ action,
7216
+ subject: JSON.stringify([read.endpoint.endpoint_id, signing]),
7217
+ summary: `Change the sandbox inbound endpoint's signing to ${describeSigning(signing)}. Events signed the old way are refused (401) from then on; the URL and secret stay the same.`,
7218
+ code: args.confirmation_code
7219
+ } : {
7220
+ action,
7221
+ subject: JSON.stringify([read.endpoint.endpoint_id]),
7222
+ summary: "Delete the sandbox inbound endpoint. Its URL answers 404 at once; the event log and mappings stay, and create_endpoint makes a new URL and secret.",
7223
+ code: args.confirmation_code
7224
+ }, nothing);
7225
+ if (gate !== null) return gate;
7226
+ const scope = localScope(context.env, context.cwd);
7227
+ if (action === "delete_endpoint") {
7228
+ const answer2 = await sandbox.client.request({ method: "DELETE", path: `${INBOUND_SANDBOX_ROUTE}/endpoint`, credentials: sandbox.credentials });
7229
+ if (!answer2.ok) return inboundFailure(answer2, action, ENDPOINT_404);
7230
+ return {
7231
+ isError: false,
7232
+ document: {
7233
+ ok: true,
7234
+ endpoint: { endpoint_id: read.endpoint.endpoint_id, deleted: true },
7235
+ steps: [
7236
+ `The sandbox inbound endpoint was deleted; its URL answers 404 now. ${INBOUND_URL_ENV} and ${INBOUND_SECRET_ENV} in local env files no longer work.`,
7237
+ `The event log and the mappings stay. Create a new endpoint with ${SETUP3} (create_endpoint: true, signing, secret_env_file, confirm: true from a person).`
7238
+ ],
7239
+ local: localState(context, args.secret_env_file, scope)
7240
+ }
7241
+ };
7242
+ }
7243
+ const answer = await sandbox.client.request({
7244
+ method: "PUT",
7245
+ path: `${INBOUND_SANDBOX_ROUTE}/endpoint/signing`,
7246
+ credentials: sandbox.credentials,
7247
+ body: signing,
7248
+ acceptStatuses: [409, 422]
7249
+ });
7250
+ if (!answer.ok) return inboundFailure(answer, action, ENDPOINT_404);
7251
+ const refusedCode = answer.status >= 400 ? bodyCode(answer.value) : null;
7252
+ if (refusedCode === "event_time_mapping_required") {
7253
+ return refusal(
7254
+ "CLAIMS_MAPPING_INVALID",
7255
+ "The new signing signs no time (a body-only signature or a secret header), and the active mapping names no event_time, so the API refused it (event_time_mapping_required). Nothing was changed. Keep signed_payload timestamp_body, or add event_time to the mapping and activate it first.",
7256
+ { action, status: answer.status, code: refusedCode, request_id: answer.requestId }
7257
+ );
7258
+ }
7259
+ if (refusedCode === "body_invalid" || refusedCode === "signing_mode_sandbox_only") {
7260
+ return refusal(
7261
+ "CLAIMS_ARGUMENTS_INVALID",
7262
+ `The API refused the signing config (${refusedCode}). Nothing was changed.`,
7263
+ { action, arguments: ["signing"], code: refusedCode, problems: bodyInvalidErrors(answer.value), request_id: answer.requestId }
7264
+ );
7265
+ }
7266
+ if (answer.status >= 400) return unexpectedRefusal(answer, action, nothing);
7267
+ const view = ENDPOINT_VIEW.safeParse(answer.value);
7268
+ const stored = view.success ? SIGNING_CONFIG.safeParse(view.data.signing) : null;
7269
+ const finalSigning = stored !== null && stored.success ? stored.data : signing;
7270
+ return {
7271
+ isError: false,
7272
+ document: {
7273
+ ok: true,
7274
+ endpoint: {
7275
+ endpoint_id: read.endpoint.endpoint_id,
7276
+ previous_secret_expires_at: view.success ? view.data.previous_secret_expires_at ?? null : null,
7277
+ created_at: view.success ? view.data.created_at ?? null : null,
7278
+ rotated_at: view.success ? view.data.rotated_at ?? null : null
7279
+ },
7280
+ signing: finalSigning,
7281
+ steps: [...signingSteps(finalSigning), "The signing changed now: set the claims system to sign this way before it sends again. The URL and secret are unchanged."],
7282
+ needs_event_time: needsEventTime(finalSigning),
7283
+ local: localState(context, args.secret_env_file, scope)
7284
+ }
7285
+ };
7286
+ }
7103
7287
  async function rotateToken(args, context, ports, sandbox, endpointId, document, scope) {
7104
7288
  const file = args.secret_env_file;
7105
7289
  const gate = await humanGate(context, ports, {
@@ -7981,7 +8165,7 @@ function sandboxFailure(failure, action, capability) {
7981
8165
  if (failure.status === 404 && (failure.code === null || failure.code === "ResourceNotFoundException")) {
7982
8166
  return refusal(
7983
8167
  "CLAIMS_SANDBOX_NOT_ENABLED",
7984
- "The sandbox webhook routes answered 404: they are not switched on for this deployment or this tenant, or the endpoint_id names no endpoint of this tenant. Switching them on is a setting Everfur holds.",
8168
+ "The sandbox webhook routes answered 404: outbound webhooks are not switched on for this deployment or for this tenant (its plan's webhooks feature), or the endpoint_id names no endpoint of this tenant. Switching them on is a setting Everfur holds. A receiver still in development on this machine is checked with everfur_verify_claims_receiver (allow_localhost: true) instead; test events go only to a public https URL.",
7985
8169
  details
7986
8170
  );
7987
8171
  }
@@ -10083,14 +10267,15 @@ a field mapping turns them into claims, documents and pet profiles. everfur_prop
10083
10267
  mapping from sample native events, offline, with the gaps and the personal data paths to scrub;
10084
10268
  everfur_save_claims_mapping saves it as the sandbox draft, and activates the draft only with confirm: true and the
10085
10269
  confirmation phrase typed back by a person who has read it, never on the agent's own initiative. Activating, creating
10086
- the inbound endpoint, rotating its secret or its URL token and creating an outbound test endpoint each also need the person's own
10270
+ the inbound endpoint, rotating its secret or its URL token, changing its signing, deleting it and creating an outbound test endpoint each also need the person's own
10087
10271
  answer: the client asks them when it can; otherwise the tool writes a one-time code to a local file and answers with
10088
10272
  its path, and the person types the code back as confirmation_code. Never open that file yourself.
10089
10273
  everfur_claims_inbound_signing_setup explains the endpoint's signing as steps for the claims system and can rotate the
10090
- sandbox secret, or the URL token after the URL leaks, into a local env file. The sandbox key can create the sandbox inbound endpoint once:
10091
- everfur_claims_inbound_signing_setup with create_endpoint, signing, secret_env_file and confirm: true, set only when
10274
+ sandbox secret, or the URL token after the URL leaks, into a local env file. The sandbox key can create the sandbox inbound endpoint
10275
+ (one per tenant): everfur_claims_inbound_signing_setup with create_endpoint, signing, secret_env_file and confirm: true, set only when
10092
10276
  a person asks for it; its URL and first secret are shown once and are written to that file as
10093
- EVERFUR_CLAIMS_INBOUND_URL and EVERFUR_CLAIMS_INBOUND_SECRET, never returned. Live inbound endpoints are set up by
10277
+ EVERFUR_CLAIMS_INBOUND_URL and EVERFUR_CLAIMS_INBOUND_SECRET, never returned. With confirm: true from a person, set_signing
10278
+ changes the sandbox endpoint's signing config and delete_endpoint deletes it (the event log and mappings stay). Live inbound endpoints are set up by
10094
10279
  Everfur, with their signing and the live mapping. everfur_send_claims_inbound_samples signs synthetic samples, posts them to the
10095
10280
  sandbox inbound URL and reports each event's status, reason code and fix; with read_event_log it sends nothing and
10096
10281
  reads the sandbox event log, for events the claims system itself sent. The tools that read the sandbox tenant's
@@ -10345,7 +10530,7 @@ function buildServer(context, ports = {}, options = {}) {
10345
10530
  "everfur_claims_inbound_signing_setup",
10346
10531
  {
10347
10532
  title: TOOL_ANNOTATIONS.everfur_claims_inbound_signing_setup.title,
10348
- description: "Read the sandbox inbound claims endpoint's signing config and explain, as plain steps, how the insurer's claims system must sign each event (HMAC-SHA256 over the timestamp and body or the body alone, hex or base64, the header names and prefix; or the secret in a header), plus whether the shared secret and inbound URL are set locally. With rotate_secret: true it rotates the sandbox secret and writes the new one to secret_env_file (mode 600); the secret is never returned. With rotate_token: true, after the inbound URL leaked, it rotates the URL token and writes the new URL to secret_env_file as EVERFUR_CLAIMS_INBOUND_URL (the old URL answers 404 at once); the URL is never returned. With create_endpoint: true, signing and confirm: true (set only when a person asks; it is a one-time action) it creates the sandbox inbound endpoint and writes its URL and first secret, shown once, to secret_env_file as EVERFUR_CLAIMS_INBOUND_URL and EVERFUR_CLAIMS_INBOUND_SECRET (mode 600); neither is returned. Live inbound endpoints are set up by Everfur. Create and each rotation also need the person's own confirmation (the client asks them, or they type back a one-time code from a local file as confirmation_code). Sandbox key from a local shell only.",
10533
+ description: "Read the sandbox inbound claims endpoint's signing config and explain, as plain steps, how the insurer's claims system must sign each event (HMAC-SHA256 over the timestamp and body or the body alone, hex or base64, the header names and prefix; or the secret in a header), plus whether the shared secret and inbound URL are set locally. With rotate_secret: true it rotates the sandbox secret and writes the new one to secret_env_file (mode 600); the secret is never returned. With rotate_token: true, after the inbound URL leaked, it rotates the URL token and writes the new URL to secret_env_file as EVERFUR_CLAIMS_INBOUND_URL (the old URL answers 404 at once); the URL is never returned. With create_endpoint: true, signing and confirm: true (set only when a person asks; one endpoint per tenant) it creates the sandbox inbound endpoint and writes its URL and first secret, shown once, to secret_env_file as EVERFUR_CLAIMS_INBOUND_URL and EVERFUR_CLAIMS_INBOUND_SECRET (mode 600); neither is returned. With set_signing: true, signing and confirm: true it changes the sandbox endpoint's signing config (URL and secret unchanged); with delete_endpoint: true and confirm: true it deletes the sandbox endpoint (its URL answers 404 at once; the event log and mappings stay). Live inbound endpoints are set up by Everfur. Create, set_signing, delete and each rotation also need the person's own confirmation (the client asks them, or they type back a one-time code from a local file as confirmation_code). Sandbox key from a local shell only.",
10349
10534
  inputSchema: CLAIMS_INBOUND_SIGNING_SETUP_INPUT_SHAPE,
10350
10535
  outputSchema: CLAIMS_INBOUND_SIGNING_SETUP_OUTPUT_SHAPE,
10351
10536
  annotations: { ...TOOL_ANNOTATIONS.everfur_claims_inbound_signing_setup }
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /*! @everfur/cli. Copyright (c) 2026 Strand Health Inc. dba Everfur. All rights reserved. Use is subject to the Everfur SDK License: https://docs.everfur.com/license */
3
- import { buildServer } from './chunk-FLW4ZANY.js';
3
+ import { buildServer } from './chunk-G7CJK7Z5.js';
4
4
  import { createServer } from 'http';
5
5
  import { timingSafeEqual } from 'crypto';
6
6
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
@@ -5476,7 +5476,7 @@ function booleanAttribute(outcome, key) {
5476
5476
  }
5477
5477
 
5478
5478
  // src/version.ts
5479
- var CLI_VERSION = "0.9.1";
5479
+ var CLI_VERSION = "0.9.2";
5480
5480
  var CLI_PUBLISHED_VERSION = "0.9.0";
5481
5481
 
5482
5482
  // src/commands/diagnose/reasons.ts
@@ -13973,8 +13973,8 @@ function planIntegration(input) {
13973
13973
  // src/registry/sdk/client/contract/contract.generated.ts
13974
13974
  var CONTRACT_SOURCE = Object.freeze({
13975
13975
  digestAlgorithm: "sha256",
13976
- digest: "f2c258aa21d5f24e8b1056db2114c3b4e5317c82119d86022fde295b059b4bfe",
13977
- generatedAt: "2026-10-31T06:47:06Z",
13976
+ digest: "af9a9a3f89b48449238033ef3227df17ccfcc3b81308764a212d25b61a4994cf",
13977
+ generatedAt: "2026-11-02T13:18:35Z",
13978
13978
  capabilitySchemaVersion: 1,
13979
13979
  errorSchemaVersion: 1
13980
13980
  });
@@ -14499,7 +14499,7 @@ var MANIFEST_default = {
14499
14499
  files: [
14500
14500
  {
14501
14501
  path: "client/contract/contract.generated.ts",
14502
- sha256: "dbfc4cc268c85c1c6177a4772a08cadd75c551f22dfe995f48b9ebdcc0df3731"
14502
+ sha256: "453c2dc536c4e1198a747a184e0f8ac60409e53ed0ed1940ebb2304f51bb75d2"
14503
14503
  },
14504
14504
  {
14505
14505
  path: "client/errors/EverfurError.ts",
@@ -17233,7 +17233,7 @@ var MEANINGS = Object.freeze({
17233
17233
  },
17234
17234
  CLAIMS_SANDBOX_NOT_ENABLED: {
17235
17235
  tools: [CLAIMS_SANDBOX, ...CLAIMS_INBOUND],
17236
- meaning: "The sandbox route answered 404 with no code of its own: the sandbox webhook or claims-inbound routes are not switched on for this tenant or deployment, the endpoint_id names no endpoint of this tenant, or (inbound) the tenant has no claims portal or no inbound endpoint exists yet. The sandbox key can create the sandbox inbound endpoint once (everfur_claims_inbound_signing_setup, create_endpoint with confirm: true from a person); its inbound URL and first secret are shown once, at creation. Live inbound endpoints are set up by Everfur.",
17236
+ meaning: "The sandbox route answered 404 with no code of its own: the sandbox webhook or claims-inbound routes are not switched on for this tenant or deployment, the endpoint_id names no endpoint of this tenant, or (inbound) the tenant has no claims portal or no inbound endpoint exists yet. The sandbox key can create the sandbox inbound endpoint (one per tenant) (everfur_claims_inbound_signing_setup, create_endpoint with confirm: true from a person); its inbound URL and first secret are shown once, at creation. Live inbound endpoints are set up by Everfur.",
17237
17237
  nextAction: "Check the endpoint_id with list_endpoints; when list_endpoints itself answers this, switching the routes on is a step Everfur holds. When an inbound route answers it and the routes are on, the sandbox endpoint may not exist yet: offer create_endpoint, and create it only when a person confirms."
17238
17238
  },
17239
17239
  CLAIMS_SANDBOX_CALL_FAILED: {
@@ -17293,13 +17293,13 @@ var MEANINGS = Object.freeze({
17293
17293
  },
17294
17294
  CLAIMS_INBOUND_CREATE_CONFIRMATION_REQUIRED: {
17295
17295
  tools: [CLAIMS_SETUP],
17296
- meaning: "create_endpoint was called without confirm: true. Creating the sandbox inbound endpoint is a one-time action (its URL and secret are shown once, and no route deletes a sandbox endpoint), so a person decides it. Nothing was created.",
17296
+ meaning: "create_endpoint was called without confirm: true. Creating the sandbox inbound endpoint shows its URL and secret once, and a tenant has one endpoint (delete_endpoint removes it), so a person decides it. Nothing was created.",
17297
17297
  nextAction: "Show the developer the signing config; call create_endpoint with confirm: true only when a person asks for it. Never confirm on your own."
17298
17298
  },
17299
17299
  CLAIMS_INBOUND_ENDPOINT_EXISTS: {
17300
17300
  tools: [CLAIMS_SETUP],
17301
17301
  meaning: "The create answered 409 endpoint_exists: this sandbox tenant already has its inbound endpoint, whose URL was shown once, at creation. Nothing was created.",
17302
- nextAction: "Tell the developer to set EVERFUR_CLAIMS_INBOUND_URL from where they saved it, and offer rotate_secret for a new secret or rotate_token for a new URL."
17302
+ nextAction: "Tell the developer to set EVERFUR_CLAIMS_INBOUND_URL from where they saved it, and offer rotate_secret for a new secret or rotate_token for a new URL; to start over, delete_endpoint (a person confirms) then create again."
17303
17303
  },
17304
17304
  CLAIMS_INBOUND_CREDENTIALS_NOT_WRITTEN: {
17305
17305
  tools: [CLAIMS_SETUP],
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /*! @everfur/cli. Copyright (c) 2026 Strand Health Inc. dba Everfur. All rights reserved. Use is subject to the Everfur SDK License: https://docs.everfur.com/license */
3
- import { VERIFY_IDENTITY_MODES, SURFACES, ENVIRONMENTS, BASE_URL_ENV_VAR, MIN_TIMEOUT_MS, MAX_TIMEOUT_MS, DEFAULT_TIMEOUT_MS, ALL_CAPABILITIES, expandCapabilities, errorOutcome, describeFailure, failureDetails, countsAsNotOn, diagnoseVerdict, isJsonObject, succeed, CAPABILITY_QUESTION, CAPABILITIES_TREE, WEB_EMBEDDING_QUESTION, PLATFORM_TREE, loadDecisionSpace, fetchContract, contractUnavailableOutcome, loadDecisionSpaceFromContract, parseEnvironment, checkTenantMode, detectProject, planIntegration, fail, ExitCode, DOCS_KEY, resolveContractPath, validateContractFile, buildSupportBundle, renderSupportBundle, chooseWidgetAuth, DIAGNOSTICS_PATH, diagnoseFailure, parseDiagnostics, buildDiagnosisDocument, PARTNER_KEY, SESSION_TOKEN, resolveCredential, ADMIN_TOKEN, withPrefix, parseOrigin, parseLoaderUrl, parseSurfaces, parseIdentityMode, runVerification, PARTNER_SECRET_KEY, resolveOffline, resolveWithoutRegistry, knownCodes, loadErrorRegistryFromContract, loadErrorRegistry, resolveAfterRegistryMiss, registryAlsoIn, buildExplanationDocument, renderExplanation, alsoInLines, resolveEndpoint, isCorrelatableRequestId, EMPTY_REGISTRY, createApiClient, offlineDocument, renderOffline, IDENTITY_QUESTION, IDENTITY_TREE, BACKEND_LANGUAGE_QUESTION, SESSION_MINT_TREE, CREDENTIAL_SPECS } from './chunk-VUXILRME.js';
3
+ import { VERIFY_IDENTITY_MODES, SURFACES, ENVIRONMENTS, BASE_URL_ENV_VAR, MIN_TIMEOUT_MS, MAX_TIMEOUT_MS, DEFAULT_TIMEOUT_MS, ALL_CAPABILITIES, expandCapabilities, errorOutcome, describeFailure, failureDetails, countsAsNotOn, diagnoseVerdict, isJsonObject, succeed, CAPABILITY_QUESTION, CAPABILITIES_TREE, WEB_EMBEDDING_QUESTION, PLATFORM_TREE, loadDecisionSpace, fetchContract, contractUnavailableOutcome, loadDecisionSpaceFromContract, parseEnvironment, checkTenantMode, detectProject, planIntegration, fail, ExitCode, DOCS_KEY, resolveContractPath, validateContractFile, buildSupportBundle, renderSupportBundle, chooseWidgetAuth, DIAGNOSTICS_PATH, diagnoseFailure, parseDiagnostics, buildDiagnosisDocument, PARTNER_KEY, SESSION_TOKEN, resolveCredential, ADMIN_TOKEN, withPrefix, parseOrigin, parseLoaderUrl, parseSurfaces, parseIdentityMode, runVerification, PARTNER_SECRET_KEY, resolveOffline, resolveWithoutRegistry, knownCodes, loadErrorRegistryFromContract, loadErrorRegistry, resolveAfterRegistryMiss, registryAlsoIn, buildExplanationDocument, renderExplanation, alsoInLines, resolveEndpoint, isCorrelatableRequestId, EMPTY_REGISTRY, createApiClient, offlineDocument, renderOffline, IDENTITY_QUESTION, IDENTITY_TREE, BACKEND_LANGUAGE_QUESTION, SESSION_MINT_TREE, CREDENTIAL_SPECS } from './chunk-VSZ4RPKA.js';
4
4
  import { isAbsolute, resolve } from 'path';
5
5
 
6
6
  // src/cli/format.ts
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  /*! @everfur/cli. Copyright (c) 2026 Strand Health Inc. dba Everfur. All rights reserved. Use is subject to the Everfur SDK License: https://docs.everfur.com/license */
3
- import { loadHostedMcpConfig, startHostedMcpServer } from './chunk-FWEDPKKK.js';
4
- import './chunk-JURZYOMH.js';
5
- import './chunk-FLW4ZANY.js';
6
- import { CLI_VERSION } from './chunk-VUXILRME.js';
3
+ import { loadHostedMcpConfig, startHostedMcpServer } from './chunk-5GXXNW3F.js';
4
+ import './chunk-LH4AWYCB.js';
5
+ import './chunk-G7CJK7Z5.js';
6
+ import { CLI_VERSION } from './chunk-VSZ4RPKA.js';
7
7
 
8
8
  // src/bin/everfur-mcp-hosted.ts
9
9
  async function main() {
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  /*! @everfur/cli. Copyright (c) 2026 Strand Health Inc. dba Everfur. All rights reserved. Use is subject to the Everfur SDK License: https://docs.everfur.com/license */
3
- import { startRemoteMcpServer, loadRemoteMcpConfig } from './chunk-JURZYOMH.js';
4
- import './chunk-FLW4ZANY.js';
5
- import { CLI_VERSION } from './chunk-VUXILRME.js';
3
+ import { startRemoteMcpServer, loadRemoteMcpConfig } from './chunk-LH4AWYCB.js';
4
+ import './chunk-G7CJK7Z5.js';
5
+ import { CLI_VERSION } from './chunk-VSZ4RPKA.js';
6
6
 
7
7
  // src/bin/everfur-mcp-http.ts
8
8
  async function main() {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /*! @everfur/cli. Copyright (c) 2026 Strand Health Inc. dba Everfur. All rights reserved. Use is subject to the Everfur SDK License: https://docs.everfur.com/license */
3
- import { runStdioServer } from './chunk-FLW4ZANY.js';
4
- import { CLI_VERSION } from './chunk-VUXILRME.js';
3
+ import { runStdioServer } from './chunk-G7CJK7Z5.js';
4
+ import { CLI_VERSION } from './chunk-VSZ4RPKA.js';
5
5
 
6
6
  // src/bin/everfur-mcp.ts
7
7
  if (process.argv.slice(2).includes("--version")) {
package/dist/everfur.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /*! @everfur/cli. Copyright (c) 2026 Strand Health Inc. dba Everfur. All rights reserved. Use is subject to the Everfur SDK License: https://docs.everfur.com/license */
3
- import { runCli } from './chunk-LALDS2WR.js';
4
- import { ExitCode, systemClock, fetchTransport, CLI_VERSION, nodeFileSystem, nodeContractCache } from './chunk-VUXILRME.js';
3
+ import { runCli } from './chunk-WL42DEHE.js';
4
+ import { ExitCode, systemClock, fetchTransport, CLI_VERSION, nodeFileSystem, nodeContractCache } from './chunk-VSZ4RPKA.js';
5
5
 
6
6
  // src/bin/everfur.ts
7
7
  async function main() {
package/dist/index.d.ts CHANGED
@@ -3651,6 +3651,6 @@ declare function parseSuppliedFacts(capabilitiesRaw: string | null, identityRaw:
3651
3651
  * install, and a bundled artifact. `tests/unit/version.test.ts` asserts this constant equals
3652
3652
  * the package.json version, so the two cannot drift.
3653
3653
  */
3654
- declare const CLI_VERSION = "0.9.1";
3654
+ declare const CLI_VERSION = "0.9.2";
3655
3655
 
3656
3656
  export { ADMIN_TOKEN, API_PREFIX, type ApiClient, type ApiFailure, type ApiResult, type ApiSuccess, BASE_URL_ENV_VAR, type BlockedCapability, type BlockedOutcome, CLI_VERSION, COMMANDS, CREDENTIAL_SPECS, type Capability, type CapabilityDiagnosis, type ClockPort, type Command, type CommandContext, type CommandOutcome, type ContractValidationOutcome, type Credential, type CredentialSpec, DEFAULT_TIMEOUT_MS, type DecisionSpace, type DecisionSpaceProvenance, type DecisionTree, type DetectedDependency, type DetectedTheme, type Diagnosis, EMPTY_REGISTRY, ERRORS_DOCUMENT_KEY, type ErrorRegistry, type ErrorRegistryEntry, ExitCode, type FileSystemPort, type FormatOptions, type FormattedOutput, type HttpMethod, type HttpRequest, type HttpResponse, IDEMPOTENT_METHODS, type IdentityMode, MISSING_FACT_NAMES, type MissingFact, type MissingFactName, type Outcome, PARTNER_KEY, PARTNER_SECRET_KEY, PLAN_DOCUMENT_KIND, PLAN_SCHEMA_VERSION, type PackageManager, type PlanDocument, type PlanInput, type PlanPrinciple, type PlanStep, type PlanWarning, type PositionalSpec, type ProjectDetection, type ProjectType, REASON_CODES, REDACTED, type ReasonCode, type RegistryLoad, type RequestSpec, type ResolvedCredential, type ResolvedEndpoint, type RunOptions, SCHEMAS, SESSION_TOKEN, type SandboxCreateStatus, type SandboxCreation, type SchemaValidation, type SchemaViolation, type SessionMintLanguage, type StepResult, THEME_TOKEN_ORDER, type TerminalOutcome, type ThemeConfidence, type ThemeDetection, type ThemeEvidence, type ThemeSource, type ThemeToken, TransportError, type TransportPort, type TreeOption, type TreeQuestion, type Verification, type VerifyStep, type WalkResult, apiUrl, buildDecisionSpace, buildDiagnosisDocument, buildExplanationDocument, buildSandboxDocument, buildVerificationDocument, clampTimeout, createApiClient, createMemoryFileSystem, createRecordingClock, describeFailure, detectProject, detectTheme, detectThemeFromText, digestOfProjection, digestsEqual, editDistance, entryFromRow, ephemeralCredential, errorCodeOf, failureDetails, failureOutcome, fetchTransport, formatOutcome, isCorrelatableRequestId, isIdempotent, isKnownReasonCode, loadDecisionSpace, loadErrorRegistry, matchCommand, missingFactsFor, nextActionFor as nextActionForErrorCode, nextActionFor$1 as nextActionForReason, nextActionsFor, nodeFileSystem, parseCapabilities, parseDiagnostics, parseIdentityMode, parseSessionMintLanguage, parseSuppliedFacts, planIntegration, projectSandboxCreate, renderDiagnosis, renderExplanation, renderPlan, renderSandboxCreate, renderVerification, resolveContractPath, resolveCredential, resolveEndpoint, runCli, runVerification, suggestCodes, systemClock, validateContractFile, validateContractPublicEnvelope, validateDiagnosisDocument, validateErrorExplanationDocument, validatePlanDocument, validateSandboxCreateDocument, validateVerificationDocument, verifyDigest, walkSingle, walkTree, withPrefix };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
2
  /*! @everfur/cli. Copyright (c) 2026 Strand Health Inc. dba Everfur. All rights reserved. Use is subject to the Everfur SDK License: https://docs.everfur.com/license */
3
- export { COMMANDS, buildSandboxDocument, buildVerificationDocument, failureOutcome, formatOutcome, matchCommand, nextActionsFor, parseCapabilities, parseIdentityMode, parseSessionMintLanguage, parseSuppliedFacts, projectSandboxCreate, renderDiagnosis, renderPlan, renderSandboxCreate, renderVerification, runCli } from './chunk-LALDS2WR.js';
4
- export { ADMIN_TOKEN, API_PREFIX, BASE_URL_ENV_VAR, CLI_VERSION, CREDENTIAL_SPECS, DEFAULT_TIMEOUT_MS, EMPTY_REGISTRY, ERRORS_DOCUMENT_KEY, ExitCode, IDEMPOTENT_METHODS, MISSING_FACT_NAMES, PARTNER_KEY, PARTNER_SECRET_KEY, PLAN_DOCUMENT_KIND, PLAN_SCHEMA_VERSION, REASON_CODES, REDACTED, SCHEMAS, SESSION_TOKEN, THEME_TOKEN_ORDER, TransportError, apiUrl, buildDecisionSpace, buildDiagnosisDocument, buildExplanationDocument, clampTimeout, createApiClient, createMemoryFileSystem, createRecordingClock, describeFailure, detectProject, detectTheme, detectThemeFromText, digestOfProjection, digestsEqual, editDistance, entryFromRow, ephemeralCredential, errorCodeOf, failureDetails, fetchTransport, isCorrelatableRequestId, isIdempotent, isKnownReasonCode, loadDecisionSpace, loadErrorRegistry, missingFactsFor, nextActionFor2 as nextActionForErrorCode, nextActionFor as nextActionForReason, nodeFileSystem, parseDiagnostics, planIntegration, renderExplanation, resolveContractPath, resolveCredential, resolveEndpoint, runVerification, suggestCodes, systemClock, validateContractFile, validateContractPublicEnvelope, validateDiagnosisDocument, validateErrorExplanationDocument, validatePlanDocument, validateSandboxCreateDocument, validateVerificationDocument, verifyDigest, walkSingle, walkTree, withPrefix } from './chunk-VUXILRME.js';
3
+ export { COMMANDS, buildSandboxDocument, buildVerificationDocument, failureOutcome, formatOutcome, matchCommand, nextActionsFor, parseCapabilities, parseIdentityMode, parseSessionMintLanguage, parseSuppliedFacts, projectSandboxCreate, renderDiagnosis, renderPlan, renderSandboxCreate, renderVerification, runCli } from './chunk-WL42DEHE.js';
4
+ export { ADMIN_TOKEN, API_PREFIX, BASE_URL_ENV_VAR, CLI_VERSION, CREDENTIAL_SPECS, DEFAULT_TIMEOUT_MS, EMPTY_REGISTRY, ERRORS_DOCUMENT_KEY, ExitCode, IDEMPOTENT_METHODS, MISSING_FACT_NAMES, PARTNER_KEY, PARTNER_SECRET_KEY, PLAN_DOCUMENT_KIND, PLAN_SCHEMA_VERSION, REASON_CODES, REDACTED, SCHEMAS, SESSION_TOKEN, THEME_TOKEN_ORDER, TransportError, apiUrl, buildDecisionSpace, buildDiagnosisDocument, buildExplanationDocument, clampTimeout, createApiClient, createMemoryFileSystem, createRecordingClock, describeFailure, detectProject, detectTheme, detectThemeFromText, digestOfProjection, digestsEqual, editDistance, entryFromRow, ephemeralCredential, errorCodeOf, failureDetails, fetchTransport, isCorrelatableRequestId, isIdempotent, isKnownReasonCode, loadDecisionSpace, loadErrorRegistry, missingFactsFor, nextActionFor2 as nextActionForErrorCode, nextActionFor as nextActionForReason, nodeFileSystem, parseDiagnostics, planIntegration, renderExplanation, resolveContractPath, resolveCredential, resolveEndpoint, runVerification, suggestCodes, systemClock, validateContractFile, validateContractPublicEnvelope, validateDiagnosisDocument, validateErrorExplanationDocument, validatePlanDocument, validateSandboxCreateDocument, validateVerificationDocument, verifyDigest, walkSingle, walkTree, withPrefix } from './chunk-VSZ4RPKA.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@everfur/cli",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "description": "Everfur CLI: plan, verify, and diagnose an Everfur pet-health integration from the terminal.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "type": "module",