@everfur/cli 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -99,7 +99,7 @@ the SDK's default opens both in the system browser until you pass your own. Lab
99
99
  edits and the signature gallery need the platform flag `partner.records_full_depth_enabled`; while it is off the
100
100
  SDK hides them.
101
101
 
102
- **The vet visit runs inside your app.** A plan that mounts `televet` installs `@everfur/sdk@^0.9.0`, a release
102
+ **The vet visit runs inside your app.** A plan that mounts `televet` installs `@everfur/sdk@^0.11.0`, a release
103
103
  whose `VetVisitButton`, `useVetVisit().open()` and `openVisit()`, and every vet entry inside chat open the visit in
104
104
  the app by default, and writes the two things that default needs: `registerEverfurDaily(...)` once at load, from
105
105
  `@everfur/sdk/televet/call` over `@daily-co/react-native-daily-js` (React Native) or from
@@ -112,7 +112,7 @@ manifest and Info.plist edits), and the notifications file opens a tapped visit
112
112
  The booking lists vets only for the member's US state and the SDK never reads a device location, so the file's
113
113
  `YOUR_USER_US_STATE` reaches the button, the chat and the notifications bridge, and `everfur verify --project-root`
114
114
  fails while it is still `null` as shipped. The hosted visit in the system browser or a new tab is the SDK's explicit
115
- `prefer="redirect"`, which no generated file passes. A plan without `televet` installs the same `@everfur/sdk@^0.9.0`
115
+ `prefer="redirect"`, which no generated file passes. A plan without `televet` installs the same `@everfur/sdk@^0.11.0`
116
116
  and none of the call.
117
117
 
118
118
  <!-- Owner-approved 2026-10-01 (production sandbox plan, PC-1/PC-2): what `test` and the key prefixes mean. -->
@@ -206,7 +206,7 @@ The Everfur MCP server ships with this package (and standalone as `@everfur/mcp`
206
206
  your agent's MCP configuration. It is the same block for Claude Code, Cursor and VS Code; only the file it
207
207
  goes in differs:
208
208
 
209
- - **Claude Code:** `.mcp.json` at the project root (or `claude mcp add-json everfur '<the everfur entry>'`
209
+ - **Claude Code:** `.mcp.json` at the project root (or `claude mcp add-json --scope user everfur '<the everfur entry>'`
210
210
  for your user scope).
211
211
  - **Cursor:** `.cursor/mcp.json` in the project (or `~/.cursor/mcp.json` for every project).
212
212
  - **VS Code:** `.vscode/mcp.json` in the workspace, which wraps the same `everfur` entry under a `servers`
@@ -219,8 +219,8 @@ goes in differs:
219
219
  "command": "npx",
220
220
  "args": ["-y", "-p", "@everfur/mcp", "everfur-mcp"],
221
221
  "env": {
222
- "EVERFUR_API_BASE_URL": "https://api-staging.everfur.com/api/v1",
223
- "EVERFUR_PARTNER_KEY": "pk_live_your_sandbox_tenant_key",
222
+ "EVERFUR_API_BASE_URL": "https://api.everfur.com/api/v1",
223
+ "EVERFUR_PARTNER_KEY": "pk_test_your_sandbox_tenant_key",
224
224
  "EVERFUR_DOCS_KEY": "dk_partner_your_docs_key",
225
225
  "EVERFUR_SESSION_TOKEN": "a_short_lived_session_your_backend_minted"
226
226
  }
@@ -271,7 +271,7 @@ answer, naming each one:
271
271
  `everfur verify` is the fail-closed check of what your tenant actually has.
272
272
  2. **How your users sign in**: `partner-user-ref` (your backend mints a session for your own user id),
273
273
  `shopify-app-proxy` (a Shopify storefront vouches for the signed-in customer) or `anonymous`.
274
- 3. **Which environment** the generated configuration targets (`staging` or `production`).
274
+ 3. **Which environment** the generated configuration targets (`test`, `staging` or `production`).
275
275
  4. **The language of the backend that mints sessions**, asked for `partner-user-ref`, because that is
276
276
  the one mode where the plan generates a session route for you, and for `events`, because the webhook
277
277
  receiver it generates (the server-side copy of every event about your members, for your own handling;
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { hostnameOf, listen, close, writeJson, serveStatelessMcp } from './chunk-SD2FC3O6.js';
3
- import { createHostedTokenVerifier, tokenBucketOf, isAccessTokenShaped, buildServer, MCP_SCOPE, tenantContextOf, sendTestUserRef, hostedVerifyUserRef, REVOKED_AUTHORIZATION_REMEDY, SYNTHETIC_USER_REF_PREFIX } from './chunk-YTDADMVX.js';
4
- import { BASE_URL_ENV_VAR, resolveEndpoint, fetchTransport, systemClock, createApiClient, withPrefix, ephemeralCredential, validateContractText, isJsonObject, describeFailure } from './chunk-DE7AGMJD.js';
2
+ import { hostnameOf, listen, close, writeJson, serveStatelessMcp } from './chunk-AEY522A6.js';
3
+ import { createHostedTokenVerifier, tokenBucketOf, isAccessTokenShaped, buildServer, MCP_SCOPE, tenantContextOf, sendTestUserRef, hostedVerifyUserRef, REVOKED_AUTHORIZATION_REMEDY, SYNTHETIC_USER_REF_PREFIX } from './chunk-EDURPYNG.js';
4
+ import { BASE_URL_ENV_VAR, resolveEndpoint, fetchTransport, systemClock, createApiClient, withPrefix, ephemeralCredential, validateContractText, isJsonObject, describeFailure } from './chunk-WPEB2AVZ.js';
5
5
  import { createServer } from 'http';
6
6
  import { InvalidTokenError, TooManyRequestsError, TemporarilyUnavailableError } from '@modelcontextprotocol/sdk/server/auth/errors.js';
7
7
  import { isIP } from 'net';
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { buildServer } from './chunk-YTDADMVX.js';
2
+ import { buildServer } from './chunk-EDURPYNG.js';
3
3
  import { createServer } from 'http';
4
4
  import { timingSafeEqual } from 'crypto';
5
5
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { ENVIRONMENTS, ENVELOPE_SHAPE, SURFACES, VERIFY_IDENTITY_MODES, refusal, API_BASE_URL_BY_ENVIRONMENT, fetchContract, NO_CONTRACT_CACHE, systemClock, fetchTransport, describeFailure, loadDecisionSpaceFromContract, uuidFromKey, resolveEndpoint, createApiClient, createContractProvider, nodeContractCache, CLI_VERSION, withPrefix, ephemeralCredential, 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, digestOfProjection, detectProject, BASE_URL_ENV_VAR, checkTenantMode, isWorkspaceRootEvidence, plannableCapabilities, blockedCapabilities, offlineDocument, toolCodeMeaning, SESSION_TOKEN, SESSION_MINT_TREE, BACKEND_LANGUAGE_QUESTION, ALL_CAPABILITIES } from './chunk-DE7AGMJD.js';
2
+ import { ENVIRONMENTS, ENVELOPE_SHAPE, SURFACES, VERIFY_IDENTITY_MODES, refusal, API_BASE_URL_BY_ENVIRONMENT, fetchContract, NO_CONTRACT_CACHE, systemClock, fetchTransport, describeFailure, loadDecisionSpaceFromContract, uuidFromKey, resolveEndpoint, createApiClient, createContractProvider, nodeContractCache, CLI_VERSION, withPrefix, ephemeralCredential, 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, digestOfProjection, detectProject, BASE_URL_ENV_VAR, checkTenantMode, isWorkspaceRootEvidence, plannableCapabilities, blockedCapabilities, offlineDocument, toolCodeMeaning, SESSION_TOKEN, SESSION_MINT_TREE, BACKEND_LANGUAGE_QUESTION, ALL_CAPABILITIES } from './chunk-WPEB2AVZ.js';
3
3
  import { z } from 'zod';
4
4
  import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
5
5
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
@@ -2336,7 +2336,13 @@ function frameOf(block) {
2336
2336
  const obj = parsed;
2337
2337
  if (typeof obj["token"] === "string") return { kind: "delta", text: obj["token"] };
2338
2338
  if (typeof obj["status"] === "string") return { kind: `status:${obj["status"]}` };
2339
- if (obj["error"] !== void 0 || typeof obj["code"] === "string") return { kind: "error" };
2339
+ if (obj["error"] !== void 0 || typeof obj["code"] === "string") {
2340
+ return {
2341
+ kind: "error",
2342
+ ...typeof obj["code"] === "string" ? { code: obj["code"] } : {},
2343
+ ...typeof obj["retryable"] === "boolean" ? { retryable: obj["retryable"] } : {}
2344
+ };
2345
+ }
2340
2346
  if (obj["done"] === true) return { kind: "done" };
2341
2347
  if (obj["metadata"] === true) return { kind: "metadata" };
2342
2348
  return { kind: "unknown" };
@@ -2365,7 +2371,7 @@ function petProfileBody(profile) {
2365
2371
  return body;
2366
2372
  }
2367
2373
  function failureFacts(failure) {
2368
- return failure.kind === "http" ? { status: failure.status, request_id: failure.requestId } : { kind: failure.kind };
2374
+ return failure.kind === "http" ? { status: failure.status, ...failure.code === null ? {} : { code: failure.code }, request_id: failure.requestId } : { kind: failure.kind };
2369
2375
  }
2370
2376
  function isObject(value) {
2371
2377
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -2456,9 +2462,14 @@ async function findPriorTurn(client, auth, message, petRef, conversationTitle) {
2456
2462
  const asked = messages[question]?.["content"];
2457
2463
  if (typeof asked !== "string" || asked.trim() !== message.trim()) continue;
2458
2464
  const reply = messages.slice(question + 1).find((m) => m["role"] === "assistant");
2465
+ const answer = storedAnswer(reply?.["content"]);
2459
2466
  return {
2460
2467
  ok: true,
2461
- prior: { conversationId, answer: storedAnswer(reply?.["content"]) },
2468
+ prior: {
2469
+ conversationId,
2470
+ answer,
2471
+ unanswered: answer !== null ? null : typeof reply?.["content"] === "string" ? "interrupted" : "pending"
2472
+ },
2462
2473
  emptyConversationId
2463
2474
  };
2464
2475
  }
@@ -2606,6 +2617,12 @@ async function sendTestMessage(args, env, ports = {}, identitySources = {}) {
2606
2617
  if (lookup.ok === false) return lookup.result;
2607
2618
  const scope = { identity: identity.kind, ...petRef === null ? {} : { pet_ref: petRef } };
2608
2619
  if (lookup.prior !== null) {
2620
+ if (lookup.prior.answer === null && lookup.prior.unanswered === "interrupted") {
2621
+ return refusal("PRIOR_TURN_INTERRUPTED", "An earlier call with this idempotency_key already sent this message and no answer was stored for it. Sending again would put the question in twice, so nothing was sent.", {
2622
+ conversation_id: lookup.prior.conversationId,
2623
+ how_to_fix: "To ask again, call with a new idempotency_key: the same key returns this turn instead of sending the message a second time."
2624
+ });
2625
+ }
2609
2626
  if (lookup.prior.answer === null) {
2610
2627
  return refusal("PRIOR_TURN_UNANSWERED", "An earlier call with this idempotency_key already sent this message and no answer was stored for it. Sending again would put the question in twice, so nothing was sent.", {
2611
2628
  conversation_id: lookup.prior.conversationId,
@@ -2677,6 +2694,7 @@ async function sendTestMessage(args, env, ports = {}, identitySources = {}) {
2677
2694
  }
2678
2695
  const histogram = {};
2679
2696
  let answer = "";
2697
+ let streamError = null;
2680
2698
  const blocks = (typeof streamed.value === "string" ? streamed.value : "").split("\n\n");
2681
2699
  blocks.pop();
2682
2700
  for (const block of blocks) {
@@ -2684,10 +2702,12 @@ async function sendTestMessage(args, env, ports = {}, identitySources = {}) {
2684
2702
  if (frame === null) continue;
2685
2703
  histogram[frame.kind] = (histogram[frame.kind] ?? 0) + 1;
2686
2704
  if (frame.text !== void 0) answer += frame.text;
2705
+ if (frame.kind === "error") streamError ??= frame;
2687
2706
  }
2688
2707
  const deltas = histogram["delta"] ?? 0;
2708
+ const completed = (histogram["done"] ?? 0) > 0 && streamError === null;
2689
2709
  const result = {
2690
- ok: deltas > 0,
2710
+ ok: deltas > 0 && completed,
2691
2711
  livemode: false,
2692
2712
  replayed: false,
2693
2713
  conversation_id: conversationId,
@@ -2697,7 +2717,15 @@ async function sendTestMessage(args, env, ports = {}, identitySources = {}) {
2697
2717
  ...scope,
2698
2718
  ...args.pet_profile === void 0 ? {} : { pet_registered: true }
2699
2719
  };
2700
- if (deltas > 0) return { isError: false, document: result };
2720
+ if (deltas > 0 && completed) return { isError: false, document: result };
2721
+ if (deltas > 0) {
2722
+ const failed = streamError;
2723
+ return failedResult(result, "STREAM_FAILED", "The stream failed before it completed.", {
2724
+ conversation_id: conversationId,
2725
+ ...failed?.code === void 0 ? {} : { stream_error_code: failed.code },
2726
+ ...failed?.retryable === void 0 ? {} : { stream_error_retryable: failed.retryable }
2727
+ });
2728
+ }
2701
2729
  return failedResult(
2702
2730
  result,
2703
2731
  "EMPTY_STREAM",
@@ -2914,7 +2942,7 @@ function buildServer(context, ports = {}, options = {}) {
2914
2942
  description: hosted ? HOSTED_TOOL_DESCRIPTIONS.sendTestMessage : "Send a REAL message and stream a real veterinary answer, against a SANDBOX tenant only. Refuses unless the entitlement verdict reports livemode false. Returns the answer plus a frame histogram, so a stream that died mid-answer is distinguishable from a short one. Asks with a signed session when one is available, and with pet_profile registers a sandbox pet first so the answer is pet-aware. Calling again with the same idempotency_key reuses that conversation and returns the existing answer instead of sending a second message.",
2915
2943
  inputSchema: {
2916
2944
  message: z.string().min(1).max(4e3).describe("What to ask. A real pet-health question gets a real answer."),
2917
- idempotency_key: z.string().min(8).describe("Required and explicit. A call with a key and message already sent reuses that conversation and returns its stored answer instead of sending again. This is done by the tool reading the conversation first; the server does not deduplicate sends."),
2945
+ idempotency_key: z.string().min(8).max(128).describe("Required and explicit. A call with a key and message already sent reuses that conversation and returns its stored answer instead of sending again. This is done by the tool reading the conversation first; the server does not deduplicate sends."),
2918
2946
  pet_ref: z.string().min(1).max(128).optional().describe("Optional pet to scope the conversation to. Must already be registered for this identity, unless pet_profile is passed, which registers it."),
2919
2947
  pet_profile: PET_PROFILE_SHAPE.optional().describe("Optional sandbox pet to register for this call's identity before the send (under pet_ref, else a fixed test ref), so the answer is scoped to it. Registered only once the sandbox fence has passed.")
2920
2948
  },
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- 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-DE7AGMJD.js';
2
+ 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-WPEB2AVZ.js';
3
3
  import { isAbsolute, resolve } from 'path';
4
4
 
5
5
  // src/cli/format.ts
@@ -113,13 +113,13 @@ var fetchTransport = Object.freeze({
113
113
  if (name === "TimeoutError" || name === "AbortError") {
114
114
  throw new TransportError("timeout", `no response within ${request.timeoutMs}ms`);
115
115
  }
116
- throw new TransportError("network", cause instanceof Error ? cause.message : String(cause));
116
+ throw new TransportError("network", describeNetworkFailure(cause));
117
117
  }
118
118
  let body;
119
119
  try {
120
120
  body = await response.text();
121
121
  } catch (cause) {
122
- throw new TransportError("network", cause instanceof Error ? cause.message : String(cause));
122
+ throw new TransportError("network", describeNetworkFailure(cause));
123
123
  }
124
124
  const headers = {};
125
125
  response.headers.forEach((value, key) => {
@@ -128,6 +128,15 @@ var fetchTransport = Object.freeze({
128
128
  return Object.freeze({ status: response.status, headers: Object.freeze(headers), body });
129
129
  }
130
130
  });
131
+ function describeNetworkFailure(cause) {
132
+ if (!(cause instanceof Error)) return String(cause);
133
+ const inner = cause.cause;
134
+ if (inner instanceof Error && inner.message.length > 0 && inner.message !== cause.message) {
135
+ return `${cause.message} (${inner.message})`;
136
+ }
137
+ const code = typeof inner === "object" && inner !== null ? inner.code : void 0;
138
+ return typeof code === "string" && code.length > 0 ? `${cause.message} (${code})` : cause.message;
139
+ }
131
140
 
132
141
  // src/time/clock.ts
133
142
  var systemClock = Object.freeze({
@@ -231,19 +240,20 @@ function resolveEndpoint(flagValue, env) {
231
240
  ]
232
241
  };
233
242
  }
243
+ const named = source === "flag" ? "--base-url" : BASE_URL_ENV_VAR;
234
244
  let parsed;
235
245
  try {
236
246
  parsed = new URL(raw);
237
247
  } catch {
238
- return { ok: false, errors: [`--base-url is not a URL: ${raw}`] };
248
+ return { ok: false, errors: [`${named} is not a URL: ${raw}`] };
239
249
  }
240
250
  if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
241
- return { ok: false, errors: [`--base-url must be http or https, not ${parsed.protocol}`] };
251
+ return { ok: false, errors: [`${named} must be http or https, not ${parsed.protocol}`] };
242
252
  }
243
253
  if (parsed.protocol === "http:" && !LOCAL_HTTP_HOSTS.has(parsed.hostname)) {
244
254
  return {
245
255
  ok: false,
246
- errors: [`--base-url must be https (http only on localhost, 127.0.0.1 or [::1]), not http://${parsed.host}`]
256
+ errors: [`${named} must be https (http only on localhost, 127.0.0.1 or [::1]), not http://${parsed.host}`]
247
257
  };
248
258
  }
249
259
  const normalised = stripTrailingSlashes(`${parsed.origin}${parsed.pathname}`);
@@ -275,8 +285,12 @@ var PARTNER_KEY = Object.freeze({
275
285
  var PARTNER_SECRET_KEY = Object.freeze({
276
286
  envVar: "EVERFUR_PARTNER_SECRET_KEY",
277
287
  prefix: "sk_partner_",
288
+ // The session mint accepts both secret families on this one header (EFBackend sessions_router
289
+ // `_SECRET_KEY_FAMILIES`): the unrestricted sk_partner_ key and the rk_partner_ restricted key the plan
290
+ // already names. Both prefixes are 11 characters, so one expected length still covers either.
291
+ alsoAccepts: Object.freeze(["rk_partner_"]),
278
292
  length: "sk_partner_".length + 64,
279
- summary: "Partner secret key (sk_partner_...). Presented only to the session mint route."
293
+ summary: "Partner secret key (sk_partner_..., or an rk_partner_... restricted key). Presented only to the session mint route."
280
294
  });
281
295
  var DOCS_KEY = Object.freeze({
282
296
  envVar: "EVERFUR_DOCS_KEY",
@@ -296,6 +310,9 @@ var ADMIN_TOKEN = Object.freeze({
296
310
  length: null,
297
311
  summary: "Admin bearer token for the /admin routes. Required by `sandbox create`."
298
312
  });
313
+ function publishableKeyShapes() {
314
+ return [...PARTNER_KEY.alsoAccepts ?? [], PARTNER_KEY.prefix].map((prefix) => `${prefix}...`).join(" or ");
315
+ }
299
316
  var CREDENTIAL_SPECS = Object.freeze([
300
317
  PARTNER_KEY,
301
318
  PARTNER_SECRET_KEY,
@@ -4914,7 +4931,7 @@ function televetCallInstallSpecs(options) {
4914
4931
  );
4915
4932
  }
4916
4933
  var TELEVET_WEB_CALL_MODULE = Object.freeze({ name: "@daily-co/daily-js", spec: "^0.91.0" });
4917
- var SDK_CONTRACT_VERSION = "2026-08-01";
4934
+ var SDK_CONTRACT_VERSION = "2026-09-19";
4918
4935
  function platformUnsupportedReason(projectType) {
4919
4936
  return `${SDK_PACKAGE} publishes no entry point for a "${projectType}" project: its device entry points import react-native, its web entry point renders with react-dom, and neither resolves inside this project shape. Until the contract names a package or install commands for the shape no plan can be produced for it, and substituting another entry point would produce a bundle that does not build.`;
4920
4937
  }
@@ -5433,8 +5450,8 @@ function booleanAttribute(outcome, key) {
5433
5450
  }
5434
5451
 
5435
5452
  // src/version.ts
5436
- var CLI_VERSION = "0.7.0";
5437
- var CLI_PUBLISHED_VERSION = "0.5.0";
5453
+ var CLI_VERSION = "0.8.0";
5454
+ var CLI_PUBLISHED_VERSION = "0.7.0";
5438
5455
 
5439
5456
  // src/commands/diagnose/reasons.ts
5440
5457
  var REASON_CODES = Object.freeze([
@@ -14779,7 +14796,7 @@ function suggestCodes(query, codes) {
14779
14796
  near.sort((left, right) => left.distance - right.distance || (left.code < right.code ? -1 : 1));
14780
14797
  return Object.freeze([...exact, ...contains.sort(), ...near.map((entry) => entry.code)].slice(0, MAX_SUGGESTIONS));
14781
14798
  }
14782
- var SECRET_LITERAL = /\b(sk_partner_|sk_egress_)[A-Za-z0-9]{16,}/;
14799
+ var SECRET_LITERAL = /\b(sk_partner_|rk_partner_|sk_egress_)[A-Za-z0-9]{16,}/;
14783
14800
  var SECRET_ENV_NAME = "EVERFUR_PARTNER_SECRET_KEY";
14784
14801
  var PUBLIC_SECRET_NAME = /\b(NEXT_PUBLIC_|VITE_|EXPO_PUBLIC_)[A-Z0-9_]*SECRET[A-Z0-9_]*/;
14785
14802
  var API_BASE_URL_LINE = /^\s*(?:export\s+)?([A-Z0-9_]*EVERFUR_API_BASE_URL)\s*=\s*["']?([^"'\s#]+)/gm;
@@ -15656,7 +15673,7 @@ function anonymousIdentity(options) {
15656
15673
  return {
15657
15674
  auth: null,
15658
15675
  step: step5("anonymous-identity", title, "SKIP", `no anonymous identity to verify with: ${PARTNER_KEY.envVar} is not set`, null, [
15659
- `export ${PARTNER_KEY.envVar} with your publishable key (${PARTNER_KEY.prefix}...)`
15676
+ `export ${PARTNER_KEY.envVar} with your publishable key (${publishableKeyShapes()})`
15660
15677
  ])
15661
15678
  };
15662
15679
  }
@@ -16483,6 +16500,8 @@ var REFUSAL_POLICY = Object.freeze({
16483
16500
  CHAT_NOT_GRANTED: { retryable: false, nextAction: "call_diagnose", docsPath: null },
16484
16501
  CONVERSATIONS_UNREADABLE: { retryable: "from_failure", nextAction: "from_failure", docsPath: "everfur://contract/errors" },
16485
16502
  PRIOR_TURN_UNANSWERED: { retryable: true, nextAction: "wait_then_retry", docsPath: null },
16503
+ // the earlier turn's stored reply is the interrupted-stream sentinel: final, so the same key can never succeed
16504
+ PRIOR_TURN_INTERRUPTED: { retryable: false, nextAction: "fix_arguments", docsPath: null },
16486
16505
  CONVERSATION_NOT_CREATED: { retryable: "from_failure", nextAction: "from_failure", docsPath: "everfur://contract/errors" },
16487
16506
  SEND_FAILED: { retryable: "from_failure", nextAction: "from_failure", docsPath: "everfur://contract/errors" },
16488
16507
  DEADLINE_EXCEEDED: { retryable: true, nextAction: "retry", docsPath: null },
@@ -16634,7 +16653,7 @@ function chooseWidgetAuth(env) {
16634
16653
  return {
16635
16654
  ok: false,
16636
16655
  outcome: errorOutcome("credential_missing", "no widget credential is configured", [
16637
- `export ${PARTNER_KEY.envVar} with your publishable key (${PARTNER_KEY.prefix}...)`,
16656
+ `export ${PARTNER_KEY.envVar} with your publishable key (${publishableKeyShapes()})`,
16638
16657
  `or export ${SESSION_TOKEN.envVar} with an existing session bearer to diagnose the signed path`
16639
16658
  ])
16640
16659
  };
@@ -16939,6 +16958,12 @@ var MEANINGS = Object.freeze({
16939
16958
  meaning: "An earlier call with this idempotency_key already sent the message and no answer was stored for it; sending again would ask the question twice, so nothing was sent.",
16940
16959
  nextAction: "Wait for the earlier answer and call again with the same idempotency_key, or use a new idempotency_key to ask again."
16941
16960
  },
16961
+ PRIOR_TURN_INTERRUPTED: {
16962
+ tools: [SEND],
16963
+ // Copy reused verbatim: PRIOR_TURN_UNANSWERED's meaning and EMPTY_STREAM's remedy sentence.
16964
+ meaning: "An earlier call with this idempotency_key already sent the message and no answer was stored for it; sending again would ask the question twice, so nothing was sent.",
16965
+ nextAction: "To ask again, call with a new idempotency_key: the same key returns this turn instead of sending the message a second time."
16966
+ },
16942
16967
  CONVERSATION_NOT_CREATED: {
16943
16968
  tools: [SEND],
16944
16969
  meaning: "A conversation could not be opened: the create call failed, or returned no conversation_id.",
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { loadHostedMcpConfig, startHostedMcpServer } from './chunk-VNPBR7JA.js';
3
- import './chunk-SD2FC3O6.js';
4
- import './chunk-YTDADMVX.js';
5
- import { CLI_VERSION } from './chunk-DE7AGMJD.js';
2
+ import { loadHostedMcpConfig, startHostedMcpServer } from './chunk-4Q2SPVPA.js';
3
+ import './chunk-AEY522A6.js';
4
+ import './chunk-EDURPYNG.js';
5
+ import { CLI_VERSION } from './chunk-WPEB2AVZ.js';
6
6
 
7
7
  // src/bin/everfur-mcp-hosted.ts
8
8
  async function main() {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { startRemoteMcpServer, loadRemoteMcpConfig } from './chunk-SD2FC3O6.js';
3
- import './chunk-YTDADMVX.js';
4
- import { CLI_VERSION } from './chunk-DE7AGMJD.js';
2
+ import { startRemoteMcpServer, loadRemoteMcpConfig } from './chunk-AEY522A6.js';
3
+ import './chunk-EDURPYNG.js';
4
+ import { CLI_VERSION } from './chunk-WPEB2AVZ.js';
5
5
 
6
6
  // src/bin/everfur-mcp-http.ts
7
7
  async function main() {
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { runStdioServer } from './chunk-YTDADMVX.js';
3
- import { CLI_VERSION } from './chunk-DE7AGMJD.js';
2
+ import { runStdioServer } from './chunk-EDURPYNG.js';
3
+ import { CLI_VERSION } from './chunk-WPEB2AVZ.js';
4
4
 
5
5
  // src/bin/everfur-mcp.ts
6
6
  if (process.argv.slice(2).includes("--version")) {
package/dist/everfur.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { runCli } from './chunk-XGOPVELV.js';
3
- import { ExitCode, systemClock, fetchTransport, CLI_VERSION, nodeFileSystem, nodeContractCache } from './chunk-DE7AGMJD.js';
2
+ import { runCli } from './chunk-U4Q4OAVK.js';
3
+ import { ExitCode, systemClock, fetchTransport, CLI_VERSION, nodeFileSystem, nodeContractCache } from './chunk-WPEB2AVZ.js';
4
4
 
5
5
  // src/bin/everfur.ts
6
6
  async function main() {
package/dist/index.d.ts CHANGED
@@ -3647,6 +3647,6 @@ declare function parseSuppliedFacts(capabilitiesRaw: string | null, identityRaw:
3647
3647
  * install, and a bundled artifact. `tests/unit/version.test.ts` asserts this constant equals
3648
3648
  * the package.json version, so the two cannot drift.
3649
3649
  */
3650
- declare const CLI_VERSION = "0.7.0";
3650
+ declare const CLI_VERSION = "0.8.0";
3651
3651
 
3652
3652
  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,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- export { COMMANDS, buildSandboxDocument, buildVerificationDocument, failureOutcome, formatOutcome, matchCommand, nextActionsFor, parseCapabilities, parseIdentityMode, parseSessionMintLanguage, parseSuppliedFacts, projectSandboxCreate, renderDiagnosis, renderPlan, renderSandboxCreate, renderVerification, runCli } from './chunk-XGOPVELV.js';
3
- 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-DE7AGMJD.js';
2
+ export { COMMANDS, buildSandboxDocument, buildVerificationDocument, failureOutcome, formatOutcome, matchCommand, nextActionsFor, parseCapabilities, parseIdentityMode, parseSessionMintLanguage, parseSuppliedFacts, projectSandboxCreate, renderDiagnosis, renderPlan, renderSandboxCreate, renderVerification, runCli } from './chunk-U4Q4OAVK.js';
3
+ 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-WPEB2AVZ.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@everfur/cli",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Everfur CLI: plan, verify, and diagnose an Everfur pet-health integration from the terminal.",
5
5
  "license": "MIT",
6
6
  "type": "module",