@everfur/cli 0.9.0 → 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-JI6USLIZ.js';
4
- import { createHostedTokenVerifier, tokenBucketOf, isAccessTokenShaped, buildServer, MCP_SCOPE, tenantContextOf, sendTestUserRef, hostedVerifyUserRef, REVOKED_AUTHORIZATION_REMEDY, SYNTHETIC_USER_REF_PREFIX } from './chunk-J7SL4FA7.js';
5
- import { BASE_URL_ENV_VAR, resolveEndpoint, fetchTransport, systemClock, createApiClient, withPrefix, ephemeralCredential, validateContractText, isJsonObject, describeFailure } from './chunk-OHA3JVME.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-OHA3JVME.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));
@@ -1956,8 +1989,16 @@ var INBOUND_CODES = Object.freeze([
1956
1989
  "inbound_sandbox",
1957
1990
  409,
1958
1991
  "fix_mapping",
1959
- "The endpoint's signing has no signed time (a body-only signature or a secret header), and the mapping names no event_time, so it cannot be activated.",
1960
- "Add event_time to the mapping, save it and activate again."
1992
+ "The endpoint's signing has no signed time (a body-only signature or a secret header), and the mapping names no event_time, so the mapping cannot be activated, or an endpoint with that signing cannot be created.",
1993
+ "Add event_time to the mapping, save it and activate it, then create the endpoint or activate again. Or sign over a timestamp (hmac with signed_payload timestamp_body)."
1994
+ ),
1995
+ inbound(
1996
+ "endpoint_exists",
1997
+ "inbound_sandbox",
1998
+ 409,
1999
+ "stop",
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.",
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.`
1961
2002
  ),
1962
2003
  inbound(
1963
2004
  "events_invalid",
@@ -2044,8 +2085,13 @@ var CLAIMS_EVENT_TYPES = Object.freeze([
2044
2085
  "claim.failed",
2045
2086
  "claim.duplicate",
2046
2087
  "claim.decided",
2088
+ "insured_pet.profile.ready",
2089
+ "insured_pet.profile.updated",
2047
2090
  "webhook_endpoint.test"
2048
2091
  ]);
2092
+ var CLAIMS_TESTABLE_EVENT_TYPES = Object.freeze(
2093
+ CLAIMS_EVENT_TYPES.filter((type) => !type.startsWith("insured_pet."))
2094
+ );
2049
2095
  var CLAIMS_DELIVERY_TIMEOUT_SECONDS = 10;
2050
2096
  var CLAIMS_RECEIVER_SLOW_SECONDS = 5;
2051
2097
  var CLAIMS_ROUTES = Object.freeze({
@@ -2947,6 +2993,12 @@ export async function processEverfurEvent(
2947
2993
  if (claimId === null) return;
2948
2994
  await store.saveClaimEvent(claimId, event.type, data);
2949
2995
  return;
2996
+ case 'insured_pet.profile.ready':
2997
+ case 'insured_pet.profile.updated':
2998
+ // REPLACE: an insured pet's profile, keyed by insured_pet_id (pet_ref can be null). ready comes once, updated once
2999
+ // per later version; keep the highest version. Each field is null when not known; read the full profile from
3000
+ // profile_path. Neither event names a claim or carries a record.
3001
+ return;
2950
3002
  default:
2951
3003
  // A type this file does not know yet: it was acknowledged, and is logged rather than refused.
2952
3004
  console.warn('everfur webhooks: unhandled event type', event.type);
@@ -3933,6 +3985,11 @@ def process_event(
3933
3985
  return
3934
3986
  kept.save_claim_event(claim_id, event_type, data)
3935
3987
  return
3988
+ if event_type in ("insured_pet.profile.ready", "insured_pet.profile.updated"):
3989
+ # REPLACE: an insured pet's profile, keyed by insured_pet_id (pet_ref can be None). ready comes once, updated once
3990
+ # per later version; keep the highest version. Each field is None when not known; read the full profile from
3991
+ # profile_path. Neither event names a claim or carries a record.
3992
+ return
3936
3993
  # A type this file does not know yet: it was acknowledged, and is logged rather than refused.
3937
3994
  log.warning("everfur webhooks: unhandled event type %s", event_type)
3938
3995
 
@@ -4550,7 +4607,7 @@ function rotateDetail() {
4550
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.`;
4551
4608
  }
4552
4609
  function goLiveDetail() {
4553
- 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.`;
4554
4611
  }
4555
4612
  function portalDetail() {
4556
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).`;
@@ -4997,7 +5054,7 @@ function checkMappingDocument(document) {
4997
5054
  extraKeys(kind, ["path", "values"], "kind", at);
4998
5055
  const path = kind["path"];
4999
5056
  if (typeof path !== "string") at("kind.path", "kind.path is required");
5000
- else pathProblem(path, "forbidden", "kind.path", at);
5057
+ else sourcePathProblem(path, "forbidden", [], "kind.path", at);
5001
5058
  const values = kind["values"];
5002
5059
  if (!isObject(values) || Object.keys(values).length === 0 || Object.keys(values).length > MAX_KIND_VALUES) {
5003
5060
  at("kind.values", `kind.values maps 1 to ${MAX_KIND_VALUES} native values to a kind`);
@@ -5062,6 +5119,8 @@ function checkMappingDocument(document) {
5062
5119
  extraKeys(listed, ["path", "fields"], `kinds.${name}.${list2}`, at);
5063
5120
  if (typeof listed["path"] !== "string") at(`kinds.${name}.${list2}.path`, "a list's path is required");
5064
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);
5065
5124
  const listFields = listed["fields"];
5066
5125
  if (!isObject(listFields) || Object.keys(listFields).length === 0 || Object.keys(listFields).length > MAX_LIST_FIELDS) {
5067
5126
  at(`kinds.${name}.${list2}.fields`, `a list maps 1 to ${MAX_LIST_FIELDS} targets`);
@@ -5069,7 +5128,7 @@ function checkMappingDocument(document) {
5069
5128
  }
5070
5129
  for (const [target, field] of Object.entries(listFields)) {
5071
5130
  if (!allowed.includes(target)) at(`kinds.${name}.${list2}.fields.${target}`, `${list2} has no target ${target.slice(0, 64)}; targets: ${allowed.join(", ")}`);
5072
- checkField(field, `kinds.${name}.${list2}.fields.${target}`, at);
5131
+ checkField(field, `kinds.${name}.${list2}.fields.${target}`, at, listKeys);
5073
5132
  }
5074
5133
  }
5075
5134
  }
@@ -5087,7 +5146,19 @@ function pathProblem(text, star, where, at) {
5087
5146
  const parsed = parsePath(text, star);
5088
5147
  if (typeof parsed === "string") at(where, parsed);
5089
5148
  }
5090
- 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 = []) {
5091
5162
  if (!isObject(field)) {
5092
5163
  at(where, "a field is an object: {path} or {paths}, with optional transforms");
5093
5164
  return;
@@ -5108,7 +5179,8 @@ function checkField(field, where, at) {
5108
5179
  if (path === void 0 && paths === void 0 && !constant) at(where, "a field needs a path, paths or a leading constant transform");
5109
5180
  if (path !== void 0) {
5110
5181
  if (typeof path !== "string") at(`${where}.path`, "a path is a string");
5111
- 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);
5112
5184
  }
5113
5185
  if (paths !== void 0) {
5114
5186
  if (!Array.isArray(paths) || paths.length === 0 || paths.length > MAX_FIELD_PATHS) {
@@ -5116,7 +5188,8 @@ function checkField(field, where, at) {
5116
5188
  } else {
5117
5189
  paths.forEach((text, index) => {
5118
5190
  if (typeof text !== "string") at(`${where}.paths[${index}]`, "a path is a string");
5119
- 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);
5120
5193
  });
5121
5194
  }
5122
5195
  }
@@ -5303,7 +5376,7 @@ var CLAIM_RULES = Object.freeze([
5303
5376
  { target: "amount_claimed_cents", scope: "claim", names: ["amountclaimed", "claimedamount", "claimamount", "requestedamount", "amountrequested", "claimed", "requested"], shape: "money", unscoped: true },
5304
5377
  { target: "billed_cents", scope: "claim", names: ["billedamount", "billed", "total", "totalamount", "invoicetotal", "invoiceamount", "amount", "totalbilled", "cost", "charges"], shape: "money", unscoped: true },
5305
5378
  { target: "clinic_name", scope: "clinic", names: ["name", "clinicname", "clinic", "vetname", "hospitalname", "practicename", "providername", "vet", "hospital", "practice", "provider"], shape: "text" },
5306
- { 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 },
5307
5380
  { target: "pet.pet_ref", scope: "pet", names: ["petid", "petref", "petnumber", "animalid", "patientid", ...ID_NAMES], shape: "ref" },
5308
5381
  { target: "pet.name", scope: "pet", names: ["name", "petname", "animalname", "patientname", "callname"], shape: "text" },
5309
5382
  { target: "pet.species", scope: "pet", names: ["species", "speciescode", "kind", "type", "animaltype", "pettype", "animalkind"], shape: "species" },
@@ -5340,7 +5413,7 @@ function rulesFor(kind) {
5340
5413
  return Object.entries(PROFILE_FROM_CLAIM).map(([target, from]) => ({ ...byTarget.get(from), target }));
5341
5414
  }
5342
5415
  var DOCUMENT_RULES = Object.freeze([
5343
- { 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 },
5344
5417
  { target: "url", scope: null, names: ["url", "link", "href", "uri", "downloadurl", "fileurl", "location", "signedurl", "presignedurl", "download"], shape: "url", unscoped: true },
5345
5418
  { target: "file_name", scope: null, names: ["filename", "name", "title", "documentname", "originalname", "originalfilename", "label"], shape: "file_name", unscoped: true },
5346
5419
  { target: "kind", scope: null, names: ["kind", "category", "type", "documenttype", "doctype", "documentkind", "doccategory", "class"], shape: "doc_kind", unscoped: true },
@@ -5361,6 +5434,8 @@ var SPECIES_SYNONYMS = Object.freeze({
5361
5434
  d: "dog",
5362
5435
  puppy: "dog",
5363
5436
  canin: "dog",
5437
+ can: "dog",
5438
+ cn: "dog",
5364
5439
  cat: "cat",
5365
5440
  cats: "cat",
5366
5441
  feline: "cat",
@@ -5442,7 +5517,7 @@ function shapeFits(shape, leaf) {
5442
5517
  case "content_type":
5443
5518
  return only("ref", "text", "int", "bool");
5444
5519
  case "base64":
5445
- 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, "")));
5446
5521
  case "url":
5447
5522
  return only("url");
5448
5523
  }
@@ -5707,11 +5782,12 @@ function transformsFor(shape, leaf, order, target, orderDecided = false) {
5707
5782
  }
5708
5783
  return { transforms, why, confidence, reviewNote, untrustedCodes };
5709
5784
  }
5710
- function pick(rule, leaves, used, parentKeys, documentElement = false) {
5785
+ function pick(rule, leaves, used, parentKeys, documentElement = false, ownerRule = true) {
5711
5786
  let best = null;
5712
5787
  let bestScore = 0;
5713
5788
  for (const leaf of leaves) {
5714
5789
  if (used.has(leaf.path)) continue;
5790
+ if (ownerRule && ownerPathProblem([...parentKeys, ...leaf.keys]) !== null) continue;
5715
5791
  if (rule.target !== "member_ref" && personalData(leaf, parentKeys, documentElement) !== null) continue;
5716
5792
  if (rule.target === "member_ref" && (isPiiKey(leaf.keys[leaf.keys.length - 1] ?? "") || leaf.shapes.has("email") || leaf.shapes.has("phone"))) continue;
5717
5793
  if (!shapeFits(rule.shape, leaf)) continue;
@@ -5918,8 +5994,26 @@ function proposeMapping(input) {
5918
5994
  const pinnedPath = pinned[rule.target];
5919
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, []);
5920
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
+ }
5921
6014
  if (leaf === null) {
5922
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.` });
5923
6017
  continue;
5924
6018
  }
5925
6019
  if (pinnedPath !== void 0 && personalData(leaf) !== null && rule.target !== "member_ref") {
@@ -6406,7 +6500,7 @@ function inboundFailure(failure, action, notFound) {
6406
6500
  }
6407
6501
  return sandboxFailure(failure, action);
6408
6502
  }
6409
- 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.`;
6410
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).`;
6411
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}`;
6412
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.";
@@ -6457,21 +6551,28 @@ function mappingSummary(view) {
6457
6551
  }
6458
6552
  function validationErrors(body) {
6459
6553
  if (typeof body !== "object" || body === null) return [];
6460
- 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"];
6461
6557
  if (!Array.isArray(errors)) return [];
6462
6558
  return errors.slice(0, 20).flatMap((item) => {
6463
6559
  if (typeof item !== "object" || item === null) return [];
6464
- const record = item;
6465
- const loc = Array.isArray(record["loc"]) ? record["loc"].map(String).join(".") : String(record["loc"] ?? "");
6466
- 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"] : "";
6467
6563
  return [{ loc: loc.slice(0, 200), msg: msg.slice(0, 300) }];
6468
6564
  });
6469
6565
  }
6470
6566
  function bodyCode(body) {
6471
- if (typeof body !== "object" || body === null) return null;
6472
- const record = body;
6473
- const code = record["error"] ?? record["code"];
6474
- 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
+ );
6475
6576
  }
6476
6577
  var SAMPLE_EVENT = z.record(z.string(), z.unknown());
6477
6578
  function loadSamples(samples, files, scope) {
@@ -6556,7 +6657,16 @@ var PREVIEW_RESULT = z.object({
6556
6657
  });
6557
6658
  async function preview(sandbox, mapping, events, action) {
6558
6659
  const body = { ...mapping === void 0 ? {} : { mapping }, events };
6559
- 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
+ }
6560
6670
  if (!answer.ok) {
6561
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);
6562
6672
  }
@@ -6633,7 +6743,9 @@ async function proposeClaimsMappingTool(args, context, ports = {}, options = {})
6633
6743
  } else {
6634
6744
  const results = await preview(sandbox, proposal.mapping, loaded.samples, "preview");
6635
6745
  if (!Array.isArray(results)) {
6636
- 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 } };
6637
6749
  } else {
6638
6750
  const relayed = results.map((item, index) => relayPreview(item, index));
6639
6751
  document["server_preview"] = { passed: relayed.every((item) => item["gaps"].length === 0), results: relayed };
@@ -6708,6 +6820,7 @@ async function saveClaimsMappingTool(args, context, ports = {}) {
6708
6820
  });
6709
6821
  if (!answer2.ok) return inboundFailure(answer2, action, MAPPING_ROUTES_404);
6710
6822
  if (answer2.status === 422) {
6823
+ if (bodyCode(answer2.value) !== "mapping_invalid") return unexpectedRefusal(answer2, action, "Nothing was saved.");
6711
6824
  return refusal("CLAIMS_MAPPING_INVALID", "The API refused the mapping (mapping_invalid); nothing was saved.", {
6712
6825
  action,
6713
6826
  problems: validationErrors(answer2.value).map((item) => `${item.loc}: ${item.msg}`),
@@ -6779,11 +6892,12 @@ async function saveClaimsMappingTool(args, context, ports = {}) {
6779
6892
  );
6780
6893
  }
6781
6894
  if (answer.status === 409 || answer.status === 422) {
6782
- 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.");
6783
6897
  return refusal(
6784
6898
  "CLAIMS_MAPPING_INVALID",
6785
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.",
6786
- { 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 }
6787
6901
  );
6788
6902
  }
6789
6903
  const view = MAPPING_VIEW.safeParse(answer.value);
@@ -6797,7 +6911,9 @@ function describeSigning(signing) {
6797
6911
  var CLAIMS_INBOUND_SIGNING_SETUP_INPUT_SHAPE = {
6798
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.`),
6799
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)."),
6800
- 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."),
6801
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."),
6802
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.`),
6803
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.`),
@@ -6851,8 +6967,7 @@ function stripUndefined(env) {
6851
6967
  return out;
6852
6968
  }
6853
6969
  function bodyInvalidErrors(body) {
6854
- const detail = typeof body === "object" && body !== null ? body["detail"] ?? body : body;
6855
- return validationErrors(detail).map((item) => `${item.loc}: ${item.msg}`);
6970
+ return validationErrors(body).map((item) => `${item.loc}: ${item.msg}`);
6856
6971
  }
6857
6972
  function doorTokenOf(urlPath) {
6858
6973
  if (typeof urlPath !== "string") return null;
@@ -6873,7 +6988,7 @@ async function createEndpoint(args, context, ports) {
6873
6988
  if (args.confirm !== true) {
6874
6989
  return refusal(
6875
6990
  "CLAIMS_INBOUND_CREATE_CONFIRMATION_REQUIRED",
6876
- "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.",
6877
6992
  { action, arguments: ["confirm"] }
6878
6993
  );
6879
6994
  }
@@ -6889,7 +7004,7 @@ async function createEndpoint(args, context, ports) {
6889
7004
  const gate = await humanGate(context, ports, {
6890
7005
  action: "create_endpoint",
6891
7006
  subject: JSON.stringify([signing, file]),
6892
- 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}.`,
6893
7008
  code: args.confirmation_code
6894
7009
  }, "Nothing was created.");
6895
7010
  if (gate !== null) return gate;
@@ -6917,21 +7032,31 @@ async function createEndpoint(args, context, ports) {
6917
7032
  }
6918
7033
  return inboundFailure(answer, action, CREATE_404);
6919
7034
  }
6920
- if (answer.status === 409) {
7035
+ const refusedCode = answer.status >= 400 ? bodyCode(answer.value) : null;
7036
+ if (refusedCode === "event_time_mapping_required") {
7037
+ return refusal(
7038
+ "CLAIMS_MAPPING_INVALID",
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.",
7040
+ { action, status: 409, code: "event_time_mapping_required", request_id: answer.requestId }
7041
+ );
7042
+ }
7043
+ if (refusedCode === "endpoint_exists") {
6921
7044
  return refusal(
6922
7045
  "CLAIMS_INBOUND_ENDPOINT_EXISTS",
6923
- `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.`,
6924
- { 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 }
6925
7048
  );
6926
7049
  }
6927
- if (answer.status === 422) {
6928
- 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.", {
6929
7052
  action,
6930
7053
  arguments: ["signing"],
7054
+ code: refusedCode,
6931
7055
  problems: bodyInvalidErrors(answer.value),
6932
7056
  request_id: answer.requestId
6933
7057
  });
6934
7058
  }
7059
+ if (answer.status === 409 || answer.status === 422) return unexpectedRefusal(answer, action, "Nothing was created.");
6935
7060
  const created = typeof answer.value === "object" && answer.value !== null ? answer.value : {};
6936
7061
  const token = doorTokenOf(created["url_path"]);
6937
7062
  const secret = typeof created["secret"] === "string" && SECRET_SHAPE.test(created["secret"]) ? created["secret"] : null;
@@ -6945,7 +7070,7 @@ async function createEndpoint(args, context, ports) {
6945
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`;
6946
7071
  return refusal(
6947
7072
  "CLAIMS_INBOUND_CREDENTIALS_NOT_WRITTEN",
6948
- `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.",
6949
7074
  { action, written_to: file, url_written: urlWritten, secret_written: secretWritten, ...failure === void 0 ? {} : { why: failure.why }, request_id: answer.requestId }
6950
7075
  );
6951
7076
  }
@@ -6966,7 +7091,7 @@ async function createEndpoint(args, context, ports) {
6966
7091
  steps: [
6967
7092
  ...signingSteps(finalSigning),
6968
7093
  `The inbound URL and secret were written to ${file}; set the same two in the claims system's config. Neither is shown again.`,
6969
- "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.`
6970
7095
  ],
6971
7096
  needs_event_time: needsEventTime(finalSigning),
6972
7097
  local: localState(context, file, scope),
@@ -6981,15 +7106,16 @@ async function createEndpoint(args, context, ports) {
6981
7106
  }
6982
7107
  async function claimsInboundSigningSetupTool(args, context, ports = {}) {
6983
7108
  if (isHosted(context)) return notHosted(SETUP3, "it reads the sandbox endpoint with the sandbox tenant's secret key from a local shell only.");
6984
- 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);
6985
7110
  if (actions.length > 1) {
6986
7111
  return refusal(
6987
7112
  "CLAIMS_ARGUMENTS_INVALID",
6988
- `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.`,
6989
7114
  { arguments: [...actions] }
6990
7115
  );
6991
7116
  }
6992
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);
6993
7119
  const scope = localScope(context.env, context.cwd);
6994
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;
6995
7121
  if (rotation !== null) {
@@ -7018,7 +7144,7 @@ async function claimsInboundSigningSetupTool(args, context, ports = {}) {
7018
7144
  steps: [
7019
7145
  ...signingSteps(signing),
7020
7146
  `${URL_SHOWN_ONCE} Keep it in the claims system's config too.`,
7021
- "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.`
7022
7148
  ],
7023
7149
  needs_event_time: needsEventTime(signing),
7024
7150
  local: localState(context, args.secret_env_file, scope)
@@ -7069,6 +7195,95 @@ async function claimsInboundSigningSetupTool(args, context, ports = {}) {
7069
7195
  }
7070
7196
  };
7071
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
+ }
7072
7287
  async function rotateToken(args, context, ports, sandbox, endpointId, document, scope) {
7073
7288
  const file = args.secret_env_file;
7074
7289
  const gate = await humanGate(context, ports, {
@@ -7834,7 +8049,7 @@ var SEND_CLAIMS_TEST_EVENTS_INPUT_SHAPE = {
7834
8049
  description: z.string().min(1).max(200).optional().describe("create_endpoint: a label for the endpoint."),
7835
8050
  enabled_events: z.array(ENABLED_EVENT).min(1).max(CLAIMS_EVENT_TYPES.length + 1).optional().describe('create_endpoint: the event types the endpoint receives, or ["*"] for all. Default ["*"].'),
7836
8051
  endpoint_id: z.string().min(1).max(128).optional().describe("delete_endpoint and send_test_event: the endpoint, as list_endpoints names it."),
7837
- event_type: z.enum(CLAIMS_EVENT_TYPES).optional().describe('send_test_event: the synthetic event to send. Its data carries "synthetic": true and a SYN-TEST- claim id.'),
8052
+ event_type: z.enum(CLAIMS_TESTABLE_EVENT_TYPES).optional().describe('send_test_event: the synthetic event to send. Its data carries "synthetic": true and a SYN-TEST- claim id.'),
7838
8053
  secret_env_file: z.string().min(1).max(1024).optional().describe("create_endpoint: absolute path of a local env file the endpoint's signing secret is appended to as EVERFUR_WEBHOOK_SECRET=..., created with mode 600 when missing. The API shows the secret once; this tool writes it there and never returns it. The file must not already set EVERFUR_WEBHOOK_SECRET. 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."),
7839
8054
  confirmation_code: z.string().min(1).max(32).optional().describe("create_endpoint: the one-time code the PERSON typed back, when the first call asked for one (the code is in a local file they open; never read it yourself). Not needed when this client asks the person directly.")
7840
8055
  };
@@ -7931,7 +8146,13 @@ function sandboxServerKey(context) {
7931
8146
  )
7932
8147
  };
7933
8148
  }
7934
- function sandboxFailure(failure, action) {
8149
+ var WEBHOOK_CAPABILITY = {
8150
+ list_endpoints: "partner_events.event.read",
8151
+ create_endpoint: "partner_events.endpoint.update",
8152
+ delete_endpoint: "partner_events.endpoint.update",
8153
+ send_test_event: "partner_events.endpoint.update"
8154
+ };
8155
+ function sandboxFailure(failure, action, capability) {
7935
8156
  if (failure.kind === "http") {
7936
8157
  const retryAfter = failure.retrySignals?.retryAfter ?? null;
7937
8158
  const details = {
@@ -7944,7 +8165,7 @@ function sandboxFailure(failure, action) {
7944
8165
  if (failure.status === 404 && (failure.code === null || failure.code === "ResourceNotFoundException")) {
7945
8166
  return refusal(
7946
8167
  "CLAIMS_SANDBOX_NOT_ENABLED",
7947
- "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.",
7948
8169
  details
7949
8170
  );
7950
8171
  }
@@ -7955,6 +8176,13 @@ function sandboxFailure(failure, action) {
7955
8176
  details
7956
8177
  );
7957
8178
  }
8179
+ if (failure.status === 403 && capability !== void 0) {
8180
+ return refusal(
8181
+ "CLAIMS_SANDBOX_CALL_FAILED",
8182
+ `The sandbox call answered 403 ${failure.code ?? "(no code)"}: a restricted key needs the ${capability} capability for this action. Use a key with it, or have it granted to this restricted key.`,
8183
+ { ...details, capability }
8184
+ );
8185
+ }
7958
8186
  return refusal(
7959
8187
  "CLAIMS_SANDBOX_CALL_FAILED",
7960
8188
  `The sandbox call answered ${failure.status} ${failure.code ?? "(no code)"}.` + (failure.code === null ? "" : " everfur_explain_claims_error explains the code."),
@@ -7983,7 +8211,7 @@ async function sendClaimsTestEventsTool(args, context, ports = {}) {
7983
8211
  return argumentsInvalid(action, ["endpoint_id"], `${action} needs endpoint_id, as list_endpoints names it.`);
7984
8212
  }
7985
8213
  if (action === "send_test_event" && args.event_type === void 0) {
7986
- return argumentsInvalid(action, ["event_type"], `send_test_event needs event_type, one of ${CLAIMS_EVENT_TYPES.join(", ")}.`);
8214
+ return argumentsInvalid(action, ["event_type"], `send_test_event needs event_type, one of ${CLAIMS_TESTABLE_EVENT_TYPES.join(", ")}.`);
7987
8215
  }
7988
8216
  const scope = localScope(context.env, context.cwd);
7989
8217
  if (action === "create_endpoint") {
@@ -8014,7 +8242,7 @@ async function sendClaimsTestEventsTool(args, context, ports = {}) {
8014
8242
  const credentials = { [CLAIMS_SECRET_KEY_HEADER]: key.credential };
8015
8243
  if (action === "list_endpoints") {
8016
8244
  const answer2 = await client.request({ method: "GET", path: SANDBOX_ROUTE, credentials });
8017
- if (!answer2.ok) return sandboxFailure(answer2, action);
8245
+ if (!answer2.ok) return sandboxFailure(answer2, action, WEBHOOK_CAPABILITY[action]);
8018
8246
  const parsed2 = z.object({ data: z.array(WEBHOOK_ENDPOINT) }).safeParse(answer2.value);
8019
8247
  if (!parsed2.success) return refusal("CLAIMS_SANDBOX_CALL_FAILED", "The endpoint list came back in an unexpected shape.", { action, request_id: answer2.requestId });
8020
8248
  return { isError: false, document: { ok: true, action, endpoints: parsed2.data.data.map(relayEndpoint) } };
@@ -8026,7 +8254,7 @@ async function sendClaimsTestEventsTool(args, context, ports = {}) {
8026
8254
  enabled_events: [...args.enabled_events ?? ["*"]]
8027
8255
  };
8028
8256
  const answer2 = await client.request({ method: "POST", path: SANDBOX_ROUTE, credentials, body });
8029
- if (!answer2.ok) return sandboxFailure(answer2, action);
8257
+ if (!answer2.ok) return sandboxFailure(answer2, action, WEBHOOK_CAPABILITY[action]);
8030
8258
  const parsed2 = WEBHOOK_ENDPOINT.extend({ signing_secret: z.string().startsWith("whsec_") }).safeParse(answer2.value);
8031
8259
  if (!parsed2.success) {
8032
8260
  return refusal("CLAIMS_SANDBOX_CALL_FAILED", "The created endpoint came back in an unexpected shape; its secret was not written.", { action, request_id: answer2.requestId });
@@ -8055,7 +8283,7 @@ async function sendClaimsTestEventsTool(args, context, ports = {}) {
8055
8283
  const endpointPath = `${SANDBOX_ROUTE}/${encodeURIComponent(args.endpoint_id)}`;
8056
8284
  if (action === "delete_endpoint") {
8057
8285
  const answer2 = await client.request({ method: "DELETE", path: endpointPath, credentials });
8058
- if (!answer2.ok) return sandboxFailure(answer2, action);
8286
+ if (!answer2.ok) return sandboxFailure(answer2, action, WEBHOOK_CAPABILITY[action]);
8059
8287
  return { isError: false, document: { ok: true, action, endpoint_id: args.endpoint_id, deleted: true } };
8060
8288
  }
8061
8289
  const answer = await client.request({
@@ -8064,7 +8292,7 @@ async function sendClaimsTestEventsTool(args, context, ports = {}) {
8064
8292
  credentials,
8065
8293
  body: { event_type: args.event_type }
8066
8294
  });
8067
- if (!answer.ok) return sandboxFailure(answer, action);
8295
+ if (!answer.ok) return sandboxFailure(answer, action, WEBHOOK_CAPABILITY[action]);
8068
8296
  const parsed = z.object({ event_id: z.string(), delivery_id: z.string() }).safeParse(answer.value);
8069
8297
  if (!parsed.success) return refusal("CLAIMS_SANDBOX_CALL_FAILED", "The test event answer came back in an unexpected shape.", { action, request_id: answer.requestId });
8070
8298
  return {
@@ -10039,14 +10267,15 @@ a field mapping turns them into claims, documents and pet profiles. everfur_prop
10039
10267
  mapping from sample native events, offline, with the gaps and the personal data paths to scrub;
10040
10268
  everfur_save_claims_mapping saves it as the sandbox draft, and activates the draft only with confirm: true and the
10041
10269
  confirmation phrase typed back by a person who has read it, never on the agent's own initiative. Activating, creating
10042
- 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
10043
10271
  answer: the client asks them when it can; otherwise the tool writes a one-time code to a local file and answers with
10044
10272
  its path, and the person types the code back as confirmation_code. Never open that file yourself.
10045
10273
  everfur_claims_inbound_signing_setup explains the endpoint's signing as steps for the claims system and can rotate the
10046
- 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:
10047
- 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
10048
10276
  a person asks for it; its URL and first secret are shown once and are written to that file as
10049
- 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
10050
10279
  Everfur, with their signing and the live mapping. everfur_send_claims_inbound_samples signs synthetic samples, posts them to the
10051
10280
  sandbox inbound URL and reports each event's status, reason code and fix; with read_event_log it sends nothing and
10052
10281
  reads the sandbox event log, for events the claims system itself sent. The tools that read the sandbox tenant's
@@ -10301,7 +10530,7 @@ function buildServer(context, ports = {}, options = {}) {
10301
10530
  "everfur_claims_inbound_signing_setup",
10302
10531
  {
10303
10532
  title: TOOL_ANNOTATIONS.everfur_claims_inbound_signing_setup.title,
10304
- 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.",
10305
10534
  inputSchema: CLAIMS_INBOUND_SIGNING_SETUP_INPUT_SHAPE,
10306
10535
  outputSchema: CLAIMS_INBOUND_SIGNING_SETUP_OUTPUT_SHAPE,
10307
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-J7SL4FA7.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,8 +5476,8 @@ function booleanAttribute(outcome, key) {
5476
5476
  }
5477
5477
 
5478
5478
  // src/version.ts
5479
- var CLI_VERSION = "0.9.0";
5480
- var CLI_PUBLISHED_VERSION = "0.8.0";
5479
+ var CLI_VERSION = "0.9.2";
5480
+ var CLI_PUBLISHED_VERSION = "0.9.0";
5481
5481
 
5482
5482
  // src/commands/diagnose/reasons.ts
5483
5483
  var REASON_CODES = Object.freeze([
@@ -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: {
@@ -17267,8 +17267,8 @@ var MEANINGS = Object.freeze({
17267
17267
  nextAction: "Tell the developer to run the tool from the local MCP server or the CLI."
17268
17268
  },
17269
17269
  CLAIMS_MAPPING_INVALID: {
17270
- tools: [CLAIMS_SAVE],
17271
- meaning: "The mapping does not pass the mapping checks (error.details.problems: a path, a transform, a limit, or pii_paths hiding a field the mapping reads), or the API refused to save or activate it. Nothing was saved or activated.",
17270
+ tools: [CLAIMS_SAVE, CLAIMS_SETUP],
17271
+ meaning: "The mapping does not pass the mapping checks (error.details.problems: a path, a transform, a limit, or pii_paths hiding a field the mapping reads), or the API refused to save or activate it, or refused a signing config that signs no time while the mapping names no event_time (error.details.code event_time_mapping_required). Nothing was saved, activated or created.",
17272
17272
  nextAction: "Fix each problem in the mapping (everfur_propose_claims_mapping can propose one again), then save again."
17273
17273
  },
17274
17274
  CLAIMS_MAPPING_CONFIRMATION_REQUIRED: {
@@ -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-OHA3JVME.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-UZZJUV5A.js';
4
- import './chunk-JI6USLIZ.js';
5
- import './chunk-J7SL4FA7.js';
6
- import { CLI_VERSION } from './chunk-OHA3JVME.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-JI6USLIZ.js';
4
- import './chunk-J7SL4FA7.js';
5
- import { CLI_VERSION } from './chunk-OHA3JVME.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-J7SL4FA7.js';
4
- import { CLI_VERSION } from './chunk-OHA3JVME.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-UROEKBHB.js';
4
- import { ExitCode, systemClock, fetchTransport, CLI_VERSION, nodeFileSystem, nodeContractCache } from './chunk-OHA3JVME.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.0";
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-UROEKBHB.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-OHA3JVME.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.0",
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",