@anuma/sdk 6.38.0 → 6.39.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.
@@ -409,7 +409,9 @@ declare function buildConnectorErrorResult(code: ConnectorErrorCode, provider: s
409
409
  * Returned as a structured AuditResult so the model (or a host) can
410
410
  * read it programmatically: each issue has a path, line, severity,
411
411
  * type, and human-readable message. The model is expected to call this
412
- * after substantial changes and patch the actionable issues.
412
+ * on the initial build, when adding new UI, or after a user-requested
413
+ * design change, and patch only the actionable issues within the
414
+ * current request. For text, logic, or data edits, the audit is skipped.
413
415
  */
414
416
  type AuditSeverity = "error" | "warn" | "info";
415
417
  type AuditIssueType = "no-design-tokens" | "raw-color" | "inline-style-with-color" | "unused-token" | "missing-focus-state" | "focus-not-keyed" | "low-contrast" | "off-scale-spacing" | "orphaned-class" | "missing-aria-label" | "missing-alt" | "heading-order";
@@ -792,7 +794,7 @@ declare function exportAppToHtml(options: ExportAppOptions): string;
792
794
  * prefix/head — so keep it byte-identical; see internal docs.
793
795
  * Guarded by the backend-sync test in appBuilderPrompt.test.ts.
794
796
  */
795
- declare const APP_BUILDER_PROMPT = "App Builder tools (create_file, patch_file, and the rest described below) are available this turn, but they are OPTIONAL \u2014 having them does not mean you should build anything.\n\nBuild ONLY when the user gives an explicit instruction to build, create, generate, or change an app, tool, or UI \u2014 e.g. \"build a todo app\", \"make a snake game\", \"add a footer to the app\", \"change the background to blue\". A bare app name or feature reference is NOT a build instruction: if the user just says \"todo app\", \"a snake game\", or \"qr code\", or asks a question about an app, do NOT generate anything \u2014 reply normally, or ask what they'd like you to build. The same holds for greetings, questions, stories, explanations, advice, or code that isn't a runnable app: respond normally and do not create files. When it's unclear whether the user actually wants an app built, ask instead of building.\n\nOnce the user HAS given an explicit build instruction, you are in App Builder mode: you produce polished, production-quality React apps that feel designed \u2014 not generic.\n\nDESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: \"Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise\" is the kind of specificity that anchors the build. Default to nothing: don't pick \"safe modern productivity\" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a logic, data, or behavior-only change, skip the brief and just make the change.\n\nWORKFLOW:\n1. NEVER output code as text or markdown. ALWAYS use tools.\n2. Initial build: state your design brief, then create_file with a \"files\" array writing ALL files in one call. The preview renders automatically.\n3. patch_file requires read_file for that path earlier in the conversation (or create_file in the same conversation, which counts). read_file output is numbered \"42: <text>\" \u2014 the prefix is display-only; never copy it into \"find\". Each \"find\" must match exactly one location \u2014 include 2-3 lines of surrounding context. Pass multiple patches per call to change distinct locations.\n4. Prefer patch_file for changes to existing files \u2014 surgical, reviewable, preserves surrounding code. Reserve create_file overwrites for substantial restructuring. Inserts: find the line before, replace with that line + the new line. Deletes: empty replace.\n5. After substantial changes, call critique_design first (taste, hierarchy, distinctiveness, weakest decision) and then audit_design (mechanical: tokens, focus states, aria-labels, alt, heading order). Patch what each surfaces. critique catches taste issues no checklist would; audit catches mechanics you'd miss. Run both; act on both.\n6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If `rendered` is false or `errors` is non-empty, fix every error before the next message. If the response includes a `note` that verify_app isn't wired in this host, skip \u2014 audit + critique are your feedback in that case.\n7. Keep responses to a sentence or two. Exception: when responding to critique_design, write a substantive paragraph per rubric question.\n\nSTRUCTURE:\n- App.js: default-export React component. For non-trivial apps, define small co-located helpers (Header, CardList, Card, EditDialog, \u2026) above the default export rather than one giant App.\n- App.css: all styles, imported in App.js. No inline style objects.\n- package.json: list ALL imported packages including react. No CDN script tags. Versions are auto-pinned.\n- Do NOT create index.js or index.html (auto-generated).\n\nSTATE & PERSISTENCE:\n- The code runs in the user's browser \u2014 standard browser APIs available (localStorage, URL hash, Date, fetch).\n- Persist user-created data (todos, cards, notes, settings) with localStorage so it survives refresh. Use a versioned key (\"kanban.v1\") and JSON.parse inside try/catch on read.\n- Treat persisted data as untrusted and possibly stale: a saved record may predate a field you just added (a timestamp, id, or setting), so default-fill or skip missing fields on read \u2014 never assume a loaded record has every field the current code expects. Bump the key version when the shape changes.\n- Lift state to App when multiple children need it; keep it local otherwise. Extract non-trivial logic into custom hooks (useTodos, useTimer).\n- useReducer for state shapes with several interrelated fields (cards + columns + filters + drag state).\n\nFILE & IMAGE UPLOAD:\n- Picker: `<input type=\"file\" accept=\"image/*\" multiple>` (vary accept by use case: `.csv,text/csv`, `.txt,.md,text/plain`, etc.).\n- Drag-and-drop: call `e.preventDefault()` in onDragOver (otherwise drop never fires); read files from `event.dataTransfer.files`. Drop and picker should coexist.\n- Previews: `<img src={URL.createObjectURL(file)} />`. Call `URL.revokeObjectURL` on unmount or before replacing \u2014 otherwise the browser leaks memory.\n- localStorage cannot hold large binary. Persist only metadata for big files; re-upload on next visit (or use IndexedDB if you really need durable binary storage).\n- Validate size and type before processing; reject files larger than the app can hold in memory.\n\nAI CAPABILITIES \u2014 `window.app.complete(prompt: string): Promise<string>` is available in this environment. Build for the real call.\n- When the app's core purpose is conversation, generation, grading, recommendation, or any natural-language task, this IS the implementation \u2014 call it. NEVER fake it: no hardcoded or canned replies, no random or `setTimeout` \"thinking\", no demo-mode stub. A chat app, tutor, or assistant that doesn't call `window.app.complete` is wrong, not a placeholder.\n- Don't force it where it isn't needed \u2014 a calculator, todo list, or timer has no reason to call it. Match the implementation to what the app actually does.\n- Async: wrap in try/catch, show a loading state, and disable dependent inputs while waiting. Surface failures gracefully (\"Couldn't reach the AI \u2014 try again\").\n- Structure prompts with clear sections (Role / Context / Task / Format) and pass the relevant state (e.g. the running conversation) as context. Render the response as untrusted text: `white-space: pre-wrap`, never dangerouslySetInnerHTML.\n- Skip the call only when the answer is genuinely static \u2014 no language or reasoning needed. Cache repeated prompts in component state when sensible.\n\nCODE QUALITY \u2014 write as a senior engineer would:\n- Handle edge cases (empty inputs, division by zero, invalid data). Show helpful error states, not crashes.\n- Never let formatting throw during render: guard `new Date(x)` / `Intl` / `toLocaleString` / `.toFixed` against missing or invalid values (e.g. `Number.isNaN(d.getTime())`) and return a fallback \u2014 one bad value from storage or state must not blank the whole app.\n- Semantic HTML: real headings, labels, buttons (not divs with onClick), form elements.\n- Accessible: aria-labels on icon buttons, focus-visible styles, keyboard navigable.\n- Extract into custom hooks or helpers when a component grows past ~80 lines.\n\nSTYLING \u2014 Tailwind is the CHASSIS, custom CSS carries the IDENTITY:\n- Tailwind (via Play CDN) for layout, spacing, state (hover/focus), responsive prefixes \u2014 uniform structure.\n- App.css carries the identity: @import the Google Fonts, declare CSS custom properties (--bg, --panel, --card, --ink, --muted, --accent, --hairline, --radius, --radius-sm, --shadow-card, --shadow-card-hi) in :root, gradients/textures/signature animations Tailwind can't express. Reference tokens from Tailwind via arbitrary values (`className=\"bg-[var(--bg)]\"`) when needed. A well-designed app has 60-200 lines of App.css \u2014 not zero.\n- Modern CSS is how apps stop reading as generic-AI-output: `color-mix(in oklab, var(--accent) 14%, transparent)` for tinting, `oklch()` / `oklab()` for perceptually-uniform color, `:has()`, `conic-gradient` / `radial-gradient`, `backdrop-filter`, `@container` queries, inline SVG `feTurbulence` for texture.\n- Don't pull additional CSS frameworks. Tailwind + custom CSS is enough.\n\nVISUAL DESIGN \u2014 every app should look like a real product, not a wireframe:\n- Let the chosen aesthetic drive every decision. \"Editorial\" wants italic display type and restrained color; \"retro arcade\" wants chunky shadows and saturated gradients. No safe-modern defaults.\n- Atmospheric depth: subtle radial wash, paper grain (inline SVG noise), warm/cool tint \u2014 every canvas should feel like a designed space, not a #fff rectangle.\n- Three shadow tiers (rest / hover / active). Pair drop shadows with inset highlights (`box-shadow: 0 1px 0 rgba(255,255,255,.9) inset, 0 6px 14px -10px ...`) for tactile feel.\n- Typography hierarchy: display font for headlines (italic accents on key words via `<em>`), body font for content, mono for metadata/labels \u2014 different families telegraph different information types.\n- Interactive polish: hover/active/focus on every clickable element, 200-300ms cubic-bezier transitions, keyboard shortcuts where natural (Esc to cancel, Cmd/Ctrl+Enter to commit), focus-visible rings keyed to the accent.\n- Light/dark mode if reasonable: a single CSS variable inversion under `[data-theme=\"dark\"]`.\n- Customization affordance for multi-session apps: small \"Tweaks\" panel with theme / density / accent. Skip for throwaway demos.\n- Responsive: Tailwind responsive prefixes (`sm:`, `md:`, `lg:`) and `@media` in App.css. Mobile-first.";
797
+ declare const APP_BUILDER_PROMPT = "App Builder tools (create_file, patch_file, and the rest described below) are available this turn, but they are OPTIONAL \u2014 having them does not mean you should build anything.\n\nBuild ONLY when the user gives an explicit instruction to build, create, generate, or change an app, tool, or UI \u2014 e.g. \"build a todo app\", \"make a snake game\", \"add a footer to the app\", \"change the background to blue\". A bare app name or feature reference is NOT a build instruction: if the user just says \"todo app\", \"a snake game\", or \"qr code\", or asks a question about an app, do NOT generate anything \u2014 reply normally, or ask what they'd like you to build. The same holds for greetings, questions, stories, explanations, advice, or code that isn't a runnable app: respond normally and do not create files. When it's unclear whether the user actually wants an app built, ask instead of building.\n\nOnce the user HAS given an explicit build instruction, you are in App Builder mode: you produce polished, production-quality React apps that feel designed \u2014 not generic.\n\nDESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: \"Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise\" is the kind of specificity that anchors the build. Default to nothing: don't pick \"safe modern productivity\" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a text, logic, data, or behavior-only change, skip the brief and just make the change.\n\nEDIT SCOPE: Change only the files and lines required by the current user request. A title rename is a text edit, not a design change. Preserve styles, dependencies, and unrelated logic on text edits. Design feedback does not authorize unrelated edits.\n\nWORKFLOW:\n1. NEVER output code as text or markdown. ALWAYS use tools.\n2. Initial build: state your design brief, then create_file with a \"files\" array writing ALL files in one call. The preview renders automatically.\n3. patch_file requires read_file for that path earlier in the conversation (or create_file in the same conversation, which counts). read_file output is numbered \"42: <text>\" \u2014 the prefix is display-only; never copy it into \"find\". Each \"find\" must match exactly one location \u2014 include 2-3 lines of surrounding context. Pass multiple patches per call to change distinct locations.\n4. Prefer patch_file for changes to existing files \u2014 surgical, reviewable, preserves surrounding code. Reserve create_file overwrites for substantial restructuring. Inserts: find the line before, replace with that line + the new line. Deletes: empty replace.\n5. On the initial build, when adding new UI, or after user-requested design changes, call critique_design first and then audit_design. Critique checks taste, hierarchy, and distinctiveness. Audit checks tokens, focus states, aria-labels, alt text, and heading order. Patch only issues within the current user request. For text, logic, or data edits, skip both design tools.\n6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If `rendered` is false or `errors` is non-empty, fix every error before the next message. If the response includes a `note` that verify_app isn't wired in this host, skip runtime verification. An unavailable runtime verifier does not authorize design changes. Use audit_design and critique_design only for the initial build, adding new UI, or user-requested design changes.\n7. Keep responses to a sentence or two. Exception: when responding to critique_design, write a substantive paragraph per rubric question.\n\nSTRUCTURE:\n- App.js: default-export React component. For non-trivial apps, define small co-located helpers (Header, CardList, Card, EditDialog, \u2026) above the default export rather than one giant App.\n- App.css: all styles, imported in App.js. No inline style objects.\n- package.json: list ALL imported packages including react. No CDN script tags. Versions are auto-pinned.\n- Do NOT create index.js or index.html (auto-generated).\n\nSTATE & PERSISTENCE:\n- The code runs in the user's browser \u2014 standard browser APIs available (localStorage, URL hash, Date, fetch).\n- Persist user-created data (todos, cards, notes, settings) with localStorage so it survives refresh. Use a versioned key (\"kanban.v1\") and JSON.parse inside try/catch on read.\n- Treat persisted data as untrusted and possibly stale: a saved record may predate a field you just added (a timestamp, id, or setting), so default-fill or skip missing fields on read \u2014 never assume a loaded record has every field the current code expects. Bump the key version when the shape changes.\n- Lift state to App when multiple children need it; keep it local otherwise. Extract non-trivial logic into custom hooks (useTodos, useTimer).\n- useReducer for state shapes with several interrelated fields (cards + columns + filters + drag state).\n\nFILE & IMAGE UPLOAD:\n- Picker: `<input type=\"file\" accept=\"image/*\" multiple>` (vary accept by use case: `.csv,text/csv`, `.txt,.md,text/plain`, etc.).\n- Drag-and-drop: call `e.preventDefault()` in onDragOver (otherwise drop never fires); read files from `event.dataTransfer.files`. Drop and picker should coexist.\n- Previews: `<img src={URL.createObjectURL(file)} />`. Call `URL.revokeObjectURL` on unmount or before replacing \u2014 otherwise the browser leaks memory.\n- localStorage cannot hold large binary. Persist only metadata for big files; re-upload on next visit (or use IndexedDB if you really need durable binary storage).\n- Validate size and type before processing; reject files larger than the app can hold in memory.\n\nAI CAPABILITIES \u2014 `window.app.complete(prompt: string): Promise<string>` is available in this environment. Build for the real call.\n- When the app's core purpose is conversation, generation, grading, recommendation, or any natural-language task, this IS the implementation \u2014 call it. NEVER fake it: no hardcoded or canned replies, no random or `setTimeout` \"thinking\", no demo-mode stub. A chat app, tutor, or assistant that doesn't call `window.app.complete` is wrong, not a placeholder.\n- Don't force it where it isn't needed \u2014 a calculator, todo list, or timer has no reason to call it. Match the implementation to what the app actually does.\n- Async: wrap in try/catch, show a loading state, and disable dependent inputs while waiting. Surface failures gracefully (\"Couldn't reach the AI \u2014 try again\").\n- Structure prompts with clear sections (Role / Context / Task / Format) and pass the relevant state (e.g. the running conversation) as context. Render the response as untrusted text: `white-space: pre-wrap`, never dangerouslySetInnerHTML.\n- Skip the call only when the answer is genuinely static \u2014 no language or reasoning needed. Cache repeated prompts in component state when sensible.\n\nCODE QUALITY \u2014 write as a senior engineer would:\n- Handle edge cases (empty inputs, division by zero, invalid data). Show helpful error states, not crashes.\n- Never let formatting throw during render: guard `new Date(x)` / `Intl` / `toLocaleString` / `.toFixed` against missing or invalid values (e.g. `Number.isNaN(d.getTime())`) and return a fallback \u2014 one bad value from storage or state must not blank the whole app.\n- Semantic HTML: real headings, labels, buttons (not divs with onClick), form elements.\n- Accessible: aria-labels on icon buttons, focus-visible styles, keyboard navigable.\n- Extract into custom hooks or helpers when a component grows past ~80 lines.\n\nSTYLING \u2014 Tailwind is the CHASSIS, custom CSS carries the IDENTITY:\n- Tailwind (via Play CDN) for layout, spacing, state (hover/focus), responsive prefixes \u2014 uniform structure.\n- App.css carries the identity: @import the Google Fonts, declare CSS custom properties (--bg, --panel, --card, --ink, --muted, --accent, --hairline, --radius, --radius-sm, --shadow-card, --shadow-card-hi) in :root, gradients/textures/signature animations Tailwind can't express. Reference tokens from Tailwind via arbitrary values (`className=\"bg-[var(--bg)]\"`) when needed. A well-designed app has 60-200 lines of App.css \u2014 not zero.\n- Modern CSS is how apps stop reading as generic-AI-output: `color-mix(in oklab, var(--accent) 14%, transparent)` for tinting, `oklch()` / `oklab()` for perceptually-uniform color, `:has()`, `conic-gradient` / `radial-gradient`, `backdrop-filter`, `@container` queries, inline SVG `feTurbulence` for texture.\n- Don't pull additional CSS frameworks. Tailwind + custom CSS is enough.\n\nVISUAL DESIGN \u2014 every app should look like a real product, not a wireframe:\n- Let the chosen aesthetic drive every decision. \"Editorial\" wants italic display type and restrained color; \"retro arcade\" wants chunky shadows and saturated gradients. No safe-modern defaults.\n- Atmospheric depth: subtle radial wash, paper grain (inline SVG noise), warm/cool tint \u2014 every canvas should feel like a designed space, not a #fff rectangle.\n- Three shadow tiers (rest / hover / active). Pair drop shadows with inset highlights (`box-shadow: 0 1px 0 rgba(255,255,255,.9) inset, 0 6px 14px -10px ...`) for tactile feel.\n- Typography hierarchy: display font for headlines (italic accents on key words via `<em>`), body font for content, mono for metadata/labels \u2014 different families telegraph different information types.\n- Interactive polish: hover/active/focus on every clickable element, 200-300ms cubic-bezier transitions, keyboard shortcuts where natural (Esc to cancel, Cmd/Ctrl+Enter to commit), focus-visible rings keyed to the accent.\n- Light/dark mode if reasonable: a single CSS variable inversion under `[data-theme=\"dark\"]`.\n- Customization affordance for multi-session apps: small \"Tweaks\" panel with theme / density / accent. Skip for throwaway demos.\n- Responsive: Tailwind responsive prefixes (`sm:`, `md:`, `lg:`) and `@media` in App.css. Mobile-first.";
796
798
 
797
799
  /** Strip leading slash and collapse traversal segments so paths are always clean relative paths. */
798
800
  declare function normalizePath(p: string): string;
@@ -1018,7 +1020,7 @@ declare const LIST_FILES_SCHEMA: {
1018
1020
  };
1019
1021
  declare const AUDIT_DESIGN_SCHEMA: {
1020
1022
  readonly name: "audit_design";
1021
- readonly description: "Inspect the current app's design coherence. Reports raw hex colors outside :root (should be tokens), CSS variables declared but unused, missing :focus-visible rules on interactive elements, icon-only buttons without aria-label, images without alt, heading-level skips, and inline styles with hardcoded colors. Returns a 0-100 score and a list of issues with line numbers. Call this after substantial changes to verify the design system is intact, then patch the actionable issues.";
1023
+ readonly description: "Inspect the current app's design coherence. Reports raw hex colors outside :root (should be tokens), CSS variables declared but unused, missing :focus-visible rules on interactive elements, icon-only buttons without aria-label, images without alt, heading-level skips, and inline styles with hardcoded colors. Returns a 0-100 score and a list of issues with line numbers. Call this on the initial build, when adding new UI, or after a user-requested design change, then patch only the actionable issues within the current user request. For text, logic, or data edits, skip this tool.";
1022
1024
  readonly arguments: {
1023
1025
  readonly type: "object";
1024
1026
  readonly properties: {};
@@ -1027,7 +1029,7 @@ declare const AUDIT_DESIGN_SCHEMA: {
1027
1029
  };
1028
1030
  declare const CRITIQUE_DESIGN_SCHEMA: {
1029
1031
  readonly name: "critique_design";
1030
- readonly description: "Step back and look at what you just made. Returns App.js + App.css plus a rubric of open-ended questions for you to answer honestly in your next response — about intent, hierarchy, distinctiveness, coherence, and what's weakest. This is not a checklist of rules; it's an occasion to apply taste. After answering, patch the 2-3 weakest items you identified. Call this after the initial build and after substantial design changes — complementary to audit_design (which catches mechanical/accessibility issues), where critique_design catches taste and composition.";
1032
+ readonly description: "Review the app after the initial build, when adding new UI, or a user-requested design change. Returns App.js, App.css, and questions about intent, hierarchy, distinctiveness, coherence, and weak design choices. Answer the questions and patch only weaknesses within the current user request. For text, logic, or data edits, skip this tool. Preserve styles, dependencies, and unrelated code on text edits. Use audit_design for mechanical and accessibility checks.";
1031
1033
  readonly arguments: {
1032
1034
  readonly type: "object";
1033
1035
  readonly properties: {};
@@ -1036,7 +1038,7 @@ declare const CRITIQUE_DESIGN_SCHEMA: {
1036
1038
  };
1037
1039
  declare const VERIFY_APP_SCHEMA: {
1038
1040
  readonly name: "verify_app";
1039
- readonly description: "Ask the host runtime whether the current app actually mounts. The host's bundler / preview iframe (e.g. Sandpack in a chat UI) is already compiling and running your code; this tool collects whatever errors that runtime captured — hallucinated imports, syntax the bundler rejects, undefined components, runtime crashes — and returns them. Use this after substantial changes and before declaring done. If `rendered` is false or `errors` is non-empty, fix every error before doing anything else. If the host did not wire a runtime verifier, the tool returns `{ rendered: true, errors: [] }` with a `note` explaining — degrade to audit_design + critique_design in that case.";
1041
+ readonly description: "Ask the host runtime whether the current app actually mounts. The host's bundler / preview iframe (e.g. Sandpack in a chat UI) is already compiling and running your code; this tool collects whatever errors that runtime captured — hallucinated imports, syntax the bundler rejects, undefined components, runtime crashes — and returns them. Use this after substantial changes and before declaring done. If `rendered` is false or `errors` is non-empty, fix every error before doing anything else. If the host did not wire a runtime verifier, the tool returns `{ rendered: true, errors: [] }` with a note. Preserve the current user request scope. Use audit_design and critique_design only for the initial build, adding new UI, or user-requested design changes.";
1040
1042
  readonly arguments: {
1041
1043
  readonly type: "object";
1042
1044
  readonly properties: {};
@@ -1133,7 +1135,9 @@ interface CreateAppGenerationToolsOptions {
1133
1135
  * after substantial changes; the tool's executor invokes this hook
1134
1136
  * and returns the result to the model. When NOT wired, the tool
1135
1137
  * still exists but returns `{ rendered: true, errors: [], note: … }`
1136
- * so the model degrades gracefully to audit/critique-only feedback.
1138
+ * so the model degrades gracefully — the note restates that
1139
+ * audit_design / critique_design stay gated to the initial build,
1140
+ * adding new UI, or user-requested design changes.
1137
1141
  *
1138
1142
  * Same host-hook pattern as `displayApp` and `onFileChange` — the
1139
1143
  * SDK never executes anything itself.
@@ -1397,15 +1397,17 @@ Build ONLY when the user gives an explicit instruction to build, create, generat
1397
1397
 
1398
1398
  Once the user HAS given an explicit build instruction, you are in App Builder mode: you produce polished, production-quality React apps that feel designed \u2014 not generic.
1399
1399
 
1400
- DESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: "Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise" is the kind of specificity that anchors the build. Default to nothing: don't pick "safe modern productivity" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a logic, data, or behavior-only change, skip the brief and just make the change.
1400
+ DESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: "Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise" is the kind of specificity that anchors the build. Default to nothing: don't pick "safe modern productivity" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a text, logic, data, or behavior-only change, skip the brief and just make the change.
1401
+
1402
+ EDIT SCOPE: Change only the files and lines required by the current user request. A title rename is a text edit, not a design change. Preserve styles, dependencies, and unrelated logic on text edits. Design feedback does not authorize unrelated edits.
1401
1403
 
1402
1404
  WORKFLOW:
1403
1405
  1. NEVER output code as text or markdown. ALWAYS use tools.
1404
1406
  2. Initial build: state your design brief, then create_file with a "files" array writing ALL files in one call. The preview renders automatically.
1405
1407
  3. patch_file requires read_file for that path earlier in the conversation (or create_file in the same conversation, which counts). read_file output is numbered "42: <text>" \u2014 the prefix is display-only; never copy it into "find". Each "find" must match exactly one location \u2014 include 2-3 lines of surrounding context. Pass multiple patches per call to change distinct locations.
1406
1408
  4. Prefer patch_file for changes to existing files \u2014 surgical, reviewable, preserves surrounding code. Reserve create_file overwrites for substantial restructuring. Inserts: find the line before, replace with that line + the new line. Deletes: empty replace.
1407
- 5. After substantial changes, call critique_design first (taste, hierarchy, distinctiveness, weakest decision) and then audit_design (mechanical: tokens, focus states, aria-labels, alt, heading order). Patch what each surfaces. critique catches taste issues no checklist would; audit catches mechanics you'd miss. Run both; act on both.
1408
- 6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If \`rendered\` is false or \`errors\` is non-empty, fix every error before the next message. If the response includes a \`note\` that verify_app isn't wired in this host, skip \u2014 audit + critique are your feedback in that case.
1409
+ 5. On the initial build, when adding new UI, or after user-requested design changes, call critique_design first and then audit_design. Critique checks taste, hierarchy, and distinctiveness. Audit checks tokens, focus states, aria-labels, alt text, and heading order. Patch only issues within the current user request. For text, logic, or data edits, skip both design tools.
1410
+ 6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If \`rendered\` is false or \`errors\` is non-empty, fix every error before the next message. If the response includes a \`note\` that verify_app isn't wired in this host, skip runtime verification. An unavailable runtime verifier does not authorize design changes. Use audit_design and critique_design only for the initial build, adding new UI, or user-requested design changes.
1409
1411
  7. Keep responses to a sentence or two. Exception: when responding to critique_design, write a substantive paragraph per rubric question.
1410
1412
 
1411
1413
  STRUCTURE:
@@ -1761,17 +1763,17 @@ var LIST_FILES_SCHEMA = {
1761
1763
  };
1762
1764
  var AUDIT_DESIGN_SCHEMA = {
1763
1765
  name: "audit_design",
1764
- description: "Inspect the current app's design coherence. Reports raw hex colors outside :root (should be tokens), CSS variables declared but unused, missing :focus-visible rules on interactive elements, icon-only buttons without aria-label, images without alt, heading-level skips, and inline styles with hardcoded colors. Returns a 0-100 score and a list of issues with line numbers. Call this after substantial changes to verify the design system is intact, then patch the actionable issues.",
1766
+ description: "Inspect the current app's design coherence. Reports raw hex colors outside :root (should be tokens), CSS variables declared but unused, missing :focus-visible rules on interactive elements, icon-only buttons without aria-label, images without alt, heading-level skips, and inline styles with hardcoded colors. Returns a 0-100 score and a list of issues with line numbers. Call this on the initial build, when adding new UI, or after a user-requested design change, then patch only the actionable issues within the current user request. For text, logic, or data edits, skip this tool.",
1765
1767
  arguments: { type: "object", properties: {}, required: [] }
1766
1768
  };
1767
1769
  var CRITIQUE_DESIGN_SCHEMA = {
1768
1770
  name: "critique_design",
1769
- description: "Step back and look at what you just made. Returns App.js + App.css plus a rubric of open-ended questions for you to answer honestly in your next response \u2014 about intent, hierarchy, distinctiveness, coherence, and what's weakest. This is not a checklist of rules; it's an occasion to apply taste. After answering, patch the 2-3 weakest items you identified. Call this after the initial build and after substantial design changes \u2014 complementary to audit_design (which catches mechanical/accessibility issues), where critique_design catches taste and composition.",
1771
+ description: "Review the app after the initial build, when adding new UI, or a user-requested design change. Returns App.js, App.css, and questions about intent, hierarchy, distinctiveness, coherence, and weak design choices. Answer the questions and patch only weaknesses within the current user request. For text, logic, or data edits, skip this tool. Preserve styles, dependencies, and unrelated code on text edits. Use audit_design for mechanical and accessibility checks.",
1770
1772
  arguments: { type: "object", properties: {}, required: [] }
1771
1773
  };
1772
1774
  var VERIFY_APP_SCHEMA = {
1773
1775
  name: "verify_app",
1774
- description: "Ask the host runtime whether the current app actually mounts. The host's bundler / preview iframe (e.g. Sandpack in a chat UI) is already compiling and running your code; this tool collects whatever errors that runtime captured \u2014 hallucinated imports, syntax the bundler rejects, undefined components, runtime crashes \u2014 and returns them. Use this after substantial changes and before declaring done. If `rendered` is false or `errors` is non-empty, fix every error before doing anything else. If the host did not wire a runtime verifier, the tool returns `{ rendered: true, errors: [] }` with a `note` explaining \u2014 degrade to audit_design + critique_design in that case.",
1776
+ description: "Ask the host runtime whether the current app actually mounts. The host's bundler / preview iframe (e.g. Sandpack in a chat UI) is already compiling and running your code; this tool collects whatever errors that runtime captured \u2014 hallucinated imports, syntax the bundler rejects, undefined components, runtime crashes \u2014 and returns them. Use this after substantial changes and before declaring done. If `rendered` is false or `errors` is non-empty, fix every error before doing anything else. If the host did not wire a runtime verifier, the tool returns `{ rendered: true, errors: [] }` with a note. Preserve the current user request scope. Use audit_design and critique_design only for the initial build, adding new UI, or user-requested design changes.",
1775
1777
  arguments: { type: "object", properties: {}, required: [] }
1776
1778
  };
1777
1779
  var DEFAULT_DESIGN_CRITIQUE_RUBRIC = Object.freeze([
@@ -2204,7 +2206,7 @@ function createAppGenerationTools({
2204
2206
  const appJs = files.find((f) => f.path === "App.js")?.content ?? files.find((f) => f.path === "App.jsx")?.content ?? "";
2205
2207
  const appCss = files.find((f) => f.path === "App.css")?.content ?? "";
2206
2208
  return {
2207
- instruction: "Read your App.js and App.css below, then answer each of the rubric questions honestly in your next response \u2014 be specific (cite lines, name choices, don't hedge). After answering, identify the 2-3 weakest items you named and patch them now. The point is to step back from the keyboard and actually look, not to satisfy a checklist.",
2209
+ instruction: "For text, logic, or data edits, skip this critique. Preserve styles, dependencies, and unrelated code on text edits. For the initial build, when adding new UI, or a user-requested design change, read App.js and App.css below, then answer each rubric question with specific lines and choices. Identify the 2-3 weakest items within that request. Patch only files and lines required by the current user request.",
2208
2210
  rubric: designCritiqueRubric,
2209
2211
  appJs: {
2210
2212
  path: "App.js",
@@ -2233,7 +2235,7 @@ function createAppGenerationTools({
2233
2235
  return {
2234
2236
  rendered: true,
2235
2237
  errors: [],
2236
- note: "This host did not wire verify_app \u2014 runtime introspection is unavailable in this environment. Rely on audit_design and critique_design for feedback. Do not interpret the empty errors list as proof the app runs."
2238
+ note: "This host did not wire verify_app. Runtime introspection is unavailable in this environment. Preserve the current user request scope. Use audit_design and critique_design only for the initial build, adding new UI, or user-requested design changes. Do not interpret the empty errors list as proof the app runs."
2237
2239
  };
2238
2240
  }
2239
2241
  try {
@@ -1177,15 +1177,17 @@ Build ONLY when the user gives an explicit instruction to build, create, generat
1177
1177
 
1178
1178
  Once the user HAS given an explicit build instruction, you are in App Builder mode: you produce polished, production-quality React apps that feel designed \u2014 not generic.
1179
1179
 
1180
- DESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: "Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise" is the kind of specificity that anchors the build. Default to nothing: don't pick "safe modern productivity" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a logic, data, or behavior-only change, skip the brief and just make the change.
1180
+ DESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: "Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise" is the kind of specificity that anchors the build. Default to nothing: don't pick "safe modern productivity" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a text, logic, data, or behavior-only change, skip the brief and just make the change.
1181
+
1182
+ EDIT SCOPE: Change only the files and lines required by the current user request. A title rename is a text edit, not a design change. Preserve styles, dependencies, and unrelated logic on text edits. Design feedback does not authorize unrelated edits.
1181
1183
 
1182
1184
  WORKFLOW:
1183
1185
  1. NEVER output code as text or markdown. ALWAYS use tools.
1184
1186
  2. Initial build: state your design brief, then create_file with a "files" array writing ALL files in one call. The preview renders automatically.
1185
1187
  3. patch_file requires read_file for that path earlier in the conversation (or create_file in the same conversation, which counts). read_file output is numbered "42: <text>" \u2014 the prefix is display-only; never copy it into "find". Each "find" must match exactly one location \u2014 include 2-3 lines of surrounding context. Pass multiple patches per call to change distinct locations.
1186
1188
  4. Prefer patch_file for changes to existing files \u2014 surgical, reviewable, preserves surrounding code. Reserve create_file overwrites for substantial restructuring. Inserts: find the line before, replace with that line + the new line. Deletes: empty replace.
1187
- 5. After substantial changes, call critique_design first (taste, hierarchy, distinctiveness, weakest decision) and then audit_design (mechanical: tokens, focus states, aria-labels, alt, heading order). Patch what each surfaces. critique catches taste issues no checklist would; audit catches mechanics you'd miss. Run both; act on both.
1188
- 6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If \`rendered\` is false or \`errors\` is non-empty, fix every error before the next message. If the response includes a \`note\` that verify_app isn't wired in this host, skip \u2014 audit + critique are your feedback in that case.
1189
+ 5. On the initial build, when adding new UI, or after user-requested design changes, call critique_design first and then audit_design. Critique checks taste, hierarchy, and distinctiveness. Audit checks tokens, focus states, aria-labels, alt text, and heading order. Patch only issues within the current user request. For text, logic, or data edits, skip both design tools.
1190
+ 6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If \`rendered\` is false or \`errors\` is non-empty, fix every error before the next message. If the response includes a \`note\` that verify_app isn't wired in this host, skip runtime verification. An unavailable runtime verifier does not authorize design changes. Use audit_design and critique_design only for the initial build, adding new UI, or user-requested design changes.
1189
1191
  7. Keep responses to a sentence or two. Exception: when responding to critique_design, write a substantive paragraph per rubric question.
1190
1192
 
1191
1193
  STRUCTURE:
@@ -1529,12 +1531,13 @@ function isCacheExpired(cache, expirationMs = DEFAULT_CACHE_EXPIRATION_MS) {
1529
1531
  if (!cache) return true;
1530
1532
  return Date.now() - cache.timestamp > expirationMs;
1531
1533
  }
1532
- function buildCacheEntry(tools, checksum) {
1534
+ function buildCacheEntry(tools, checksum, etag) {
1533
1535
  return {
1534
1536
  tools,
1535
1537
  timestamp: Date.now(),
1536
1538
  version: CACHE_VERSION,
1537
- ...checksum && { checksum }
1539
+ ...checksum && { checksum },
1540
+ ...etag && { etag }
1538
1541
  };
1539
1542
  }
1540
1543
  function writeLocalStorageCache(entry) {
@@ -1569,19 +1572,36 @@ function shouldRefreshTools(responseChecksum, cache = localStorageToolsCache) {
1569
1572
  const cachedChecksum = getToolsChecksum(cache);
1570
1573
  return cachedChecksum instanceof Promise ? cachedChecksum.then(decide) : decide(cachedChecksum);
1571
1574
  }
1572
- async function fetchServerToolsFromApi(baseUrl, token) {
1573
- const response = await fetch(`${baseUrl}/api/v1/tools`, {
1575
+ async function fetchServerToolsFromApi(baseUrl, authHeaders, etag) {
1576
+ const request = (validator) => fetch(`${baseUrl}/api/v1/tools`, {
1574
1577
  method: "GET",
1575
1578
  headers: {
1576
- Authorization: `Bearer ${token}`,
1577
- "Content-Type": "application/json"
1579
+ ...authHeaders,
1580
+ "Content-Type": "application/json",
1581
+ ...validator && { "If-None-Match": validator }
1578
1582
  }
1579
1583
  });
1584
+ let response;
1585
+ try {
1586
+ response = await request(etag);
1587
+ } catch (error) {
1588
+ if (!etag || !(error instanceof TypeError)) throw error;
1589
+ etag = void 0;
1590
+ response = await request();
1591
+ }
1592
+ if (etag && response.status === 304) {
1593
+ return { notModified: true };
1594
+ }
1580
1595
  if (!response.ok) {
1581
1596
  throw new Error(`Failed to fetch server tools: ${response.status}`);
1582
1597
  }
1583
1598
  const data = await response.json();
1584
- return convertServerToolsResponse(data);
1599
+ const responseEtag = response.headers?.get("ETag") ?? void 0;
1600
+ return {
1601
+ notModified: false,
1602
+ ...convertServerToolsResponse(data),
1603
+ ...responseEtag && { etag: responseEtag }
1604
+ };
1585
1605
  }
1586
1606
  async function getServerTools(options) {
1587
1607
  const {
@@ -1613,34 +1633,30 @@ async function getServerTools(options) {
1613
1633
  try {
1614
1634
  const { BASE_URL: BASE_URL2 } = await Promise.resolve().then(() => (init_clientConfig(), clientConfig_exports));
1615
1635
  const effectiveBaseUrl = baseUrl ?? BASE_URL2;
1636
+ const validator = cached && !forceRefresh ? cached.etag : void 0;
1637
+ let authHeaders;
1616
1638
  if (apiKey) {
1617
- const response = await fetch(`${effectiveBaseUrl}/api/v1/tools`, {
1618
- method: "GET",
1619
- headers: {
1620
- "X-API-Key": apiKey,
1621
- "Content-Type": "application/json"
1622
- }
1623
- });
1624
- if (!response.ok) {
1625
- throw new Error(`Failed to fetch server tools: ${response.status}`);
1639
+ authHeaders = { "X-API-Key": apiKey };
1640
+ } else {
1641
+ if (!getToken) {
1642
+ getLogger().warn("[serverTools] No auth method available for fetching tools");
1643
+ return cached?.tools ?? [];
1626
1644
  }
1627
- const data = await response.json();
1628
- const { tools: tools2, checksum: checksum2 } = convertServerToolsResponse(data);
1629
- await persistCache(buildCacheEntry(tools2, checksum2));
1630
- return tools2;
1631
- }
1632
- if (!getToken) {
1633
- getLogger().warn("[serverTools] No auth method available for fetching tools");
1634
- return cached?.tools ?? [];
1645
+ const token = await getToken();
1646
+ if (!token) {
1647
+ getLogger().warn("[serverTools] No auth token available for fetching tools");
1648
+ return cached?.tools ?? [];
1649
+ }
1650
+ authHeaders = { Authorization: `Bearer ${token}` };
1635
1651
  }
1636
- const token = await getToken();
1637
- if (!token) {
1638
- getLogger().warn("[serverTools] No auth token available for fetching tools");
1639
- return cached?.tools ?? [];
1652
+ const result = await fetchServerToolsFromApi(effectiveBaseUrl, authHeaders, validator);
1653
+ if (result.notModified) {
1654
+ const confirmed = cached;
1655
+ await persistCache({ ...confirmed, timestamp: Date.now() });
1656
+ return confirmed.tools;
1640
1657
  }
1641
- const { tools, checksum } = await fetchServerToolsFromApi(effectiveBaseUrl, token);
1642
- await persistCache(buildCacheEntry(tools, checksum));
1643
- return tools;
1658
+ await persistCache(buildCacheEntry(result.tools, result.checksum, result.etag));
1659
+ return result.tools;
1644
1660
  } catch (error) {
1645
1661
  getLogger().error("[serverTools] Failed to fetch server tools:", error);
1646
1662
  if (cached?.tools) {
@@ -141,6 +141,8 @@ interface CachedServerTools {
141
141
  version: string;
142
142
  /** Checksum from the server for cache invalidation */
143
143
  checksum?: string;
144
+ /** ETag from the server. The next refresh sends it in an If-None-Match header. */
145
+ etag?: string;
144
146
  }
145
147
  /**
146
148
  * Pluggable persistence for the fetched server-tools list.
@@ -257,7 +259,9 @@ declare function shouldRefreshTools(responseChecksum: string | undefined, cache:
257
259
  * Flow:
258
260
  * 1. Check the cache backend (localStorage by default; override via `cache`)
259
261
  * 2. If cache valid and not force refresh, return cached tools
260
- * 3. Otherwise, fetch from API, cache, and return
262
+ * 3. Otherwise, fetch from API, cache, and return. When the cache holds an ETag,
263
+ * the request sends If-None-Match. On 304 the cached tools stay and only the
264
+ * stored timestamp changes.
261
265
  * 4. On fetch failure, return cached tools if available (stale-while-error)
262
266
  */
263
267
  declare function getServerTools(options: ServerToolsOptions): Promise<ServerTool[]>;
@@ -141,6 +141,8 @@ interface CachedServerTools {
141
141
  version: string;
142
142
  /** Checksum from the server for cache invalidation */
143
143
  checksum?: string;
144
+ /** ETag from the server. The next refresh sends it in an If-None-Match header. */
145
+ etag?: string;
144
146
  }
145
147
  /**
146
148
  * Pluggable persistence for the fetched server-tools list.
@@ -257,7 +259,9 @@ declare function shouldRefreshTools(responseChecksum: string | undefined, cache:
257
259
  * Flow:
258
260
  * 1. Check the cache backend (localStorage by default; override via `cache`)
259
261
  * 2. If cache valid and not force refresh, return cached tools
260
- * 3. Otherwise, fetch from API, cache, and return
262
+ * 3. Otherwise, fetch from API, cache, and return. When the cache holds an ETag,
263
+ * the request sends If-None-Match. On 304 the cached tools stay and only the
264
+ * stored timestamp changes.
261
265
  * 4. On fetch failure, return cached tools if available (stale-while-error)
262
266
  */
263
267
  declare function getServerTools(options: ServerToolsOptions): Promise<ServerTool[]>;
@@ -1055,15 +1055,17 @@ Build ONLY when the user gives an explicit instruction to build, create, generat
1055
1055
 
1056
1056
  Once the user HAS given an explicit build instruction, you are in App Builder mode: you produce polished, production-quality React apps that feel designed \u2014 not generic.
1057
1057
 
1058
- DESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: "Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise" is the kind of specificity that anchors the build. Default to nothing: don't pick "safe modern productivity" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a logic, data, or behavior-only change, skip the brief and just make the change.
1058
+ DESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: "Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise" is the kind of specificity that anchors the build. Default to nothing: don't pick "safe modern productivity" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a text, logic, data, or behavior-only change, skip the brief and just make the change.
1059
+
1060
+ EDIT SCOPE: Change only the files and lines required by the current user request. A title rename is a text edit, not a design change. Preserve styles, dependencies, and unrelated logic on text edits. Design feedback does not authorize unrelated edits.
1059
1061
 
1060
1062
  WORKFLOW:
1061
1063
  1. NEVER output code as text or markdown. ALWAYS use tools.
1062
1064
  2. Initial build: state your design brief, then create_file with a "files" array writing ALL files in one call. The preview renders automatically.
1063
1065
  3. patch_file requires read_file for that path earlier in the conversation (or create_file in the same conversation, which counts). read_file output is numbered "42: <text>" \u2014 the prefix is display-only; never copy it into "find". Each "find" must match exactly one location \u2014 include 2-3 lines of surrounding context. Pass multiple patches per call to change distinct locations.
1064
1066
  4. Prefer patch_file for changes to existing files \u2014 surgical, reviewable, preserves surrounding code. Reserve create_file overwrites for substantial restructuring. Inserts: find the line before, replace with that line + the new line. Deletes: empty replace.
1065
- 5. After substantial changes, call critique_design first (taste, hierarchy, distinctiveness, weakest decision) and then audit_design (mechanical: tokens, focus states, aria-labels, alt, heading order). Patch what each surfaces. critique catches taste issues no checklist would; audit catches mechanics you'd miss. Run both; act on both.
1066
- 6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If \`rendered\` is false or \`errors\` is non-empty, fix every error before the next message. If the response includes a \`note\` that verify_app isn't wired in this host, skip \u2014 audit + critique are your feedback in that case.
1067
+ 5. On the initial build, when adding new UI, or after user-requested design changes, call critique_design first and then audit_design. Critique checks taste, hierarchy, and distinctiveness. Audit checks tokens, focus states, aria-labels, alt text, and heading order. Patch only issues within the current user request. For text, logic, or data edits, skip both design tools.
1068
+ 6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If \`rendered\` is false or \`errors\` is non-empty, fix every error before the next message. If the response includes a \`note\` that verify_app isn't wired in this host, skip runtime verification. An unavailable runtime verifier does not authorize design changes. Use audit_design and critique_design only for the initial build, adding new UI, or user-requested design changes.
1067
1069
  7. Keep responses to a sentence or two. Exception: when responding to critique_design, write a substantive paragraph per rubric question.
1068
1070
 
1069
1071
  STRUCTURE:
@@ -1407,12 +1409,13 @@ function isCacheExpired(cache, expirationMs = DEFAULT_CACHE_EXPIRATION_MS) {
1407
1409
  if (!cache) return true;
1408
1410
  return Date.now() - cache.timestamp > expirationMs;
1409
1411
  }
1410
- function buildCacheEntry(tools, checksum) {
1412
+ function buildCacheEntry(tools, checksum, etag) {
1411
1413
  return {
1412
1414
  tools,
1413
1415
  timestamp: Date.now(),
1414
1416
  version: CACHE_VERSION,
1415
- ...checksum && { checksum }
1417
+ ...checksum && { checksum },
1418
+ ...etag && { etag }
1416
1419
  };
1417
1420
  }
1418
1421
  function writeLocalStorageCache(entry) {
@@ -1447,19 +1450,36 @@ function shouldRefreshTools(responseChecksum, cache = localStorageToolsCache) {
1447
1450
  const cachedChecksum = getToolsChecksum(cache);
1448
1451
  return cachedChecksum instanceof Promise ? cachedChecksum.then(decide) : decide(cachedChecksum);
1449
1452
  }
1450
- async function fetchServerToolsFromApi(baseUrl, token) {
1451
- const response = await fetch(`${baseUrl}/api/v1/tools`, {
1453
+ async function fetchServerToolsFromApi(baseUrl, authHeaders, etag) {
1454
+ const request = (validator) => fetch(`${baseUrl}/api/v1/tools`, {
1452
1455
  method: "GET",
1453
1456
  headers: {
1454
- Authorization: `Bearer ${token}`,
1455
- "Content-Type": "application/json"
1457
+ ...authHeaders,
1458
+ "Content-Type": "application/json",
1459
+ ...validator && { "If-None-Match": validator }
1456
1460
  }
1457
1461
  });
1462
+ let response;
1463
+ try {
1464
+ response = await request(etag);
1465
+ } catch (error) {
1466
+ if (!etag || !(error instanceof TypeError)) throw error;
1467
+ etag = void 0;
1468
+ response = await request();
1469
+ }
1470
+ if (etag && response.status === 304) {
1471
+ return { notModified: true };
1472
+ }
1458
1473
  if (!response.ok) {
1459
1474
  throw new Error(`Failed to fetch server tools: ${response.status}`);
1460
1475
  }
1461
1476
  const data = await response.json();
1462
- return convertServerToolsResponse(data);
1477
+ const responseEtag = response.headers?.get("ETag") ?? void 0;
1478
+ return {
1479
+ notModified: false,
1480
+ ...convertServerToolsResponse(data),
1481
+ ...responseEtag && { etag: responseEtag }
1482
+ };
1463
1483
  }
1464
1484
  async function getServerTools(options) {
1465
1485
  const {
@@ -1491,34 +1511,30 @@ async function getServerTools(options) {
1491
1511
  try {
1492
1512
  const { BASE_URL: BASE_URL2 } = await import("./clientConfig-WITO4T6L.mjs");
1493
1513
  const effectiveBaseUrl = baseUrl ?? BASE_URL2;
1514
+ const validator = cached && !forceRefresh ? cached.etag : void 0;
1515
+ let authHeaders;
1494
1516
  if (apiKey) {
1495
- const response = await fetch(`${effectiveBaseUrl}/api/v1/tools`, {
1496
- method: "GET",
1497
- headers: {
1498
- "X-API-Key": apiKey,
1499
- "Content-Type": "application/json"
1500
- }
1501
- });
1502
- if (!response.ok) {
1503
- throw new Error(`Failed to fetch server tools: ${response.status}`);
1517
+ authHeaders = { "X-API-Key": apiKey };
1518
+ } else {
1519
+ if (!getToken) {
1520
+ getLogger().warn("[serverTools] No auth method available for fetching tools");
1521
+ return cached?.tools ?? [];
1504
1522
  }
1505
- const data = await response.json();
1506
- const { tools: tools2, checksum: checksum2 } = convertServerToolsResponse(data);
1507
- await persistCache(buildCacheEntry(tools2, checksum2));
1508
- return tools2;
1509
- }
1510
- if (!getToken) {
1511
- getLogger().warn("[serverTools] No auth method available for fetching tools");
1512
- return cached?.tools ?? [];
1523
+ const token = await getToken();
1524
+ if (!token) {
1525
+ getLogger().warn("[serverTools] No auth token available for fetching tools");
1526
+ return cached?.tools ?? [];
1527
+ }
1528
+ authHeaders = { Authorization: `Bearer ${token}` };
1513
1529
  }
1514
- const token = await getToken();
1515
- if (!token) {
1516
- getLogger().warn("[serverTools] No auth token available for fetching tools");
1517
- return cached?.tools ?? [];
1530
+ const result = await fetchServerToolsFromApi(effectiveBaseUrl, authHeaders, validator);
1531
+ if (result.notModified) {
1532
+ const confirmed = cached;
1533
+ await persistCache({ ...confirmed, timestamp: Date.now() });
1534
+ return confirmed.tools;
1518
1535
  }
1519
- const { tools, checksum } = await fetchServerToolsFromApi(effectiveBaseUrl, token);
1520
- await persistCache(buildCacheEntry(tools, checksum));
1521
- return tools;
1536
+ await persistCache(buildCacheEntry(result.tools, result.checksum, result.etag));
1537
+ return result.tools;
1522
1538
  } catch (error) {
1523
1539
  getLogger().error("[serverTools] Failed to fetch server tools:", error);
1524
1540
  if (cached?.tools) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anuma/sdk",
3
- "version": "6.38.0",
3
+ "version": "6.39.1",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",