@everfur/cli 0.2.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -32,12 +32,11 @@ interface CredentialSpec {
32
32
  /**
33
33
  * Additional accepted prefixes, beyond `prefix`.
34
34
  *
35
- * The prefix a publishable key must carry is a property of the DEPLOYMENT, not of the tenant: production and
36
- * staging both take `pk_live_` (a staging sandbox tenant is issued a `pk_live_` key and refuses `pk_test_`), and
37
- * `pk_test_` is the prefix a deployment configured as a sandbox deployment would take instead; no deployed
38
- * environment is configured that way today, so no deployed environment accepts it. The CLI cannot tell which
39
- * deployment it is pointed at before it makes a call, so it accepts both shapes. The SERVER is the authority: each
40
- * deployment refuses the prefix it does not take on the fast-fail path, so accepting both here narrows nothing.
35
+ * The prefix a publishable key carries names the TENANT MODE (EFBackend #1630): a sandbox tenant is issued `pk_test_`
36
+ * and a live tenant `pk_live_`, on production and staging alike, and a sandbox created before `pk_test_` keys were
37
+ * issued may still carry `pk_live_` (commands/plan/environment.ts). Each deployment accepts `pk_test_` only for a
38
+ * sandbox tenant's row, so a test key never resolves a live tenant. The CLI cannot tell a tenant's mode from here, so
39
+ * it accepts both shapes; the SERVER is the authority, and accepting both here narrows nothing.
41
40
  */
42
41
  readonly alsoAccepts?: readonly string[];
43
42
  /** Exact expected length when the prefix is known, or null. */
@@ -282,6 +281,13 @@ declare const ExitCode: Readonly<{
282
281
  * and escalates to a human, which is the only thing that resolves it.
283
282
  */
284
283
  readonly BLOCKED: 9;
284
+ /**
285
+ * The command needs the Everfur contract and none could be had: no `--contract` file, no `EVERFUR_CONTRACT_PUBLIC`,
286
+ * and no `EVERFUR_DOCS_KEY` to fetch it with. Distinct from 2 (tester run, 2026-10-01): the invocation is fine and
287
+ * a wrapper that prompts for a corrected command line would loop; the missing piece is a credential a partner has
288
+ * to obtain, and the error document says where.
289
+ */
290
+ readonly CONTRACT_CREDENTIAL_MISSING: 10;
285
291
  }>;
286
292
  type ExitCode = (typeof ExitCode)[keyof typeof ExitCode];
287
293
 
@@ -663,6 +669,13 @@ declare const SCHEMAS: Readonly<{
663
669
  $ref: string;
664
670
  };
665
671
  };
672
+ checklist: {
673
+ description: string;
674
+ type: string;
675
+ items: {
676
+ $ref: string;
677
+ };
678
+ };
666
679
  warnings: {
667
680
  type: string;
668
681
  items: {
@@ -885,19 +898,86 @@ declare const SCHEMAS: Readonly<{
885
898
  type: string;
886
899
  pattern: string;
887
900
  };
901
+ successColor: {
902
+ type: string;
903
+ pattern: string;
904
+ };
905
+ warningColor: {
906
+ type: string;
907
+ pattern: string;
908
+ };
909
+ infoColor: {
910
+ type: string;
911
+ pattern: string;
912
+ };
913
+ successColorDark: {
914
+ type: string;
915
+ pattern: string;
916
+ };
917
+ warningColorDark: {
918
+ type: string;
919
+ pattern: string;
920
+ };
921
+ infoColorDark: {
922
+ type: string;
923
+ pattern: string;
924
+ };
925
+ dangerColor: {
926
+ type: string;
927
+ pattern: string;
928
+ };
929
+ dangerColorDark: {
930
+ type: string;
931
+ pattern: string;
932
+ };
888
933
  brightness: {
889
934
  enum: string[];
890
935
  };
936
+ backgroundColor: {
937
+ type: string;
938
+ pattern: string;
939
+ description: string;
940
+ };
941
+ backgroundColorDark: {
942
+ type: string;
943
+ pattern: string;
944
+ description: string;
945
+ };
946
+ textColor: {
947
+ type: string;
948
+ pattern: string;
949
+ description: string;
950
+ };
951
+ textColorDark: {
952
+ type: string;
953
+ pattern: string;
954
+ description: string;
955
+ };
891
956
  surfaceStyle: {
892
957
  enum: string[];
893
958
  };
894
959
  radiusScale: {
895
960
  enum: string[];
896
961
  };
962
+ borderRadius: {
963
+ type: string;
964
+ minimum: number;
965
+ description: string;
966
+ };
967
+ fontSizeBase: {
968
+ type: string;
969
+ exclusiveMinimum: number;
970
+ description: string;
971
+ };
897
972
  fontFamily: {
898
973
  type: string;
899
974
  minLength: number;
900
975
  };
976
+ headingFontFamily: {
977
+ type: string;
978
+ minLength: number;
979
+ description: string;
980
+ };
901
981
  fontRegular: {
902
982
  type: string;
903
983
  minLength: number;
@@ -1082,6 +1162,31 @@ declare const SCHEMAS: Readonly<{
1082
1162
  };
1083
1163
  };
1084
1164
  };
1165
+ PlanChecklistItem: {
1166
+ type: string;
1167
+ required: string[];
1168
+ properties: {
1169
+ id: {
1170
+ type: string;
1171
+ minLength: number;
1172
+ };
1173
+ requirement: {
1174
+ type: string;
1175
+ minLength: number;
1176
+ };
1177
+ verify: {
1178
+ type: string;
1179
+ minLength: number;
1180
+ };
1181
+ steps: {
1182
+ type: string;
1183
+ items: {
1184
+ type: string;
1185
+ minLength: number;
1186
+ };
1187
+ };
1188
+ };
1189
+ };
1085
1190
  DecisionSpaceProvenance: {
1086
1191
  type: string;
1087
1192
  required: string[];
@@ -1117,6 +1222,34 @@ declare const SCHEMAS: Readonly<{
1117
1222
  type: string;
1118
1223
  minLength: number;
1119
1224
  };
1225
+ requiredWhen: {
1226
+ description: string;
1227
+ type: string;
1228
+ required: string[];
1229
+ properties: {
1230
+ fact: {
1231
+ type: string;
1232
+ minLength: number;
1233
+ };
1234
+ oneOf: {
1235
+ type: string;
1236
+ minItems: number;
1237
+ items: {
1238
+ type: string;
1239
+ minLength: number;
1240
+ };
1241
+ };
1242
+ };
1243
+ };
1244
+ options: {
1245
+ description: string;
1246
+ type: string;
1247
+ minItems: number;
1248
+ items: {
1249
+ type: string;
1250
+ minLength: number;
1251
+ };
1252
+ };
1120
1253
  };
1121
1254
  };
1122
1255
  PlanStep: {
@@ -1684,6 +1817,11 @@ declare const SCHEMAS: Readonly<{
1684
1817
  type: string;
1685
1818
  minimum: number;
1686
1819
  };
1820
+ notApplicable: {
1821
+ description: string;
1822
+ type: string;
1823
+ minimum: number;
1824
+ };
1687
1825
  };
1688
1826
  };
1689
1827
  steps: {
@@ -1782,7 +1920,8 @@ declare const SCHEMAS: Readonly<{
1782
1920
  minLength: number;
1783
1921
  };
1784
1922
  httpStatus: {
1785
- type: string;
1923
+ description: string;
1924
+ type: string[];
1786
1925
  minimum: number;
1787
1926
  };
1788
1927
  namingFamily: {
@@ -1790,11 +1929,41 @@ declare const SCHEMAS: Readonly<{
1790
1929
  minLength: number;
1791
1930
  };
1792
1931
  retryable: {
1793
- type: string;
1932
+ description: string;
1933
+ type: string[];
1794
1934
  };
1795
1935
  confirmedOnWire: {
1936
+ description: string;
1937
+ type: string[];
1938
+ };
1939
+ alsoIn: {
1796
1940
  description: string;
1797
1941
  type: string;
1942
+ items: {
1943
+ type: string;
1944
+ required: string[];
1945
+ properties: {
1946
+ namingFamily: {
1947
+ type: string;
1948
+ minLength: number;
1949
+ };
1950
+ declaredIn: {
1951
+ type: string;
1952
+ minLength: number;
1953
+ };
1954
+ cause: {
1955
+ type: string;
1956
+ minLength: number;
1957
+ };
1958
+ retryable: {
1959
+ type: string[];
1960
+ };
1961
+ nextAction: {
1962
+ type: string;
1963
+ minLength: number;
1964
+ };
1965
+ };
1966
+ };
1798
1967
  };
1799
1968
  surfaces: {
1800
1969
  type: string;
@@ -2029,6 +2198,8 @@ type ApiFailure = {
2029
2198
  readonly retryable: boolean;
2030
2199
  readonly requestId: string | null;
2031
2200
  readonly attempts: number;
2201
+ /** When to try again, as the response said it (retrySignalsOf). Absent where nothing built one. */
2202
+ readonly retrySignals?: RetrySignals;
2032
2203
  } | {
2033
2204
  readonly ok: false;
2034
2205
  readonly kind: 'malformed';
@@ -2102,6 +2273,24 @@ declare function errorCodeOf(body: unknown): {
2102
2273
  readonly code: string | null;
2103
2274
  readonly wireMessage: string;
2104
2275
  };
2276
+ /**
2277
+ * Build the `http` failure with `wireMessage` NON-ENUMERABLE.
2278
+ *
2279
+ * Written as a builder rather than an object literal because a literal cannot express
2280
+ * "present on the type, invisible to a serialiser". The property is defined after the fact and
2281
+ * the whole thing is frozen, so the field is readable by a deliberate `failure.wireMessage` and
2282
+ * by nothing that walks the object.
2283
+ */
2284
+ /**
2285
+ * WHEN TO TRY AGAIN, AS THE RESPONSE SAID IT (tester run, 2026-10-01). The registry's note for the daily quota says
2286
+ * `resets_at` in the body is the only reliable retry signal on that path (there is no Retry-After), and no command
2287
+ * printed it. Both are read here, and only in a shape that cannot carry free text: `resets_at` as an ISO 8601 UTC or
2288
+ * offset timestamp, `Retry-After` as delta-seconds or an HTTP date. Anything else is dropped, never rendered.
2289
+ */
2290
+ interface RetrySignals {
2291
+ readonly resetsAt: string | null;
2292
+ readonly retryAfter: string | null;
2293
+ }
2105
2294
  declare function createApiClient(options: ApiClientOptions): ApiClient;
2106
2295
  /**
2107
2296
  * One-line human summary of a failure. Assembled from OPERATOR-OWNED DATA ONLY: the method and
@@ -2379,22 +2568,36 @@ declare function renderSandboxCreate(creation: SandboxCreation, revocation: Sand
2379
2568
  * THE MAPPING is to the SDK's `EverfurThemeInput` (everfur-sdk-rn src/client/theme/input.ts), and only where
2380
2569
  * it is unambiguous: primary or brand to `primaryColor`; accent or secondary to `accentColor`, unless it reads
2381
2570
  * as a surface tint (under 1.5:1 against the background, the shadcn `--accent` hover wash); the background to
2382
- * `brightness` (pinned when the project declares no dark variant) and, for a light ground close to one of the
2383
- * SDK's three compiled surfaces, `surfaceStyle`; a base radius to `radiusScale` by size; the first family of a
2571
+ * `brightness` (pinned when the project declares no dark variant) and, as declared, `backgroundColor` (branding v2
2572
+ * below); a base radius to `borderRadius` in px; the first family of a
2384
2573
  * font stack to `fontFamily` when it is a plain family name (the web, where the page loads the weights itself); a
2385
2574
  * React Native theme file's `fontFamily` literals to the registered faces `fontRegular`, `fontMedium` and
2386
2575
  * `fontBold` (written as the SDK's `fonts` map, names only: the app registers the faces, the SDK bundles no font
2387
- * and synthesizes no weight on a named face). The foreground is read as evidence only: the SDK
2388
- * computes its text colours from the ground (WCAG), and the prop has no text token outside slots. Every colour
2576
+ * and synthesizes no weight on a named face). The foreground is the body text, `textColor` (branding v2). Every colour
2389
2577
  * is written as `#RRGGBB`, the form the SDK parses; `hsl()` and `oklch()` are converted (theme-color.ts).
2390
2578
  *
2579
+ * BRANDING V2, THE LITERAL FIELDS (SDK 0.9.0; hosted MCP integration tests, 2026-10-04). The ground (and its dark twin)
2580
+ * as `backgroundColor`, never the nearest of the SDK's compiled surfaces, and no `surfaceStyle` beside it; the body text
2581
+ * as `textColor`; the radius as `borderRadius` and the body size as `fontSizeBase`, both in px; a danger colour
2582
+ * (`--destructive`, `--danger`, `--error`) as `dangerColor`, mapped like the status colours below. A stock Tailwind app
2583
+ * that names its colours by the default palette is read through that palette (tailwind-palette.ts): `@apply` utilities,
2584
+ * a v4 `var(--color-<name>-<shade>)`, and a v3 `colors.<name>[<shade>]` from `tailwindcss/colors`.
2585
+ *
2586
+ * BRANDING V2 (SDK 0.9.0, 2026-10-03). Three status colours and a heading family, mapped by name only: a success,
2587
+ * warning or info colour the project declares (`--success`, `--color-warning`, Tailwind v3 `colors.info`, a React
2588
+ * Native colours key `success`) to `successColor`, `warningColor` or `infoColor`, with its dark twin where the project
2589
+ * declares one; a heading font stack (`--font-heading`, `--font-display`, Tailwind v3 `fontFamily.heading`) to
2590
+ * `headingFontFamily`, its first plain family. A project that declares none of them gets none: the SDK keeps
2591
+ * Everfur's own status paint and heading faces, and no colour is chosen here. They ride on the reading the gate
2592
+ * grades and never raise or lower it, so a project that declares only a status colour is still refused.
2593
+ *
2391
2594
  * THE CONFIDENCE GATE. `high` when a primary and a background both come from one source with literal values;
2392
2595
  * `medium` when only some tokens were read; `low` otherwise. A computed colour the mapping wanted drops the
2393
2596
  * grade one level; a config that runs code at load time, or builds a theme value with a template literal, is
2394
2597
  * `low` whatever it declares. At `low` the theme is empty: nothing read from a source this tool could not fully
2395
2598
  * trust is written into a partner's app.
2396
2599
  */
2397
- type ThemeSource = 'tailwind-v4' | 'tailwind-v3' | 'css-variables' | 'react-navigation' | 'rn-colors' | 'none';
2600
+ type ThemeSource = 'tailwind-v4' | 'tailwind-v3' | 'css-variables' | 'tailwind-classes' | 'react-navigation' | 'rn-colors' | 'none';
2398
2601
  type ThemeConfidence = 'high' | 'medium' | 'low';
2399
2602
  /**
2400
2603
  * The subset of the SDK's `EverfurThemeInput` a plan writes. Every value is a string, so the emitted literal
@@ -2421,6 +2624,32 @@ interface DetectedTheme {
2421
2624
  readonly fontRegular?: string;
2422
2625
  readonly fontMedium?: string;
2423
2626
  readonly fontBold?: string;
2627
+ /** Branding v2 status colours, `#RRGGBB`, only where the project declares them by name (see the header). */
2628
+ readonly successColor?: string;
2629
+ readonly warningColor?: string;
2630
+ readonly infoColor?: string;
2631
+ /** Their dark twins, when the project declares a dark variant of the same key (or is dark only). */
2632
+ readonly successColorDark?: string;
2633
+ readonly warningColorDark?: string;
2634
+ readonly infoColorDark?: string;
2635
+ /** Branding v2: the family of the headings, one plain family name, never a stack. */
2636
+ readonly headingFontFamily?: string;
2637
+ /** Branding v2: errors and destructive actions, `#RRGGBB`, and its dark twin, where the project declares them by name. */
2638
+ readonly dangerColor?: string;
2639
+ readonly dangerColorDark?: string;
2640
+ /**
2641
+ * Branding v2: the ground of the light palette and of the dark one, `#RRGGBB`, exactly as the project declares it
2642
+ * (SDK 0.9.0 background_color). Written instead of the nearest surfaceStyle preset, which snapped slate-50 to cream.
2643
+ */
2644
+ readonly backgroundColor?: string;
2645
+ readonly backgroundColorDark?: string;
2646
+ /** Branding v2: the body text of the light and dark palettes, `#RRGGBB` (the SDK keeps it at 4.5:1 on every ground). */
2647
+ readonly textColor?: string;
2648
+ readonly textColorDark?: string;
2649
+ /** Branding v2: the medium corner radius in px (the SDK clamps 0 to 32), written instead of a radiusScale. */
2650
+ readonly borderRadius?: number;
2651
+ /** Branding v2: the body text size in px (the SDK clamps 12 to 20). */
2652
+ readonly fontSizeBase?: number;
2424
2653
  }
2425
2654
  type ThemeToken = keyof DetectedTheme;
2426
2655
  /** The order the tokens are written in generated code. */
@@ -2510,6 +2739,124 @@ interface ThemeProp {
2510
2739
  readonly source: string;
2511
2740
  }
2512
2741
 
2742
+ /**
2743
+ * The detection vocabulary. Every value here is something the CLI can establish from files on
2744
+ * disk. Anything it cannot establish lives in `src/commands/plan/facts.ts` as a supplied fact,
2745
+ * and the two sets are deliberately disjoint.
2746
+ */
2747
+ type ProjectType = 'expo-managed' | 'bare-react-native' | 'flutter' | 'web' | 'shopify-storefront' | 'unknown';
2748
+ /**
2749
+ * How a web project embeds the Everfur surface, read from the project: `in-page` when package.json
2750
+ * declares react-dom (the SDK's React components render in the host's own tree), `frame` otherwise (the
2751
+ * loader puts the surface in an iframe on Everfur's origin, and nothing is installed). The platform tree
2752
+ * asks this as its `web-embedding` question; `--embedding` overrides the detected answer. Null for every
2753
+ * other project shape.
2754
+ */
2755
+ type WebEmbedding = 'in-page' | 'frame';
2756
+ /**
2757
+ * The web framework facet of a `web` project (see `web-framework.ts`). It spells the generated files; the
2758
+ * contract's platform tree still branches on the project type, which this never replaces.
2759
+ */
2760
+ type WebFramework = 'next-app-router' | 'next-pages-router' | 'vite-react' | 'remix' | 'static-html' | 'other-web';
2761
+ interface WebFrameworkDetection {
2762
+ readonly framework: WebFramework;
2763
+ /** `src/` when the framework's source root is `src/` (Next.js with src/app, a Vite app), else empty. */
2764
+ readonly sourceDir: '' | 'src/';
2765
+ readonly evidence: readonly string[];
2766
+ }
2767
+ type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun' | 'not-applicable' | 'undetermined';
2768
+ type DependencySource = 'package.json' | 'pubspec.yaml';
2769
+ type DependencyScope = 'dependencies' | 'devDependencies' | 'peerDependencies' | 'sdk';
2770
+ /**
2771
+ * `declared` is the range written in the manifest. `installed` is the exact version resolved
2772
+ * on disk when the dependency tree is present. Reporting both is the honest answer: a plan
2773
+ * built against `^50.0.0` with nothing installed is materially less certain than one built
2774
+ * against a resolved 50.0.17, and a reader deserves to see which of the two they are getting.
2775
+ */
2776
+ interface DetectedDependency {
2777
+ readonly name: string;
2778
+ readonly declared: string | null;
2779
+ readonly installed: string | null;
2780
+ readonly source: DependencySource;
2781
+ readonly scope: DependencyScope;
2782
+ }
2783
+ interface ProjectDetection {
2784
+ readonly root: string;
2785
+ readonly projectType: ProjectType;
2786
+ /** Human-readable file-level facts that produced `projectType`, in the order they were found. */
2787
+ readonly projectTypeEvidence: readonly string[];
2788
+ readonly packageManager: PackageManager;
2789
+ readonly packageManagerEvidence: readonly string[];
2790
+ readonly dependencies: readonly DetectedDependency[];
2791
+ /** The detected embedding of a `web` project; null for every other shape. Its evidence is in `projectTypeEvidence`. */
2792
+ readonly webEmbedding: WebEmbedding | null;
2793
+ /**
2794
+ * The detected framework of a `web` project; null (or absent, for a detection built by hand) for every
2795
+ * other shape.
2796
+ */
2797
+ readonly webFramework?: WebFrameworkDetection | null;
2798
+ /**
2799
+ * What the project already says about its own look (theme-detect.ts), for the shapes the plan writes a provider
2800
+ * for (web, Expo, bare React Native); null for every other shape, and absent for a detection built by hand.
2801
+ */
2802
+ readonly theme?: ThemeDetection | null;
2803
+ /**
2804
+ * Expo Router, for a React Native project that uses it (expo-router.ts); null when it does not, and absent for a
2805
+ * detection built by hand. It decides where the plan tells the app to mount its Everfur module: Expo Router never
2806
+ * renders App.tsx, and every file under its routes directory is a route.
2807
+ */
2808
+ readonly expoRouter?: ExpoRouterDetection | null;
2809
+ /**
2810
+ * The URL schemes a React Native project declares and the application ids beside them (app-schemes.ts), so the
2811
+ * visit-return step can say whether one of them is a destination Everfur would register (MCP-14). Null for every
2812
+ * other shape, and absent for a detection built by hand.
2813
+ */
2814
+ readonly appSchemes?: AppSchemeDetection | null;
2815
+ /**
2816
+ * The Node server a web project already runs (express, fastify, koa or hono in its dependencies), so the plan writes
2817
+ * the session route for that server instead of a development server of its own. Null when it declares none, and
2818
+ * absent for a detection built by hand.
2819
+ */
2820
+ readonly nodeServer?: NodeServerDetection | null;
2821
+ /**
2822
+ * Whether the project already has a `server/` directory and a `server/tsconfig.json` in it, so the plan never writes
2823
+ * over a tsconfig the project owns. Absent for a detection built by hand, which then has neither.
2824
+ */
2825
+ readonly serverDirectory?: ServerDirectoryDetection | null;
2826
+ /**
2827
+ * True when the project already has a `.env.example` at its root, so the plan adds its lines to it rather than
2828
+ * handing over a whole file that replaces the app's own (hosted MCP mobile integration test, 2026-10-04).
2829
+ */
2830
+ readonly envExampleExists?: boolean;
2831
+ }
2832
+ /** The Node server frameworks the plan writes a session route for, in the order they are looked for. */
2833
+ type NodeServerFramework = 'express' | 'fastify' | 'koa' | 'hono';
2834
+ interface NodeServerDetection {
2835
+ readonly framework: NodeServerFramework;
2836
+ readonly evidence: readonly string[];
2837
+ }
2838
+ interface ServerDirectoryDetection {
2839
+ readonly exists: boolean;
2840
+ readonly tsconfig: boolean;
2841
+ }
2842
+ /** What a React Native project declares about its own URL schemes. */
2843
+ interface AppSchemeDetection {
2844
+ /** Every declared scheme, in the order app.json, iOS, Android. */
2845
+ readonly schemes: readonly string[];
2846
+ /** The application ids declared beside them (the iOS bundle identifier, the Android package). */
2847
+ readonly appIds: readonly string[];
2848
+ /** The first declared scheme in reverse-DNS form, which is the only form Everfur registers; null when there is none. */
2849
+ readonly reverseDns: string | null;
2850
+ /** The file and key each scheme was read from. */
2851
+ readonly evidence: readonly string[];
2852
+ }
2853
+ /** An Expo Router project: its routes directory, and the files that said so. */
2854
+ interface ExpoRouterDetection {
2855
+ /** `app`, or `src/app` when the routes live there (Expo Router reads `src/app` when `app` is absent). */
2856
+ readonly appDir: 'app' | 'src/app';
2857
+ readonly evidence: readonly string[];
2858
+ }
2859
+
2513
2860
  /**
2514
2861
  * THE SURFACE CHECKS, run when `--surfaces` names them: each asks whether one Everfur surface works for THIS tenant
2515
2862
  * with the session `verify` just minted, from the same wire a partner's app uses.
@@ -2522,11 +2869,13 @@ interface ThemeProp {
2522
2869
  * is kept, so only the origin, the path and the expiry reach the report.
2523
2870
  * theme the branding the verdict's render_hints carry, rendered by the SDK's own resolver (theme-render.ts, over
2524
2871
  * the SDK code mirrored into src/registry/sdk): which fields are overridden and which the tenant locked,
2525
- * whether the SDK drops the whole branding for a schema_version it does not read, whether it would drop a
2526
- * logo or font URL, whether text on the brand fill it paints reaches WCAG 4.5:1 on each palette it shows
2527
- * (light unless a brightness says otherwise, both for auto), and which configured slot colours its guard
2528
- * repaints. The inks it pushes until they read (brand text, links) and the dark variants it derives are
2529
- * reported, not failed. With a project (`--project-root`, `project_root`) or a pasted `theme_source`, the
2872
+ * whether the SDK drops the whole branding for a schema_version it does not read, whether it would ignore
2873
+ * a logo or assistant avatar that is not an image uploaded in the partner console (SDK 0.9.0) or drop a font
2874
+ * URL that is not https, whether text on the brand fill it paints reaches WCAG 4.5:1 on each palette it
2875
+ * shows (light unless a brightness says otherwise, both for auto), and which configured slot colours its
2876
+ * guard repaints, all seventeen slots of branding v2. The inks it pushes until they read (brand text,
2877
+ * links, and the branding v2 status colours), the dark variants it derives, and that font_sources load
2878
+ * in-page only (the hosted frame keeps Everfur's fonts) are reported, not failed. With a project (`--project-root`, `project_root`) or a pasted `theme_source`, the
2530
2879
  * branding is judged MERGED with the `theme` prop `everfur plan` writes from that theme, as the SDK merges
2531
2880
  * them: the prop wins per field unless the tenant locked it.
2532
2881
  *
@@ -2584,8 +2933,12 @@ type VerifyIdentityMode = (typeof VERIFY_IDENTITY_MODES)[number];
2584
2933
  * GATED is the fourth answer, added with the surface checks: the step ran and found a surface Everfur has switched
2585
2934
  * off for the tenant. It is neither a failure of the integration (FAIL) nor something the operator can supply to make
2586
2935
  * the step run (SKIP), so it moves the status in neither direction.
2936
+ *
2937
+ * N/A is the fifth, added with the embedding (timed integration run, 2026-09-26): a check that does not apply to this
2938
+ * integration, such as the frame's embed fence for a page that renders in-page. It was not run, and nothing the
2939
+ * operator supplies would make it apply, so, like GATED, it moves the status in neither direction.
2587
2940
  */
2588
- type StepResult = 'PASS' | 'FAIL' | 'SKIP' | 'GATED';
2941
+ type StepResult = 'PASS' | 'FAIL' | 'SKIP' | 'GATED' | 'N/A';
2589
2942
  interface VerifyStep {
2590
2943
  /** Stable within a schemaVersion. Callers may key on it. */
2591
2944
  readonly id: string;
@@ -2654,6 +3007,11 @@ interface VerifyOptions {
2654
3007
  * exercise: the embed fence, the CORS exposure, the session policy, the loader. Null skips them.
2655
3008
  */
2656
3009
  readonly origin?: string | null;
3010
+ /**
3011
+ * How that page embeds the surface. Null reads it from `project` when one is given (react-dom means in-page), and
3012
+ * is otherwise `frame`, what `origin` has always meant. `in-page` reports the frame's two checks N/A.
3013
+ */
3014
+ readonly embedding?: WebEmbedding | null;
2657
3015
  /** The transport for the loader probe, which leaves the API host. Null skips that one check. */
2658
3016
  readonly transport?: TransportPort | null;
2659
3017
  readonly timeoutMs?: number;
@@ -2690,6 +3048,8 @@ interface VerifyOptions {
2690
3048
  * the prop read from a pasted `theme_source`, which wins over the project on disk, as it does for the plan.
2691
3049
  */
2692
3050
  readonly themeProp?: ThemeProp | null;
3051
+ /** Why a pasted `theme_source` gave no theme prop; the theme check then fails rather than judging the branding alone. */
3052
+ readonly themeSourceUnread?: string | null;
2693
3053
  }
2694
3054
  interface Verification {
2695
3055
  readonly steps: readonly VerifyStep[];
@@ -2741,98 +3101,6 @@ declare const nodeFileSystem: FileSystemPort;
2741
3101
  */
2742
3102
  declare function createMemoryFileSystem(files: Readonly<Record<string, string>>): FileSystemPort;
2743
3103
 
2744
- /**
2745
- * The detection vocabulary. Every value here is something the CLI can establish from files on
2746
- * disk. Anything it cannot establish lives in `src/commands/plan/facts.ts` as a supplied fact,
2747
- * and the two sets are deliberately disjoint.
2748
- */
2749
- type ProjectType = 'expo-managed' | 'bare-react-native' | 'flutter' | 'web' | 'shopify-storefront' | 'unknown';
2750
- /**
2751
- * How a web project embeds the Everfur surface, read from the project: `in-page` when package.json
2752
- * declares react-dom (the SDK's React components render in the host's own tree), `frame` otherwise (the
2753
- * loader puts the surface in an iframe on Everfur's origin, and nothing is installed). The platform tree
2754
- * asks this as its `web-embedding` question; `--embedding` overrides the detected answer. Null for every
2755
- * other project shape.
2756
- */
2757
- type WebEmbedding = 'in-page' | 'frame';
2758
- /**
2759
- * The web framework facet of a `web` project (see `web-framework.ts`). It spells the generated files; the
2760
- * contract's platform tree still branches on the project type, which this never replaces.
2761
- */
2762
- type WebFramework = 'next-app-router' | 'next-pages-router' | 'vite-react' | 'remix' | 'static-html' | 'other-web';
2763
- interface WebFrameworkDetection {
2764
- readonly framework: WebFramework;
2765
- /** `src/` when the framework's source root is `src/` (Next.js with src/app, a Vite app), else empty. */
2766
- readonly sourceDir: '' | 'src/';
2767
- readonly evidence: readonly string[];
2768
- }
2769
- type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun' | 'not-applicable' | 'undetermined';
2770
- type DependencySource = 'package.json' | 'pubspec.yaml';
2771
- type DependencyScope = 'dependencies' | 'devDependencies' | 'peerDependencies' | 'sdk';
2772
- /**
2773
- * `declared` is the range written in the manifest. `installed` is the exact version resolved
2774
- * on disk when the dependency tree is present. Reporting both is the honest answer: a plan
2775
- * built against `^50.0.0` with nothing installed is materially less certain than one built
2776
- * against a resolved 50.0.17, and a reader deserves to see which of the two they are getting.
2777
- */
2778
- interface DetectedDependency {
2779
- readonly name: string;
2780
- readonly declared: string | null;
2781
- readonly installed: string | null;
2782
- readonly source: DependencySource;
2783
- readonly scope: DependencyScope;
2784
- }
2785
- interface ProjectDetection {
2786
- readonly root: string;
2787
- readonly projectType: ProjectType;
2788
- /** Human-readable file-level facts that produced `projectType`, in the order they were found. */
2789
- readonly projectTypeEvidence: readonly string[];
2790
- readonly packageManager: PackageManager;
2791
- readonly packageManagerEvidence: readonly string[];
2792
- readonly dependencies: readonly DetectedDependency[];
2793
- /** The detected embedding of a `web` project; null for every other shape. Its evidence is in `projectTypeEvidence`. */
2794
- readonly webEmbedding: WebEmbedding | null;
2795
- /**
2796
- * The detected framework of a `web` project; null (or absent, for a detection built by hand) for every
2797
- * other shape.
2798
- */
2799
- readonly webFramework?: WebFrameworkDetection | null;
2800
- /**
2801
- * What the project already says about its own look (theme-detect.ts), for the shapes the plan writes a provider
2802
- * for (web, Expo, bare React Native); null for every other shape, and absent for a detection built by hand.
2803
- */
2804
- readonly theme?: ThemeDetection | null;
2805
- /**
2806
- * Expo Router, for a React Native project that uses it (expo-router.ts); null when it does not, and absent for a
2807
- * detection built by hand. It decides where the plan tells the app to mount its Everfur module: Expo Router never
2808
- * renders App.tsx, and every file under its routes directory is a route.
2809
- */
2810
- readonly expoRouter?: ExpoRouterDetection | null;
2811
- /**
2812
- * The URL schemes a React Native project declares and the application ids beside them (app-schemes.ts), so the
2813
- * visit-return step can say whether one of them is a destination Everfur would register (MCP-14). Null for every
2814
- * other shape, and absent for a detection built by hand.
2815
- */
2816
- readonly appSchemes?: AppSchemeDetection | null;
2817
- }
2818
- /** What a React Native project declares about its own URL schemes. */
2819
- interface AppSchemeDetection {
2820
- /** Every declared scheme, in the order app.json, iOS, Android. */
2821
- readonly schemes: readonly string[];
2822
- /** The application ids declared beside them (the iOS bundle identifier, the Android package). */
2823
- readonly appIds: readonly string[];
2824
- /** The first declared scheme in reverse-DNS form, which is the only form Everfur registers; null when there is none. */
2825
- readonly reverseDns: string | null;
2826
- /** The file and key each scheme was read from. */
2827
- readonly evidence: readonly string[];
2828
- }
2829
- /** An Expo Router project: its routes directory, and the files that said so. */
2830
- interface ExpoRouterDetection {
2831
- /** `app`, or `src/app` when the routes live there (Expo Router reads `src/app` when `app` is absent). */
2832
- readonly appDir: 'app' | 'src/app';
2833
- readonly evidence: readonly string[];
2834
- }
2835
-
2836
3104
  declare function detectProject(fs: FileSystemPort, root: string): ProjectDetection;
2837
3105
 
2838
3106
  type AttributeValue = string | number | boolean | null | readonly string[];
@@ -2984,7 +3252,7 @@ interface PlanCode {
2984
3252
  /** Suggested path, relative to the project root. */
2985
3253
  readonly path: string;
2986
3254
  /** For syntax highlighting and for an agent deciding how to write it. */
2987
- readonly language: 'tsx' | 'ts' | 'dart' | 'html' | 'liquid' | 'dotenv';
3255
+ readonly language: 'tsx' | 'ts' | 'dart' | 'html' | 'liquid' | 'dotenv' | 'json' | 'gitignore';
2988
3256
  readonly contents: string;
2989
3257
  }
2990
3258
 
@@ -3046,6 +3314,21 @@ interface MissingFact {
3046
3314
  readonly reason: string;
3047
3315
  /** The exact invocation change that resolves it. */
3048
3316
  readonly supplyWith: string;
3317
+ /**
3318
+ * Present when the fact is needed only for some answers to ANOTHER fact missing from the same refusal (additive to
3319
+ * v1): it is required only when `fact` is one of `oneOf`. It is asked in the same round so a caller can collect every
3320
+ * answer at once, rather than learn of it only after answering the other; given with any other answer, it is unused.
3321
+ */
3322
+ readonly requiredWhen?: MissingFactCondition;
3323
+ /**
3324
+ * Present when only some of the fact's answers resolve this refusal (additive to v1): the identity modes a
3325
+ * capability or the project shape admits, never the one it just refused. A caller offers these and no others.
3326
+ */
3327
+ readonly options?: readonly string[];
3328
+ }
3329
+ interface MissingFactCondition {
3330
+ readonly fact: MissingFactName;
3331
+ readonly oneOf: readonly string[];
3049
3332
  }
3050
3333
  type PlanPhase = 'install' | 'native' | 'configure' | 'code' | 'verify';
3051
3334
  interface PlanStep {
@@ -3111,6 +3394,18 @@ interface PlanPrinciple {
3111
3394
  readonly statement: string;
3112
3395
  readonly docPath: string | null;
3113
3396
  }
3397
+ /**
3398
+ * One item of a ready plan's definition of done (checklist.ts): what must hold when the agent is finished, and the
3399
+ * check that proves it. Derived from the steps, so the same plan always carries the same list. Additive to schema v1.
3400
+ */
3401
+ interface PlanChecklistItem {
3402
+ /** Stable within a schemaVersion: a fixed name per kind of requirement. */
3403
+ readonly id: string;
3404
+ readonly requirement: string;
3405
+ readonly verify: string;
3406
+ /** The step ids the item covers; empty for an item about the project as a whole. */
3407
+ readonly steps: readonly string[];
3408
+ }
3114
3409
  /** Which decision space produced this plan, so a stale plan can be traced to a stale contract. */
3115
3410
  interface DecisionSpaceProvenance {
3116
3411
  readonly source: string;
@@ -3187,6 +3482,11 @@ interface PlanDocument {
3187
3482
  readonly platformBlock?: PlatformBlock | null;
3188
3483
  /** The principles of every tree this plan consulted. */
3189
3484
  readonly principles: readonly PlanPrinciple[];
3485
+ /**
3486
+ * The definition of done of a READY plan: every item must hold, each proved by its `verify`, before the integration is
3487
+ * reported finished. Absent on a refusal. Additive to schema v1 (optional; absent on documents written before it).
3488
+ */
3489
+ readonly checklist?: readonly PlanChecklistItem[];
3190
3490
  readonly warnings: readonly PlanWarning[];
3191
3491
  /** Null only on the refusal that says no decision space was found. */
3192
3492
  readonly decisionSpace: DecisionSpaceProvenance | null;
@@ -3256,6 +3556,13 @@ interface PlanInput {
3256
3556
  * detection's own (which is absent too for a detection built by hand, and then no theme step is planned).
3257
3557
  */
3258
3558
  readonly theme?: ThemeDetection | null;
3559
+ /**
3560
+ * For a live tenant: true when it has a paired sandbox (the hosted verify then mints on that sandbox), false when it
3561
+ * has none. Absent or null is unknown, which a local plan always is. A live plan's verify is the read-only anonymous
3562
+ * check unless this is true (hosted MCP web integration test, 2026-10-04): the Everfur API mints no verify session on
3563
+ * a live tenant, and OD24 verifies a live tenant with reads only.
3564
+ */
3565
+ readonly tenantPairedSandbox?: boolean | null;
3259
3566
  }
3260
3567
  /**
3261
3568
  * Compute the missing facts in a fixed order: the contract first, because everything else is
@@ -3340,6 +3647,6 @@ declare function parseSuppliedFacts(capabilitiesRaw: string | null, identityRaw:
3340
3647
  * install, and a bundled artifact. `tests/unit/version.test.ts` asserts this constant equals
3341
3648
  * the package.json version, so the two cannot drift.
3342
3649
  */
3343
- declare const CLI_VERSION = "0.2.1";
3650
+ declare const CLI_VERSION = "0.4.1";
3344
3651
 
3345
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 };