From dfbaa2fc29cc3d14d2a1c7635dd66f52e1544f24 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sun, 1 Nov 2026 09:32:38 -0800 Subject: [PATCH] Plugin shots wait for the worker and restore after --act; terminal approval prompt (#37066) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(plugins): dev watch asks for first-load approval in a terminal; acronym-aware names - In an interactive terminal without --json, a first dev watch load that needs approval shows the grants (as plugin inspect prints them) and asks Approve and load? [y/N]; yes reloads with the host's fingerprint and keeps watching. --json and non-TTY runs keep the exit-3 flow. - create keeps known acronyms uppercase when it derives a name from the id (pr-queue → PR Queue). * fix(plugins): a declined dev watch approval prints only the re-run command The person just read the grants in the prompt, so the exit-3 error no longer repeats them: Not approved. To approve later, run: . * feat(plugins): shots wait for the worker; --act restores the panel; Table and Tree acts - A shot settles once the panel has no plugin.request or host call in flight and no new tree for a quiet spell (capped at 3 s), so a cold worker's skeleton is not captured; pendingRequests reports what was still pending. - After --act and the capture, the guest restores every plugin-written atom it had before (new ui.snapshot/ui.restore; persisted atoms re-persist) and Orca remounts its drawn controls; restored: true|false. Worker-side effects are not rolled back. - --act gains the kit's slide, sort, selectRows, activateRow, loadMore, expand, collapse, selectItem and activateItem. - Docs: the dev watch first-load prompt; shot settle, restore and the new verbs. * fix(plugins): a shot waits for the theme repaint and retries a bare capture Linux CI captured a dark --theme shot as a bare background (2 colors). The renderer now waits until the document shows the asked color scheme and paints, adds a frame after a --width resize, and main recaptures a panel image that is still a background and a border (two colors or fewer) up to 8 times, 150 ms apart, before returning it. Html panels keep their guest composite. * fix(plugins): capture the main window with stayHidden webContents.capturePage(rect, { stayHidden: true }) keeps a hidden window rendering for the capture, as the components gallery screenshots do. The repaint wait stays, and the bare-capture retry stays as a fallback. --- docs/reference/plugin-authoring.md | 34 ++- .../plugins/declarative/orca-runtime.mjs | 80 +++++-- .../plugins/declarative/orca-testing.mjs | 2 +- skill-guides/orca-cli/references/plugins.md | 10 +- .../references/workflow.md | 22 +- src/cli/bundled-skill-guides.ts | 32 ++- src/cli/handlers/plugin-authoring.ts | 6 +- src/cli/handlers/plugin-dev-watch.ts | 9 +- src/cli/handlers/plugin-view.test.ts | 31 +++ src/cli/handlers/plugin-view.ts | 18 +- src/cli/plugin-authoring/plugin-create.ts | 11 +- .../plugin-display-name.test.ts | 21 ++ .../plugin-authoring/plugin-display-name.ts | 15 ++ .../plugin-authoring/plugin-grant-lines.ts | 20 ++ .../plugin-dev-watch-approval.test.ts | 183 +++++++++++++++ .../plugin-dev-watch-approval.ts | 128 +++++++++++ .../plugin-dev-watch/plugin-dev-watch-loop.ts | 11 +- src/cli/specs/plugin-view.ts | 6 +- src/cli/specs/plugin.ts | 1 + .../plugins/view/plugin-view-capture.test.ts | 64 +++++- src/main/plugins/view/plugin-view-capture.ts | 48 +++- .../plugins/view/plugin-view-desktop.test.ts | 20 +- src/main/plugins/view/plugin-view-desktop.ts | 145 ++++++------ .../plugins/view/plugin-view-reply-schema.ts | 4 +- .../declarative/PluginDeclarativeTable.tsx | 1 + .../declarative/PluginDeclarativeTree.tsx | 19 +- .../plugin-declarative-act-targets.ts | 46 +++- .../view/plugin-view-act-test-harness.tsx | 70 ++++++ .../plugins/view/plugin-view-acts.test.tsx | 89 ++------ .../plugins/view/plugin-view-acts.ts | 208 +++++++++--------- .../plugins/view/plugin-view-capture-acts.ts | 65 ++++++ .../view/plugin-view-data-acts.test.tsx | 164 ++++++++++++++ .../plugins/view/plugin-view-data-acts.ts | 137 ++++++++++++ .../view/plugin-view-panel-settle.test.ts | 85 +++++++ .../plugins/view/plugin-view-panel-settle.ts | 47 +++- .../view/plugin-view-request-handler.ts | 40 ++-- .../right-sidebar/PluginDeclarativePanel.tsx | 32 +-- .../plugin-frame-host-declarative.test.ts | 27 +++ .../right-sidebar/plugin-frame-host.ts | 4 + .../plugin-panel-act-driver.test.ts | 74 +++++++ .../right-sidebar/plugin-panel-act-driver.ts | 89 ++++++-- .../right-sidebar/use-plugin-frame-host.ts | 18 +- .../plugin-declarative-message-names.ts | 6 +- .../runtime/declarative-act-snapshot.test.ts | 66 ++++++ .../runtime/declarative-act-snapshot.ts | 31 +++ .../declarative/runtime/declarative-atoms.ts | 16 ++ .../runtime/declarative-renderer.test.ts | 2 + .../runtime/declarative-renderer.ts | 2 + .../plugins/view/plugin-shot-acts.test.ts | 28 ++- src/shared/plugins/view/plugin-shot-acts.ts | 51 ++++- .../plugins/view/plugin-view-protocol.ts | 5 +- tests/e2e/plugin-shot.spec.ts | 150 ++++++++++++- 52 files changed, 2081 insertions(+), 412 deletions(-) create mode 100644 src/cli/plugin-authoring/plugin-display-name.test.ts create mode 100644 src/cli/plugin-authoring/plugin-display-name.ts create mode 100644 src/cli/plugin-authoring/plugin-grant-lines.ts create mode 100644 src/cli/plugin-dev-watch/plugin-dev-watch-approval.test.ts create mode 100644 src/cli/plugin-dev-watch/plugin-dev-watch-approval.ts create mode 100644 src/renderer/src/components/plugins/view/plugin-view-act-test-harness.tsx create mode 100644 src/renderer/src/components/plugins/view/plugin-view-capture-acts.ts create mode 100644 src/renderer/src/components/plugins/view/plugin-view-data-acts.test.tsx create mode 100644 src/renderer/src/components/plugins/view/plugin-view-data-acts.ts create mode 100644 src/renderer/src/components/plugins/view/plugin-view-panel-settle.test.ts create mode 100644 src/renderer/src/components/right-sidebar/plugin-panel-act-driver.test.ts create mode 100644 src/shared/plugins/declarative/runtime/declarative-act-snapshot.test.ts create mode 100644 src/shared/plugins/declarative/runtime/declarative-act-snapshot.ts diff --git a/docs/reference/plugin-authoring.md b/docs/reference/plugin-authoring.md index e01b4ab06fc..01c1604477f 100644 --- a/docs/reference/plugin-authoring.md +++ b/docs/reference/plugin-authoring.md @@ -359,9 +359,13 @@ to exit at once. With `--json` it prints one JSON object per line, with a `type` prints what each components panel drew or threw, with `file:line:col`; it reports a failure while Orca does not run the plugin (pending approval, errored, invalid), even when the panels render (`ok` false, `checkOk` true, and `pluginStatus`). Like `orca plugin check`, -it runs your code on this machine outside Orca's sandbox, and it needs a local folder. The first load needs approval like `orca plugin dev load` (it exits with code 3 and -prints the command to re-run with `--approve`; with `--json`, as one line). The re-run owns the -folder the refused attempt added, so its Ctrl-C unloads it. +it runs your code on this machine outside Orca's sandbox, and it needs a local folder. When the first load needs approval and you run it in a terminal, it prints what the plugin +would be granted (execution, each capability, what it adds) and asks `Approve and load? [y/N]`; +`y` loads it with that approval and keeps watching. Any other answer, Ctrl-C, `--json`, or +output that is not a terminal (a coding agent, a pipe) fails like `orca plugin dev load`: it +exits with code 3 and prints the command to re-run with `--approve` (with `--json`, as one line). +It never approves on its own. The re-run owns the folder the refused attempt added, so its +Ctrl-C unloads it. ### See the panel @@ -370,23 +374,33 @@ panel, to `.orca/shots/-.png` (or `--out `): in the plu you run it inside one (the nearest `orca-plugin.json`, up to the repository root), else in the current folder. It opens the panel in the right sidebar, waits until the current code has drawn (a components panel's first tree, an HTML -panel's page loaded; up to 15 seconds), and captures it even while Orca's window is hidden or +panel's page loaded; up to 15 seconds) and, for a components panel, until its host calls such as +`plugin.request` have answered and redrawn (at most 3 seconds more), and captures it even while Orca's window is hidden or behind others, without showing, raising or focusing it. `--width ` sizes the panel for that capture only. `--theme light|dark` paints Orca in that mode for that capture only, and only while its window is hidden or minimized: with the window on screen, the shot keeps the current theme rather than repaint the app in front of you, and says so (`themeApplied: false` and a `themeReason`). Your width and theme setting are always put back. `--json` prints `{ path, width, -height, theme, themeApplied, themeReason?, settled, errors }`, where `errors` holds the error -banner the panel shows and the errors it logged during the capture. A coding agent reads the +height, theme, themeApplied, themeReason?, settled, errors, pendingRequests?, actions?, +restored? }`, where `errors` holds the error banner the panel shows and the errors it logged +during the capture, and `pendingRequests` counts host calls still unanswered (above 0, the image +may show the panel still loading). A coding agent reads the image to see what it built. `--act ''` drives a components panel before the capture, with the test kit's verbs: a list (at most 20) such as `[{"type":{"label":"New task"},"text":"Ship","submit":true}, {"press":{"text":"Add"}},{"select":{"label":"View"},"value":"done"},{"toggle":{"label":"Hide -done"}}]`, whose queries match like the kit's (`text`, `label`, `testId`, `type`, `role`). Each -act goes through Orca's own control, as your typing or click would, and waits for the panel to -redraw. `actions` in the result has one `{ ok, error? }` per act; the first failure skips the -rest, the PNG shows the panel at that point, and the command exits 1. It acts only on that +done"}}]`, whose queries match like the kit's (`text`, `label`, `testId`, `type`, `role`). The +kit's Slider, Table and Tree verbs work too: `{"slide":Q,"value":7}`, `{"sort":Q,"column":"name"}`, +`{"selectRows":Q,"keys":["a"]}`, `{"activateRow":Q,"key":"a"}`, `{"loadMore":Q}`, and +`expand`, `collapse`, `selectItem`, `activateItem` with a `key`. Each act goes through Orca's own +control, as your typing or click would, and waits for the panel to redraw and its host calls to +answer. `actions` in the result has one `{ ok, error? }` per act; the first failure skips the +rest, the PNG shows the panel at that point, and the command exits 1. Once captured, Orca puts +the panel's atoms back, persisted ones included, so later shots and you see the panel as it was +(`restored: true`; false when it reloaded during the acts). What handlers did outside the panel +is not rolled back: a press whose handler sends `plugin.request('counter.add')` leaves the +worker's storage changed. It acts only on that plugin's panel and only while Orca's window is hidden or minimized, so it never clicks under you; html panels refuse it. An act is not a person's press: a Link's href stays unopened and calls that need a gesture (`shell.openExternal`, `files.saveAs`) are refused. diff --git a/resources/plugins/declarative/orca-runtime.mjs b/resources/plugins/declarative/orca-runtime.mjs index f46ccab622e..62a34a57e01 100644 --- a/resources/plugins/declarative/orca-runtime.mjs +++ b/resources/plugins/declarative/orca-runtime.mjs @@ -257,6 +257,17 @@ function applyStorageValue(key, value) { assign(inner, value === void 0 ? inner.initial : value, false); } } +function captureAtomValues() { + const values = /* @__PURE__ */ new Map(); + for (const inner of writableAtoms) { + values.set(inner, inner.value); + } + return () => { + for (const [inner, value] of values) { + assign(inner, value, true); + } + }; +} function hydrateAtoms(scope, values) { snapshot[scope] = new Map(values); for (const target of keyed.values()) { @@ -359,7 +370,11 @@ var PLUGIN_DECLARATIVE_MESSAGES = { /** guest → host, `{ entries: [{ scope, key, version, value }] }`: persisted atoms changed. */ persist: "ui.persist", /** guest → host, `{ document, entries: [{ key, version, value? }] }`: keyed memory atoms changed. */ - retain: "ui.retain" + retain: "ui.retain", + /** host → guest, `{ document }`: remember every atom's value before `orca plugin shot --act`. */ + snapshot: "ui.snapshot", + /** host → guest, `{ document }`: put the atoms back to the last `ui.snapshot`. */ + restore: "ui.restore" }; var PLUGIN_DECLARATIVE_CATALOG_VERSION = 3; var PLUGIN_DECLARATIVE_COMPONENT_PROPS = { @@ -755,27 +770,6 @@ function createMemoryRetention(post) { }; } -// src/shared/plugins/declarative/runtime/declarative-renderer-support.ts -var MIN_RENDER_INTERVAL_MS = 16; -var MAX_RETAINED_RENDERS = 32; -var HYDRATION_TIMEOUT_MS = 3e3; -function errorMessage(error) { - return describePluginError(error).slice(0, 4096); -} -function defaultSchedule(flush, delayMs) { - if (delayMs > 0) { - setTimeout(flush, delayMs); - } else { - queueMicrotask(flush); - } -} -function newDocumentId(now) { - return `${now.toString(36)}-${Math.random().toString(36).slice(2, 10)}`; -} -function isCallable(value) { - return typeof value === "function"; -} - // src/shared/plugins/declarative/runtime/declarative-host-messages.ts function readHostMessage(payload) { if (typeof payload !== "object" || payload === null) { @@ -816,6 +810,47 @@ function readStoredValues(raw) { return values; } +// src/shared/plugins/declarative/runtime/declarative-act-snapshot.ts +function actSnapshotSubscriptions(on2, document2) { + let restore = null; + const ours = (payload) => readHostMessage(payload).document === document2; + return [ + on2(PLUGIN_DECLARATIVE_MESSAGES.snapshot, (payload) => { + if (ours(payload)) { + restore = captureAtomValues(); + } + }), + on2(PLUGIN_DECLARATIVE_MESSAGES.restore, (payload) => { + if (ours(payload) && restore) { + const pending = restore; + restore = null; + pending(); + } + }) + ]; +} + +// src/shared/plugins/declarative/runtime/declarative-renderer-support.ts +var MIN_RENDER_INTERVAL_MS = 16; +var MAX_RETAINED_RENDERS = 32; +var HYDRATION_TIMEOUT_MS = 3e3; +function errorMessage(error) { + return describePluginError(error).slice(0, 4096); +} +function defaultSchedule(flush, delayMs) { + if (delayMs > 0) { + setTimeout(flush, delayMs); + } else { + queueMicrotask(flush); + } +} +function newDocumentId(now) { + return `${now.toString(36)}-${Math.random().toString(36).slice(2, 10)}`; +} +function isCallable(value) { + return typeof value === "function"; +} + // src/shared/plugins/declarative/runtime/declarative-panel-context.ts function createPanelContext(onRetain) { const visibility = hostAtom(true); @@ -1121,6 +1156,7 @@ function createOrcaDeclarativeRuntime(options) { bridge.on(PLUGIN_DECLARATIVE_MESSAGES.ack, acknowledge), bridge.on(PLUGIN_DECLARATIVE_MESSAGES.hydrate, panel.hydrate), bridge.on(PLUGIN_DECLARATIVE_MESSAGES.visibility, panel.setVisibility), + ...actSnapshotSubscriptions(bridge.on.bind(bridge), document2), bridge.on("theme", (payload) => { const { colorScheme } = readHostMessage(payload); if ((colorScheme === "light" || colorScheme === "dark") && read(theme.atom).colorScheme !== colorScheme) { diff --git a/resources/plugins/declarative/orca-testing.mjs b/resources/plugins/declarative/orca-testing.mjs index 059405fe14b..28e99fe4e52 100644 --- a/resources/plugins/declarative/orca-testing.mjs +++ b/resources/plugins/declarative/orca-testing.mjs @@ -61,4 +61,4 @@ ${u}`:u:"",l=Function,p=`return (input) => { ${u} }`,m;try{m=new l(...a,p)(...s)}catch(f){throw new M(`this schema (generated code failed to evaluate: ${f.message})`)}return n?.debug&&(m.code=c),m.definite=o.definite,m}function D(e,n){for(let[o,t]of e.constants)if(t===n)return o;let i=`c${e.constantCounter++}`;return e.constants.set(i,n),i}function ft(e,n){return e.definite=!1,D(e,n)}function z(e){return`v${e.varCounter++}`}function M$(e,n){let i=e._zod.run({value:n,issues:[]},{});if(i&&typeof i.then=="function")return ce;let o=i;return o.issues.length===0?o.value:ce}function ae(e,n,i,o,t=!0){let r=e.content.length,a=n.constants.size,s=n.constantCounter,u=n.varCounter;try{return q(e,n,i,o,t)}catch(c){if(!(c instanceof M)||!c.islandable)throw c;if(e.content.length=r,n.constants.size>a){let l=Array.from(n.constants.keys()).slice(a);for(let p of l)n.constants.delete(p)}return n.constantCounter=s,n.varCounter=u,Z$(e,n,i,o)}}function Z$(e,n,i,o){n.definite=!1;let t=D(n,i),r=D(n,M$),a=z(n);return e.write(`const ${a} = ${r}(${t}, ${o});`),e.write(`if (${a} === INVALID) return INVALID;`),a}var V$=new Set(["max_size","min_size","size_equals","max_length","min_length","length_equals"]);function F$(e,n,i,o){let t=i._zod.def.checks;if(!t||t.length===0)return o;let r=o;for(let a of t){let s=a._zod.def;if(s.when&&!V$.has(s.check))throw new M('check with a custom "when" condition');switch(s.check){case"greater_than":G$(e,n,s,r);break;case"less_than":B$(e,n,s,r);break;case"multiple_of":J$(e,n,s,r);break;case"number_format":sf(e,s,r);break;case"min_length":{let u=He(s.minimum,"min_length"),c=Fu(e,n,r,`${r}.length >= ${u} && ${r}.length < ${s.minimum*2}`);e.write(`if (${c} < ${u}) return INVALID;`);break}case"max_length":{let u=He(s.maximum,"max_length"),c=Fu(e,n,r,`${r}.length > ${u}`);e.write(`if (${c} > ${u}) return INVALID;`);break}case"length_equals":{let u=He(s.length,"length_equals"),c=Fu(e,n,r,`${r}.length >= ${u} && ${r}.length <= ${s.length*2}`);e.write(`if (${c} !== ${u}) return INVALID;`);break}case"min_size":e.write(`if (${r}.size < ${He(s.minimum,"min_size")}) return INVALID;`);break;case"max_size":e.write(`if (${r}.size > ${He(s.maximum,"max_size")}) return INVALID;`);break;case"size_equals":e.write(`if (${r}.size !== ${He(s.size,"size_equals")}) return INVALID;`);break;case"string_format":r=uf(e,n,s,r);break;case"custom":r=Y$(e,n,a,r);break;case"bigint_format":K$(e,s,r);break;case"mime_type":H$(e,n,s,r);break;case"property":X$(e,n,s,r);break;case"properties":W$(e,n,s,r);break;case"overwrite":{let u=z(n);q$(e,n,a,r,u),r=u;break}default:throw new M(`check type ${s.check}`)}}return r}function Fu(e,n,i,o){let t=D(n,ct),r=z(n);return e.write(`const ${r} = typeof ${i} === "string" && ${o} ? ${t}(${i}) : ${i}.length;`),r}function He(e,n){if(typeof e!="number"||!Number.isFinite(e))throw new M(`${n} bound of type ${typeof e}`);return`${e}`}function af(e,n){if(typeof n=="bigint")return`${n}n`;if(typeof n=="number"){if(Number.isNaN(n))throw new M("comparison check with NaN bound");return`${n}`}if(n instanceof Date){if(Number.isNaN(n.getTime()))throw new M("comparison check with Invalid Date bound");return D(e,n)}throw new M(`comparison check bound of type ${typeof n}`)}function G$(e,n,i,o){let t=i.inclusive?"<":"<=";e.write(`if (${o} ${t} ${af(n,i.value)}) return INVALID;`)}function B$(e,n,i,o){let t=i.inclusive?">":">=";e.write(`if (${o} ${t} ${af(n,i.value)}) return INVALID;`)}function J$(e,n,i,o){if(typeof i.value=="bigint"){if(i.value===BigInt(0))throw new M("multiple_of check with a zero divisor");e.write(`if (${o} % ${i.value}n !== 0n) return INVALID;`)}else{let t=D(n,wn);e.write(`if (${t}(${o}, ${He(i.value,"multiple_of")}) !== 0) return INVALID;`)}}function sf(e,n,i){let o=n.format;switch(o){case"safeint":e.write(`if (!Number.isSafeInteger(${i})) return INVALID;`);break;case"int32":e.write(`if (!Number.isInteger(${i}) || ${i} < -2147483648 || ${i} > 2147483647) return INVALID;`);break;case"uint32":e.write(`if (!Number.isInteger(${i}) || ${i} < 0 || ${i} > 4294967295) return INVALID;`);break;case"float32":e.write(`if (!Number.isFinite(${i}) || ${i} < -3.4028234663852886e38 || ${i} > 3.4028234663852886e38) return INVALID;`);break;case"float64":e.write(`if (!Number.isFinite(${i})) return INVALID;`);break;default:throw new M(`number format ${o}`)}}function K$(e,n,i){let o=n.format;if(o)switch(o){case"int64":e.write(`if (${i} < -9223372036854775808n || ${i} > 9223372036854775807n) return INVALID;`);break;case"uint64":e.write(`if (${i} < 0n || ${i} > 18446744073709551615n) return INVALID;`);break;default:throw new M(`bigint format ${o}`)}}function H$(e,n,i,o){let t=i.mime;if(t&&t.length>0){let r=D(n,new Set(t));e.write(`if (!${r}.has(${o}.type)) return INVALID;`)}}function W$(e,n,i,o){if(i.when)throw new M('check with a custom "when" condition');e.write(`if (${o} == null) return INVALID;`);let t=i.shape;for(let r of Reflect.ownKeys(t)){let a=typeof r=="symbol"?D(n,r):se(r),s=z(n);e.write(`const ${s} = ${o}[${a}];`),ae(e,n,t[r],s,!1)}}function X$(e,n,i,o){let t=`${o}[${JSON.stringify(i.property)}]`;q(e,n,i.schema,t)}function q$(e,n,i,o,t){let r=i._zod.def.tx;if(!r)throw new M("overwrite check without a transform function");if(gt(r))throw new Pe("z.compile: async overwrite transforms are not supported");let a=D(n,r);e.write(`const ${t} = ${a}(${o});`)}function Gu(){throw new ve}function Ku(e){this.issues.push(e)}function Y$(e,n,i,o){let t=i._zod.def;if(t.fn){if(gt(t.fn))throw new Pe("z.compile: async .refine() predicates are not supported");let r=ft(n,t.fn),a=D(n,Gu),s=z(n);return e.write(`const ${s} = ${r}(${o});`),e.write(`if (${s} instanceof Promise) ${a}();`),e.write(`if (!${s}) return INVALID;`),o}if(i._zod.check){if(gt(i._zod.check))throw new Pe("z.compile: async .superRefine() / check functions are not supported");let r=i._zod.check,s=ft(n,c=>{let l={value:c,issues:[],addIssue:Ku};return r(l)instanceof Promise&&Gu(),l.issues.length===0?l.value:ce}),u=z(n);return e.write(`const ${u} = ${s}(${o});`),e.write(`if (${u} === INVALID) return INVALID;`),u}throw new M("custom check without a predicate or check function")}var Q$=new Set(["cidrv4","cuid","cuid2","date","datetime","duration","e164","email","emoji","ends_with","guid","includes","ipv4","ksuid","lowercase","mac","nanoid","regex","starts_with","time","ulid","uppercase","uuid","xid"]);function uf(e,n,i,o,t=!0){let r=i.format;if(r==="base64"){let c=D(n,Bn);return e.write(`if (!${c}(${o})) return INVALID;`),o}if(r==="base64url"){let c=D(n,li);return e.write(`if (!${c}(${o})) return INVALID;`),o}if(r==="jwt"){let c=D(n,mi),l=D(n,i.alg??null);return e.write(`if (!${c}(${o}, ${l})) return INVALID;`),o}if(r==="ipv6"){let c=D(n,Gn);return e.write(`if (!${c}(${o})) return INVALID;`),o}if(r==="cidrv6"){let c=D(n,ui);return e.write(`if (!${c}(${o})) return INVALID;`),o}if(r==="credit_card"){let c=D(n,di);return e.write(`if (!${c}(${o})) return INVALID;`),o}if(r==="iban"){let c=D(n,pi);return e.write(`if (!${c}(${o})) return INVALID;`),o}let a=i;if(r==="url"||r==="httpurl"||a.normalize||a.hostname!==void 0||a.protocol!==void 0){let c=D(n,oi),l=D(n,i),p=z(n),m=z(n);if(e.write(`const ${p} = ${o}.trim();`),e.write(`const ${m} = ${c}(${p}, ${l});`),e.write(`if (typeof ${m} === "number") return INVALID;`),a.hostname!==void 0){let h=D(n,ai);e.write(`if (!${h}(${m}, ${l}.hostname)) return INVALID;`)}if(a.protocol!==void 0){let h=D(n,si);e.write(`if (!${h}(${m}, ${l}.protocol)) return INVALID;`)}if(!t)return null;let f=z(n),g=a.normalize?`${m}.href`:`${D(n,Fn)}(${p})`;return e.write(`const ${f} = ${g};`),f}let s=i.fn;if(s){if(gt(s))throw new M(`async string format ${r}`);let c=D(n,s);return e.write(`if (!${c}(${o})) return INVALID;`),o}if(Q$.has(r)&&i.pattern){let c=D(n,i.pattern);return e.write(`${c}.lastIndex = 0;`),e.write(`if (!${c}.test(${o})) return INVALID;`),o}let u=i.format;switch(u){case"regex":throw new M("regex format without a pattern");case"lowercase":e.write(`if (${o} !== ${o}.toLowerCase()) return INVALID;`);break;case"uppercase":e.write(`if (${o} !== ${o}.toUpperCase()) return INVALID;`);break;case"includes":e.write(`if (!${o}.includes(${se(i.includes)})) return INVALID;`);break;case"starts_with":{let c=i.prefix;e.write(`if (${o}.slice(0, ${c.length}) !== ${se(c)}) return INVALID;`);break}case"ends_with":{let c=i.suffix;e.write(`if (${o}.slice(-${c.length}) !== ${se(c)}) return INVALID;`);break}default:throw new M(`string format ${u}`)}return o}function q(e,n,i,o,t=!0){let r=i._zod.def,a=r.type;if(r.coerce)throw new M(`coercion (z.coerce.${a}())`);let s=t||!!r.checks?.length,u;switch(a){case"string":u=e_(e,n,i,o,s);break;case"number":u=t_(e,i,o);break;case"boolean":u=n_(e,o);break;case"bigint":u=r_(e,i,o);break;case"symbol":u=i_(e,o);break;case"undefined":u=o_(e,o);break;case"null":u=a_(e,o);break;case"any":case"unknown":u=o;break;case"never":e.write("return INVALID;"),u=o;break;case"void":u=s_(e,o);break;case"nan":u=u_(e,o);break;case"date":u=c_(e,o);break;case"object":u=l_(e,n,i,o,s);break;case"optional":u=d_(e,n,i,o,s);break;case"nullable":u=f_(e,n,i,o,s);break;case"array":u=g_(e,n,i,o,s);break;case"literal":u=v_(e,n,i,o);break;case"enum":u=h_(e,n,i,o);break;case"readonly":{let c=nf(e,n,i,o),l=z(n);e.write(`const ${l} = Object.freeze(${c});`),u=l;break}case"success":nf(e,n,i,o),u="true";break;case"default":case"prefault":u=y_(e,n,i,o);break;case"nonoptional":u=b_(e,n,i,o);break;case"tuple":u=$_(e,n,i,o);break;case"union":u=__(e,n,i,o);break;case"intersection":u=I_(e,n,i,o);break;case"record":u=w_(e,n,i,o);break;case"map":u=P_(e,n,i,o);break;case"set":u=A_(e,n,i,o);break;case"file":u=T_(e,o);break;case"template_literal":u=z_(e,n,i,o);break;case"lazy":u=N_(e,n,i,o);break;case"pipe":u=E_(e,n,i,o);break;case"custom":u=O_(e,n,i,o);break;case"transform":u=U_(e,n,i,o);break;case"catch":u=j_(e,n,i,o);break;default:throw new M(`schema type ${a}`)}return u===null?null:F$(e,n,i,u)}function e_(e,n,i,o,t=!0){e.write(`if (typeof ${o} !== "string") return INVALID;`);let r=i._zod.def;return r.format===void 0?o:uf(e,n,r,o,t)}function t_(e,n,i){e.write(`if (typeof ${i} !== "number" || !Number.isFinite(${i})) return INVALID;`);let o=n._zod.def;return o.check==="number_format"&&o.format&&sf(e,{format:o.format},i),i}function n_(e,n){return e.write(`if (typeof ${n} !== "boolean") return INVALID;`),n}function r_(e,n,i){e.write(`if (typeof ${i} !== "bigint") return INVALID;`);let o=n._zod.def;if(o.format)switch(o.format){case"int64":e.write(`if (${i} < -9223372036854775808n || ${i} > 9223372036854775807n) return INVALID;`);break;case"uint64":e.write(`if (${i} < 0n || ${i} > 18446744073709551615n) return INVALID;`);break}return i}function i_(e,n){return e.write(`if (typeof ${n} !== "symbol") return INVALID;`),n}function o_(e,n){return e.write(`if (${n} !== undefined) return INVALID;`),n}function a_(e,n){return e.write(`if (${n} !== null) return INVALID;`),n}function s_(e,n){return e.write(`if (${n} !== undefined) return INVALID;`),n}function u_(e,n){return e.write(`if (typeof ${n} !== "number" || !Number.isNaN(${n})) return INVALID;`),n}function c_(e,n){return e.write(`if (!(${n} instanceof Date) || Number.isNaN(${n}.getTime())) return INVALID;`),n}function l_(e,n,i,o,t=!0){let r=i._zod.def;e.write(`if (typeof ${o} !== "object" || ${o} === null || Array.isArray(${o})) return INVALID;`);let a=r.shape,s=Object.keys(a),u=Object.getOwnPropertySymbols(a),c=u.length?[...s,...u]:s,l=I=>typeof I=="symbol"?D(n,I):se(I),p=I=>typeof I=="symbol"?`[${l(I)}]`:se(I),m=a;if(s.includes("__proto__"))throw new M('object shape key "__proto__"');let f=new Map;for(let I of c){let A=m[I],C=l(I),V=z(n);if(e.write(`const ${V} = ${o}[${C}];`),A._zod.optin!==void 0){let w=z(n);e.write(`let ${w} = (() => {`),e.indented(T=>{let E=ae(T,n,A,V);T.write(`return ${E};`)}),e.write("})();"),A._zod.optout==="optional"?(e.write(`if (${w} === INVALID) {`),e.indented(T=>{T.write(`if (${C} in ${o}) return INVALID;`),T.write(`${w} = undefined;`)}),e.write("}")):e.write(`if (${w} === INVALID) return INVALID;`),f.set(I,w)}else{m_(A)&&e.write(`if (!(${C} in ${o})) return INVALID;`);let w=ae(e,n,A,V,t);w!==null&&f.set(I,w)}}let g=r.catchall,h="none";if(g){let I=g._zod.def.type;if(I==="never"){let A=s.map(C=>`k !== ${se(C)}`).join(" && ")||"true";e.write(`for (const k in ${o}) {`),e.indented(C=>{C.write(`if (${A}) return INVALID;`)}),e.write("}")}else(I==="unknown"||I==="any")&&!g._zod.def.checks?.length?h="passthrough":h="schema"}let k=z(n),x=c.some(I=>tf(m[I])||Bu(m[I]));if(!t){if(h==="schema"){let I=s.length>0?D(n,new Set(s)):null;e.write(`for (const k in ${o}) {`),e.indented(A=>{A.write('if (k === "__proto__") continue;'),I&&A.write(`if (${I}.has(k)) continue;`);let C=z(n);A.write(`const ${C} = ${o}[k];`),ae(A,n,g,C,!1)}),e.write("}")}return null}if(x){e.write(`const ${k} = {};`);for(let I of c){let A=l(I),C=f.get(I);Bu(m[I])?e.write(`if (${A} in ${o}) ${k}[${A}] = ${C};`):tf(m[I])?e.write(`if (${C} !== undefined || ${A} in ${o}) ${k}[${A}] = ${C};`):e.write(`${k}[${A}] = ${C};`)}}else{let I=c.map(A=>`${p(A)}: ${f.get(A)}`).join(", ");e.write(`const ${k} = { ${I} };`)}if(h!=="none"){let I=s.length>0?D(n,new Set(s)):null;e.write(`for (const k in ${o}) {`),e.indented(A=>{if(A.write('if (k === "__proto__") continue;'),I&&A.write(`if (${I}.has(k)) continue;`),h==="passthrough")A.write(`${k}[k] = ${o}[k];`);else{let C=z(n);A.write(`const ${C} = ${o}[k];`);let V=ae(A,n,g,C);A.write(`${k}[k] = ${V};`)}}),e.write("}")}return k}function d_(e,n,i,o,t=!0){let r=i._zod.def;if(p_(i))return q(e,n,r.innerType,o,t);if(r.innerType._zod.optin==="defaulted"){let s=z(n),u=z(n);return e.write(`let ${s};`),e.write(`if (${o} === undefined) {`),e.indented(c=>{c.write(`const ${u} = (() => {`),c.indented(l=>{let p=q(l,n,r.innerType,o);l.write(`return ${p};`)}),c.write("})();"),c.write(`if (${u} !== INVALID) ${s} = ${u};`)}),e.write("} else {"),e.indented(c=>{let l=q(c,n,r.innerType,o);c.write(`${s} = ${l};`)}),e.write("}"),s}let a=t?z(n):null;return a&&e.write(`let ${a};`),e.write(`if (${o} !== undefined) {`),e.indented(s=>{let u=q(s,n,r.innerType,o,t);a&&u!==null&&s.write(`${a} = ${u};`)}),e.write("}"),a}function p_(e){return e._zod.traits?.has("$ZodExactOptional")===!0}function m_(e){return e._zod.optin===void 0&&mt(e)}function mt(e){if(e._zod.def.coerce)return!0;let n=e._zod.def;switch(n.type){case"any":case"unknown":case"undefined":case"void":case"default":case"prefault":case"transform":case"custom":case"lazy":return!0;case"string":case"number":case"boolean":case"bigint":case"symbol":case"null":case"never":case"nan":case"date":case"object":case"array":case"tuple":case"record":case"map":case"set":case"file":case"template_literal":return!1;case"nonoptional":return n.innerType?mt(n.innerType):!1;case"literal":return!!n.values?.includes(void 0);case"enum":return!!e._zod.values?.has(void 0);case"optional":case"nullable":case"readonly":case"success":return n.innerType?mt(n.innerType):!0;case"catch":return!0;case"union":return n.options?n.options.some(mt):!0;case"intersection":return!n.left||!n.right?!0:mt(n.left)&&mt(n.right);case"pipe":return n.in?mt(n.in):!0;default:return!0}}function Bu(e){return e._zod.optin==="optional"&&e._zod.optout==="optional"}function tf(e){return(e._zod.optin!=="defaulted"||e._zod.optout==="optional")&&Bt(e)}function Bt(e){let n=e._zod.def;switch(n.type){case"string":case"number":case"boolean":case"bigint":case"symbol":case"null":case"nan":case"date":case"object":case"array":case"tuple":case"record":case"map":case"set":case"file":case"template_literal":case"never":case"success":return!1;case"literal":return!!n.values?.includes(void 0);case"enum":return!!e._zod.values?.has(void 0);case"optional":return!0;case"nullable":case"readonly":case"nonoptional":return n.innerType?Bt(n.innerType):!0;case"union":return n.options?n.options.some(Bt):!0;case"intersection":return!n.left||!n.right||Bt(n.left)||Bt(n.right);case"pipe":return n.out?Bt(n.out):!0;default:return!0}}function f_(e,n,i,o,t=!0){let r=i._zod.def,a=t?z(n):null;return a&&e.write(`let ${a} = null;`),e.write(`if (${o} !== null) {`),e.indented(s=>{let u=q(s,n,r.innerType,o,t);a&&u!==null&&s.write(`${a} = ${u};`)}),e.write("}"),a}function Hu(e,n,i){for(let[o,t]of jt(n._zod.def.checks))e.write(`if (${i} > ${He(o,t._zod.def.check)}) return INVALID;`)}function g_(e,n,i,o,t=!0){let r=i._zod.def;e.write(`if (!Array.isArray(${o})) return INVALID;`),Hu(e,i,`${o}.length`);let a=t?z(n):null,s=z(n),u=z(n);return a&&e.write(`const ${a} = new Array(${o}.length);`),e.write(`for (let ${s} = 0; ${s} < ${o}.length; ${s}++) {`),e.indented(c=>{c.write(`const ${u} = ${o}[${s}];`);let l=ae(c,n,r.element,u,t);a&&l!==null&&c.write(`${a}[${s}] = ${l};`)}),e.write("}"),a}function v_(e,n,i,o){let r=i._zod.def.values;if(r.length!==1){let s=D(n,new Set(r));return e.write(`if (!${s}.has(${o})) return INVALID;`),o}let a=r[0];if(typeof a=="number"&&Number.isNaN(a)){let s=D(n,new Set(r));return e.write(`if (!${s}.has(${o})) return INVALID;`),o}if(typeof a=="string")e.write(`if (${o} !== ${se(a)}) return INVALID;`);else if(typeof a=="number"||typeof a=="boolean")e.write(`if (${o} !== ${a}) return INVALID;`);else if(a===null)e.write(`if (${o} !== null) return INVALID;`);else if(a===void 0)e.write(`if (${o} !== undefined) return INVALID;`);else if(typeof a=="bigint")e.write(`if (${o} !== ${a}n) return INVALID;`);else throw new M(`literal type ${typeof a}`);return o}function h_(e,n,i,o){let t=i._zod.values;if(!t)throw new M("enum schema without enumerated values");let r=D(n,t);return e.write(`if (!${r}.has(${o})) return INVALID;`),o}function nf(e,n,i,o){let t=i._zod.def;return q(e,n,t.innerType,o)}function y_(e,n,i,o){let t=i._zod.def,a=Object.getOwnPropertyDescriptor(i._zod.def,"defaultValue")?()=>i._zod.def.defaultValue:void 0;if(i._zod.def.type==="prefault"){if(!a)return q(e,n,t.innerType,o);let u=D(n,a),c=z(n);return e.write(`let ${c} = ${o};`),e.write(`if (${o} === undefined) ${c} = ${u}();`),q(e,n,t.innerType,c)}let s=z(n);if(a){let u=D(n,a),c=D(n,Sn);e.write(`let ${s};`),e.write(`if (${o} === undefined) {`),e.indented(l=>{l.write(`${s} = ${c}(${u}());`)}),e.write("} else {"),e.indented(l=>{let p=q(l,n,t.innerType,o);l.write(`${s} = ${p} === undefined ? ${c}(${u}()) : ${p};`)}),e.write("}")}else e.write(`let ${s};`),e.write(`if (${o} !== undefined) {`),e.indented(u=>{let c=q(u,n,t.innerType,o);u.write(`${s} = ${c};`)}),e.write("}");return s}function b_(e,n,i,o){let t=i._zod.def,r=q(e,n,t.innerType,o),a=z(n);return e.write(`const ${a} = ${r};`),e.write(`if (${a} === undefined) return INVALID;`),a}function $_(e,n,i,o){let t=i._zod.def,r=t.items,a=t.rest;e.write(`if (!Array.isArray(${o})) return INVALID;`);let s=rf(r,"optin"),u=rf(r,"optout");a?e.write(`if (${o}.length < ${s}) return INVALID;`):e.write(`if (${o}.length < ${s} || ${o}.length > ${r.length}) return INVALID;`);let c=z(n);e.write(`const ${c} = [];`);for(let l=0;l=u)e.write(`if (${c}.length === ${l}) {`),e.indented(m=>{m.write(`if (${l} < ${o}.length) {`),m.indented(f=>{let g=z(n);f.write(`const ${g} = ${o}[${l}];`);let h=ae(f,n,p,g);f.write(`${c}[${l}] = ${h};`)}),m.write("} else {"),m.indented(f=>{if(Bu(p)){f.write(`${c}.length = ${l};`);return}let g=z(n),h=z(n);f.write(`const ${g} = undefined;`),f.write(`const ${h} = (() => {`),f.indented(k=>{let x=ae(k,n,p,g);k.write(`return ${x};`)}),f.write("})();"),f.write(`if (${h} === INVALID || ${h} === undefined) ${c}.length = ${l};`),f.write(`else ${c}[${l}] = ${h};`)}),m.write("}")}),e.write("}");else{let m=z(n);e.write(`const ${m} = ${o}[${l}];`);let f=ae(e,n,p,m);e.write(`${c}[${l}] = ${f};`)}}if(a){let l=z(n),p=z(n);e.write(`for (let ${l} = ${r.length}; ${l} < ${o}.length; ${l}++) {`),e.indented(m=>{m.write(`const ${p} = ${o}[${l}];`);let f=ae(m,n,a,p);m.write(`${c}[${l}] = ${f};`)}),e.write("}")}return c}function rf(e,n){for(let i=e.length-1;i>=0;i--)if(!(n==="optin"?e[i]._zod.optin!==void 0:e[i]._zod.optout==="optional"))return i+1;return 0}function __(e,n,i,o){let t=i._zod.def,r=t.options;if(t.discriminator)return k_(e,n,t,o);if(t.inclusive===!1)throw new M("exclusive unions (z.xor)");if(r.length===0)return e.write("return INVALID;"),o;if(r.length===1)return q(e,n,r[0],o);if(r.every(u=>u._zod.def.type==="literal"&&!u._zod.def.checks?.length)){let u=new Set(r.flatMap(l=>l._zod.def.values)),c=D(n,u);return e.write(`if (!${c}.has(${o})) return INVALID;`),o}let s=z(n);e.write(`let ${s};`);for(let u=0;u {`):e.write(`if (${s} === INVALID) ${s} = (() => {`),e.indented(l=>{let p=q(l,n,c,o);l.write(`return ${p};`)}),e.write("})();")}return e.write(`if (${s} === INVALID) return INVALID;`),s}function k_(e,n,i,o){if(i.unionFallback)throw new M("discriminated union with unionFallback");if(i.options.length===0)return e.write("return INVALID;"),o;let t=z(n),r=z(n);e.write(`const ${t} = ${o}?.[${se(i.discriminator)}];`),e.write(`let ${r};`);let a=!0,s=new Set;for(let u of i.options){let c=u._zod.propValues?.[i.discriminator];if(!c||c.size===0)throw new M("discriminated union option without static discriminator values");for(let m of c){if(s.has(m))throw new M(`duplicate discriminator value ${String(m)}`);s.add(m)}let l=Array.from(c,m=>x_(n,t,m)),p=a?"if":"else if";e.write(`${p} (${l.join(" || ")}) {`),e.indented(m=>{let f=q(m,n,u,o);m.write(`${r} = ${f};`)}),e.write("}"),a=!1}return e.write("else { return INVALID; }"),r}function x_(e,n,i){if(typeof i=="string")return`${n} === ${se(i)}`;if(typeof i=="number")return Number.isNaN(i)?`Number.isNaN(${n})`:`${n} === ${i}`;if(typeof i=="boolean")return`${n} === ${i}`;if(i===null)return`${n} === null`;if(i===void 0)return`${n} === undefined`;if(typeof i=="bigint")return`${n} === ${i}n`;if(typeof i=="symbol"){let o=D(e,i);return`${n} === ${o}`}throw new M(`literal discriminator value ${String(i)}`)}function I_(e,n,i,o){let t=i._zod.def;n.definite=!1;let r=ae(e,n,t.left,o),a=ae(e,n,t.right,o),s=D(n,Vt),u=z(n);return e.write(`const ${u} = ${s}(${r}, ${a});`),e.write(`if (!${u}.valid) return INVALID;`),`${u}.data`}function w_(e,n,i,o){let t=i._zod.def,r=D(n,_e);e.write(`if (!${r}(${o})) return INVALID;`);let a=z(n),s=z(n),u=z(n);e.write(`const ${a} = {};`);let c=t,l=c.partial?void 0:t.keyType._zod.values;if(l){let f=[];for(let h of l){if(!(typeof h=="string"||typeof h=="number"||typeof h=="symbol"))throw new M(`record key value ${String(h)}`);let k=typeof h=="number"?h.toString():h;if(k==="__proto__")throw new M('record key "__proto__"');f.push(k);let x=D(n,h),I=q(e,n,t.keyType,x),A=z(n);e.write(`const ${A} = ${o}[${S_(n,k)}];`);let C=ae(e,n,t.valueType,A);e.write(`${a}[${I}] = ${C};`)}let g=D(n,new Set(f));return e.write(`for (const ${s} in ${o}) {`),e.indented(h=>{h.write(`if (${g}.has(${s})) continue;`),c.mode==="loose"?h.write(`if (${s} !== "__proto__") ${a}[${s}] = ${o}[${s}];`):h.write("return INVALID;")}),e.write("}"),a}let p=t.keyType._zod.def;if(!(p.type==="string"&&p.format===void 0&&!p.coerce&&(p.checks?.length??0)===0)){let f=t.mode==="loose",g=Ni(t.keyType);g.definite===!1&&(n.definite=!1);let h=D(n,g),k=D(n,Me),x=z(n);return of(e,n,o,s,I=>{I.write(`let ${x} = ${h}(${s});`),I.write(`if (${x} === INVALID && typeof ${s} === "string" && ${k}.test(${s})) ${x} = ${h}(Number(${s}));`),f?I.write(`if (${x} === INVALID) { ${a}[${s}] = ${o}[${s}]; continue; }`):I.write(`if (${x} === INVALID) return INVALID;`),I.write(`if (${x} === "__proto__") continue;`);let A=z(n);I.write(`const ${A} = ${o}[${s}];`);let C=ae(I,n,t.valueType,A);I.write(`${a}[${x}] = ${C};`)}),a}return of(e,n,o,s,f=>{f.write(`const ${u} = ${o}[${s}];`);let g=ae(f,n,t.valueType,u);f.write(`${a}[${s}] = ${g};`)},"return INVALID;"),a}function of(e,n,i,o,t,r){let a=D(n,Object.prototype.propertyIsEnumerable),s=z(n),u=z(n),c=z(n);e.write(`const ${s} = Object.getOwnPropertySymbols(${i});`),e.write(`const ${u} = Object.getOwnPropertyNames(${i});`),e.write(`for (let ${c} = 0; ${c} < ${u}.length; ${c}++) {`),e.indented(l=>{l.write(`const ${o} = ${u}[${c}];`),l.write(`if (${o} === "__proto__" || !${a}.call(${i}, ${o})) continue;`),t(l)}),e.write("}"),e.write(`for (let ${c} = 0; ${c} < ${s}.length; ${c}++) {`),e.indented(l=>{l.write(`const ${o} = ${s}[${c}];`),l.write(`if (!${a}.call(${i}, ${o})) continue;`),r?l.write(r):t(l)}),e.write("}")}function S_(e,n){return typeof n=="string"?se(n):D(e,n)}function P_(e,n,i,o){let t=i._zod.def;e.write(`if (!(${o} instanceof Map)) return INVALID;`),Hu(e,i,`${o}.size`);let r=z(n),a=z(n),s=z(n);return e.write(`const ${r} = new Map();`),e.write(`for (const [${a}, ${s}] of ${o}) {`),e.indented(u=>{let c=q(u,n,t.keyType,a),l=q(u,n,t.valueType,s);u.write(`${r}.set(${c}, ${l});`)}),e.write("}"),r}function A_(e,n,i,o){let t=i._zod.def;e.write(`if (!(${o} instanceof Set)) return INVALID;`),Hu(e,i,`${o}.size`);let r=z(n),a=z(n);return e.write(`const ${r} = new Set();`),e.write(`for (const ${a} of ${o}) {`),e.indented(s=>{let u=q(s,n,t.valueType,a);s.write(`${r}.add(${u});`)}),e.write("}"),r}function T_(e,n){return e.write(`if (!(${n} instanceof File)) return INVALID;`),n}function z_(e,n,i,o){e.write(`if (typeof ${o} !== "string") return INVALID;`);let t=i._zod.pattern;if(t){let r=D(n,t);e.write(`${r}.lastIndex = 0;`),e.write(`if (!${r}.test(${o})) return INVALID;`)}return o}function N_(e,n,i,o){let t=i._zod.def,r=ft(n,t.getter),a=D(n,{parser:null});e.write(`if (!${a}.parser) {`),e.indented(u=>{u.write(`const inner = ${r}();`),u.write(`${a}.parser = function(input) {`),u.indented(c=>{c.write("const result = inner._zod.run({ value: input, issues: [] }, {});"),c.write("return result.issues.length === 0 ? result.value : INVALID;")}),u.write("};")}),e.write("}");let s=z(n);return e.write(`const ${s} = ${a}.parser(${o});`),e.write(`if (${s} === INVALID) return INVALID;`),s}function E_(e,n,i,o){let t=i._zod.def,r=q(e,n,t.in,o);if(t.transform){if(gt(t.transform))throw new Pe("z.compile: async transforms in pipes are not supported");let a=t.transform,u=ft(n,l=>{let p={value:l,issues:[],addIssue:Ku},m=a(l,p);return m instanceof Promise?ce:p.issues.length===0?m:ce}),c=z(n);return e.write(`const ${c} = ${u}(${r});`),e.write(`if (${c} === INVALID) return INVALID;`),q(e,n,t.out,c)}else return q(e,n,t.out,r)}function gt(e){return typeof e=="function"&&(e.constructor.name==="AsyncFunction"||e[Symbol.toStringTag]==="AsyncFunction")}function O_(e,n,i,o){let t=i._zod.def;if(t.fn){if(gt(t.fn))throw new Pe("z.compile: async custom predicates are not supported");let r=ft(n,t.fn),a=D(n,Gu),s=z(n);e.write(`const ${s} = ${r}(${o});`),e.write(`if (${s} instanceof Promise) ${a}();`),e.write(`if (!${s}) return INVALID;`)}else throw new M("custom schema without a predicate function");return o}function D_(e,n,i){let o=e._zod.run({value:i,issues:[]},{});if(o&&typeof o.then=="function")return ce;let t=o;return t.issues.length===0?t.value:n()}function j_(e,n,i,o){let t=i._zod.def;if(!t.catchValue[Ur])throw new M("catch with a callback (only a constant catch value compiles)",!1);let r=z(n);e.write(`let ${r} = (() => {`),e.indented(c=>{let l=ae(c,n,t.innerType,o);c.write(`return ${l};`)}),e.write("})();");let a=D(n,t.innerType),s=ft(n,t.catchValue),u=D(n,D_);return e.write(`if (${r} === INVALID) {`),e.indented(c=>{c.write(`${r} = ${u}(${a}, ${s}, ${o});`),c.write(`if (${r} === INVALID) return INVALID;`)}),e.write("}"),r}function U_(e,n,i,o){let t=i._zod.def;if(t.transform){if(gt(t.transform))throw new Pe("z.compile: async transforms are not supported");let r=t.transform,s=ft(n,c=>{let l={value:c,issues:[],addIssue:Ku},p=r(c,l);return p instanceof Promise?ce:l.issues.length===0?p:ce}),u=z(n);return e.write(`const ${u} = ${s}(${o});`),e.write(`if (${u} === INVALID) return INVALID;`),u}return o}function Ei(e){return e.checks&&(e.checks=[...e.checks]),e}function Wu(e,n){return new e(Ei({type:"string",...S(n)}))}function Xu(e,n){return new e(Ei({type:"string",coerce:!0,...S(n)}))}function Oi(e,n){return new e({type:"string",format:"email",check:"string_format",abort:!1,...S(n)})}function Di(e,n){return new e({type:"string",format:"guid",check:"string_format",abort:!1,...S(n)})}function ji(e,n){return new e({type:"string",format:"uuid",check:"string_format",abort:!1,...S(n)})}function Ui(e,n){return new e({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v4",...S(n)})}function Ci(e,n){return new e({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v6",...S(n)})}function Li(e,n){return new e({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v7",...S(n)})}function nr(e,n){return new e({type:"string",format:"url",check:"string_format",abort:!1,...S(n)})}function Ri(e,n){return new e({type:"string",format:"emoji",check:"string_format",abort:!1,...S(n)})}function Mi(e,n){return new e({type:"string",format:"nanoid",check:"string_format",abort:!1,...S(n)})}function Zi(e,n){return new e({type:"string",format:"cuid",check:"string_format",abort:!1,...S(n)})}function Vi(e,n){return new e({type:"string",format:"cuid2",check:"string_format",abort:!1,...S(n)})}function Fi(e,n){return new e({type:"string",format:"ulid",check:"string_format",abort:!1,...S(n)})}function Gi(e,n){return new e({type:"string",format:"xid",check:"string_format",abort:!1,...S(n)})}function Bi(e,n){return new e({type:"string",format:"ksuid",check:"string_format",abort:!1,...S(n)})}function Ji(e,n){return new e({type:"string",format:"ipv4",check:"string_format",abort:!1,...S(n)})}function Ki(e,n){return new e({type:"string",format:"ipv6",check:"string_format",abort:!1,...S(n)})}function qu(e,n){return new e({type:"string",format:"mac",check:"string_format",abort:!1,...S(n)})}function Hi(e,n){return new e({type:"string",format:"cidrv4",check:"string_format",abort:!1,...S(n)})}function Wi(e,n){return new e({type:"string",format:"cidrv6",check:"string_format",abort:!1,...S(n)})}function Xi(e,n){return new e({type:"string",format:"base64",check:"string_format",abort:!1,...S(n)})}function qi(e,n){return new e({type:"string",format:"base64url",check:"string_format",abort:!1,...S(n)})}function Yi(e,n){return new e({type:"string",format:"e164",check:"string_format",abort:!1,...S(n)})}function Yu(e,n){return new e({type:"string",format:"credit_card",check:"string_format",abort:!1,...S(n)})}function Qu(e,n){return new e({type:"string",format:"iban",check:"string_format",abort:!1,...S(n)})}function Qi(e,n){return new e({type:"string",format:"jwt",check:"string_format",abort:!1,...S(n)})}var ec={Any:null,Minute:-1,Second:0,Millisecond:3,Microsecond:6};function rr(e,n){return new e({type:"string",format:"datetime",check:"string_format",offset:!1,local:!1,precision:null,...S(n)})}function ir(e,n){return new e({type:"string",format:"date",check:"string_format",...S(n)})}function or(e,n){return new e({type:"string",format:"time",check:"string_format",precision:null,...S(n)})}function ar(e,n){return new e({type:"string",format:"duration",check:"string_format",...S(n)})}function tc(e,n){return new e(Ei({type:"number",checks:[],...S(n)}))}function nc(e,n){return new e(Ei({type:"number",coerce:!0,checks:[],...S(n)}))}function rc(e,n){return new e({type:"number",check:"number_format",abort:!1,format:"safeint",...S(n)})}function ic(e,n){return new e({type:"number",check:"number_format",abort:!1,format:"float32",...S(n)})}function oc(e,n){return new e({type:"number",check:"number_format",abort:!1,format:"float64",...S(n)})}function ac(e,n){return new e({type:"number",check:"number_format",abort:!1,format:"int32",...S(n)})}function sc(e,n){return new e({type:"number",check:"number_format",abort:!1,format:"uint32",...S(n)})}function uc(e,n){return new e({type:"boolean",...S(n)})}function cc(e,n){return new e({type:"boolean",coerce:!0,...S(n)})}function lc(e,n){return new e({type:"bigint",...S(n)})}function dc(e,n){return new e({type:"bigint",coerce:!0,...S(n)})}function pc(e,n){return new e({type:"bigint",check:"bigint_format",abort:!1,format:"int64",...S(n)})}function mc(e,n){return new e({type:"bigint",check:"bigint_format",abort:!1,format:"uint64",...S(n)})}function fc(e,n){return new e({type:"symbol",...S(n)})}function gc(e,n){return new e({type:"undefined",...S(n)})}function vc(e,n){return new e({type:"null",...S(n)})}function hc(e){return new e({type:"any"})}function yc(e){return new e({type:"unknown"})}function bc(e,n){return new e({type:"never",...S(n)})}function $c(e,n){return new e({type:"void",...S(n)})}function _c(e,n){return new e({type:"date",...S(n)})}function kc(e,n){return new e({type:"date",coerce:!0,...S(n)})}function xc(e,n){return new e({type:"nan",...S(n)})}function ze(e,n){return new Yr({check:"less_than",...S(n),value:e,inclusive:!1})}function be(e,n){return new Yr({check:"less_than",...S(n),value:e,inclusive:!0})}function Ne(e,n){return new Qr({check:"greater_than",...S(n),value:e,inclusive:!1})}function $e(e,n){return new Qr({check:"greater_than",...S(n),value:e,inclusive:!0})}function eo(e){return Ne(0,e)}function to(e){return ze(0,e)}function no(e){return be(0,e)}function ro(e){return $e(0,e)}function We(e,n){return new os({check:"multiple_of",...S(n),value:e})}function Xe(e,n){return new us({check:"max_size",...S(n),maximum:e})}function Ee(e,n){return new cs({check:"min_size",...S(n),minimum:e})}function vt(e,n){return new ls({check:"size_equals",...S(n),size:e})}function ht(e,n){return new ds({check:"max_length",...S(n),maximum:e})}function Ze(e,n){return new ps({check:"min_length",...S(n),minimum:e})}function yt(e,n){return new ms({check:"length_equals",...S(n),length:e})}function Jt(e,n){return new fs({check:"string_format",format:"regex",...S(n),pattern:e})}function Kt(e){return new gs({check:"string_format",format:"lowercase",...S(e)})}function Ht(e){return new vs({check:"string_format",format:"uppercase",...S(e)})}function Wt(e,n){return new hs({check:"string_format",format:"includes",...S(n),includes:e})}function Xt(e,n){return new ys({check:"string_format",format:"starts_with",...S(n),prefix:e})}function qt(e,n){return new bs({check:"string_format",format:"ends_with",...S(n),suffix:e})}function io(e,n,i){return new $s({check:"property",property:e,schema:n,...S(i)})}function Yt(e,n){return new _s({check:"properties",shape:e,...S(n)})}function Qt(e,n){return new ks({check:"mime_type",mime:e,...S(n)})}function Ae(e){return new xs({check:"overwrite",tx:e})}function en(e){return Ae(n=>n.normalize(e))}function tn(){return Ae(e=>e.trim())}function nn(){return Ae(e=>e.toLowerCase())}function rn(){return Ae(e=>e.toUpperCase())}function on(){return Ae(e=>sa(e))}function Ic(e,n,i){return new e({type:"array",element:n,...S(i)})}function C_(e,n,i){return new e({type:"union",options:n,...S(i)})}function L_(e,n,i){return new e({type:"union",options:n,inclusive:!1,...S(i)})}function R_(e,n,i,o){return new e({type:"union",options:i,discriminator:n,...S(o)})}function M_(e,n,i){return new e({type:"intersection",left:n,right:i})}function Z_(e,n,i,o){let t=i instanceof j,r=t?o:i,a=t?i:null;return new e({type:"tuple",items:n,rest:a,...S(r)})}function V_(e,n,i,o){return new e({type:"record",keyType:n,valueType:i,...S(o)})}function F_(e,n,i,o){return new e({type:"map",keyType:n,valueType:i,...S(o)})}function G_(e,n,i){return new e({type:"set",valueType:n,...S(i)})}function B_(e,n,i){let o=Array.isArray(n)?Object.fromEntries(n.map(t=>[t,t])):n;return new e({type:"enum",entries:o,...S(i)})}function J_(e,n,i){return new e({type:"enum",entries:n,...S(i)})}function K_(e,n,i){return new e({type:"literal",values:Array.isArray(n)?n:[n],...S(i)})}function wc(e,n){return new e({type:"file",...S(n)})}function H_(e,n){return new e({type:"transform",transform:n})}function W_(e,n){return new e({type:"optional",innerType:n})}function X_(e,n){return new e({type:"nullable",innerType:n})}function q_(e,n,i){return new e({type:"default",innerType:n,get defaultValue(){return typeof i=="function"?i():Sn(i)}})}function Y_(e,n,i){return new e({type:"nonoptional",innerType:n,...S(i)})}function Q_(e,n){return new e({type:"success",innerType:n})}function ek(e,n,i){return new e({type:"catch",innerType:n,catchValue:typeof i=="function"?i:ma(i)})}function tk(e,n,i){return new e({type:"pipe",in:n,out:i})}function nk(e,n){return new e({type:"readonly",innerType:n})}function rk(e,n,i){return new e({type:"template_literal",parts:n,...S(i)})}function ik(e,n){return new e({type:"lazy",getter:n})}function ok(e,n){return new e({type:"promise",innerType:n})}function Sc(e,n,i){let o=S(i);return o.abort??(o.abort=!0),new e({type:"custom",check:"custom",fn:n,...o})}function Pc(e,n,i){return new e({type:"custom",check:"custom",fn:n,...S(i)})}function Ac(e,n){let i=cf(o=>(o.addIssue=t=>{if(typeof t=="string")o.issues.push(Ut(t,o.value,i._zod.def));else{let r=t;r.fatal&&(r.continue=!1),r.code??(r.code="custom"),"input"in r||(r.input=o.value),r.inst??(r.inst=i),r.continue??(r.continue=!i._zod.def.abort),o.issues.push(Ut(r))}},e(o.value,o)),n);return i}function cf(e,n){let i=new W({check:"custom",...S(n)});return i._zod.check=e,i}function Tc(e){let n=new W({check:"describe"});return n._zod.onattach=[i=>{let o=oe.get(i)??{};oe.add(i,{...o,description:e})}],n._zod.check=()=>{},n}function zc(e){let n=new W({check:"meta"});return n._zod.onattach=[i=>{let o=oe.get(i)??{};oe.add(i,{...o,...e})}],n._zod.check=()=>{},n}function Nc(e,n){let i=S(n),o=i.truthy??["true","1","yes","on","y","enabled"],t=i.falsy??["false","0","no","off","n","disabled"];i.case!=="sensitive"&&(o=o.map(f=>typeof f=="string"?f.toLowerCase():f),t=t.map(f=>typeof f=="string"?f.toLowerCase():f));let r=new Set(o),a=new Set(t),s=e.Codec??Wn,u=e.Boolean??Kn,c=e.String??pt,l=new c({type:"string",error:i.error}),p=new u({type:"boolean",error:i.error}),m=new s({type:"pipe",in:l,out:p,transform:((f,g)=>{let h=f;return i.case!=="sensitive"&&(h=h.toLowerCase()),r.has(h)?!0:a.has(h)?!1:(g.issues.push({code:"invalid_value",expected:"stringbool",values:[...r,...a],input:g.value,inst:m,continue:!1}),{})}),reverseTransform:((f,g)=>f===!0?o[0]||"true":t[0]||"false"),error:i.error});return m._zod.bag.truthy=o,m._zod.bag.falsy=t,m._zod.bag.case=i.case??"insensitive",m}function bt(e,n,i,o={}){let t=S(o),r={check:"string_format",type:"string",format:n,fn:typeof i=="function"?i:s=>i.test(s),...t};return i instanceof RegExp&&(r.pattern=i),new e(r)}function sr(e,...n){for(let i of n)for(let o of Reflect.ownKeys(i))Object.prototype.propertyIsEnumerable.call(i,o)&&ie(e,o,i[o]);return e}function qe(e){let n=e?.target??"draft-2020-12";return n==="draft-4"&&(n="draft-04"),n==="draft-7"&&(n="draft-07"),{processors:e.processors??{},metadataRegistry:e?.metadata??oe,target:n,unrepresentable:e?.unrepresentable??"throw",override:e?.override??(()=>{}),io:e?.io??"output",counter:0,seen:new Map,sharedDefsExtractedFor:void 0,sharedEmitDoneFor:void 0,cycles:e?.cycles??"ref",reused:e?.reused??"inline",intersections:[],deferred:[],external:e?.external??void 0}}function te(e,n,i,o,t){let r=typeof n.unrepresentable=="function"?n.unrepresentable({zodSchema:e,path:o.path,message:t}):n.unrepresentable;if(r==="any")return!1;if(r===void 0||r==="throw")throw new Error(t);return Object.assign(i,r),!0}function J(e,n,i={path:[],schemaPath:[]}){var o;let t=e._zod.def,r=n.seen.get(e);if(r)return r.count++,i.schemaPath.includes(e)&&(r.cycle=i.path),r.schema;let a={schema:{},count:1,cycle:void 0,path:i.path};n.seen.set(e,a),n.sharedDefsExtractedFor=void 0,n.sharedEmitDoneFor=void 0;let s=e._zod.toJSONSchema?.();if(s)a.schema=s;else{let l={...i,schemaPath:[...i.schemaPath,e],path:i.path};if(e._zod.processJSONSchema)e._zod.processJSONSchema(n,a.schema,l);else{let m=a.schema,f=n.processors[t.type];if(!f)throw new Error(`[toJSONSchema]: Non-representable type encountered: ${t.type}`);f(e,n,m,l)}let p=e._zod.parent;p&&(a.ref||(a.ref=p),J(p,n,l),n.seen.get(p).isParent=!0)}let u=n.metadataRegistry.get(e);return u&&sr(a.schema,u),n.io==="input"&&le(e)&&(delete a.schema.examples,delete a.schema.default),n.io==="input"&&"_prefault"in a.schema&&((o=a.schema).default??(o.default=a.schema._prefault)),delete a.schema._prefault,n.seen.get(e).schema}function lf(e){return e.replace(/~/g,"~0").replace(/\//g,"~1")}function Ye(e,n){let i=e.seen.get(n);if(!i)throw new Error("Unprocessed schema. This is a bug in Zod.");if(e.external&&e.sharedDefsExtractedFor===e.external)return;let o=new Map;for(let a of e.seen.entries()){let s=e.metadataRegistry.get(a[0])?.id;if(s){let u=o.get(s);if(u&&u!==a[0])throw new Error(`Duplicate schema id "${s}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`);o.set(s,a[0])}}let t=a=>{let s=e.target==="draft-2020-12"?"$defs":"definitions";if(e.external){let p=e.external.registry.get(a[0])?.id,m=e.external.uri??(g=>g);if(p)return{ref:m(p)};let f=a[1].defId??a[1].schema.id??`schema${e.counter++}`;return a[1].defId=f,{defId:f,ref:`${m("__shared")}#/${s}/${lf(f)}`}}let u="#",c=`${u}/${s}/`;if(a[1]===i&&!a[1].schema.id)return{ref:u};let l=a[1].schema.id??`__schema${e.counter++}`;return{defId:l,ref:c+lf(l)}},r=a=>{if(a[1].schema.$ref)return;let s=a[1],{ref:u,defId:c}=t(a);s.def={...s.schema},c&&(s.defId=c);let l=s.schema;for(let p in l)delete l[p];l.$ref=u};if(e.cycles==="throw")for(let a of e.seen.entries()){let s=a[1];if(s.cycle)throw new Error(`Cycle detected: #/${s.cycle?.join("/")}/ -Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`)}for(let a of e.seen.entries()){let s=a[1];if(n===a[0]){r(a);continue}if(e.external){let c=e.external.registry.get(a[0])?.id;if(n!==a[0]&&c){r(a);continue}}if(e.metadataRegistry.get(a[0])?.id){r(a);continue}if(s.cycle){r(a);continue}s.count>1&&e.reused==="ref"&&r(a)}e.external&&(e.sharedDefsExtractedFor=e.external)}function mf(e){let n=e.anyOf;if(!Array.isArray(n)||n.length===0||e.type!==void 0)return;let i=[];for(let o of n){if(!o||typeof o!="object")return;mf(o);let t=Object.keys(o);if(t.length!==1||t[0]!=="type")return;let r=o.type;for(let a of Array.isArray(r)?r:[r]){if(typeof a!="string")return;i.includes(a)||i.push(a)}}delete e.anyOf,e.type=i.length===1?i[0]:i}var ff=new Set(["type","properties","required","additionalProperties"]),df=["oneOf","anyOf"];function pf(e){let n=e.additionalProperties;return n===void 0||n===!1||typeof n!="object"||n===null?null:Object.keys(n).length?n:null}function Ec(e){let n=[];for(let r of e){if(typeof r!="object"||r.type!=="object")return null;for(let a in r)if(!ff.has(a))return null;n.push(r)}let i={},o=new Set;for(let r of n){for(let a in r.properties){if(Object.prototype.hasOwnProperty.call(i,a))continue;let s=[];for(let c of n){let l=c.properties?.[a]??pf(c);l!=null&&(s.some(p=>JSON.stringify(p)===JSON.stringify(l))||s.push(l))}let u=s.length===1?s[0]:Ec(s)??{allOf:s};ie(i,a,u)}for(let a of r.required??[])o.add(a)}let t={type:"object",properties:i};if(o.size&&(t.required=[...o]),n.every(r=>r.additionalProperties===!1))t.additionalProperties=!1;else{let r=[];for(let a of n){let s=pf(a);s&&!r.some(u=>JSON.stringify(u)===JSON.stringify(s))&&r.push(s)}r.length===1?t.additionalProperties=r[0]:r.length>1&&(t.additionalProperties={allOf:r})}return t}function ak(e){let n=e.allOf;if(!Array.isArray(n)||n.length<2)return;for(let t of ff)if(t in e)return;let i=n.filter(t=>df.some(r=>Array.isArray(t[r]))),o=null;if(!i.length)o=Ec(n);else{let t=i[0],r=df.find(u=>Array.isArray(t[u]));if(Object.keys(t).length!==1)return;let a=n.filter(u=>u!==t),s=t[r].map(u=>Ec([...a,u]));if(s.some(u=>!u))return;o={[r]:s}}o&&(delete e.allOf,sr(e,o))}function Qe(e,n){let i=e.seen.get(n);if(!i)throw new Error("Unprocessed schema. This is a bug in Zod.");let o=s=>{let u=e.seen.get(s);if(u.ref===null)return;let c=u.def??u.schema,l={...c},p=u.ref;if(u.ref=null,p){o(p);let f=e.seen.get(p),g=f.schema;if(g.$ref&&(e.target==="draft-07"||e.target==="draft-04"||e.target==="openapi-3.0")?(c.allOf=c.allOf??[],c.allOf.push(g)):sr(c,g),sr(c,l),s._zod.parent===p)for(let k in c)k==="$ref"||k==="allOf"||k in l||delete c[k];if(g.$ref&&f.def)for(let k in c)k==="$ref"||k==="allOf"||k in f.def&&JSON.stringify(c[k])===JSON.stringify(f.def[k])&&delete c[k]}let m=s._zod.parent;if(m&&m!==p){o(m);let f=e.seen.get(m);if(f?.schema.$ref&&(c.$ref=f.schema.$ref,f.def))for(let g in c)g==="$ref"||g==="allOf"||g in f.def&&JSON.stringify(c[g])===JSON.stringify(f.def[g])&&delete c[g]}e.override({zodSchema:s,jsonSchema:c,path:u.path??[]})};if(!e.external||e.sharedEmitDoneFor!==e.external){for(let s of[...e.seen.entries()].reverse())o(s[0]);if(e.target!=="openapi-3.0")for(let s of e.seen.entries())mf(s[1].def??s[1].schema);for(let s of e.deferred)s();if(e.intersections.length){let s=new Map;for(let u of e.seen.values())for(let c of[u.schema,u.def]){let l=c?.allOf;if(!Array.isArray(l))continue;let p=s.get(l);p?p.push(c):s.set(l,[c])}for(let u of e.intersections)for(let c of s.get(u)??[])ak(c)}}let t={};if(e.target==="draft-2020-12"?t.$schema="https://json-schema.org/draft/2020-12/schema":e.target==="draft-07"?t.$schema="http://json-schema.org/draft-07/schema#":e.target==="draft-04"?t.$schema="http://json-schema.org/draft-04/schema#":e.target,e.external?.uri){let s=e.external.registry.get(n)?.id;if(!s)throw new Error("Schema is missing an `id` property");t.$id=e.external.uri(s)}sr(t,i.defId?i.schema:i.def??i.schema);let r=e.metadataRegistry.get(n)?.id;r!==void 0&&t.id===r&&delete t.id;let a=e.external?.defs??{};if(!e.external||e.sharedEmitDoneFor!==e.external)for(let s of e.seen.entries()){let u=s[1];u.def&&u.defId&&(u.def.id===u.defId&&delete u.def.id,ie(a,u.defId,u.def))}e.external&&(e.sharedEmitDoneFor=e.external),e.external||Object.keys(a).length>0&&(e.target==="draft-2020-12"?t.$defs=a:t.definitions=a);try{let s=JSON.parse(JSON.stringify(t));return Object.defineProperty(s,"~standard",{value:{...n["~standard"],jsonSchema:{input:an(n,"input",e.processors),output:an(n,"output",e.processors)}},enumerable:!1,writable:!1}),s}catch{throw new Error("Error converting schema to JSON.")}}function le(e,n){let i=n??{seen:new Set};if(i.seen.has(e))return!1;i.seen.add(e);let o=e._zod.def;if(o.type==="transform")return!0;if(o.type==="array")return le(o.element,i);if(o.type==="set")return le(o.valueType,i);if(o.type==="lazy")return le(o.getter(),i);if(o.type==="promise"||o.type==="optional"||o.type==="nonoptional"||o.type==="nullable"||o.type==="readonly"||o.type==="default"||o.type==="prefault"||o.type==="catch")return le(o.innerType,i);if(o.type==="intersection")return le(o.left,i)||le(o.right,i);if(o.type==="record"||o.type==="map")return le(o.keyType,i)||le(o.valueType,i);if(o.type==="pipe")return e._zod.traits.has("$ZodCodec")?!0:le(o.in,i)||le(o.out,i);if(o.type==="object"){for(let t in o.shape)if(le(o.shape[t],i))return!0;return!1}if(o.type==="union"){for(let t of o.options)if(le(t,i))return!0;return!1}if(o.type==="tuple"){for(let t of o.items)if(le(t,i))return!0;return!!(o.rest&&le(o.rest,i))}return!1}var Oc=(e,n={})=>i=>{let o=qe({...i,processors:n});return J(e,o),Ye(o,e),Qe(o,e)},an=(e,n,i={})=>o=>{let{libraryOptions:t,target:r}=o??{},a=qe({...t??{},target:r,io:n,processors:i});return J(e,a),Ye(a,e),Qe(a,e)};var sn=(e,n,i)=>{(e[n]===void 0||i>e[n])&&(e[n]=i)},un=(e,n,i)=>{(e[n]===void 0||i{sn(e,"minimum",n),un(e,"maximum",n)},bf=(e,n)=>{e.multipleOf??(e.multipleOf=[]),e.multipleOf.includes(n)||e.multipleOf.push(n)},$f=(e,n)=>{e.patterns??(e.patterns=new Set),e.patterns.add(n)},_f=(e,n)=>{e.mime=e.mime?e.mime.filter(i=>n.includes(i)):[...n]},kf=(e,n)=>{e.format=n,n.includes("int")&&(e.isInt=!0)},vf=(e,n)=>sn(e,"minimum",n.minimum),hf=(e,n)=>un(e,"maximum",n.maximum),yf=e=>(n,i)=>{kf(n,i.format);let[o,t]=e[i.format];sn(n,"minimum",o),un(n,"maximum",t)},sk={greater_than:(e,n)=>sn(e,n.inclusive?"minimum":"exclusiveMinimum",n.value),less_than:(e,n)=>un(e,n.inclusive?"maximum":"exclusiveMaximum",n.value),multiple_of:(e,n)=>bf(e,n.value),number_format:yf(An),bigint_format:yf(Tn),min_length:vf,max_length:hf,length_equals:(e,n)=>gf(e,n.length),min_size:vf,max_size:hf,size_equals:(e,n)=>gf(e,n.size),string_format:(e,n)=>{kf(e,n.format),n.pattern&&$f(e,n.pattern),(n.format==="base64"||n.format==="base64url")&&(e.contentEncoding=n.format),(n.local||n.precision===-1)&&(e.laxFormat=!0)},mime_type:(e,n)=>_f(e,n.mime)};function ne(e){let n={},i=e._zod.def,o=e._zod.traits.has("$ZodCheck")?[e,...i.checks??[]]:i.checks??[];for(let r of o)sk[r._zod.def.check]?.(n,r._zod.def);let t=e._zod.bag;t.minimum!==void 0&&sn(n,"minimum",t.minimum),t.exclusiveMinimum!==void 0&&sn(n,"exclusiveMinimum",t.exclusiveMinimum),t.maximum!==void 0&&un(n,"maximum",t.maximum),t.exclusiveMaximum!==void 0&&un(n,"exclusiveMaximum",t.exclusiveMaximum),t.multipleOf!==void 0&&bf(n,t.multipleOf),t.format!==void 0&&(n.format??(n.format=t.format),t.format.includes("int")&&(n.isInt=!0)),t.mime&&_f(n,t.mime);for(let r of t.patterns??[])$f(n,r);return n}var uk={guid:"uuid",url:"uri",datetime:"date-time",json_string:"json-string",regex:""},ck=new Map([[ci,Ra],[Jn,Ma]]),xf=e=>ck.get(e)??e,Uc=(e,n,i,o)=>{let t=i;t.type="string";let{minimum:r,maximum:a,format:s,patterns:u,contentEncoding:c,laxFormat:l}=ne(e);if(typeof r=="number"&&(t.minLength=r),typeof a=="number"&&(t.maxLength=a),s&&(t.format=uk[s]??s,t.format===""&&delete t.format,(s==="time"||l)&&delete t.format),c&&(t.contentEncoding=c),u&&u.size>0){let p=[...u].map(xf);p.length===1?t.pattern=p[0].source:p.length>1&&(t.allOf=[...p.map(m=>({...n.target==="draft-07"||n.target==="draft-04"||n.target==="openapi-3.0"?{type:"string"}:{},pattern:m.source}))])}},Cc=(e,n,i,o)=>{let t=i,{minimum:r,maximum:a,multipleOf:s,exclusiveMaximum:u,exclusiveMinimum:c,isInt:l}=ne(e);t.type=l?"integer":"number";let p=typeof c=="number"&&c>=(r??Number.NEGATIVE_INFINITY),m=typeof u=="number"&&u<=(a??Number.POSITIVE_INFINITY),f=n.target==="draft-04"||n.target==="openapi-3.0";if(p?f?(t.minimum=c,t.exclusiveMinimum=!0):t.exclusiveMinimum=c:typeof r=="number"&&(t.minimum=r),m?f?(t.maximum=u,t.exclusiveMaximum=!0):t.exclusiveMaximum=u:typeof a=="number"&&(t.maximum=a),s){let g=new Set;for(let x of s)Number.isFinite(x)&&x!==0?g.add(Math.abs(x)):te(e,n,t,o,`A multipleOf divisor of ${x} cannot be represented in JSON Schema`);let[h,...k]=g;h!==void 0&&(t.multipleOf=h),k.length&&(t.allOf=[...t.allOf??[],...k.map(x=>({multipleOf:x}))])}},Lc=(e,n,i,o)=>{i.type="boolean"},Rc=(e,n,i,o)=>{te(e,n,i,o,"BigInt cannot be represented in JSON Schema")},Mc=(e,n,i,o)=>{te(e,n,i,o,"Symbols cannot be represented in JSON Schema")},Zc=(e,n,i,o)=>{n.target==="openapi-3.0"?(i.type="string",i.nullable=!0,i.enum=[null]):i.type="null"},Vc=(e,n,i,o)=>{te(e,n,i,o,"Undefined cannot be represented in JSON Schema")},Fc=(e,n,i,o)=>{te(e,n,i,o,"Void cannot be represented in JSON Schema")},Gc=(e,n,i,o)=>{i.not={}},Bc=(e,n,i,o)=>{},Jc=(e,n,i,o)=>{},Kc=(e,n,i,o)=>{te(e,n,i,o,"Date cannot be represented in JSON Schema")},Hc=(e,n,i,o)=>{let t=e._zod.def,r=Nt(t.entries);if(r.length===0){i.not={};return}r.every(a=>typeof a=="number")&&(i.type="number"),r.every(a=>typeof a=="string")&&(i.type="string"),i.enum=r},Wc=(e,n,i,o)=>{let t=e._zod.def;if(t.values.length===0){i.not={};return}let r=[];for(let a of t.values)if(a===void 0){if(te(e,n,i,o,"Literal `undefined` cannot be represented in JSON Schema"))return}else if(typeof a=="bigint"){if(te(e,n,i,o,"BigInt literals cannot be represented in JSON Schema"))return;r.push(Number(a))}else r.push(a);if(r.length!==0)if(r.length===1){let a=r[0];i.type=a===null?"null":typeof a,n.target==="draft-04"||n.target==="openapi-3.0"?i.enum=[a]:i.const=a}else r.every(a=>typeof a=="number")&&(i.type="number"),r.every(a=>typeof a=="string")&&(i.type="string"),r.every(a=>typeof a=="boolean")&&(i.type="boolean"),r.every(a=>a===null)&&(i.type="null"),i.enum=r},Xc=(e,n,i,o)=>{te(e,n,i,o,"NaN cannot be represented in JSON Schema")},qc=(e,n,i,o)=>{let t=i,r=e._zod.pattern;if(!r)throw new Error("Pattern not found in template literal");t.type="string",t.pattern=r.source},Yc=(e,n,i,o)=>{let t=i;t.type="string",t.format="binary",t.contentEncoding="binary";let{minimum:r,maximum:a,mime:s}=ne(e);r!==void 0&&(t.minLength=r),a!==void 0&&(t.maxLength=a),s&&(s.length===0?t.not={}:s.length===1?t.contentMediaType=s[0]:t.anyOf=s.map(u=>({contentMediaType:u})))},Qc=(e,n,i,o)=>{i.type="boolean"},el=(e,n,i,o)=>{te(e,n,i,o,"Custom types cannot be represented in JSON Schema")},tl=(e,n,i,o)=>{te(e,n,i,o,"Function types cannot be represented in JSON Schema")},nl=(e,n,i,o)=>{te(e,n,i,o,"Transforms cannot be represented in JSON Schema")},rl=(e,n,i,o)=>{te(e,n,i,o,"Map cannot be represented in JSON Schema")},il=(e,n,i,o)=>{te(e,n,i,o,"Set cannot be represented in JSON Schema")},ol=(e,n,i,o)=>{let t=i,r=e._zod.def,{minimum:a,maximum:s}=ne(e);typeof a=="number"&&(t.minItems=a),typeof s=="number"&&(t.maxItems=s),t.type="array",t.items=J(r.element,n,{...o,path:[...o.path,"items"]})};function ur(e){let n=e._zod.def;return n.type==="pipe"&&n.in._zod.traits.has("$ZodTransform")?ur(n.out):n.type==="catch"?ur(n.innerType):e._zod.optin}var al=(e,n,i,o)=>{let t=i,r=e._zod.def,a=r.shape;if(Object.getOwnPropertySymbols(a).length&&te(e,n,t,o,"Symbol keys cannot be represented in JSON Schema"))return;t.type="object",t.properties={};for(let c in a)ie(t.properties,c,J(a[c],n,{...o,path:[...o.path,"properties",c]}));let u=[];for(let c of Object.keys(a)){let l=r.shape[c];(n.io==="input"?ur(l)===void 0:l._zod.optout===void 0)&&u.push(c)}u.length>0&&(t.required=u),r.catchall?._zod.def.type==="never"?t.additionalProperties=!1:r.catchall?r.catchall&&(t.additionalProperties=J(r.catchall,n,{...o,path:[...o.path,"additionalProperties"]})):n.io==="output"&&(t.additionalProperties=!1)},ao=(e,n,i,o)=>{let t=e._zod.def,r=t.inclusive===!1,a=t.options.map((s,u)=>J(s,n,{...o,path:[...o.path,r?"oneOf":"anyOf",u]}));r?i.oneOf=a:i.anyOf=a},sl=(e,n,i,o)=>{let t=e._zod.def,r=J(t.left,n,{...o,path:[...o.path,"allOf",0]}),a=J(t.right,n,{...o,path:[...o.path,"allOf",1]}),s=c=>"allOf"in c&&Object.keys(c).length===1,u=[...s(r)?r.allOf:[r],...s(a)?a.allOf:[a]];i.allOf=u,n.intersections.push(u)},ul=(e,n,i,o)=>{let t=i,r=e._zod.def;t.type="array";let a=n.target==="draft-2020-12"?"prefixItems":"items",s=n.target==="draft-2020-12"||n.target==="openapi-3.0"?"items":"additionalItems",u=r.items.map((h,k)=>J(h,n,{...o,path:[...o.path,a,k]})),c=r.rest?J(r.rest,n,{...o,path:[...o.path,s,...n.target==="openapi-3.0"?[r.items.length]:[]]}):null,l=r.items.length;for(;l>0;){let h=r.items[l-1];if(!(n.io==="input"?ur(h)!==void 0:h._zod.optout==="optional"))break;l--}let p=r.items.length,m=!r.rest;n.target==="draft-2020-12"?(t.prefixItems=u,m?t.items=!1:c&&(t.items=c),l>0&&(t.minItems=l),m&&(t.maxItems=p)):n.target==="openapi-3.0"?(t.items={anyOf:u},c&&t.items.anyOf.push(c),l>0&&(t.minItems=l),m&&(t.maxItems=p)):(t.items=u,m?t.additionalItems=!1:c&&(t.additionalItems=c),l>0&&(t.minItems=l),m&&(t.maxItems=p));let{minimum:f,maximum:g}=ne(e);typeof f=="number"&&(t.minItems=f),typeof g=="number"&&(t.maxItems=g)};function Dc(e,n,i){if(n.$ref){if(i.has(n))return n;i.add(n);let g=e.get(n)?.def;if(!g)return n;let h=Dc(e,g,i);return h===g?n:h}for(let g of["anyOf","oneOf"]){let h=n[g];if(!Array.isArray(h))continue;let k=h.map(x=>Dc(e,x,i));k.some((x,I)=>x!==h[I])&&(n={...n,[g]:k})}let o=Array.isArray(n.type)?n.type:[n.type],t=!o.includes("string")&&o.some(g=>g==="number"||g==="integer"),r=n.enum??(n.const!==void 0?[n.const]:void 0);if(!t&&!r?.some(g=>typeof g=="number"))return n;let{minimum:a,maximum:s,exclusiveMinimum:u,exclusiveMaximum:c,multipleOf:l,format:p,id:m,...f}=n;return f.enum?f.enum=f.enum.map(g=>typeof g=="number"?String(g):g):typeof f.const=="number"&&(f.const=String(f.const)),t&&(f.type="string",r||(f.pattern=(o.includes("number")?Me:Rn).source)),f}var jc=new WeakMap;function lk(e){let n=new Map;for(let o of e.seen.values())o.def&&!n.has(o.schema)&&n.set(o.schema,o);let i=new Map;for(let o of jc.get(e)??[]){let t=e.seen.get(o),r=(t?.def??t?.schema)?.propertyNames;if(!r||r===!0||i.has(r))continue;let a=Dc(n,r,new Set);a!==r&&i.set(r,a)}if(i.size)for(let o of e.seen.values())for(let t of[o.schema,o.def]){let r=t&&i.get(t.propertyNames);r&&(t.propertyNames=r)}}var cl=(e,n,i,o)=>{let t=i,r=e._zod.def;t.type="object";let a=r.keyType,s=ne(a).patterns;if(r.mode==="loose"&&s&&s.size>0){let l=J(r.valueType,n,{...o,path:[...o.path,"patternProperties","*"]});t.patternProperties={};for(let p of s)ie(t.patternProperties,xf(p).source,l)}else{if(n.target==="draft-07"||n.target==="draft-2020-12"){t.propertyNames=J(r.keyType,n,{...o,path:[...o.path,"propertyNames"]});let l=jc.get(n);l||(l=[],jc.set(n,l),n.deferred.push(()=>lk(n))),l.push(e)}t.additionalProperties=J(r.valueType,n,{...o,path:[...o.path,"additionalProperties"]})}let u=a._zod.values,c=n.io==="input"&&ur(r.valueType)!==void 0;if(u&&!r.partial&&!c){let l=[...u].filter(p=>typeof p=="string"||typeof p=="number");l.length>0&&(t.required=l.map(String))}},ll=(e,n,i,o)=>{let t=e._zod.def,r=J(t.innerType,n,o),a=n.seen.get(e);n.target==="openapi-3.0"?(a.ref=t.innerType,i.nullable=!0):i.anyOf=[r,{type:"null"}]},dl=(e,n,i,o)=>{let t=e._zod.def;J(t.innerType,n,o);let r=n.seen.get(e);r.ref=t.innerType},pl=Symbol();function If(e,n,i,o,t){let r=!1,a=JSON.stringify(e,(s,u)=>typeof u!="bigint"?u:(r=!0,null));return r?(te(n,i,o,t,"BigInt defaults cannot be represented in JSON Schema"),pl):JSON.parse(a)}var ml=(e,n,i,o)=>{let t=e._zod.def;J(t.innerType,n,o);let r=n.seen.get(e);r.ref=t.innerType;let a=If(t.defaultValue,e,n,i,o);a!==pl&&(i.default=a)},fl=(e,n,i,o)=>{let t=e._zod.def;J(t.innerType,n,o);let r=n.seen.get(e);if(r.ref=t.innerType,n.io!=="input")return;let a=If(t.defaultValue,e,n,i,o);a!==pl&&(i._prefault=a)},gl=(e,n,i,o)=>{let t=e._zod.def;J(t.innerType,n,o);let r=n.seen.get(e);r.ref=t.innerType;let a;try{a=t.catchValue(void 0)}catch{te(e,n,i,o,"Dynamic catch values are not supported in JSON Schema");return}i.default=a},vl=(e,n,i,o)=>{let t=e._zod.def,r=t.in._zod.traits.has("$ZodTransform"),a=n.io==="input"?r?t.out:t.in:t.out;J(a,n,o);let s=n.seen.get(e);s.ref=a},hl=(e,n,i,o)=>{let t=e._zod.def;J(t.innerType,n,o);let r=n.seen.get(e);r.ref=t.innerType,i.readOnly=!0},yl=(e,n,i,o)=>{let t=e._zod.def;J(t.innerType,n,o);let r=n.seen.get(e);r.ref=t.innerType},so=(e,n,i,o)=>{let t=e._zod.def;J(t.innerType,n,o);let r=n.seen.get(e);r.ref=t.innerType},bl=(e,n,i,o)=>{let t=e._zod.innerType;J(t,n,o);let r=n.seen.get(e);r.ref=t},oo={string:Uc,number:Cc,boolean:Lc,bigint:Rc,symbol:Mc,null:Zc,undefined:Vc,void:Fc,never:Gc,any:Bc,unknown:Jc,date:Kc,enum:Hc,literal:Wc,nan:Xc,template_literal:qc,file:Yc,success:Qc,custom:el,function:tl,transform:nl,map:rl,set:il,array:ol,object:al,union:ao,intersection:sl,tuple:ul,record:cl,nullable:ll,nonoptional:dl,default:ml,prefault:fl,catch:gl,pipe:vl,readonly:hl,promise:yl,optional:so,lazy:bl};function uo(e,n){if("_idmap"in e){let o=e,t=qe({...n,processors:oo}),r={};for(let u of o._idmap.entries()){let[c,l]=u;J(l,t)}let a={},s={registry:o,uri:n?.uri,defs:r};t.external=s;for(let u of o._idmap.entries()){let[c,l]=u;Ye(t,l),ie(a,c,Qe(t,l))}if(Object.keys(r).length>0){let u=t.target==="draft-2020-12"?"$defs":"definitions";a.__shared={[u]:r}}return{schemas:a}}let i=qe({...n,processors:oo});return J(e,i),Ye(i,e),Qe(i,e)}var co=class{get metadataRegistry(){return this.ctx.metadataRegistry}get target(){return this.ctx.target}get unrepresentable(){return this.ctx.unrepresentable}get override(){return this.ctx.override}get io(){return this.ctx.io}get counter(){return this.ctx.counter}set counter(n){this.ctx.counter=n}get seen(){return this.ctx.seen}constructor(n){let i=n?.target??"draft-2020-12";i==="draft-4"&&(i="draft-04"),i==="draft-7"&&(i="draft-07"),this.ctx=qe({processors:oo,target:i,...n?.metadata&&{metadata:n.metadata},...n?.unrepresentable&&{unrepresentable:n.unrepresentable},...n?.override&&{override:n.override},...n?.io&&{io:n.io}})}process(n,i={path:[],schemaPath:[]}){return J(n,this.ctx,i)}emit(n,i){i&&(i.cycles&&(this.ctx.cycles=i.cycles),i.reused&&(this.ctx.reused=i.reused),i.external&&(this.ctx.external=i.external)),this.ctx.sharedDefsExtractedFor=void 0,this.ctx.sharedEmitDoneFor=void 0,Ye(this.ctx,n);let o=Qe(this.ctx,n),{"~standard":t,...r}=o;return r}};var wf={};var vn={};Ce(vn,{ZodAny:()=>Zl,ZodArray:()=>Bl,ZodBase64:()=>To,ZodBase64URL:()=>zo,ZodBigInt:()=>fn,ZodBigIntFormat:()=>Oo,ZodBoolean:()=>mn,ZodCIDRv4:()=>Po,ZodCIDRv6:()=>Ao,ZodCUID:()=>$o,ZodCUID2:()=>_o,ZodCatch:()=>pd,ZodCodec:()=>yr,ZodCreditCard:()=>Ol,ZodCustom:()=>br,ZodCustomStringFormat:()=>xt,ZodDate:()=>pr,ZodDefault:()=>ad,ZodDiscriminatedUnion:()=>Kl,ZodE164:()=>No,ZodEmail:()=>vo,ZodEmoji:()=>yo,ZodEnum:()=>ln,ZodExactOptional:()=>Co,ZodFile:()=>nd,ZodFunction:()=>kd,ZodGUID:()=>ho,ZodIBAN:()=>Dl,ZodIPv4:()=>wo,ZodIPv6:()=>So,ZodISODate:()=>tt,ZodISODateTime:()=>et,ZodISODuration:()=>rt,ZodISOTime:()=>nt,ZodInstanceOf:()=>wd,ZodIntersection:()=>Hl,ZodJWT:()=>Eo,ZodKSUID:()=>Io,ZodLazy:()=>bd,ZodLiteral:()=>td,ZodMAC:()=>El,ZodMap:()=>Ql,ZodNaN:()=>fd,ZodNanoID:()=>bo,ZodNever:()=>Fl,ZodNonOptional:()=>Lo,ZodNull:()=>Rl,ZodNullable:()=>od,ZodNumber:()=>pn,ZodNumberFormat:()=>It,ZodObject:()=>fr,ZodOptional:()=>vr,ZodPipe:()=>hr,ZodPrefault:()=>ud,ZodPreprocess:()=>gd,ZodPromise:()=>_d,ZodReadonly:()=>vd,ZodRecord:()=>cn,ZodSet:()=>ed,ZodString:()=>dn,ZodStringFormat:()=>H,ZodSuccess:()=>dd,ZodSymbol:()=>Cl,ZodTemplateLiteral:()=>yd,ZodTransform:()=>rd,ZodTuple:()=>Xl,ZodType:()=>L,ZodULID:()=>ko,ZodURL:()=>dr,ZodUUID:()=>Oe,ZodUndefined:()=>Ll,ZodUnion:()=>gr,ZodUnknown:()=>Vl,ZodVoid:()=>Gl,ZodXID:()=>xo,ZodXor:()=>Jl,_ZodString:()=>go,_default:()=>sd,_function:()=>Cg,any:()=>fg,array:()=>mr,base64:()=>Hf,base64url:()=>Wf,bigint:()=>cg,boolean:()=>Ul,catch:()=>md,check:()=>Lg,cidrv4:()=>Jf,cidrv6:()=>Kf,codec:()=>Og,creditCard:()=>qf,cuid:()=>Lf,cuid2:()=>Rf,currencyCode:()=>rg,custom:()=>Rg,date:()=>vg,describe:()=>Mg,discriminatedUnion:()=>kg,e164:()=>Xf,email:()=>Af,emoji:()=>Uf,enum:()=>jo,exactOptional:()=>id,file:()=>Tg,float32:()=>og,float64:()=>ag,function:()=>Cg,guid:()=>Tf,hash:()=>ig,hex:()=>ng,hostname:()=>tg,httpUrl:()=>jf,iban:()=>Yf,instanceof:()=>Vg,int:()=>mo,int32:()=>sg,int64:()=>lg,intersection:()=>Wl,invertCodec:()=>Dg,ipv4:()=>Ff,ipv6:()=>Bf,json:()=>Gg,jwt:()=>Qf,keyof:()=>hg,ksuid:()=>Vf,lazy:()=>$d,literal:()=>Ag,looseObject:()=>$g,looseRecord:()=>Ig,mac:()=>Gf,map:()=>wg,meta:()=>Zg,nan:()=>Eg,nanoid:()=>Cf,nativeEnum:()=>Pg,never:()=>Do,nonoptional:()=>ld,null:()=>Ml,nullable:()=>lr,nullish:()=>zg,number:()=>jl,object:()=>yg,optional:()=>_t,partialRecord:()=>xg,pipe:()=>fo,prefault:()=>cd,preprocess:()=>Bg,promise:()=>Ug,readonly:()=>hd,record:()=>Yl,refine:()=>xd,set:()=>Sg,strictObject:()=>bg,string:()=>cr,stringFormat:()=>eg,stringbool:()=>Fg,success:()=>Ng,superRefine:()=>Id,symbol:()=>pg,templateLiteral:()=>jg,transform:()=>Uo,tuple:()=>ql,uint32:()=>ug,uint64:()=>dg,ulid:()=>Mf,undefined:()=>mg,union:()=>gn,unknown:()=>$t,url:()=>Df,uuid:()=>zf,uuidv4:()=>Nf,uuidv6:()=>Ef,uuidv7:()=>Of,void:()=>gg,xid:()=>Zf,xor:()=>_g});var lo={};Ce(lo,{endsWith:()=>qt,gt:()=>Ne,gte:()=>$e,includes:()=>Wt,length:()=>yt,lowercase:()=>Kt,lt:()=>ze,lte:()=>be,maxLength:()=>ht,maxSize:()=>Xe,mime:()=>Qt,minLength:()=>Ze,minSize:()=>Ee,multipleOf:()=>We,negative:()=>to,nonnegative:()=>ro,nonpositive:()=>no,normalize:()=>en,overwrite:()=>Ae,positive:()=>eo,properties:()=>Yt,property:()=>io,regex:()=>Jt,size:()=>vt,slugify:()=>on,startsWith:()=>Xt,toLowerCase:()=>nn,toUpperCase:()=>rn,trim:()=>tn,uppercase:()=>Ht});var Sf=new WeakSet([Object.prototype,Error.prototype]);function po(e,n,i){Object.defineProperty(e,n,{configurable:!0,enumerable:!1,get(){let o=i(this);return Object.defineProperty(this,n,{value:o,configurable:!0,writable:!0}),o},set(o){Object.defineProperty(this,n,{value:o,configurable:!0,writable:!0})}})}var Pf=(e,n)=>{ba.init(e,n),e.name="ZodError";let i=Object.getPrototypeOf(e);Sf.has(i)||(Sf.add(i),po(i,"format",o=>t=>jn(o,t)),po(i,"flatten",o=>t=>Dn(o,t)),po(i,"addIssue",o=>t=>{o.issues.push(t),o.message=JSON.stringify(o.issues,Et,2)}),po(i,"addIssues",o=>t=>{o.issues.push(...t),o.message=JSON.stringify(o.issues,Et,2)}),Object.defineProperty(i,"isEmpty",{configurable:!0,enumerable:!1,get(){return this.issues.length===0}}))},pk=v("ZodError",Pf),ye=v("ZodError",Pf,void 0,{Parent:Error});var $l=Ct(ye),_l=Lt(ye),kl=Rt(ye),xl=Mt(ye),Il=Mr(ye),wl=Zr(ye),Sl=Vr(ye),Pl=Fr(ye),Al=Gr(ye),Tl=Br(ye),zl=Jr(ye),Nl=Kr(ye);function fk(){re.localeError||Y(wi())}function kt(){re.memoizer||Y({memoizer:Qn()})}var L=v("ZodType",(e,n)=>(fk(),j.init(e,n),e.def=n,e.type=n.type,e),{check(...e){let n=this.def;return this.clone(b.mergeDefs(n,{checks:[...n.checks??[],...e.map(i=>typeof i=="function"?{_zod:{check:i,def:{check:"custom"},onattach:[]}}:i)]}),{parent:!0})},with(...e){return this.check(...e)},clone(e,n){return G(this,e,n)},brand(){return this},register(e,n){return e.add(this,n),this},refine(e,n){return this.check(xd(e,n))},superRefine(e,n){return this.check(Id(e,n))},overwrite(e){return this.check(Ae(e))},optional(){return _t(this)},exactOptional(){return id(this)},nullable(){return lr(this)},nullish(){return _t(lr(this))},nonoptional(e){return ld(this,e)},array(){return mr(this)},or(e){return gn([this,e])},and(e){return Wl(this,e)},transform(e){return fo(this,Uo(e))},default(e){return sd(this,e)},prefault(e){return cd(this,e)},catch(e){return md(this,e)},pipe(e){return fo(this,e)},readonly(){return hd(this)},describe(e){let n=this.clone();return oe.add(n,{description:e}),n},meta(...e){if(e.length===0)return oe.get(this);let n=this.clone();return oe.add(n,e[0]),n},isOptional(){return this.safeParse(void 0).success},isNullable(){return this.safeParse(null).success},apply(e,...n){return n.length===0?e(this):e(this,...n)},get"~standard"(){return b.hide(this,"~standard",{...ii(this),jsonSchema:{input:an(this,"input"),output:an(this,"output")}})},set"~standard"(e){b.own(this,"~standard",e)},parse:function e(n,i){return $l(this,n,i,{callee:e})},parseAsync:async function e(n,i){return await _l(this,n,i,{callee:e})},safeParse(e,n){return kl(this,e,n)},async safeParseAsync(e,n){return xl(this,e,n)},get spa(){return this?.safeParseAsync},set spa(e){b.own(this,"spa",e)},validate(e,n){return Un(this,e,n)},validateAsync(e,n){return Cn(this,e,n)},encode:function e(n,i){return Il(this,n,i,{callee:e})},decode:function e(n,i){return wl(this,n,i,{callee:e})},encodeAsync:async function e(n,i){return await Sl(this,n,i,{callee:e})},decodeAsync:async function e(n,i){return await Pl(this,n,i,{callee:e})},safeEncode(e,n){return Al(this,e,n)},safeDecode(e,n){return Tl(this,e,n)},async safeEncodeAsync(e,n){return zl(this,e,n)},async safeDecodeAsync(e,n){return Nl(this,e,n)},toJSONSchema(e){return Oc(this,{})(e)},get description(){return oe.get(this)?.description},get _def(){return this._zod.def}}),go=v("_ZodString",(e,n)=>{pt.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Uc(e,i,o,t)},b.derived({format:e=>ne(e).format??null,minLength:e=>ne(e).minimum??null,maxLength:e=>ne(e).maximum??null},{regex(...e){return this.check(Jt(...e))},includes(...e){return this.check(Wt(...e))},startsWith(...e){return this.check(Xt(...e))},endsWith(...e){return this.check(qt(...e))},min(...e){return this.check(Ze(...e))},max(...e){return this.check(ht(...e))},length(...e){return this.check(yt(...e))},nonempty(...e){return this.check(Ze(1,...e))},lowercase(e){return this.check(Kt(e))},uppercase(e){return this.check(Ht(e))},trim(){return this.check(tn())},normalize(...e){return this.check(en(...e))},toLowerCase(){return this.check(nn())},toUpperCase(){return this.check(rn())},slugify(){return this.check(on())}})),dn=v("ZodString",(e,n)=>{pt.init(e,n),go.init(e,n)},{email(e){return this.check(Oi(vo,e))},url(e){return this.check(nr(dr,e))},jwt(e){return this.check(Qi(Eo,e))},emoji(e){return this.check(Ri(yo,e))},guid(e){return this.check(Di(ho,e))},uuid(e){return this.check(ji(Oe,e))},uuidv4(e){return this.check(Ui(Oe,e))},uuidv6(e){return this.check(Ci(Oe,e))},uuidv7(e){return this.check(Li(Oe,e))},nanoid(e){return this.check(Mi(bo,e))},cuid(e){return this.check(Zi($o,e))},cuid2(e){return this.check(Vi(_o,e))},ulid(e){return this.check(Fi(ko,e))},base64(e){return this.check(Xi(To,e))},base64url(e){return this.check(qi(zo,e))},xid(e){return this.check(Gi(xo,e))},ksuid(e){return this.check(Bi(Io,e))},ipv4(e){return this.check(Ji(wo,e))},ipv6(e){return this.check(Ki(So,e))},cidrv4(e){return this.check(Hi(Po,e))},cidrv6(e){return this.check(Wi(Ao,e))},e164(e){return this.check(Yi(No,e))},datetime(e){return this.check(rr(et,e))},date(e){return this.check(ir(tt,e))},time(e){return this.check(or(nt,e))},duration(e){return this.check(ar(rt,e))}});function cr(e){return Wu(dn,e)}var H=v("ZodStringFormat",(e,n)=>{B.init(e,n),go.init(e,n)}),et=v("ZodISODateTime",(e,n)=>{Rs.init(e,n),H.init(e,n)}),tt=v("ZodISODate",(e,n)=>{Ms.init(e,n),H.init(e,n)}),nt=v("ZodISOTime",(e,n)=>{Zs.init(e,n),H.init(e,n)}),rt=v("ZodISODuration",(e,n)=>{Vs.init(e,n),H.init(e,n)}),vo=v("ZodEmail",(e,n)=>{As.init(e,n),H.init(e,n)});function Af(e){return Oi(vo,e)}var ho=v("ZodGUID",(e,n)=>{Ss.init(e,n),H.init(e,n)});function Tf(e){return Di(ho,e)}var Oe=v("ZodUUID",(e,n)=>{Ps.init(e,n),H.init(e,n)});function zf(e){return ji(Oe,e)}function Nf(e){return Ui(Oe,e)}function Ef(e){return Ci(Oe,e)}function Of(e){return Li(Oe,e)}var dr=v("ZodURL",(e,n)=>{Ns.init(e,n),H.init(e,n)});function Df(e){return nr(dr,e)}function jf(e){return nr(dr,{protocol:Ln,hostname:Va,...b.normalizeParams(e)})}var yo=v("ZodEmoji",(e,n)=>{Es.init(e,n),H.init(e,n)});function Uf(e){return Ri(yo,e)}var bo=v("ZodNanoID",(e,n)=>{Os.init(e,n),H.init(e,n)});function Cf(e){return Mi(bo,e)}var $o=v("ZodCUID",(e,n)=>{Ds.init(e,n),H.init(e,n)});function Lf(e){return Zi($o,e)}var _o=v("ZodCUID2",(e,n)=>{js.init(e,n),H.init(e,n)});function Rf(e){return Vi(_o,e)}var ko=v("ZodULID",(e,n)=>{Us.init(e,n),H.init(e,n)});function Mf(e){return Fi(ko,e)}var xo=v("ZodXID",(e,n)=>{Cs.init(e,n),H.init(e,n)});function Zf(e){return Gi(xo,e)}var Io=v("ZodKSUID",(e,n)=>{Ls.init(e,n),H.init(e,n)});function Vf(e){return Bi(Io,e)}var wo=v("ZodIPv4",(e,n)=>{Fs.init(e,n),H.init(e,n)});function Ff(e){return Ji(wo,e)}var El=v("ZodMAC",(e,n)=>{Bs.init(e,n),H.init(e,n)});function Gf(e){return qu(El,e)}var So=v("ZodIPv6",(e,n)=>{Gs.init(e,n),H.init(e,n)});function Bf(e){return Ki(So,e)}var Po=v("ZodCIDRv4",(e,n)=>{Js.init(e,n),H.init(e,n)});function Jf(e){return Hi(Po,e)}var Ao=v("ZodCIDRv6",(e,n)=>{Ks.init(e,n),H.init(e,n)});function Kf(e){return Wi(Ao,e)}var To=v("ZodBase64",(e,n)=>{Hs.init(e,n),H.init(e,n)});function Hf(e){return Xi(To,e)}var zo=v("ZodBase64URL",(e,n)=>{Ws.init(e,n),H.init(e,n)});function Wf(e){return qi(zo,e)}var No=v("ZodE164",(e,n)=>{Xs.init(e,n),H.init(e,n)});function Xf(e){return Yi(No,e)}var Ol=v("ZodCreditCard",(e,n)=>{qs.init(e,n),H.init(e,n)});function qf(e){return Yu(Ol,e)}var Dl=v("ZodIBAN",(e,n)=>{Ys.init(e,n),H.init(e,n)});function Yf(e){return Qu(Dl,e)}var Eo=v("ZodJWT",(e,n)=>{Qs.init(e,n),H.init(e,n)});function Qf(e){return Qi(Eo,e)}var xt=v("ZodCustomStringFormat",(e,n)=>{eu.init(e,n),H.init(e,n)});function eg(e,n,i={}){return bt(xt,e,n,i)}function tg(e){return bt(xt,"hostname",Za,e)}function ng(e){return bt(xt,"hex",ns,e)}function rg(e){return bt(xt,"currency_code",Ga,e)}function ig(e,n){let i=n?.enc??"hex",o=`${e}_${i}`,t=xe[o];if(!t)throw new Error(`Unrecognized hash format: ${o}`);return bt(xt,o,t,n)}var pn=v("ZodNumber",(e,n)=>{fi.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Cc(e,i,o,t),e.isFinite=!0},b.derived({minValue:e=>{let{minimum:n,exclusiveMinimum:i}=ne(e);return Math.max(n??Number.NEGATIVE_INFINITY,i??Number.NEGATIVE_INFINITY)},maxValue:e=>{let{maximum:n,exclusiveMaximum:i}=ne(e);return Math.min(n??Number.POSITIVE_INFINITY,i??Number.POSITIVE_INFINITY)},isInt:e=>{let{isInt:n,multipleOf:i}=ne(e);return!!n||!!i?.some(Number.isSafeInteger)},format:e=>ne(e).format??null},{gt(e,n){return this.check(Ne(e,n))},gte(e,n){return this.check($e(e,n))},min(e,n){return this.check($e(e,n))},lt(e,n){return this.check(ze(e,n))},lte(e,n){return this.check(be(e,n))},max(e,n){return this.check(be(e,n))},int(e){return this.check(mo(e))},safe(e){return this.check(mo(e))},positive(e){return this.check(Ne(0,e))},nonnegative(e){return this.check($e(0,e))},negative(e){return this.check(ze(0,e))},nonpositive(e){return this.check(be(0,e))},multipleOf(e,n){return this.check(We(e,n))},step(e,n){return this.check(We(e,n))},finite(){return this}}));function jl(e){return tc(pn,e)}var It=v("ZodNumberFormat",(e,n)=>{tu.init(e,n),pn.init(e,n)});function mo(e){return rc(It,e)}function og(e){return ic(It,e)}function ag(e){return oc(It,e)}function sg(e){return ac(It,e)}function ug(e){return sc(It,e)}var mn=v("ZodBoolean",(e,n)=>{Kn.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Lc(e,i,o,t)});function Ul(e){return uc(mn,e)}var fn=v("ZodBigInt",(e,n)=>{gi.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Rc(e,i,o,t)},b.derived({minValue:e=>ne(e).minimum??null,maxValue:e=>ne(e).maximum??null,format:e=>ne(e).format??null},{gte(e,n){return this.check($e(e,n))},min(e,n){return this.check($e(e,n))},gt(e,n){return this.check(Ne(e,n))},lt(e,n){return this.check(ze(e,n))},lte(e,n){return this.check(be(e,n))},max(e,n){return this.check(be(e,n))},positive(e){return this.check(Ne(BigInt(0),e))},negative(e){return this.check(ze(BigInt(0),e))},nonpositive(e){return this.check(be(BigInt(0),e))},nonnegative(e){return this.check($e(BigInt(0),e))},multipleOf(e,n){return this.check(We(e,n))}}));function cg(e){return lc(fn,e)}var Oo=v("ZodBigIntFormat",(e,n)=>{nu.init(e,n),fn.init(e,n)});function lg(e){return pc(Oo,e)}function dg(e){return mc(Oo,e)}var Cl=v("ZodSymbol",(e,n)=>{ru.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Mc(e,i,o,t)});function pg(e){return fc(Cl,e)}var Ll=v("ZodUndefined",(e,n)=>{iu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Vc(e,i,o,t)});function mg(e){return gc(Ll,e)}var Rl=v("ZodNull",(e,n)=>{ou.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Zc(e,i,o,t)});function Ml(e){return vc(Rl,e)}var Zl=v("ZodAny",(e,n)=>{au.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Bc(e,i,o,t)});function fg(){return hc(Zl)}var Vl=v("ZodUnknown",(e,n)=>{su.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Jc(e,i,o,t)});function $t(){return yc(Vl)}var Fl=v("ZodNever",(e,n)=>{uu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Gc(e,i,o,t)});function Do(e){return bc(Fl,e)}var Gl=v("ZodVoid",(e,n)=>{cu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Fc(e,i,o,t)});function gg(e){return $c(Gl,e)}var pr=v("ZodDate",(e,n)=>{lu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Kc(e,i,o,t),e.min=(i,o)=>e.check($e(i,o)),e.max=(i,o)=>e.check(be(i,o))},b.derived({minDate:e=>{let{minimum:n}=ne(e);return n?new Date(n):null},maxDate:e=>{let{maximum:n}=ne(e);return n?new Date(n):null}},{}));function vg(e){return _c(pr,e)}var Bl=v("ZodArray",(e,n)=>{kt(),pu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>ol(e,i,o,t),e.element=n.element},{min(e,n){return this.check(Ze(e,n))},nonempty(e){return this.check(Ze(1,e))},max(e,n){return this.check(ht(e,n))},length(e,n){return this.check(yt(e,n))},unwrap(){return this.element}});function mr(e,n){return Ic(Bl,e,n)}function hg(e){let n=e._zod.def.shape;return jo(Object.keys(n))}var fr=v("ZodObject",(e,n)=>{kt(),mu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>al(e,i,o,t),b.installLazyProp(e,"shape",i=>i._zod.def.shape,!1)},{keyof(){return jo(Object.keys(this._zod.def.shape))},catchall(e){return this.clone(b.mergeDefs(this._zod.def,{catchall:e}))},passthrough(){return this.clone(b.mergeDefs(this._zod.def,{catchall:$t()}))},loose(){return this.clone(b.mergeDefs(this._zod.def,{catchall:$t()}))},strict(){return this.clone(b.mergeDefs(this._zod.def,{catchall:Do()}))},strip(){return this.clone(b.mergeDefs(this._zod.def,{catchall:void 0}))},extend(e){return b.extend(this,e)},safeExtend(e){return b.safeExtend(this,e)},merge(e){return b.merge(this,e)},pick(e){return b.pick(this,e)},omit(e){return b.omit(this,e)},partial(...e){return b.partial(vr,this,e[0])},exactPartial(...e){return b.partial(Co,this,e[0],"exactPartial")},required(...e){return b.required(Lo,this,e[0])}});function yg(e,n){let i={type:"object",shape:e??{},...b.normalizeParams(n)};return new fr(i)}function bg(e,n){return new fr({type:"object",shape:e,catchall:Do(),...b.normalizeParams(n)})}function $g(e,n){return new fr({type:"object",shape:e,catchall:$t(),...b.normalizeParams(n)})}var gr=v("ZodUnion",(e,n)=>{Hn.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>ao(e,i,o,t),e.options=n.options});function gn(e,n){return new gr({type:"union",options:e,...b.normalizeParams(n)})}var Jl=v("ZodXor",(e,n)=>{gr.init(e,n),fu.init(e,n),e._zod.processJSONSchema=(i,o,t)=>ao(e,i,o,t),e.options=n.options});function _g(e,n){return new Jl({type:"union",options:e,inclusive:!1,...b.normalizeParams(n)})}var Kl=v("ZodDiscriminatedUnion",(e,n)=>{gr.init(e,n),vu.init(e,n)});function kg(e,n,i){return new Kl({type:"union",options:n,discriminator:e,...b.normalizeParams(i)})}var Hl=v("ZodIntersection",(e,n)=>{hu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>sl(e,i,o,t)});function Wl(e,n){return new Hl({type:"intersection",left:e,right:n})}var Xl=v("ZodTuple",(e,n)=>{kt(),vi.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>ul(e,i,o,t)},{rest(e){return this.clone({...this._zod.def,rest:e})},partial(){let e=this._zod.def;if(e.checks?.length)throw new Error(".partial() cannot be used on tuple schemas containing refinements");return this.clone({...e,items:e.items.map(n=>new vr({type:"optional",innerType:n}))})}});function ql(e,n,i){let o=n instanceof j,t=o?i:n,r=o?n:null;return new Xl({type:"tuple",items:e,rest:r,...b.normalizeParams(t)})}var cn=v("ZodRecord",(e,n)=>{kt(),yu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>cl(e,i,o,t),e.keyType=n.keyType,e.valueType=n.valueType});function Yl(e,n,i){return!n||!n._zod?new cn({type:"record",keyType:cr(),valueType:e,...b.normalizeParams(n)}):new cn({type:"record",keyType:e,valueType:n,...b.normalizeParams(i)})}function xg(e,n,i){return new cn({type:"record",keyType:e,valueType:n,...b.normalizeParams(i),partial:!0})}function Ig(e,n,i){return new cn({type:"record",keyType:e,valueType:n,mode:"loose",...b.normalizeParams(i)})}var Ql=v("ZodMap",(e,n)=>{kt(),bu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>rl(e,i,o,t),e.keyType=n.keyType,e.valueType=n.valueType,e.min=(...i)=>e.check(Ee(...i)),e.nonempty=i=>e.check(Ee(1,i)),e.max=(...i)=>e.check(Xe(...i)),e.size=(...i)=>e.check(vt(...i))});function wg(e,n,i){return new Ql({type:"map",keyType:e,valueType:n,...b.normalizeParams(i)})}var ed=v("ZodSet",(e,n)=>{kt(),$u.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>il(e,i,o,t),e.min=(...i)=>e.check(Ee(...i)),e.nonempty=i=>e.check(Ee(1,i)),e.max=(...i)=>e.check(Xe(...i)),e.size=(...i)=>e.check(vt(...i))});function Sg(e,n){return new ed({type:"set",valueType:e,...b.normalizeParams(n)})}var ln=v("ZodEnum",(e,n)=>{_u.init(e,n),L.init(e,n),e._zod.processJSONSchema=(o,t,r)=>Hc(e,o,t,r),e.enum=n.entries,e.options=[...e._zod.values];let i=new Set(Object.keys(n.entries));e.extract=(o,t)=>{let r={};for(let a of o)if(i.has(a))r[a]=n.entries[a];else throw new Error(`Key ${a} not found in enum`);return new ln({...n,checks:[],...b.normalizeParams(t),entries:r})},e.exclude=(o,t)=>{let r={...n.entries};for(let a of o)if(i.has(a))delete r[a];else throw new Error(`Key ${a} not found in enum`);return new ln({...n,checks:[],...b.normalizeParams(t),entries:r})}});function jo(e,n){let i=Array.isArray(e)?Object.fromEntries(e.map(o=>[o,o])):e;return new ln({type:"enum",entries:i,...b.normalizeParams(n)})}function Pg(e,n){return new ln({type:"enum",entries:e,...b.normalizeParams(n)})}var td=v("ZodLiteral",(e,n)=>{ku.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Wc(e,i,o,t),e.values=new Set(n.values),Object.defineProperty(e,"value",{get(){if(n.values.length>1)throw new Error("This schema contains multiple valid literal values. Use `.values` instead.");return n.values[0]}})});function Ag(e,n){return new td({type:"literal",values:Array.isArray(e)?e:[e],...b.normalizeParams(n)})}var nd=v("ZodFile",(e,n)=>{xu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Yc(e,i,o,t),e.min=(i,o)=>e.check(Ee(i,o)),e.max=(i,o)=>e.check(Xe(i,o)),e.mime=(i,o)=>e.check(Qt(Array.isArray(i)?i:[i],o))});function Tg(e){return wc(nd,e)}var rd=v("ZodTransform",(e,n)=>{kt(),Iu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>nl(e,i,o,t),e._zod.parse=(i,o)=>{if(o.direction==="backward")throw new Ke(e.constructor.name);i.addIssue=r=>{if(typeof r=="string")i.issues.push(b.issue(r,i.value,n));else{let a=r;a.fatal&&(a.continue=!1),a.code??(a.code="custom"),"input"in a||(a.input=i.value),a.inst??(a.inst=e),i.issues.push(b.issue(a))}};let t=n.transform(i.value,i);return t instanceof Promise?t.then(r=>(i.value=r,i)):(i.value=t,i)}});function Uo(e){return new rd({type:"transform",transform:e})}var vr=v("ZodOptional",(e,n)=>{hi.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>so(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function _t(e){return new vr({type:"optional",innerType:e})}var Co=v("ZodExactOptional",(e,n)=>{wu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>so(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function id(e){return new Co({type:"optional",innerType:e})}var od=v("ZodNullable",(e,n)=>{Su.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>ll(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function lr(e){return new od({type:"nullable",innerType:e})}function zg(e){return _t(lr(e))}var ad=v("ZodDefault",(e,n)=>{Pu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>ml(e,i,o,t),e.unwrap=()=>e._zod.def.innerType,e.removeDefault=e.unwrap});function sd(e,n){return new ad({type:"default",innerType:e,get defaultValue(){return typeof n=="function"?n():b.shallowClone(n)}})}var ud=v("ZodPrefault",(e,n)=>{Au.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>fl(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function cd(e,n){return new ud({type:"prefault",innerType:e,get defaultValue(){return typeof n=="function"?n():b.shallowClone(n)}})}var Lo=v("ZodNonOptional",(e,n)=>{Tu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>dl(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function ld(e,n){return new Lo({type:"nonoptional",innerType:e,...b.normalizeParams(n)})}var dd=v("ZodSuccess",(e,n)=>{zu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Qc(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function Ng(e){return new dd({type:"success",innerType:e})}var pd=v("ZodCatch",(e,n)=>{Nu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>gl(e,i,o,t),e.unwrap=()=>e._zod.def.innerType,e.removeCatch=e.unwrap});function md(e,n){return new pd({type:"catch",innerType:e,catchValue:typeof n=="function"?n:b.constantCatch(n)})}var fd=v("ZodNaN",(e,n)=>{Eu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Xc(e,i,o,t)});function Eg(e){return xc(fd,e)}var hr=v("ZodPipe",(e,n)=>{yi.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>vl(e,i,o,t),e.in=n.in,e.out=n.out});function fo(e,n){return new hr({type:"pipe",in:e,out:n})}var yr=v("ZodCodec",(e,n)=>{hr.init(e,n),Wn.init(e,n)});function Og(e,n,i){return new yr({type:"pipe",in:e,out:n,transform:i.decode,reverseTransform:i.encode})}function Dg(e){let n=e._zod.def;return new yr({type:"pipe",in:n.out,out:n.in,transform:n.reverseTransform,reverseTransform:n.transform})}var gd=v("ZodPreprocess",(e,n)=>{hr.init(e,n),Ou.init(e,n)}),vd=v("ZodReadonly",(e,n)=>{Du.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>hl(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function hd(e){return new vd({type:"readonly",innerType:e})}var yd=v("ZodTemplateLiteral",(e,n)=>{ju.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>qc(e,i,o,t)});function jg(e,n){return new yd({type:"template_literal",parts:e,...b.normalizeParams(n)})}var bd=v("ZodLazy",(e,n)=>{Xn.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>bl(e,i,o,t),e.unwrap=()=>e._zod.def.getter()});function $d(e){return new bd({type:"lazy",getter:e})}var _d=v("ZodPromise",(e,n)=>{Cu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>yl(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function Ug(e){return new _d({type:"promise",innerType:e})}var kd=v("ZodFunction",(e,n)=>{Uu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>tl(e,i,o,t)});function Cg(e){return new kd({type:"function",input:Array.isArray(e?.input)?ql(e?.input):e?.input??mr($t()),output:e?.output??$t()})}var br=v("ZodCustom",(e,n)=>{Lu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>el(e,i,o,t)});function Lg(e){let n=new W({check:"custom"});return n._zod.check=e,n}function Rg(e,n){return Sc(br,e??(()=>!0),n)}function xd(e,n={}){return Pc(br,e,n)}function Id(e,n){return Ac(e,n)}var Mg=Tc,Zg=zc,wd=v("ZodInstanceOf",(e,n)=>{br.init(e,n)},{properties(e,n){return this.check(Yt(e,n))}});function Vg(e,n={}){let i=new wd({type:"custom",check:"custom",fn:o=>o instanceof e,abort:!0,...b.normalizeParams(n)});return i._zod.bag.Class=e,i._zod.check=o=>{o.value instanceof e||o.issues.push({code:"invalid_type",expected:e.name,input:o.value,inst:i,path:[...i._zod.def.path??[]]})},i}var Fg=(...e)=>Nc({Codec:yr,Boolean:mn,String:dn},...e);function Gg(e){let n=$d(()=>gn([cr(e),jl(),Ul(),Ml(),mr(n),Yl(cr(),n)]));return n}function Bg(e,n){return new gd({type:"pipe",in:Uo(e),out:n})}var gk={invalid_type:"invalid_type",too_big:"too_big",too_small:"too_small",invalid_format:"invalid_format",not_multiple_of:"not_multiple_of",unrecognized_keys:"unrecognized_keys",invalid_union:"invalid_union",invalid_key:"invalid_key",invalid_element:"invalid_element",invalid_value:"invalid_value",custom:"custom"};function vk(e){Y({customError:e})}function hk(){return Y().customError}var Sd;Sd||(Sd={});var $r={};Ce($r,{ZodISODate:()=>tt,ZodISODateTime:()=>et,ZodISODuration:()=>rt,ZodISOTime:()=>nt,date:()=>bk,datetime:()=>yk,duration:()=>_k,time:()=>$k});function yk(e){return rr(et,e)}function bk(e){return ir(tt,e)}function $k(e){return or(nt,e)}function _k(e){return ar(rt,e)}var P={...vn,...lo,iso:$r},kk=new Set(["$schema","$ref","$defs","definitions","$id","id","$comment","$anchor","$vocabulary","$dynamicRef","$dynamicAnchor","type","enum","const","anyOf","oneOf","allOf","not","properties","required","additionalProperties","patternProperties","propertyNames","minProperties","maxProperties","items","prefixItems","additionalItems","minItems","maxItems","uniqueItems","contains","minContains","maxContains","minLength","maxLength","pattern","format","minimum","maximum","exclusiveMinimum","exclusiveMaximum","multipleOf","description","default","contentEncoding","contentMediaType","contentSchema","unevaluatedItems","unevaluatedProperties","if","then","else","dependentSchemas","dependentRequired","nullable","readOnly"]);function xk(e,n){let i=e.$schema;return i==="https://json-schema.org/draft/2020-12/schema"?"draft-2020-12":i==="http://json-schema.org/draft-07/schema#"?"draft-7":i==="http://json-schema.org/draft-04/schema#"?"draft-4":n??"draft-2020-12"}function Jg(e,n){return e.map((i,o)=>oo).check(o=>{let t=o.value;if(typeof t!="object"||t===null||Array.isArray(t))return;let r=Object.getOwnPropertyNames(t);if(n.minProperties!==void 0&&r.length=${n.minProperties} properties`,input:t,inst:e,continue:!0}),n.maxProperties!==void 0&&r.length>n.maxProperties&&o.issues.push({origin:"object",code:"too_big",maximum:n.maxProperties,inclusive:!0,message:`Too big: expected object to have <=${n.maxProperties} properties`,input:t,inst:e,continue:!0}),n.keySchema)for(let a of r){let s=n.keySchema.safeParse(a);s.success||o.issues.push({code:"invalid_key",origin:"record",issues:s.error.issues,input:a,path:[a],continue:!0})}}).pipe(e)}function Pd(e,n){if(e===null)return"z";let i=typeof e;if(i!=="object"){if(i==="number"&&Number.isNaN(e))return null;let o=String(e);return`${i[0]}${o.length}:${o}`}if(n.has(e))return null;n.add(e);try{if(Array.isArray(e)){let r=[];for(let a of e){let s=Pd(a,n);if(s===null)return null;r.push(s)}return`a${r.length}:[${r.join(",")}]`}let o=Object.keys(e).sort(),t=[];for(let r of o){let a=Pd(e[r],n);if(a===null)return null;t.push(`${r.length}:${r}=${a}`)}return`o${t.length}:{${t.join(",")}}`}finally{n.delete(e)}}var Pk=new Set(["items","prefixItems","additionalItems","additionalProperties","contains","propertyNames","not","if","then","else","allOf","anyOf","oneOf","unevaluatedItems","unevaluatedProperties","contentSchema"]),Ak=new Set(["properties","patternProperties","dependentSchemas","dependencies","$defs","definitions"]);function _r(e){return typeof e!="object"||e===null?!1:Array.isArray(e)?e.some(_r):typeof e.$ref=="string"?!0:Object.entries(e).some(([n,i])=>Pk.has(n)?_r(i):!Ak.has(n)||typeof i!="object"||i===null?!1:Object.values(i).some(_r))}function Kg(e){return e===1?"element":"elements"}function Tk(e,n){return P.transform(o=>o).check(o=>{let t=o.value;if(Array.isArray(t)){if(n.uniqueItems===!0){let r=new Map;for(let a=0;a=a)break;sn.maxContains&&o.issues.push({code:"custom",message:`Array must contain at most ${n.maxContains} matching ${Kg(n.maxContains)}`,input:t,continue:!0})}}}).pipe(e)}function Hg(e,n){if(e!==!1)return e===void 0||e===!0?P.any():de(e,n)}var zk=/^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/;function Wg(e,n){if(e.not!==void 0){if(typeof e.not=="object"&&Object.keys(e.not).length===0)return P.never();throw new Error("not is not supported in Zod (except { not: {} } for never)")}if(e.unevaluatedItems!==void 0)throw new Error("unevaluatedItems is not supported");if(e.unevaluatedProperties!==void 0)throw new Error("unevaluatedProperties is not supported");if(e.if!==void 0||e.then!==void 0||e.else!==void 0)throw new Error("Conditional schemas (if/then/else) are not supported");if(e.dependentSchemas!==void 0||e.dependentRequired!==void 0)throw new Error("dependentSchemas and dependentRequired are not supported");if(e.$ref){let t=e.$ref;if(n.refs.has(t))return n.refs.get(t);if(n.processing.has(t))return P.lazy(()=>{if(!n.refs.has(t))throw new Error(`Circular reference not resolved: ${t}`);return n.refs.get(t)});n.processing.add(t);let r=wk(t,n),a=de(r,n);return n.refs.set(t,a),n.processing.delete(t),a}if(e.enum!==void 0){let t=e.enum;if(n.version==="openapi-3.0"&&e.nullable===!0&&t.length===1&&t[0]===null)return P.null();if(t.length===0)return P.never();if(t.length===1)return P.literal(t[0]);if(t.every(a=>typeof a=="string"))return P.enum(t);let r=t.map(a=>P.literal(a));return r.length<2?r[0]:P.union([r[0],r[1],...r.slice(2)])}if(e.const!==void 0)return P.literal(e.const);let i=e.type;if(Array.isArray(i)){let t=i.map(r=>{let a={...e,type:r};return Wg(a,n)});return t.length===0?P.never():t.length===1?t[0]:P.union(t)}if(!i)return P.any();let o;switch(i){case"string":{let t=P.string();if(e.format){let r=e.format;r==="email"?t=t.check(P.email()):r==="uri"||r==="uri-reference"?t=t.check(P.url()):r==="uuid"||r==="guid"?t=t.check(P.uuid()):r==="date-time"?t=t.check(P.iso.datetime({offset:!0})):r==="date"?t=t.check(P.iso.date()):r==="time"?t=t.check(P.regex(zk)):r==="duration"?t=t.check(P.iso.duration()):r==="hostname"?t=t.check(P.hostname()):r==="ipv4"?t=t.check(P.ipv4()):r==="ipv6"?t=t.check(P.ipv6()):r==="mac"?t=t.check(P.mac()):r==="cidr"?t=t.check(P.cidrv4()):r==="cidr-v6"?t=t.check(P.cidrv6()):r==="base64"?t=t.check(P.base64()):r==="base64url"?t=t.check(P.base64url()):r==="e164"?t=t.check(P.e164()):r==="credit_card"?t=t.check(P.creditCard()):r==="iban"?t=t.check(P.iban()):r==="jwt"?t=t.check(P.jwt()):r==="emoji"?t=t.check(P.emoji()):r==="nanoid"?t=t.check(P.nanoid()):r==="cuid"?t=t.check(P.cuid()):r==="cuid2"?t=t.check(P.cuid2()):r==="ulid"?t=t.check(P.ulid()):r==="xid"?t=t.check(P.xid()):r==="ksuid"&&(t=t.check(P.ksuid()))}typeof e.minLength=="number"&&(t=t.min(e.minLength)),typeof e.maxLength=="number"&&(t=t.max(e.maxLength)),e.pattern&&(t=t.regex(new RegExp(e.pattern))),o=t;break}case"number":case"integer":{let t=i==="integer"?P.number().int():P.number();typeof e.minimum=="number"&&e.exclusiveMinimum!==!0&&(t=t.min(e.minimum)),typeof e.maximum=="number"&&e.exclusiveMaximum!==!0&&(t=t.max(e.maximum)),typeof e.exclusiveMinimum=="number"?t=t.gt(e.exclusiveMinimum):e.exclusiveMinimum===!0&&typeof e.minimum=="number"&&(t=t.gt(e.minimum)),typeof e.exclusiveMaximum=="number"?t=t.lt(e.exclusiveMaximum):e.exclusiveMaximum===!0&&typeof e.maximum=="number"&&(t=t.lt(e.maximum)),typeof e.multipleOf=="number"&&(t=t.multipleOf(e.multipleOf)),o=t;break}case"boolean":{o=P.boolean();break}case"null":{o=P.null();break}case"object":{let t={},r=e.properties||{},a=new Set(e.required||[]),s=typeof e.additionalProperties=="object"?de(e.additionalProperties,n):void 0;for(let[p,m]of Object.entries(r)){let f=de(m,n);ie(t,p,a.has(p)?f:f.optional())}if(e.patternProperties){let p=e.patternProperties,m=Object.keys(p),f=[];for(let h of m){let k=de(p[h],n),x=P.string().regex(new RegExp(h));f.push(P.looseRecord(x,k))}let g=[];if(Object.keys(t).length>0&&g.push(P.object(t).passthrough()),g.push(...f),g.length===0)o=P.object({}).passthrough();else if(g.length===1)o=g[0];else{let h=P.intersection(g[0],g[1]);for(let k=2;knew RegExp(I)),x=o;o=o.check(I=>{if(!_e(I.value))return;let A=[];for(let C of Object.keys(I.value))h.includes(C)||k.some(V=>V.test(C))||A.push(C);A.length&&I.issues.push({code:"unrecognized_keys",keys:A,input:I.value,inst:x})})}}else{let p=P.object(t);e.additionalProperties===!1?o=p.strict():s?o=p.catchall(s):o=p.passthrough()}let u=e.propertyNames!==void 0&&e.propertyNames!==!0,c=typeof e.minProperties=="number"?e.minProperties:void 0,l=typeof e.maxProperties=="number"?e.maxProperties:void 0;if(u||c!==void 0||l!==void 0){let p;if(u){let m=typeof e.propertyNames=="object"&&e.propertyNames.type===void 0?{type:"string",...e.propertyNames}:e.propertyNames;p=de(m,n)}o=Sk(o,{keySchema:p,minProperties:c,maxProperties:l})}break}case"array":{let t=e.prefixItems,r=e.items;if(t&&Array.isArray(t)){let a=typeof e.minItems=="number"?e.minItems:0,s=t.map(p=>de(p,n)),u=Jg(s,a),c=Array.isArray(r)?void 0:Hg(r,n),l=P.tuple(u);o=c?l.rest(c):l,typeof e.minItems=="number"&&(o=o.check(P.minLength(e.minItems))),typeof e.maxItems=="number"&&(o=o.check(P.maxLength(e.maxItems)))}else if(Array.isArray(r)){let a=typeof e.minItems=="number"?e.minItems:0,s=r.map(p=>de(p,n)),u=Jg(s,a),c=Hg(e.additionalItems,n),l=P.tuple(u);o=c?l.rest(c):l,typeof e.minItems=="number"&&(o=o.check(P.minLength(e.minItems))),typeof e.maxItems=="number"&&(o=o.check(P.maxLength(e.maxItems)))}else if(r!==void 0){let a=de(r,n),s=P.array(a);typeof e.minItems=="number"&&(s=s.min(e.minItems)),typeof e.maxItems=="number"&&(s=s.max(e.maxItems)),o=s}else o=P.array(P.any());(e.uniqueItems===!0||e.contains!==void 0)&&(o=Tk(o,{uniqueItems:e.uniqueItems===!0,containsSchema:e.contains!==void 0?de(e.contains,n):void 0,minContains:typeof e.minContains=="number"?e.minContains:void 0,maxContains:typeof e.maxContains=="number"?e.maxContains:void 0}));break}default:throw new Error(`Unsupported type: ${i}`)}return o}function de(e,n){if(typeof e=="boolean")return e?P.any():P.never();let i=Wg(e,n),o=e.type||e.enum!==void 0||e.const!==void 0;if(e.anyOf&&Array.isArray(e.anyOf)){let s=e.anyOf.map(c=>de(c,n)),u=P.union(s);i=o?P.intersection(i,u):u}if(e.oneOf&&Array.isArray(e.oneOf)){let s=e.oneOf.map(c=>de(c,n)),u=P.xor(s);i=o?P.intersection(i,u):u}if(e.allOf&&Array.isArray(e.allOf))if(e.allOf.length===0)i=o?i:P.any();else{let s=o?i:de(e.allOf[0],n),u=o?0:1;for(let c=u;c0&&n.registry.add(i,t),e.description&&(i=i.describe(e.description)),i}function Xg(e,n){if(typeof e=="boolean")return e?P.any():P.never();let i;try{i=JSON.parse(JSON.stringify(e))}catch{throw new Error("fromJSONSchema input is not valid JSON (possibly cyclic); use $defs/$ref for recursive schemas")}let o=xk(i,n?.defaultTarget),t=i.$defs||i.definitions||{},r={version:o,defs:t,refs:new Map,processing:new Set,rootSchema:i,registry:n?.registry??oe};return de(i,r)}var qg=Symbol("z.visit/resolving");function kr(e,n){let i=typeof n=="function"?n:(a,s)=>{let u=n[a._zod.def.type];return u?u(a,s):a},o=new Map;function t(a){let s=o.get(a);if(s===qg)return new Xn({type:"lazy",getter:()=>o.get(a)});if(s!==void 0)return s;o.set(a,qg);let u=r(a),c=i(u,u!==a);return o.set(a,c),c}function r(a){let s=a._zod.def,u=s.type;switch(u){case"object":{let c=s.shape,l=Object.keys(c),p=!1,m={};for(let g of l){let h=t(c[g]);h!==c[g]&&(p=!0),m[g]=h}let f=s.catchall;return s.catchall&&(f=t(s.catchall),f!==s.catchall&&(p=!0)),p?G(a,{...s,shape:m,catchall:f}):a}case"array":{let c=t(s.element);return c===s.element?a:G(a,{...s,element:c})}case"tuple":{let c=s.items,l=!1,p=[];for(let f of c){let g=t(f);g!==f&&(l=!0),p.push(g)}let m=s.rest;return s.rest&&(m=t(s.rest),m!==s.rest&&(l=!0)),l?G(a,{...s,items:p,rest:m}):a}case"record":case"map":{let c=t(s.keyType),l=t(s.valueType);return c===s.keyType&&l===s.valueType?a:G(a,{...s,keyType:c,valueType:l})}case"set":{let c=t(s.valueType);return c===s.valueType?a:G(a,{...s,valueType:c})}case"union":{let c=s.options,l=!1,p=[];for(let m of c){let f=t(m);f!==m&&(l=!0),p.push(f)}return l?G(a,{...s,options:p}):a}case"intersection":{let c=t(s.left),l=t(s.right);return c===s.left&&l===s.right?a:G(a,{...s,left:c,right:l})}case"optional":case"nullable":case"default":case"prefault":case"catch":case"readonly":case"nonoptional":case"promise":case"success":{let c=t(s.innerType);return c===s.innerType?a:G(a,{...s,innerType:c})}case"pipe":{let c=t(s.in),l=t(s.out);return c===s.in&&l===s.out?a:G(a,{...s,in:c,out:l})}case"function":{let c=t(s.input),l=t(s.output);return c===s.input&&l===s.output?a:G(a,{...s,input:c,output:l})}case"lazy":{let c=s.getter,{_cachedInner:l,...p}=s;return G(a,{...p,getter:()=>t(c())})}case"template_literal":case"string":case"number":case"int":case"boolean":case"bigint":case"symbol":case"undefined":case"null":case"void":case"never":case"any":case"unknown":case"date":case"nan":case"enum":case"literal":case"file":case"transform":case"custom":return a;default:return a}}return t(e)}function Yg(e){return kr(e,{object:n=>n.partial(),union:n=>{let i=n._zod.def;return i.discriminator===void 0?n:gn(i.options)}})}function Nk(e,n){if(!n?.length)return e;let i=e._zod.def;return G(e,Se(i,{checks:[...i.checks??[],...n]}),{parent:!0})}function Qg(e){return Nk(e.out,e.checks)}function Ek(e){return e.in._zod.traits.has("$ZodTransform")?Qg(e):e.in}function ev(e){return kr(e,{pipe:n=>Ek(n._zod.def),default:(n,i)=>i?_t(n._zod.def.innerType):n,catch:(n,i)=>i?n._zod.def.innerType:n})}function tv(e){return kr(e,{pipe:n=>Qg(n._zod.def),prefault:(n,i)=>i?n._zod.def.innerType:n})}var Ad={};Ce(Ad,{bigint:()=>Uk,boolean:()=>jk,date:()=>Ck,number:()=>Dk,string:()=>Ok});function Ok(e){return Xu(dn,e)}function Dk(e){return nc(pn,e)}function jk(e){return cc(mn,e)}function Uk(e){return dc(fn,e)}function Ck(e){return kc(pr,e)}var Lk=new Set(["__proto__","prototype","constructor"]),wt=d.string().min(1).max(256).refine(e=>!Lk.has(e),"reserved storage key"),Ro=d.json(),Mo=256*1024,Rk=5*1024*1024,nv=1024,rv=d.strictObject({key:wt}),iv=d.object({value:Ro}),ov=d.strictObject({key:wt,value:Ro}),av=d.object({ok:d.literal(!0)}),sv=d.strictObject({key:wt}),uv=d.object({ok:d.literal(!0)}),cv=d.strictObject({}).optional(),lv=d.object({keys:d.array(d.string()).max(nv)}),dv=d.strictObject({key:wt}),pv=d.object({value:d.string().nullable()}),mv=d.strictObject({key:wt,value:d.string().max(64*1024)}),fv=d.object({ok:d.literal(!0)}),gv=d.strictObject({key:wt}),vv=d.object({ok:d.literal(!0)}),hv=d.strictObject({}).optional(),yv=d.object({status:d.enum(["os-keyring","unavailable"])}),bv=d.strictObject({}).optional(),$v=d.object({settings:d.record(d.string(),Ro)}),_v=d.strictObject({key:wt,value:Ro}),kv=d.object({ok:d.literal(!0)});var Zo="x-orca-enum-since";var it="1.4.160",Td="1.4.245";var xr="1.4.246";var xv=xr,Iv=xr,Zk="Relative to the plugin root; `..` segments and Windows device names such as `CON` are refused.";function wv(e,n,i){return ot(`${e} ${Zk}`,n,i)}function ot(e,n,i){return i?{description:e,"x-orca-since":n,examples:[...i]}:{description:e,"x-orca-since":n}}var hn=["workspace.created","workspace.removed","agent.status.changed","workspace.changed"],nT=hn.length,Vk={"workspace.created":Td,"workspace.removed":Td,"agent.status.changed":it,"workspace.changed":Iv},Vo=new Map([["worktree.created","workspace.created"],["worktree.removed","workspace.removed"]]);var rT=d.object({on:d.enum(hn).meta({...ot("Event delivered to the plugin worker.",it),[Zo]:Vk})}).strict().meta({id:"EventContribution",description:"An event subscription. Requires `main`, the `trusted-worker` execution profile and the capability of the event's domain: `workspace:read` for workspace events, `agent:read` for agent events."});var pe=["worker","panel","editor"],Sv=["worker"],yn=["panel","editor"],ee=e=>e;function Pv(e,n){return n==="worker"?e.since:Math.max(e.since,e.framesSince??0)}var Fk=["success","failure","cancellation","superseded"],Av=[...Fk,"interruption","unconfirmed"];var bn=["working","blocked","waiting","done"];var CT=new Set(bn);var at=d.string().regex(/^[A-Za-z0-9_.:-]{1,128}$/,"is 1-128 letters, digits, or . _ : -");var Ev=12e4,JT=1024*1024,KT=256*1024;var Bk=d.object({id:d.string().min(1).max(64),surface:d.enum(["panel","editor"]),contributionId:d.string().min(1).max(256)}),HT=d.object({name:at,input:d.unknown(),panel:Bk}),WT=d.object({event:at,payload:d.unknown(),panel:d.string().min(1).max(64).optional()}),Ov=["storage","settings"],XT=d.object({area:d.enum(Ov),key:d.string().min(1).max(256)}),qT=d.discriminatedUnion("kind",[d.object({kind:d.literal("message"),event:at,payload:d.unknown()}),d.object({kind:d.literal("event"),event:d.enum(hn),payload:d.unknown()}),d.object({kind:d.literal("changed"),area:d.enum(Ov),key:d.string()})]);var Jk=d.strictObject({name:at,input:d.json().optional(),timeoutMs:d.number().int().min(1).max(Ev).optional()}),Kk=d.object({output:d.json()}),Hk=50,Wk=d.strictObject({}).optional(),Xk=d.object({agents:d.array(d.object({terminalId:d.string().min(1).max(1024).nullable(),title:d.string().max(512).nullable(),agent:d.string().max(128).nullable(),state:d.enum(bn),stateStartedAt:d.number().finite()})).max(Hk)}),qk=d.strictObject({event:d.enum(hn)}),Yk=d.object({ok:d.literal(!0)}),Dv={"plugin.request":ee({summary:"Asks the plugin's own worker to run the handler it registered with `orca.panels.handle(name)`, starting the worker if needed; resolves with what the handler returned. `unknown_method` when no handler has that name.",since:2,scope:"plugin-private",capability:null,mutation:!1,surfaces:yn,params:Jk,result:Kk}),"agents.list":ee({summary:"The agents in the focused workspace: their terminal, title, agent kind and status. `agent.status.changed` reports each change after.",since:2,scope:"active-workspace",capability:"agent:read",mutation:!1,surfaces:pe,params:Wk,result:Xk}),"events.subscribe":ee({summary:"Delivers a workspace or agent event to this panel as `orca.on(event)`; needs the event's read capability. The frame APIs call it for you.",since:2,scope:"plugin-private",capability:null,mutation:!1,surfaces:yn,params:qk,result:Yk})};var Qk=4096,ex=50,Ir=512,Fo=1024,tx=d.strictObject({}).optional(),zd=d.object({branch:d.string().max(Ir),displayName:d.string().max(Ir),terminals:d.array(d.object({id:d.string().min(1).max(Fo),title:d.string().max(Ir).optional()}).strict()).max(ex)}).strict().nullable(),nx=zd,rx=d.strictObject({terminalId:d.string().min(1).max(Fo),text:d.string().min(1).max(Qk),enter:d.boolean().default(!1)}),ix=d.object({accepted:d.boolean()}),ox=d.strictObject({title:d.string().min(1).max(120),body:d.string().max(1e3).optional()}),ax=d.object({delivered:d.boolean()});var sx=8192,ux=["http:","https:","mailto:"],jv=64*1024*1024,cx=d.strictObject({url:d.string().min(1).max(sx).refine(fx,"url must be an http:, https: or mailto: URL")}),lx=d.object({opened:d.boolean(),reason:d.enum(["cancelled","consent-unavailable"]).optional()}),dx=d.union([d.string().max(jv),d.custom(e=>e instanceof ArrayBuffer||e instanceof Uint8Array,"data must be a string or ArrayBuffer").refine(e=>e.byteLength<=jv,"data exceeds 64 MiB").meta({type:"ArrayBuffer"})]),px=d.strictObject({suggestedName:d.string().min(1).max(255).optional(),mimeType:d.string().min(1).max(255).optional(),data:dx}),mx=d.object({status:d.enum(["saved","cancelled"])});function fx(e){try{return ux.includes(new URL(e).protocol)}catch{return!1}}var St={"workspace.readContext":ee({summary:"Branch, name and terminal ids of the focused workspace, or null when none is focused.",since:0,scope:"active-workspace",capability:"workspace:read",mutation:!1,surfaces:pe,params:tx,result:nx}),"terminal.sendText":ee({summary:"Types text into one terminal named by id, optionally pressing Enter.",since:0,scope:"explicit-terminal",capability:"terminal:send",mutation:!0,surfaces:Sv,params:rx,result:ix}),"notifications.show":ee({summary:"Shows a desktop notification.",since:0,scope:"desktop",capability:"notifications:show",mutation:!0,surfaces:pe,params:ox,result:ax}),"storage.get":ee({summary:"Reads a JSON value from the plugin's private store; null when absent.",since:0,scope:"plugin-private",capability:"storage:own",mutation:!1,framesSince:2,surfaces:pe,params:rv,result:iv}),"storage.set":ee({summary:"Writes a JSON value to the plugin's private store.",since:0,scope:"plugin-private",capability:"storage:own",mutation:!0,framesSince:2,surfaces:pe,params:ov,result:av}),"storage.delete":ee({summary:"Removes a key from the plugin's private store.",since:0,scope:"plugin-private",capability:"storage:own",mutation:!0,framesSince:2,surfaces:pe,params:sv,result:uv}),"storage.keys":ee({summary:"Lists the keys in the plugin's private store.",since:0,scope:"plugin-private",capability:"storage:own",mutation:!1,framesSince:2,surfaces:pe,params:cv,result:lv}),"secrets.get":ee({summary:"Reads a secret from the plugin's encrypted secrets file; null when absent.",since:0,scope:"plugin-private",capability:"secrets:own",mutation:!1,framesSince:2,surfaces:pe,params:dv,result:pv}),"secrets.set":ee({summary:"Stores a secret in the plugin's encrypted secrets file.",since:0,scope:"plugin-private",capability:"secrets:own",mutation:!0,framesSince:2,surfaces:pe,params:mv,result:fv}),"secrets.delete":ee({summary:"Removes a secret from the plugin's encrypted secrets file.",since:0,scope:"plugin-private",capability:"secrets:own",mutation:!0,framesSince:2,surfaces:pe,params:gv,result:vv}),"secrets.protection":ee({summary:"How secrets are protected at rest: `os-keyring`, or `unavailable` (no OS key store, or Linux `basic_text`), where `secrets.set` fails.",since:1,scope:"plugin-private",capability:"secrets:own",mutation:!1,framesSince:2,surfaces:pe,params:hv,result:yv}),"settings.get":ee({summary:"Reads every setting the plugin owns.",since:0,scope:"plugin-private",capability:"settings:own",mutation:!1,framesSince:2,surfaces:pe,params:bv,result:$v}),"settings.set":ee({summary:"Writes one setting the plugin owns.",since:0,scope:"plugin-private",capability:"settings:own",mutation:!0,framesSince:2,surfaces:pe,params:_v,result:kv}),"shell.openExternal":ee({summary:"Opens an http:, https: or mailto: URL in the default browser. Needs a click or key press in the frame; desktop app only. Orca asks the person before an http(s) host the plugin was not allowed; `opened` is false if they cancel.",since:1,scope:"desktop",capability:null,userActivation:!0,mutation:!1,surfaces:yn,params:cx,result:lx}),"files.saveAs":ee({summary:"Offers data (a string or ArrayBuffer, up to 64 MiB) in Orca's save dialog; the plugin never learns the path. Needs a click or key press in the frame; desktop app only.",since:1,scope:"desktop",capability:null,userActivation:!0,mutation:!0,surfaces:yn,params:px,result:mx}),...Dv},Uv=Object.keys(St).filter(Cv);function Cv(e){return Object.hasOwn(St,e)}function Nd(e){return Cv(e)?St[e]:null}var Lv=Math.max(...Uv.map(e=>St[e].since));function wr(e){return Uv.filter(n=>St[n].surfaces.includes(e))}function Rv(e,n){return wr(e).filter(i=>n||St[i].userActivation!==!0)}function Mv(e,n="panel"){return Math.max(0,...e.map(i=>Pv(St[i],n)))}var Fe=1,dz=d.number().refine(e=>e===Fe,{error:e=>typeof e.input=="number"&&e.input>Fe?`targets host API ${e.input}, but this Orca supports only ${Fe}; update Orca`:`must be ${Fe}`}).meta({const:Fe});var gx=new Set(["rate_limited","unavailable","timeout","conflict"]);function De(e,n=e,i){return Object.assign(new Error(n),{code:e,retryable:gx.has(e),...i===void 0?{}:{retryAfterMs:i}})}var vx=new Set(["plugin.request","events.subscribe","storage.get","storage.set","storage.delete","storage.keys","settings.get","settings.set","secrets.get","secrets.set","secrets.delete","secrets.protection"]);function Go(e,n){return typeof e=="object"&&e!==null&&n in e?Object.getOwnPropertyDescriptor(e,n)?.value:void 0}function Zv(e){let n={storage:new Map(Object.entries(e.storage??{})),settings:new Map(Object.entries(e.settings??{})),secrets:new Map(Object.entries(e.secrets??{}))},i=new Set,o=(a,s,u)=>{if(u===void 0?n[a].delete(s):n[a].set(s,u),a!=="secrets")for(let c of i)c(a,s);return{ok:!0}},t=null;async function r(a){let s=String(Go(a,"name")),u=Go(a,"input");if(!e.requests||!Object.hasOwn(e.requests,s)){if(t)return{output:await t(s,u)??null};throw De("unknown_method",`no panel handler named ${s}`)}let c=e.requests[s];return{output:(typeof c=="function"?await c(u):c)??null}}return{handles:a=>vx.has(a),async answer(a,s){let u=String(Go(s,"key")),c=Go(s,"value");switch(a){case"plugin.request":return r(s);case"storage.get":return{value:n.storage.get(u)??null};case"storage.keys":return{keys:[...n.storage.keys()]};case"settings.get":return{settings:Object.fromEntries(n.settings)};case"secrets.get":return{value:n.secrets.get(u)??null};case"secrets.protection":return{status:"os-keyring"};case"storage.set":return o("storage",u,c);case"settings.set":return o("settings",u,c);case"secrets.set":return o("secrets",u,c);case"storage.delete":return o("storage",u,void 0);case"secrets.delete":return o("secrets",u,void 0);default:return{ok:!0}}},routeRequests(a){return t=a,()=>{t===a&&(t=null)}},onChange(a){return i.add(a),()=>i.delete(a)},snapshot:()=>({storage:Object.fromEntries(n.storage),settings:Object.fromEntries(n.settings),secrets:Object.fromEntries(n.secrets)})}}var Bo=class extends Error{constructor(i,o){super(o);this.code=i}code};function hx(e){return typeof e=="function"}var Vv={"workspace.readContext":null,"notifications.show":{delivered:!0},"shell.openExternal":{opened:!0},"files.saveAs":{status:"saved"},"agents.list":{agents:[]}};function Fv(e,n){let i=new Set(e.capabilities??n),o=new Map(Object.entries(e.results??{})),t=Zv(e),r={panel:Rv("panel",!0),worker:wr("worker")},a=[],s=[],u=new Set,c=0,l=(g,h)=>{throw new Bo(g,h)};async function p(g,h,k){let x=Nd(g);if(!x)return l("unknown_method",`${g} does not exist in this Orca`);if(!x.surfaces.includes(k))return l("not_permitted",`${g} is not available to ${k}s`);if(x.userActivation===!0){if(c===0)return l("not_permitted",`${g} needs a click or key press in the frame`);c-=1}if(x.capability&&!i.has(x.capability))return l("capability_denied",`${g} needs the ${x.capability} capability`);let I=x.params.safeParse(h);return I.success?I.data:l("invalid_params",I.error.issues[0]?.message??"invalid params")}async function m(g,h,k){let x;try{x=await p(g,h,k)}catch(T){throw T instanceof Bo?(s.push({method:g,code:T.code,message:T.message}),De(T.code,T.message)):T}let I=Nd(g);if(!I)throw De("unknown_method",g);let A=!o.has(g)&&t.handles(g);if(!o.has(g)&&!A&&!Object.hasOwn(Vv,g))throw De("unavailable",`the test configured no result for ${g}`);let C=o.has(g)?o.get(g):Vv[g],V=A?await t.answer(g,x):hx(C)?await C(x):C,w=I.result.safeParse(V);if(!w.success)throw new TypeError(`mockHost: the result configured for ${g} does not match the host API: ${w.error.issues[0]?.message??"invalid result"}`);return w.data}let f=g=>({api:{major:Fe,minor:Mv(r[g])},call(h,k){a.push({method:h,params:k});let x=m(h,k,g);return u.add(x),x.catch(()=>{}).finally(()=>u.delete(x)),x},has:h=>r[g].some(k=>k===h)});return{calls:a,refusals:s,capabilities:[...i],callsOf:g=>a.filter(h=>h.method===g).map(h=>h.params),respond:(g,h)=>o.set(g,h),grantGesture:()=>{c=1},data:()=>t.snapshot(),onDataChange:g=>t.onChange(g),routeRequests:g=>t.routeRequests(g),async idle(){for(;u.size>0;)await Promise.allSettled(u)},bridge:f("panel"),worker:f("worker")}}var je={render:"ui.render",event:"ui.event",error:"ui.error",ack:"ui.ack",ready:"ui.ready",hydrate:"ui.hydrate",visibility:"ui.visibility",persist:"ui.persist",retain:"ui.retain"};var yx={Input:{value:"value",change:"onChange"},Textarea:{value:"value",change:"onChange"},Switch:{value:"checked",change:"onChange"},Checkbox:{value:"checked",change:"onChange"},Select:{value:"value",change:"onChange"},RadioGroup:{value:"value",change:"onChange"},Slider:{value:"value",change:"onChange"},Tabs:{value:"value",change:"onChange"},Collapsible:{value:"open",change:"onChange"},Table:{value:"selected",change:"onSelectionChange"},Tree:{value:"selected",change:"onSelect"}},bx=new Map(Object.entries(yx));function Ed(e){return bx.get(e)??null}var Jo="$edit";var $x=/[\p{Cc}\p{Cf}\p{Cs}\p{Zl}\p{Zp}]/u,_x=new Set(["‌","‍"]);function kx(e){return _x.has(e)||!$x.test(e)}function Gv(e){return[...e].filter(kx).join("")}var xx=/[\t\n\v\f\r\u0085\u2028\u2029]+/g;function Ix(e){return Gv(e.replace(xx," "))}function Bv(e){let n=e.overwrite(Ix);return e.minLength?n.min(e.minLength,"must contain visible characters"):n}var wx=/^(?:con|prn|aux|nul|clock\$|conin\$|conout\$|com[1-9\u00B9\u00B2\u00B3]|lpt[1-9\u00B9\u00B2\u00B3])(?:\..*)?$/i,Sx=/[<>:"|?*]/,Ko=String.raw`[^<>:"|?*\x00-\x1f\\/]*[^<>:"|?*\x00-\x1f\\/. ]`,Od=new RegExp(`^${Ko}(?:[\\\\/]${Ko})*$`),Sz=new RegExp(`^${Ko}(?:/${Ko})*$`);function Px(e){return e.length===0||e==="."||e===".."?"empty and dot path segments are not allowed":e.endsWith(".")||e.endsWith(" ")?"path segments may not end with a dot or space":Sx.test(e)||[...e].some(n=>n.charCodeAt(0)<=31)?"path segment contains a Windows-forbidden character or alternate-data-stream colon":wx.test(e)?"path segment is a Windows reserved device name":null}function Ax(e){if(e.length===0||e.startsWith("/")||e.startsWith("\\"))return"must be a non-empty relative path";let n=e.split(/[\\/]/);for(let i of n){let o=Px(i);if(o)return o}return null}function Dd(e){return Ax(e)===null}var Jv=/^[a-z0-9]+(?:-[a-z0-9]+)*$/,Tx=new Set(["__proto__","prototype","constructor"]),jd=64;function Kv(e){return Tx.has(e)}var Ud="must be a portable relative path inside the plugin directory",Hv=d.string().max(jd).regex(Jv,"must be kebab-case (a-z, 0-9, dashes)").refine(e=>!Kv(e),"must not be a reserved name"),Wv=d.string().min(1).max(1024).regex(Od,Ud).refine(e=>!Od.test(e)||Dd(e),Ud),Dz=d.string().min(1).max(1024).transform(e=>e.replace(/[\\/]+$/,"")).refine(Dd,Ud),jz=d.string().min(1).max(256).regex(/^[A-Za-z0-9]+(?:[._-][A-Za-z0-9]+)*$/,"must be a portable command id");var $n=["activity","bar-chart-3","bell","blocks","book","bot","bug","calendar","cloud","code","database","file-text","flag","folder","gauge","globe","hammer","layers","lightbulb","package","plug","puzzle","rocket","star","terminal","wrench","zap","add","remove","delete","edit","refresh","search","settings","check","close","info","warning","error","open-external","copy","download","upload","play","pause","stop","more","expand","collapse","next","filter","branch","file","agent","link"],zx=Object.fromEntries($n.slice($n.indexOf("add")).map(e=>[e,xr])),Fz=new Map($n.map(e=>[e.replaceAll("-",""),e]));var Nx=["html","components"],Ex=/\.(?:m?js|tsx?|mts|jsx)$/i,Gz=d.object({id:Hv.meta(ot("Panel id, unique among this plugin's panels. The reserved names `constructor` and `prototype` are refused.",it,["dashboard"])),title:Bv(d.string().min(1).max(256)).meta(ot("Title shown on the panel tab and its tooltip.",it,["Dashboard"])),icon:d.enum($n).optional().meta({...ot("Icon shown in the right-sidebar activity bar. Defaults to `plug`.",it,["database"]),[Zo]:zx}),entry:Wv.meta(wv(`What the panel runs: an HTML page for \`ui: "html"\`, a \`.js\`/\`.mjs\` module for \`ui: "components"\`. Either may instead be a \`.ts\`/\`.tsx\`/\`.mts\`/\`.jsx\` file, which Orca transpiles when it loads (needs \`engines.orca\` \`>=${xv}\`; an \`html\` panel then gets a generated page around it). It is trusted code: install panels you trust.`,it,["dist/panel.html"])),ui:d.enum(Nx).optional().meta(ot("How the panel draws its UI. `html` (default) shows `entry` as a web page in an isolated frame; `components` runs `entry` as a hidden module and Orca draws the component tree it returns with its own controls.",xr,["components"]))}).strict().refine(e=>e.ui!=="components"||Ex.test(e.entry),{path:["entry"],message:"a components panel entry must be a .js, .mjs, .ts, .tsx, .mts or .jsx module"}).meta({id:"PanelContribution",description:"A sidebar panel. Requires the `sandboxed-ui` execution profile or higher."});var O={maxNodes:5e3,maxDepth:64,maxTreeBytes:524288,maxTextLength:16384,maxLabelLength:1024,maxPropsPerNode:32,maxSelectOptions:500,maxEventArgs:8,maxCallbackIdLength:64,maxRadioOptions:50,maxTableColumns:32,maxTableRows:5e3,maxTreeItems:2e3,maxTreeItemDepth:16,maxKeyValueItems:200,maxDocumentLength:65536,maxEventArgItems:5e3},Jz={maxBytes:640*1024,maxMessages:200,perMs:1e4,maxDepth:O.maxDepth*2+24,maxObjects:O.maxNodes*8+1024};var Ho=/^[A-Za-z0-9_.:-]+$/,Xv=d.object({$callback:d.string().min(1).max(O.maxCallbackIdLength).regex(Ho)}).strict(),qv=["neutral","accent","success","warning","danger"],Z=d.string().max(O.maxLabelLength),F=Z.min(1),X=Xv.optional(),Te=d.string().regex(/^[a-z0-9-]{1,64}$/),_n=d.enum(["none","xs","sm","md","lg"]).optional(),Cd=d.enum(["start","center","end","stretch"]).optional(),Ge=d.enum(qv).optional(),Wo=d.enum(["xs","sm","md"]).optional(),Ld=d.enum(["solid","outline","ghost"]).optional(),N=d.boolean().optional(),kn=d.string().max(O.maxTextLength),Sr=d.enum(["sm","md","lg","none"]).optional(),Pt=d.string().min(1).max(O.maxLabelLength),me={[Jo]:d.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).optional()};function U(e,n){return{props:e,children:n}}var Ox=d.object({label:F,labelHidden:N,value:kn.optional(),defaultValue:kn.optional(),placeholder:Z.optional(),rows:d.number().int().min(2).max(20).optional(),maxLength:d.number().int().positive().max(O.maxTextLength).optional(),invalid:N,disabled:N,onChange:X,onSubmit:X,...me}).strict(),Dx=d.object({label:F,description:Z.optional(),checked:N,defaultChecked:N,disabled:N,onChange:X,...me}).strict(),jx=d.object({label:F,labelHidden:N,value:Z.optional(),defaultValue:Z.optional(),options:d.array(d.object({value:F,label:F,description:Z.optional(),disabled:N}).strict()).max(O.maxRadioOptions),orientation:d.enum(["vertical","horizontal"]).optional(),disabled:N,onChange:X,...me}).strict(),Xo=d.number().refine(Number.isFinite,"must be finite"),Ux=d.object({label:F,labelHidden:N,value:Xo.optional(),defaultValue:Xo.optional(),min:Xo.optional(),max:Xo.optional(),step:d.number().positive().refine(Number.isFinite).optional(),showValue:N,disabled:N,onChange:X,...me}).strict(),Cx=d.object({label:F,description:Z.optional(),error:Z.optional(),required:N}).strict(),Yv={Textarea:U(Ox,"none"),Checkbox:U(Dx,"none"),RadioGroup:U(jx,"none"),Slider:U(Ux,"none"),Field:U(Cx,"any")};var Lx=d.object({label:F,value:Z.optional(),defaultValue:Z.optional(),onChange:X,...me}).strict(),Rx=d.object({value:F,label:F,icon:Te.optional(),disabled:N}).strict(),Mx=d.object({title:F,description:Z.optional(),open:N,defaultOpen:N,disabled:N,onChange:X,...me}).strict(),Zx=d.object({label:F,gap:_n}).strict(),Vx=d.object({columns:d.number().int().min(1).max(6).optional(),minItemWidth:d.enum(["xs","sm","md","lg"]).optional(),gap:_n}).strict(),Qv={Tabs:U(Lx,"tabs"),Tab:U(Rx,"any"),Collapsible:U(Mx,"any"),Toolbar:U(Zx,"any"),Grid:U(Vx,"any")};function Pr(e){return typeof e=="object"&&e!==null}var Ar=["long","short","duration"],Rd=d.number().refine(Number.isFinite,"must be a finite time in milliseconds"),eh=d.object({type:d.literal("relative"),at:Rd,format:d.enum(Ar).optional()}).strict(),Fx=[["day",864e5],["hour",36e5],["minute",6e4],["second",1e3]];function Gx(e){let n=Math.abs(e),[i,o]=Fx.find(([,t])=>n>=t)??["second",1e3];return{value:Math.trunc(e/o),unit:i}}function th(e,n,i,o){let{value:t,unit:r}=Gx(e-n);return i==="duration"?new Intl.NumberFormat(o,{style:"unit",unit:r,unitDisplay:"narrow"}).format(Math.abs(t)):new Intl.RelativeTimeFormat(o,{numeric:i==="long"?"auto":"always",style:i==="long"?"long":"narrow"}).format(t,r)}var Md=d.string().min(1).max(64),Bx=d.union([d.string().max(O.maxLabelLength),d.number(),d.boolean(),d.null(),eh]),nh=e=>new Set(e.map(n=>n.key)).size===e.length,Jx=d.object({label:F,columns:d.array(d.object({key:Md,label:F,align:d.enum(["start","center","end"]).optional(),width:d.enum(["auto","xs","sm","md","lg"]).optional(),minWidth:d.enum(["auto","xs","sm","md"]).optional(),hideBelow:d.enum(["sm","md"]).optional(),sortable:N}).strict()).min(1).max(O.maxTableColumns).refine(nh,"column keys must be unique"),rows:d.array(d.object({key:Pt,cells:d.record(Md,Bx.refine(e=>typeof e!="number"||Number.isFinite(e))).refine(e=>Object.keys(e).length<=O.maxTableColumns),disabled:N}).strict()).max(O.maxTableRows).refine(nh,"row keys must be unique"),sort:d.object({column:Md,direction:d.enum(["asc","desc"])}).strict().optional(),selectionMode:d.enum(["none","single","multiple"]).optional(),selected:d.array(Pt).max(O.maxTableRows).optional(),defaultSelected:d.array(Pt).max(O.maxTableRows).optional(),hasMore:N,loading:N,emptyText:Z.optional(),maxHeight:Sr,onSortChange:X,onSelectionChange:X,onRowAction:X,onLoadMore:X,...me}).strict(),Kx=d.object({key:Pt,label:F,description:Z.optional(),icon:Te.optional(),disabled:N,hasChildren:N,children:d.array(d.unknown()).optional()}).strict();function Hx(e){let n=[],i=new Set,o=[{raw:e,out:n,depth:1}],t=0;for(let r=o.pop();r;r=o.pop()){if(r.depth>O.maxTreeItemDepth)return`items nest deeper than ${O.maxTreeItemDepth}`;for(let a of r.raw){if(++t>O.maxTreeItems)return`more than ${O.maxTreeItems} items`;let s=Kx.safeParse(Pr(a)?a:null);if(!s.success)return"each item needs a key and a label";let{children:u,...c}=s.data;if(i.has(c.key))return`duplicate item key ${JSON.stringify(c.key.slice(0,64))}`;i.add(c.key);let l=c;r.out.push(l),u&&(l.children=[],o.push({raw:u,out:l.children,depth:r.depth+1}))}}return n}var Wx=d.array(d.unknown()).transform((e,n)=>{let i=Hx(e);return typeof i=="string"?(n.addIssue({code:"custom",message:i}),d.NEVER):i}),Xx=d.object({label:F,items:Wx,selected:Z.optional(),defaultSelected:Z.optional(),expanded:d.array(Pt).max(O.maxTreeItems).optional(),defaultExpanded:d.array(Pt).max(O.maxTreeItems).optional(),maxHeight:Sr,onSelect:X,onToggle:X,onAction:X,...me}).strict(),rh={Table:U(Jx,"none"),Tree:U(Xx,"none")};var ih=d.string().max(O.maxDocumentLength),qx=/\.(?:png|jpe?g|webp)$/i;function Yx(e){return qx.test(e)&&!/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(e)&&!/[\\\0?#]/.test(e)&&e.split("/").every(n=>n!==""&&n!=="."&&n!=="..")}var Qx=d.object({content:ih}).strict(),eI=d.object({code:ih,language:d.string().regex(/^[A-Za-z0-9_+#.-]{1,64}$/).optional(),label:Z.optional(),lineNumbers:N,wrap:N,maxHeight:Sr}).strict(),tI=d.object({src:d.string().max(512).refine(Yx,"must be an image file in the plugin"),alt:Z,size:d.enum(["xs","sm","md","lg","full"]).optional(),fit:d.enum(["contain","cover"]).optional(),rounded:N}).strict(),nI=d.object({label:Z.optional(),items:d.array(d.object({label:F,value:d.union([Z,d.number().refine(Number.isFinite),d.boolean(),d.null()]),tone:Ge,code:N}).strict()).max(O.maxKeyValueItems)}).strict(),rI=d.object({tone:Ge,title:Z.optional(),icon:Te.optional()}).strict(),iI=d.object({at:Rd,format:d.enum(Ar).optional(),tone:Ge,muted:N}).strict(),oI=d.object({shape:d.enum(["text","block","circle"]).optional(),lines:d.number().int().min(1).max(10).optional(),label:Z.optional()}).strict(),oh={Markdown:U(Qx,"none"),CodeView:U(eI,"none"),Image:U(tI,"none"),KeyValue:U(nI,"none"),Callout:U(rI,"any"),Skeleton:U(oI,"none"),RelativeTime:U(iI,"none")};var aI=$n,ah=new Set(aI),sI=d.object({gap:_n,align:Cd}).strict(),uI=d.object({gap:_n,align:Cd,justify:d.enum(["start","center","end","between"]).optional(),wrap:N}).strict(),cI=d.object({tone:Ge,muted:N,size:Wo,weight:d.enum(["regular","medium","semibold"]).optional(),truncate:N}).strict(),lI=d.object({level:d.union([d.literal(1),d.literal(2),d.literal(3)]).optional()}).strict(),dI=d.object({variant:Ld,tone:Ge,size:Wo,icon:Te.optional(),tooltip:Z.optional(),disabled:N,onPress:X}).strict(),pI=d.object({icon:Te,label:F,tooltip:Z.optional(),variant:Ld,tone:Ge,size:Wo,disabled:N,onPress:X}).strict(),mI=d.object({tone:Ge}).strict(),fI=d.object({title:Z.optional(),description:Z.optional()}).strict(),gI=d.object({label:Z.optional()}).strict(),vI=d.object({title:Z.optional(),description:Z.optional(),icon:Te.optional(),current:N,disabled:N,onPress:X}).strict(),hI=d.object({label:F,labelHidden:N,value:kn.optional(),defaultValue:kn.optional(),placeholder:Z.optional(),type:d.enum(["text","search","password"]).optional(),maxLength:d.number().int().positive().max(O.maxTextLength).optional(),invalid:N,disabled:N,onChange:X,onSubmit:X,...me}).strict(),yI=d.object({label:F,checked:N,defaultChecked:N,disabled:N,onChange:X,...me}).strict(),bI=d.object({label:F,labelHidden:N,value:Z.optional(),defaultValue:Z.optional(),placeholder:Z.optional(),options:d.array(d.object({value:F,label:F,disabled:N}).strict()).max(O.maxSelectOptions),disabled:N,onChange:X,...me}).strict(),$I=d.object({orientation:d.enum(["horizontal","vertical"]).optional()}).strict(),_I=d.object({label:F,labelHidden:N,value:d.number().min(0).max(100).optional()}).strict(),kI=d.object({label:F,labelHidden:N}).strict(),xI=d.object({title:F,description:Z.optional(),icon:Te.optional()}).strict(),II=d.object({href:d.string().max(2048).regex(/^(https?:\/\/|mailto:)/i).optional(),onPress:X}).strict(),wI=d.object({block:N}).strict(),Tr={Stack:U(sI,"any"),Row:U(uI,"any"),Text:U(cI,"inline"),Heading:U(lI,"inline"),Button:U(dI,"text"),IconButton:U(pI,"none"),Badge:U(mI,"text"),Card:U(fI,"any"),List:U(gI,"items"),ListItem:U(vI,"any"),Input:U(hI,"none"),Switch:U(yI,"none"),Select:U(bI,"none"),Separator:U($I,"none"),Progress:U(_I,"none"),Spinner:U(kI,"none"),EmptyState:U(xI,"any"),Link:U(II,"text"),Code:U(wI,"text"),...Yv,...Qv,...rh,...oh};function Zd(e){return typeof e=="string"&&Object.hasOwn(Tr,e)}var PN=Object.keys(Tr).filter(Zd),sh=new Set(["Text","Link","Code","Badge","RelativeTime"]),uh=new Set(["Button","IconButton","Input","Switch","Select","Link","ListItem","Textarea","Checkbox","RadioGroup","Slider","Tabs","Collapsible","Table","Tree","Markdown"]),qo={items:"ListItem",tabs:"Tab"};var SI=new Set(["type","key","props","children"]),Vd=32,PI=8,AI=/^[A-Z][A-Za-z0-9]{0,63}$/,TI=20,zI=new Map([[qo.items,"items"],[qo.tabs,"tabs"]]),NI={ListItem:"List",Tab:"Tabs"};function ch(e){return e==="items"||e==="tabs"?qo[e]:void 0}var Yo=class extends Error{};function Q(e,n){throw new Yo(`${e}: ${n}`)}function EI(e,n){return e===void 0?[]:(Array.isArray(e)||Q(n,"children must be an array"),e)}function OI(e,n,i){let o=Tr[e].props.shape,t={};for(let[r,a]of Object.entries(n)){if(a===void 0)continue;if(!Object.hasOwn(o,r)){i(`${e}: ignored unknown prop "${r.slice(0,64)}"`);continue}let s=o[r].safeParse(a);if(!s.success){i(`${e}: ignored invalid ${r}`);continue}t[r]=s.data}for(let[r,a]of Object.entries(o))if(!Object.hasOwn(t,r)&&!a.safeParse(void 0).success)return i(`${e}: missing required ${r}; showing a placeholder`),null;return typeof t.icon=="string"&&!ah.has(t.icon)&&i(`${e}: unknown icon "${t.icon}"; showing a fallback glyph`),t}function lh(e){if(e===null)return{ok:!0,tree:null,nodes:0,warnings:[]};let n=new Set,i=c=>{n.sizeO.maxTextLength&&Q(x,"text is too long"),r+ ++a>O.maxNodes&&Q(x,`more than ${O.maxNodes} nodes`),s+=PI+we.length,s>O.maxTreeBytes&&Q(x,`tree exceeds ${O.maxTreeBytes} bytes`),k.push(we);continue}Pr(l)||Q(x,"expected a node, string or number");let I=l.type,A=Zd(I);!A&&(typeof I!="string"||!AI.test(I))&&Q(x,`invalid component name ${JSON.stringify(String(I)).slice(0,80)}`),(f==="none"||f==="text")&&Q(x,`${m} accepts only text`),f==="inline"&&A&&!sh.has(I)&&Q(x,`${m} accepts only text, Text, Link, Code, Badge and RelativeTime`);let C=ch(f),V=typeof I=="string"?zI.get(I):void 0;C!==void 0&&I!==C&&Q(x,`${m} holds only ${C}`),V!==void 0&&V!==f&&Q(x,`${I} must be a direct child of ${NI[I]??"its container"}`),g&&uh.has(I)&&Q(x,`a ListItem with onPress cannot contain a ${I}`),++r+a>O.maxNodes&&Q(x,`more than ${O.maxNodes} nodes`),p>O.maxDepth&&Q(x,`deeper than ${O.maxDepth}`);for(let we of Object.keys(l))SI.has(we)||Q(x,`unknown node field ${we.slice(0,64)}`);let w=l.key;w!==void 0&&((typeof w!="string"||w.length>O.maxLabelLength)&&Q(x,"key must be a short string"),h.has(w)&&Q(x,`duplicate key ${JSON.stringify(w.slice(0,64))} among siblings`),h.add(w));let T=w===void 0?{}:{key:w};if(!A){i(`unknown component ${I}; showing a placeholder`),k.push({type:"Unsupported",...T,props:{name:I},children:[]}),s+=Vd+I.length;continue}let E=l.props??{};(!Pr(E)||Object.keys(E).length>O.maxPropsPerNode)&&Q(x,"props must be an object with few fields");let K=OI(I,E,i);if(!K){k.push({type:"Unsupported",...T,props:{name:I},children:[]}),s+=Vd+I.length;continue}s+=Vd+JSON.stringify(K).length,s>O.maxTreeBytes&&Q(x,`tree exceeds ${O.maxTreeBytes} bytes`);let Tt=[],Er={type:I,...T,props:K,children:Tt};k.push(Er);let xn=EI(l.children,x);xn.length>O.maxNodes&&Q(x,`more than ${O.maxNodes} children`);let na=new Set,Jh=g||I==="ListItem"&&K.onPress!==void 0;for(let we=xn.length-1;we>=0;we--)t.push({raw:xn[we],depth:p+1,parentType:I,policy:Tr[I].children,inPressable:Jh,siblingKeys:na,out:Tt,path:`${x}.children.${we}`})}}catch(c){if(c instanceof Yo)return{ok:!1,error:c.message};throw c}let u=o[0];return typeof u=="object"?{ok:!0,tree:u,nodes:r,warnings:[...n]}:{ok:!1,error:"tree: expected a node"}}var zr=d.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),At=d.string().min(1).max(64),Fd=d.union([d.string().max(O.maxTextLength),d.number().refine(Number.isFinite),d.boolean(),d.null()]),dh=d.array(Fd).max(O.maxEventArgItems),DI=d.union([Fd,dh,d.record(d.string().max(64),d.union([Fd,dh])).refine(e=>Object.keys(e).length<=16,"too many fields")]),RN=d.object({document:At,revision:zr,callback:d.string().min(1).max(O.maxCallbackIdLength).regex(Ho),args:d.array(DI).max(O.maxEventArgs),edit:zr.optional()}).strict(),jI=d.object({document:At,revision:zr,tree:d.unknown()}).strict(),ph=d.object({document:At.optional(),revision:zr,message:d.string().max(O.maxLabelLength*4),stack:d.string().max(8192).optional()}).strict();function mh(e){let n=jI.safeParse(e);if(!n.success)return{ok:!1,document:null,revision:null,error:"malformed render"};let{document:i,revision:o}=n.data,t=lh(n.data.tree);return t.ok?{...t,document:i,revision:o}:{ok:!1,document:i,revision:o,error:t.error}}var MN=d.object({document:At,revision:zr,accepted:d.boolean(),retryAfterMs:d.number().int().nonnegative().max(6e4).optional()}).strict(),ZN=d.object({document:At}).strict(),fh=/^[A-Za-z0-9_.:-]{1,128}$/,UI=["plugin","workspace"],Gd=d.number().int().min(0).max(1e6),VN=d.object({version:Gd,value:d.json()}).strict().refine(e=>JSON.stringify(e.value).length<=Mo,"persisted value is too large"),gh=d.object({document:At,entries:d.array(d.object({scope:d.enum(UI),key:d.string().regex(fh),version:Gd,value:d.json()}).strict()).min(1).max(64)}).strict(),FN=d.object({document:At,entries:d.array(d.object({key:d.string().regex(fh),version:Gd,value:d.json().optional()}).strict().refine(e=>JSON.stringify(e.value??null).length<=Mo,"retained value is too large")).min(1).max(64)}).strict();import{installOrcaDeclarativeRuntime as WI}from"./orca-runtime.mjs";var CI={Stack:"group",Row:"group",Card:"region",Text:"text",Heading:"heading",Button:"button",IconButton:"button",Badge:"status",List:"list",ListItem:"listitem",Input:"textbox",Switch:"switch",Select:"combobox",Separator:"separator",Progress:"progressbar",Spinner:"status",EmptyState:"group",Link:"link",Code:"code",Textarea:"textbox",Checkbox:"checkbox",RadioGroup:"radiogroup",Slider:"slider",Field:"group",Tabs:"tablist",Tab:"tab",Collapsible:"group",Toolbar:"toolbar",Grid:"group",Table:"grid",Tree:"tree",Markdown:"document",CodeView:"code",Image:"img",KeyValue:"list",Callout:"note",Skeleton:"status",RelativeTime:"time",Unsupported:"unsupported"};function hh(e,n){if(typeof e!="number")return"";let i=Ar.find(o=>o===n)??"short";return th(e,Date.now(),i,"en")}function LI(e){return typeof e=="object"&&e!==null&&"at"in e?hh(e.at,"format"in e?e.format:void 0):String(e??"")}var RI=["title","description","content","code","error","alt"];function MI(e){let n=[],i=[e.rows,e.items].flatMap(o=>Array.isArray(o)?o:[]);for(let o=i.shift();o!==void 0;o=i.shift()){if(typeof o!="object"||o===null)continue;let t={...o};typeof t.cells=="object"&&t.cells!==null&&n.push(...Object.values(t.cells).map(LI));for(let r of["label","value"])t[r]!==void 0&&t[r]!==null&&n.push(String(t[r]));Array.isArray(t.children)&&i.push(...t.children)}return n}function yh(e){if(typeof e=="string")return e;let n=e.props,i=RI.map(o=>n[o]).filter(o=>typeof o=="string");return e.type==="RelativeTime"?hh(n.at,n.format):e.type==="Tab"?typeof n.label=="string"?n.label:"":[...i,...MI(n),...e.children.map(yh)].join(" ")}var Bd=e=>e.replace(/\s+/g," ").trim();function ZI(e){let n=e.props,i=n.label??n.title;return typeof i=="string"?i:void 0}function VI(e,n){let i=e.props,o=e.type==="ListItem"&&i.onPress!==void 0;return{type:e.type,key:e.key?.startsWith("#")?void 0:e.key,role:o?"button":CI[e.type]??"generic",label:ZI(e),text:Bd(yh(e)),props:i,disabled:i.disabled===!0,path:n}}function Qo(e){let n=[],i=(o,t)=>{n.push(VI(o,t)),o.children.forEach((r,a)=>{typeof r!="string"&&i(r,`${t}/${r.key??`#${a}`}`)})};return e&&i(e,e.key??"#0"),n}function vh(e,n){return e===void 0?!1:typeof n=="string"?Bd(e)===Bd(n):n.test(e)}function bh(e,n){return(n.type===void 0||e.type===n.type)&&(n.role===void 0||e.role===n.role)&&(n.text===void 0||vh(e.text,n.text))&&(n.label===void 0||vh(e.label,n.label))&&(n.testId===void 0||e.key===n.testId)}function $h(e){return e.filter(n=>!e.some(i=>i.path.startsWith(`${n.path}/`)))}function _h(e){return Object.entries(e).map(([n,i])=>`${n}: ${i instanceof RegExp?String(i):JSON.stringify(i)}`).join(", ")}function Jd(e){if(typeof e=="string")return e;let n={};for(let[i,o]of Object.entries(e.props)){if(i.startsWith("$"))continue;let t=typeof o=="object"&&o!==null&&"$callback"in o;n[i]=t?"[handler]":o}return{type:e.type,...e.key&&!e.key.startsWith("#")?{key:e.key}:{},...Object.keys(n).length>0?{props:n}:{},...e.children.length>0?{children:e.children.map(Jd)}:{}}}var FI={value:"defaultValue",checked:"defaultChecked",open:"defaultOpen",selected:"defaultSelected"};function Kd(e){return typeof e=="string"||typeof e=="boolean"||typeof e=="number"||Array.isArray(e)&&e.every(n=>typeof n=="string")}function GI(e){switch(e.type){case"Switch":case"Checkbox":case"Collapsible":return!1;case"Slider":return typeof e.props.min=="number"?e.props.min:0;case"Table":return[];default:return""}}function kh(){let e=new Map;function n(t){let r=Ed(t.type);if(!r)throw new Error(`a ${t.type} has no value; expected a form control, Tabs or Table`);return r}function i(t){let r=e.get(t.path);if(r)return r;let{value:a}=n(t),s=t.props[a],u=t.props[FI[a]??""],l={value:Kd(s)?s:Kd(u)?u:GI(t),sent:0};return e.set(t.path,l),l}function o(t,r){let{value:a,change:s}=n(t);if(t.props[a]!==void 0&&t.props[s]===void 0)throw new Error(`the ${t.type} is read-only: it has a ${a} and no ${s}`);let u=i(t);return u.sent+=1,u.value=r,{value:r,id:u.sent}}return{observe(t){let r=new Map;for(let a of t){let s=Ed(a.type);if(!s)continue;let u=e.get(a.path)??i(a),c=a.props[s.value],l=a.props[Jo];Kd(c)&&(typeof l=="number"?l:0)>=u.sent&&(u.value=c),r.set(a.path,u)}e=r},valueOf:t=>i(t).value,edit:o,typeInto(t,r,a){if(t.type!=="Input"&&t.type!=="Textarea")throw new Error(`type: a ${t.type} takes no text; expected an Input or Textarea`);let s=a?"":String(i(t).value),u=[];a&&u.push(o(t,s));for(let c of r)s+=c,u.push(o(t,s));return u},toggle(t){if(!["Switch","Checkbox","Collapsible"].includes(t.type))throw new Error(`toggle: expected a Switch, Checkbox or Collapsible, not a ${t.type}`);return o(t,!i(t).value)}}}function xh(e){let n=new Map,i=(s,u)=>{let c=n.get(s)??new Set;return c.add(u),n.set(s,c),{dispose:()=>c.delete(u)}},o=(s,u)=>{for(let c of n.get(s)??[])c(u)},t=s=>u=>typeof u=="object"&&u!==null&&s in u?Object.getOwnPropertyDescriptor(u,s)?.value:void 0,r=()=>{};return{facades:{plugin:{request:(s,u,c)=>{let l=typeof c=="object"&&c!==null&&"timeoutMs"in c?c.timeoutMs:void 0;return e("plugin.request",{name:s,...u===void 0?{}:{input:u},...typeof l=="number"?{timeoutMs:l}:{}}).then(t("output"))},on:(s,u)=>i(`message:${s}`,u)},storage:{get:s=>e("storage.get",{key:s}).then(u=>t("value")(u)??null),set:(s,u)=>e("storage.set",{key:s,value:u}).then(r),delete:s=>e("storage.delete",{key:s}).then(r),keys:async()=>{let s=t("keys")(await e("storage.keys"));return Array.isArray(s)?s.map(String):[]},onDidChange:s=>i("changed:storage",u=>s({key:String(u)}))},settings:{get:async s=>{let u=t("settings")(await e("settings.get"));return s===void 0?u:t(s)(u)},set:(s,u)=>e("settings.set",{key:s,value:u}).then(r),onDidChange:s=>i("changed:settings",u=>s({key:String(u)}))},secrets:{get:async s=>{let u=t("value")(await e("secrets.get",{key:s}));return typeof u=="string"?u:null},set:(s,u)=>e("secrets.set",{key:s,value:u}).then(r),delete:s=>e("secrets.delete",{key:s}).then(r)}},post:(s,u)=>o(`message:${s}`,u),changed:(s,u)=>o(`changed:${s}`,u)}}var Ih=Symbol.for("orca.testing.stored");function wh(e,n){return Object.freeze({[Ih]:!0,version:n,value:e})}function BI(e){return typeof e=="object"&&e!==null&&Ih in e}function Sh(e,n){for(let i of["plugin","workspace"])for(let[o,t]of Object.entries(n?.[i]??{}))e[i].set(o,BI(t)?{version:t.version,value:t.value}:{version:1,value:t})}var JI={sm:360,md:480};function Ph(e,n){let i=e.filter(o=>!o.hideBelow||n>=JI[o.hideBelow]);return i.length>0?i:e.slice(0,1)}var Hd=(e,n)=>e.path.startsWith(`${n.path}/`);function ea(e,n){return n.filter(i=>i.type==="Tab"&&Hd(i,e)&&!i.path.slice(e.path.length+1).includes("/"))}function Wd(e,n,i){let o=ea(e,n);return o.find(t=>t.props.value===i)??o.find(t=>!t.disabled)}function Ah(e,n){let i=[];for(let o of e)if(!i.some(t=>Hd(o,t))&&(o.type==="Collapsible"&&n(o)!==!0&&i.push(o),o.type==="Tabs")){let t=Wd(o,e,n(o));i.push(...ea(o,e).filter(r=>r!==t))}return e.filter(o=>!i.some(t=>Hd(o,t)))}function Th(e){return typeof e=="object"&&e!==null&&"key"in e&&typeof e.key=="string"}function Xd(e){return Array.isArray(e.props.rows)?e.props.rows.filter(Th):[]}function qd(e){let n=[],i=Array.isArray(e.props.items)?[...e.props.items]:[];for(let o=i.shift();o!==void 0;o=i.shift())if(Th(o)){n.push(o);let t="children"in o?o.children:void 0;Array.isArray(t)&&i.push(...t)}return n}function Ie(e,n,i){if(e.type!==n)throw new Error(`${i}: expected a ${n}, not a ${e.type}`)}function Yd(e,n,i){let o=Xd(e).find(t=>t.key===n);if(!o||o.disabled===!0)throw new Error(`${i}: the Table has no enabled row "${n}"`);return o}function ta(e,n,i){let o=qd(e).find(t=>t.key===n);if(!o)throw new Error(`${i}: the Tree has no item "${n}"`);return o}function zh(e){return e.hasChildren===!0||Array.isArray(e.children)&&e.children.length>0}function Nh(e,n){let o=(Array.isArray(e.props.columns)?e.props.columns:[]).find(a=>typeof a=="object"&&a!==null&&"key"in a&&a.key===n);if(!o||typeof o!="object"||!("sortable"in o)||o.sortable!==!0)throw new Error(`sort: the Table has no sortable column "${n}"`);let t=e.props.sort,r=typeof t=="object"&&t!==null&&"column"in t&&t.column===n&&"direction"in t&&t.direction==="asc";return{column:n,direction:r?"desc":"asc"}}function KI(e,n){return e.type==="Tabs"?ea(e,n).map(o=>({value:o.props.value,disabled:o.disabled})):(Array.isArray(e.props.options)?e.props.options:[]).map(o=>typeof o=="object"&&o!==null&&"value"in o?{value:o.value,disabled:"disabled"in o&&o.disabled===!0}:{value:void 0,disabled:!0})}function Eh({host:e,controls:n,resolve:i,elements:o,dispatch:t,settled:r}){let a=new Map,s=l=>{let p=a.get(l.path);if(!p){let m=l.props.expanded??l.props.defaultExpanded;p=new Set(Array.isArray(m)?m.filter(f=>typeof f=="string"):[]),a.set(l.path,p)}return p},u=async(l,p,m,f)=>{let g=n.edit(l,m);t(p,[f],g.id),await r()},c=async(l,p,m,f)=>{let g=i(l,f);if(Ie(g,"Tree",f),!zh(ta(g,p,f)))throw new Error(`${f}: the Tree item "${p}" has no children`);let h=s(g);h.has(p)!==m&&(m?h.add(p):h.delete(p),t(g.props.onToggle,[{key:p,expanded:m}]),await r())};return{async press(l){let p=i(l,"press"),{href:m,onPress:f}=p.props;if(p.type==="Link"&&typeof m=="string")e.grantGesture(),e.bridge.call("shell.openExternal",{url:m}).catch(()=>{});else{if(f===void 0)throw new Error(`press: the ${p.type} has no onPress`);e.grantGesture()}t(f,[]),await r()},async type(l,p,m={}){let f=i(l,"type");for(let g of n.typeInto(f,p,m.replace===!0))t(f.props.onChange,[g.value],g.id),await r();m.submit&&(t(f.props.onSubmit,[n.valueOf(f)]),await r())},async submit(l){let p=i(l,"submit");t(p.props.onSubmit,[n.valueOf(p)]),await r()},async toggle(l){let p=i(l,"toggle"),m=n.toggle(p);t(p.props.onChange,[m.value],m.id),await r()},async select(l,p){let m=i(l,"select");if(!["Select","RadioGroup","Tabs"].includes(m.type))throw new Error(`select: expected a Select, RadioGroup or Tabs, not a ${m.type}`);let f=KI(m,o()).find(g=>g.value===p);if(!f||f.disabled)throw new Error(`select: the ${m.type} has no enabled option "${p}"`);await u(m,m.props.onChange,p,p)},async slide(l,p){let m=i(l,"slide");Ie(m,"Slider","slide");let f=typeof m.props.min=="number"?m.props.min:0,g=typeof m.props.max=="number"?m.props.max:100;if(!Number.isFinite(p)||pg)throw new Error(`slide: ${p} is outside the Slider's ${f} to ${g}`);await u(m,m.props.onChange,p,p)},async sort(l,p){let m=i(l,"sort");if(Ie(m,"Table","sort"),m.props.onSortChange===void 0)throw new Error("sort: the Table has no onSortChange");t(m.props.onSortChange,[Nh(m,p)]),await r()},async selectRows(l,p){let m=i(l,"selectRows");Ie(m,"Table","selectRows");let f=m.props.selectionMode??"none";if(f==="none"||f==="single"&&p.length>1)throw new Error(`selectRows: the Table's selectionMode is ${String(f)}`);p.forEach(g=>Yd(m,g,"selectRows")),await u(m,m.props.onSelectionChange,[...p],{keys:[...p]})},async activateRow(l,p){let m=i(l,"activateRow");if(Ie(m,"Table","activateRow"),Yd(m,p,"activateRow"),m.props.onRowAction===void 0)throw new Error("activateRow: the Table has no onRowAction");t(m.props.onRowAction,[{key:p}]),await r()},async loadMore(l){let p=i(l,"loadMore");if(Ie(p,"Table","loadMore"),p.props.hasMore!==!0||p.props.onLoadMore===void 0)throw new Error("loadMore: the Table has no more rows (hasMore and onLoadMore)");t(p.props.onLoadMore,[]),await r()},expand:(l,p)=>c(l,p,!0,"expand"),collapse:(l,p)=>c(l,p,!1,"collapse"),async selectItem(l,p){let m=i(l,"selectItem");if(Ie(m,"Tree","selectItem"),ta(m,p,"selectItem").disabled===!0)throw new Error(`selectItem: the Tree item "${p}" is disabled`);await u(m,m.props.onSelect,p,{key:p})},async activateItem(l,p){let m=i(l,"activateItem");if(Ie(m,"Tree","activateItem"),ta(m,p,"activateItem").disabled===!0||!m.props.onAction)throw new Error(`activateItem: the Tree item "${p}" cannot be activated`);t(m.props.onAction,[{key:p}]),await r()},expandedOf:l=>{let p=i(l,"expandedOf");return Ie(p,"Tree","expandedOf"),qd(p).map(m=>m.key).filter(m=>s(p).has(m))},columnsOf:(l,p={})=>{let m=i(l,"columnsOf");Ie(m,"Table","columnsOf");let g=(Array.isArray(m.props.columns)?m.props.columns:[]).flatMap(h=>{if(typeof h!="object"||h===null||!("key"in h))return[];let k="hideBelow"in h?h.hideBelow:void 0;return typeof h.key=="string"?[{key:h.key,hideBelow:k==="sm"||k==="md"?k:void 0}]:[]});return Ph(g,p.width??Number.POSITIVE_INFINITY).map(h=>h.key)},rowsOf:l=>{let p=i(l,"rowsOf");return Ie(p,"Table","rowsOf"),Xd(p).map(m=>m.key)}}}var Ue=e=>{let n=(e??"").replace(/\s+/g," ").trim();return JSON.stringify(n.length>60?`${n.slice(0,59)}…`:n)},Oh=e=>Array.isArray(e)?e.length:0;function HI(e,n){let{props:i}=e;switch(e.type){case"Heading":return`Heading ${Ue(e.text)}`;case"Callout":return`Callout ${String(i.tone??"neutral")} ${Ue(e.label??e.text)}`;case"EmptyState":return`EmptyState ${Ue(e.label)}`;case"Table":return`Table ${Ue(e.label)}: ${Oh(i.rows)} row(s)${i.hasMore===!0?", more":""}`;case"Tree":return`Tree ${Ue(e.label)}: ${Oh(i.items)} top-level item(s)`;case"Tabs":return`Tabs ${Ue(e.label)}: ${Ue(n.get(e.path))} selected`;case"Skeleton":case"Spinner":return`${e.type} ${Ue(e.label??"Loading")}`;case"Text":return i.tone==="danger"||i.tone==="warning"?`Text ${String(i.tone)} ${Ue(e.text)}`:null;default:return null}}function Dh(e,n){let i=[];for(let o of e){if(o.type==="List"){let r=e.filter(a=>a.type==="ListItem"&&a.path.startsWith(`${o.path}/`)).length;i.push(`List ${Ue(o.label)}: ${r} item(s)`);continue}let t=HI(o,n);t&&i.push(t)}return i.length>12?[...i.slice(0,12),`… ${i.length-12} more`]:i}function jh(e){return"path"in e}var XI=100,qI=()=>new Promise(e=>typeof setImmediate=="function"?setImmediate(e):setTimeout(e,0));async function Uh(e,n){let i=n.host,o=new Map,t=(w,T)=>{for(let E of o.get(w)??[])E(T)},r=[],a=[],s=[],u={plugin:new Map,workspace:new Map};Sh(u,n.persisted);let c=n.visible??!0,l={document:"",revision:0,tree:null},p=kh(),m=xh(i.bridge.call),f=i.onDataChange(m.changed);function g(w,T){if(w===je.ready)t(je.hydrate,{panel:{id:n.panelId??"panel"},visible:c,plugin:Object.fromEntries(u.plugin),workspace:Object.fromEntries(u.workspace)});else if(w===je.render){let E=mh(T);if(!E.ok){a.push({kind:"refused",message:E.error}),E.document!==null&&E.revision!==null&&t(je.ack,{document:E.document,revision:E.revision,accepted:!1});return}s.push(...E.warnings.filter(K=>!s.includes(K))),l={document:E.document,revision:E.revision,tree:E.tree},p.observe(Qo(E.tree)),t(je.ack,{document:E.document,revision:E.revision,accepted:!0})}else if(w===je.error){let E=ph.safeParse(T);a.push(E.success?{kind:"plugin",message:E.data.message,...E.data.stack?{stack:E.data.stack}:{}}:{kind:"plugin",message:String(T)})}else if(w===je.persist){let E=gh.safeParse(T);if(!E.success){a.push({kind:"refused",message:"persisted state Orca would not store"});return}for(let K of E.data.entries)u[K.scope].set(K.key,{version:K.version,value:K.value})}}let h=WI({post:g,awaitHydration:!0,colorScheme:n.theme??"dark",schedule:w=>r.push(w),bridge:{api:i.bridge.api,locale:n.locale??"en",host:{call:i.bridge.call,has:i.bridge.has},...m.facades,on(w,T){let E=o.get(w)??new Set;return E.add(T),o.set(w,E),{dispose:()=>E.delete(T)}}}});async function k(){for(let w=0;wAh(Qo(l.tree),w=>p.valueOf(w)),I=w=>$h(x().filter(T=>bh(T,w)));function A(w,T){let E=jh(w)?x().find(K=>K.path===w.path):I(w)[0];if(!E)throw new Error(jh(w)?`${T}: the element is no longer in the panel`:`${T}: nothing in the panel matches { ${_h(w)} }`);if(E.disabled)throw new Error(`${T}: the ${E.type} is disabled`);return E}function C(w,T,E){let K=typeof w=="object"&&w!==null&&"$callback"in w?w.$callback:null;typeof K=="string"&&t(je.event,{document:l.document,revision:l.revision,callback:K,args:T,...E===void 0?{}:{edit:E}})}await Promise.resolve(typeof e=="function"?{default:e}:e).then(w=>h.boot(w)).catch(w=>a.push({kind:"plugin",message:w instanceof Error?w.message:String(w),...w instanceof Error&&w.stack?{stack:w.stack}:{}})),await k();let V=Eh({host:i,controls:p,resolve:A,elements:x,dispatch:C,settled:k});return{host:i,errors:a,warnings:s,get refusals(){return i.refusals},find:w=>I(w)[0]??null,findAll:I,tree:()=>l.tree?Jd(l.tree):null,drawnTree:()=>l.tree,summary:()=>{let w=Qo(l.tree),T=x(),E=new Map(T.filter(K=>K.type==="Tabs").map(K=>[K.path,Wd(K,w,p.valueOf(K))?.label??""]));return Dh(T,E)},get persisted(){let w=T=>Object.fromEntries([...u[T]].map(([E,K])=>[E,K.value]));return{plugin:w("plugin"),workspace:w("workspace"),storage:i.data().storage}},settled:k,...V,valueOf:w=>p.valueOf(A(w,"valueOf")),async emit(w,T){t(w,T),await k()},async post(w,T){m.post(w,T),await k()},async setVisible(w){c=w,t(je.visibility,{visible:w}),await k()},async rerender(){h.rerender(),await k()},async unmount(){h.dispose(),o.clear(),f()}}}var Ch={workspaceId:d.string().min(1).max(2048),kind:d.enum(["worktree","folder"])},YI=d.object({...Ch,path:d.string().min(1).max(32*1024),branch:d.string().max(1024)}),QI=d.object({...Ch,path:d.string().min(1).max(32*1024)}),ew=d.object({workspaceId:d.string().min(1).max(2048).nullable(),paneKey:d.string().min(1).max(2048),terminalId:d.string().min(1).max(Fo).optional(),title:d.string().max(Ir).optional(),state:d.enum(bn),receivedAt:d.number().finite().positive(),mainAgent:d.object({state:d.enum(bn),outcome:d.enum(Av).optional(),stateStartedAt:d.number().finite()}).optional()}),tw=d.object({context:zd}),Qd={"workspace.created":YI,"workspace.removed":QI,"agent.status.changed":ew,"workspace.changed":tw};function nw(e){return typeof e!="object"||e===null||!("workspaceId"in e)||"worktreeId"in e?e:{...e,worktreeId:e.workspaceId}}function Nr(e,n){return typeof e=="object"&&e!==null&&n in e?Object.getOwnPropertyDescriptor(e,n)?.value:void 0}function ep(e,n){return e.add(n),{dispose:()=>{e.delete(n)}}}var rw=new Set(wr("worker"));function Lh(){return{commands:new Map,events:new Map,panelRequests:new Map,dataListeners:{storage:new Set,settings:new Set}}}function Rh(e){let{tables:n,hostCall:i}=e,o=async(t,r)=>{await i(t,r)};return Object.freeze({api:Object.freeze({major:Fe,minor:Lv}),commands:Object.freeze({register(t,r){return n.commands.set(t,r),{dispose:()=>{n.commands.delete(t)}}}}),events:Object.freeze({on(t,r){let a=Vo.get(t)??t,s=n.events.get(a)??new Set;n.events.set(a,s);let u=a!==t||t==="agent.status.changed",c=ep(s,p=>r(u?nw(p):p));if(t!=="workspace.changed")return c;let l=!0;return i("workspace.readContext").then(p=>l&&r({context:p})).catch(()=>{}),{dispose:()=>{l=!1,c.dispose()}}}}),host:Object.freeze({call:(t,r,a)=>i(t,r,a),has:t=>rw.has(t)}),panels:Object.freeze({handle(t,r){if(at.parse(t),typeof r!="function")throw new TypeError("orca.panels.handle needs a handler function");return n.panelRequests.set(t,r),{dispose:()=>{n.panelRequests.get(t)===r&&n.panelRequests.delete(t)}}},post(t,r,a){at.parse(t),e.postToPanels({event:t,payload:r,...a?.panel?{panel:a.panel}:{}})}}),storage:Object.freeze({get:async t=>Nr(await i("storage.get",{key:t}),"value")??null,set:(t,r)=>o("storage.set",{key:t,value:r}),delete:t=>o("storage.delete",{key:t}),keys:async()=>{let t=Nr(await i("storage.keys"),"keys");return Array.isArray(t)?t.filter(r=>typeof r=="string"):[]},onDidChange:t=>ep(n.dataListeners.storage,t)}),settings:Object.freeze({get:async t=>{let r=Nr(await i("settings.get"),"settings"),a=typeof r=="object"&&r!==null?{...r}:{};return t===void 0?a:Nr(a,t)},set:(t,r)=>o("settings.set",{key:t,value:r}),onDidChange:t=>ep(n.dataListeners.settings,t)}),secrets:Object.freeze({get:async t=>{let r=Nr(await i("secrets.get",{key:t}),"value");return typeof r=="string"?r:null},set:(t,r)=>o("secrets.set",{key:t,value:r}),delete:t=>o("secrets.delete",{key:t})}),grantedCapabilities:Object.freeze([...e.grantedCapabilities]),log:t=>e.log(String(t))})}var Mh={id:"test-panel",surface:"panel",contributionId:"panel"};function iw(e){return Object.hasOwn(Qd,e)}function ow(e){return e instanceof Error?e.message:String(e)}async function Zh(e,n){let{host:i}=n,o=new Set(n.events),t=Lh(),r=[],a=[],s=!0,u=e.default;if(typeof u!="function")throw new TypeError(typeof e.activate=="function"?"mountWorker: the module exports activate by name, but Orca calls the default export: write `export default function activate(orca)`":"mountWorker: the module has no default-exported activate(orca) function");let c=e.deactivate;if(c!==void 0&&typeof c!="function")throw new TypeError("mountWorker: the module exports a deactivate that is not a function");let l=Rh({tables:t,hostCall:(h,k)=>i.worker.call(h,k),postToPanels:h=>{a.push(h)},log:h=>{r.push(h)},grantedCapabilities:i.capabilities}),p=i.onDataChange((h,k)=>{for(let x of t.dataListeners[h])x({key:k})});await u(l);let m=n.commands?[...t.commands.keys()].find(h=>!n.commands?.includes(h)):void 0;if(m!==void 0)throw new Error(`registered undeclared command ${m}: list it in contributes.commands`);async function f(h,k,x){let I=t.panelRequests.get(h);if(!I)throw De("unknown_method",`no panel handler named ${h}`);let A={...Mh,contributionId:x??Mh.contributionId};return I(k,{panel:A,signal:new AbortController().signal})}let g=i.routeRequests((h,k)=>f(h,k));return{host:i,logs:r,posts:a,get refusals(){return i.refusals},async emit(h,k){if(!iw(h))throw new Error(`emit: "${h}" is not an event Orca sends to workers`);if(!o.has(h))throw new Error(`emit: "${h}" never arrives: it is not in contributes.events`);let x=Qd[h].safeParse(k);if(!x.success)throw new TypeError(`emit: that ${h} payload is not one Orca sends: ${x.error.issues[0]?.message??""}`);let I=t.events.get(Vo.get(h)??h)??[];await Promise.all([...I].map(async A=>A(x.data))),await i.idle()},async command(h,k){let x=t.commands.get(h);if(!x)throw new Error(`command: the worker registered no "${h}"`);let I=await x(k,{signal:new AbortController().signal});return await i.idle(),I},async request(h,k,x={}){let I=await f(h,k,x.panel);return await i.idle(),I},async deactivate(){if(s){s=!1,p(),g(),t.events.clear(),t.commands.clear(),t.panelRequests.clear();try{await(typeof c=="function"?c():void 0)}catch(h){throw new Error(`deactivate threw: ${ow(h)}`,{cause:h})}await i.idle()}}}}import{test as FE,describe as GE,beforeEach as BE,afterEach as JE}from"node:test";import{default as HE}from"node:assert/strict";function Gh(){for(let e=process.cwd();;e=Vh(e))try{let n=JSON.parse(aw(sw(e,"orca-plugin.json"),"utf8"));return np(n)?n:null}catch{if(Vh(e)===e)return null}}function np(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function tp(e,n){return Array.isArray(e)?e.flatMap(i=>np(i)&&typeof i[n]=="string"?[i[n]]:[]):[]}function Fh(e){return e&&np(e.contributes)?e.contributes:{}}function Bh(e={}){return Fv(e,tp(Gh()?.capabilities,"kind"))}function CE(e,n={}){let i=Gh();return Zh(e,{host:n.host??Bh(),events:n.events??tp(Fh(i).events,"on"),commands:n.commands??(i?tp(Fh(i).commands,"id"):null)})}function LE(e,n={}){return Uh(e,{...n,host:n.host??Bh()})}function RE(e){return e}export{JE as afterEach,HE as assert,BE as beforeEach,RE as defineCheck,GE as describe,De as hostError,Bh as mockHost,LE as mount,CE as mountWorker,wh as stored,FE as test}; +Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`)}for(let a of e.seen.entries()){let s=a[1];if(n===a[0]){r(a);continue}if(e.external){let c=e.external.registry.get(a[0])?.id;if(n!==a[0]&&c){r(a);continue}}if(e.metadataRegistry.get(a[0])?.id){r(a);continue}if(s.cycle){r(a);continue}s.count>1&&e.reused==="ref"&&r(a)}e.external&&(e.sharedDefsExtractedFor=e.external)}function mf(e){let n=e.anyOf;if(!Array.isArray(n)||n.length===0||e.type!==void 0)return;let i=[];for(let o of n){if(!o||typeof o!="object")return;mf(o);let t=Object.keys(o);if(t.length!==1||t[0]!=="type")return;let r=o.type;for(let a of Array.isArray(r)?r:[r]){if(typeof a!="string")return;i.includes(a)||i.push(a)}}delete e.anyOf,e.type=i.length===1?i[0]:i}var ff=new Set(["type","properties","required","additionalProperties"]),df=["oneOf","anyOf"];function pf(e){let n=e.additionalProperties;return n===void 0||n===!1||typeof n!="object"||n===null?null:Object.keys(n).length?n:null}function Ec(e){let n=[];for(let r of e){if(typeof r!="object"||r.type!=="object")return null;for(let a in r)if(!ff.has(a))return null;n.push(r)}let i={},o=new Set;for(let r of n){for(let a in r.properties){if(Object.prototype.hasOwnProperty.call(i,a))continue;let s=[];for(let c of n){let l=c.properties?.[a]??pf(c);l!=null&&(s.some(p=>JSON.stringify(p)===JSON.stringify(l))||s.push(l))}let u=s.length===1?s[0]:Ec(s)??{allOf:s};ie(i,a,u)}for(let a of r.required??[])o.add(a)}let t={type:"object",properties:i};if(o.size&&(t.required=[...o]),n.every(r=>r.additionalProperties===!1))t.additionalProperties=!1;else{let r=[];for(let a of n){let s=pf(a);s&&!r.some(u=>JSON.stringify(u)===JSON.stringify(s))&&r.push(s)}r.length===1?t.additionalProperties=r[0]:r.length>1&&(t.additionalProperties={allOf:r})}return t}function ak(e){let n=e.allOf;if(!Array.isArray(n)||n.length<2)return;for(let t of ff)if(t in e)return;let i=n.filter(t=>df.some(r=>Array.isArray(t[r]))),o=null;if(!i.length)o=Ec(n);else{let t=i[0],r=df.find(u=>Array.isArray(t[u]));if(Object.keys(t).length!==1)return;let a=n.filter(u=>u!==t),s=t[r].map(u=>Ec([...a,u]));if(s.some(u=>!u))return;o={[r]:s}}o&&(delete e.allOf,sr(e,o))}function Qe(e,n){let i=e.seen.get(n);if(!i)throw new Error("Unprocessed schema. This is a bug in Zod.");let o=s=>{let u=e.seen.get(s);if(u.ref===null)return;let c=u.def??u.schema,l={...c},p=u.ref;if(u.ref=null,p){o(p);let f=e.seen.get(p),g=f.schema;if(g.$ref&&(e.target==="draft-07"||e.target==="draft-04"||e.target==="openapi-3.0")?(c.allOf=c.allOf??[],c.allOf.push(g)):sr(c,g),sr(c,l),s._zod.parent===p)for(let k in c)k==="$ref"||k==="allOf"||k in l||delete c[k];if(g.$ref&&f.def)for(let k in c)k==="$ref"||k==="allOf"||k in f.def&&JSON.stringify(c[k])===JSON.stringify(f.def[k])&&delete c[k]}let m=s._zod.parent;if(m&&m!==p){o(m);let f=e.seen.get(m);if(f?.schema.$ref&&(c.$ref=f.schema.$ref,f.def))for(let g in c)g==="$ref"||g==="allOf"||g in f.def&&JSON.stringify(c[g])===JSON.stringify(f.def[g])&&delete c[g]}e.override({zodSchema:s,jsonSchema:c,path:u.path??[]})};if(!e.external||e.sharedEmitDoneFor!==e.external){for(let s of[...e.seen.entries()].reverse())o(s[0]);if(e.target!=="openapi-3.0")for(let s of e.seen.entries())mf(s[1].def??s[1].schema);for(let s of e.deferred)s();if(e.intersections.length){let s=new Map;for(let u of e.seen.values())for(let c of[u.schema,u.def]){let l=c?.allOf;if(!Array.isArray(l))continue;let p=s.get(l);p?p.push(c):s.set(l,[c])}for(let u of e.intersections)for(let c of s.get(u)??[])ak(c)}}let t={};if(e.target==="draft-2020-12"?t.$schema="https://json-schema.org/draft/2020-12/schema":e.target==="draft-07"?t.$schema="http://json-schema.org/draft-07/schema#":e.target==="draft-04"?t.$schema="http://json-schema.org/draft-04/schema#":e.target,e.external?.uri){let s=e.external.registry.get(n)?.id;if(!s)throw new Error("Schema is missing an `id` property");t.$id=e.external.uri(s)}sr(t,i.defId?i.schema:i.def??i.schema);let r=e.metadataRegistry.get(n)?.id;r!==void 0&&t.id===r&&delete t.id;let a=e.external?.defs??{};if(!e.external||e.sharedEmitDoneFor!==e.external)for(let s of e.seen.entries()){let u=s[1];u.def&&u.defId&&(u.def.id===u.defId&&delete u.def.id,ie(a,u.defId,u.def))}e.external&&(e.sharedEmitDoneFor=e.external),e.external||Object.keys(a).length>0&&(e.target==="draft-2020-12"?t.$defs=a:t.definitions=a);try{let s=JSON.parse(JSON.stringify(t));return Object.defineProperty(s,"~standard",{value:{...n["~standard"],jsonSchema:{input:an(n,"input",e.processors),output:an(n,"output",e.processors)}},enumerable:!1,writable:!1}),s}catch{throw new Error("Error converting schema to JSON.")}}function le(e,n){let i=n??{seen:new Set};if(i.seen.has(e))return!1;i.seen.add(e);let o=e._zod.def;if(o.type==="transform")return!0;if(o.type==="array")return le(o.element,i);if(o.type==="set")return le(o.valueType,i);if(o.type==="lazy")return le(o.getter(),i);if(o.type==="promise"||o.type==="optional"||o.type==="nonoptional"||o.type==="nullable"||o.type==="readonly"||o.type==="default"||o.type==="prefault"||o.type==="catch")return le(o.innerType,i);if(o.type==="intersection")return le(o.left,i)||le(o.right,i);if(o.type==="record"||o.type==="map")return le(o.keyType,i)||le(o.valueType,i);if(o.type==="pipe")return e._zod.traits.has("$ZodCodec")?!0:le(o.in,i)||le(o.out,i);if(o.type==="object"){for(let t in o.shape)if(le(o.shape[t],i))return!0;return!1}if(o.type==="union"){for(let t of o.options)if(le(t,i))return!0;return!1}if(o.type==="tuple"){for(let t of o.items)if(le(t,i))return!0;return!!(o.rest&&le(o.rest,i))}return!1}var Oc=(e,n={})=>i=>{let o=qe({...i,processors:n});return J(e,o),Ye(o,e),Qe(o,e)},an=(e,n,i={})=>o=>{let{libraryOptions:t,target:r}=o??{},a=qe({...t??{},target:r,io:n,processors:i});return J(e,a),Ye(a,e),Qe(a,e)};var sn=(e,n,i)=>{(e[n]===void 0||i>e[n])&&(e[n]=i)},un=(e,n,i)=>{(e[n]===void 0||i{sn(e,"minimum",n),un(e,"maximum",n)},bf=(e,n)=>{e.multipleOf??(e.multipleOf=[]),e.multipleOf.includes(n)||e.multipleOf.push(n)},$f=(e,n)=>{e.patterns??(e.patterns=new Set),e.patterns.add(n)},_f=(e,n)=>{e.mime=e.mime?e.mime.filter(i=>n.includes(i)):[...n]},kf=(e,n)=>{e.format=n,n.includes("int")&&(e.isInt=!0)},vf=(e,n)=>sn(e,"minimum",n.minimum),hf=(e,n)=>un(e,"maximum",n.maximum),yf=e=>(n,i)=>{kf(n,i.format);let[o,t]=e[i.format];sn(n,"minimum",o),un(n,"maximum",t)},sk={greater_than:(e,n)=>sn(e,n.inclusive?"minimum":"exclusiveMinimum",n.value),less_than:(e,n)=>un(e,n.inclusive?"maximum":"exclusiveMaximum",n.value),multiple_of:(e,n)=>bf(e,n.value),number_format:yf(An),bigint_format:yf(Tn),min_length:vf,max_length:hf,length_equals:(e,n)=>gf(e,n.length),min_size:vf,max_size:hf,size_equals:(e,n)=>gf(e,n.size),string_format:(e,n)=>{kf(e,n.format),n.pattern&&$f(e,n.pattern),(n.format==="base64"||n.format==="base64url")&&(e.contentEncoding=n.format),(n.local||n.precision===-1)&&(e.laxFormat=!0)},mime_type:(e,n)=>_f(e,n.mime)};function ne(e){let n={},i=e._zod.def,o=e._zod.traits.has("$ZodCheck")?[e,...i.checks??[]]:i.checks??[];for(let r of o)sk[r._zod.def.check]?.(n,r._zod.def);let t=e._zod.bag;t.minimum!==void 0&&sn(n,"minimum",t.minimum),t.exclusiveMinimum!==void 0&&sn(n,"exclusiveMinimum",t.exclusiveMinimum),t.maximum!==void 0&&un(n,"maximum",t.maximum),t.exclusiveMaximum!==void 0&&un(n,"exclusiveMaximum",t.exclusiveMaximum),t.multipleOf!==void 0&&bf(n,t.multipleOf),t.format!==void 0&&(n.format??(n.format=t.format),t.format.includes("int")&&(n.isInt=!0)),t.mime&&_f(n,t.mime);for(let r of t.patterns??[])$f(n,r);return n}var uk={guid:"uuid",url:"uri",datetime:"date-time",json_string:"json-string",regex:""},ck=new Map([[ci,Ra],[Jn,Ma]]),xf=e=>ck.get(e)??e,Uc=(e,n,i,o)=>{let t=i;t.type="string";let{minimum:r,maximum:a,format:s,patterns:u,contentEncoding:c,laxFormat:l}=ne(e);if(typeof r=="number"&&(t.minLength=r),typeof a=="number"&&(t.maxLength=a),s&&(t.format=uk[s]??s,t.format===""&&delete t.format,(s==="time"||l)&&delete t.format),c&&(t.contentEncoding=c),u&&u.size>0){let p=[...u].map(xf);p.length===1?t.pattern=p[0].source:p.length>1&&(t.allOf=[...p.map(m=>({...n.target==="draft-07"||n.target==="draft-04"||n.target==="openapi-3.0"?{type:"string"}:{},pattern:m.source}))])}},Cc=(e,n,i,o)=>{let t=i,{minimum:r,maximum:a,multipleOf:s,exclusiveMaximum:u,exclusiveMinimum:c,isInt:l}=ne(e);t.type=l?"integer":"number";let p=typeof c=="number"&&c>=(r??Number.NEGATIVE_INFINITY),m=typeof u=="number"&&u<=(a??Number.POSITIVE_INFINITY),f=n.target==="draft-04"||n.target==="openapi-3.0";if(p?f?(t.minimum=c,t.exclusiveMinimum=!0):t.exclusiveMinimum=c:typeof r=="number"&&(t.minimum=r),m?f?(t.maximum=u,t.exclusiveMaximum=!0):t.exclusiveMaximum=u:typeof a=="number"&&(t.maximum=a),s){let g=new Set;for(let x of s)Number.isFinite(x)&&x!==0?g.add(Math.abs(x)):te(e,n,t,o,`A multipleOf divisor of ${x} cannot be represented in JSON Schema`);let[h,...k]=g;h!==void 0&&(t.multipleOf=h),k.length&&(t.allOf=[...t.allOf??[],...k.map(x=>({multipleOf:x}))])}},Lc=(e,n,i,o)=>{i.type="boolean"},Rc=(e,n,i,o)=>{te(e,n,i,o,"BigInt cannot be represented in JSON Schema")},Mc=(e,n,i,o)=>{te(e,n,i,o,"Symbols cannot be represented in JSON Schema")},Zc=(e,n,i,o)=>{n.target==="openapi-3.0"?(i.type="string",i.nullable=!0,i.enum=[null]):i.type="null"},Vc=(e,n,i,o)=>{te(e,n,i,o,"Undefined cannot be represented in JSON Schema")},Fc=(e,n,i,o)=>{te(e,n,i,o,"Void cannot be represented in JSON Schema")},Gc=(e,n,i,o)=>{i.not={}},Bc=(e,n,i,o)=>{},Jc=(e,n,i,o)=>{},Kc=(e,n,i,o)=>{te(e,n,i,o,"Date cannot be represented in JSON Schema")},Hc=(e,n,i,o)=>{let t=e._zod.def,r=Nt(t.entries);if(r.length===0){i.not={};return}r.every(a=>typeof a=="number")&&(i.type="number"),r.every(a=>typeof a=="string")&&(i.type="string"),i.enum=r},Wc=(e,n,i,o)=>{let t=e._zod.def;if(t.values.length===0){i.not={};return}let r=[];for(let a of t.values)if(a===void 0){if(te(e,n,i,o,"Literal `undefined` cannot be represented in JSON Schema"))return}else if(typeof a=="bigint"){if(te(e,n,i,o,"BigInt literals cannot be represented in JSON Schema"))return;r.push(Number(a))}else r.push(a);if(r.length!==0)if(r.length===1){let a=r[0];i.type=a===null?"null":typeof a,n.target==="draft-04"||n.target==="openapi-3.0"?i.enum=[a]:i.const=a}else r.every(a=>typeof a=="number")&&(i.type="number"),r.every(a=>typeof a=="string")&&(i.type="string"),r.every(a=>typeof a=="boolean")&&(i.type="boolean"),r.every(a=>a===null)&&(i.type="null"),i.enum=r},Xc=(e,n,i,o)=>{te(e,n,i,o,"NaN cannot be represented in JSON Schema")},qc=(e,n,i,o)=>{let t=i,r=e._zod.pattern;if(!r)throw new Error("Pattern not found in template literal");t.type="string",t.pattern=r.source},Yc=(e,n,i,o)=>{let t=i;t.type="string",t.format="binary",t.contentEncoding="binary";let{minimum:r,maximum:a,mime:s}=ne(e);r!==void 0&&(t.minLength=r),a!==void 0&&(t.maxLength=a),s&&(s.length===0?t.not={}:s.length===1?t.contentMediaType=s[0]:t.anyOf=s.map(u=>({contentMediaType:u})))},Qc=(e,n,i,o)=>{i.type="boolean"},el=(e,n,i,o)=>{te(e,n,i,o,"Custom types cannot be represented in JSON Schema")},tl=(e,n,i,o)=>{te(e,n,i,o,"Function types cannot be represented in JSON Schema")},nl=(e,n,i,o)=>{te(e,n,i,o,"Transforms cannot be represented in JSON Schema")},rl=(e,n,i,o)=>{te(e,n,i,o,"Map cannot be represented in JSON Schema")},il=(e,n,i,o)=>{te(e,n,i,o,"Set cannot be represented in JSON Schema")},ol=(e,n,i,o)=>{let t=i,r=e._zod.def,{minimum:a,maximum:s}=ne(e);typeof a=="number"&&(t.minItems=a),typeof s=="number"&&(t.maxItems=s),t.type="array",t.items=J(r.element,n,{...o,path:[...o.path,"items"]})};function ur(e){let n=e._zod.def;return n.type==="pipe"&&n.in._zod.traits.has("$ZodTransform")?ur(n.out):n.type==="catch"?ur(n.innerType):e._zod.optin}var al=(e,n,i,o)=>{let t=i,r=e._zod.def,a=r.shape;if(Object.getOwnPropertySymbols(a).length&&te(e,n,t,o,"Symbol keys cannot be represented in JSON Schema"))return;t.type="object",t.properties={};for(let c in a)ie(t.properties,c,J(a[c],n,{...o,path:[...o.path,"properties",c]}));let u=[];for(let c of Object.keys(a)){let l=r.shape[c];(n.io==="input"?ur(l)===void 0:l._zod.optout===void 0)&&u.push(c)}u.length>0&&(t.required=u),r.catchall?._zod.def.type==="never"?t.additionalProperties=!1:r.catchall?r.catchall&&(t.additionalProperties=J(r.catchall,n,{...o,path:[...o.path,"additionalProperties"]})):n.io==="output"&&(t.additionalProperties=!1)},ao=(e,n,i,o)=>{let t=e._zod.def,r=t.inclusive===!1,a=t.options.map((s,u)=>J(s,n,{...o,path:[...o.path,r?"oneOf":"anyOf",u]}));r?i.oneOf=a:i.anyOf=a},sl=(e,n,i,o)=>{let t=e._zod.def,r=J(t.left,n,{...o,path:[...o.path,"allOf",0]}),a=J(t.right,n,{...o,path:[...o.path,"allOf",1]}),s=c=>"allOf"in c&&Object.keys(c).length===1,u=[...s(r)?r.allOf:[r],...s(a)?a.allOf:[a]];i.allOf=u,n.intersections.push(u)},ul=(e,n,i,o)=>{let t=i,r=e._zod.def;t.type="array";let a=n.target==="draft-2020-12"?"prefixItems":"items",s=n.target==="draft-2020-12"||n.target==="openapi-3.0"?"items":"additionalItems",u=r.items.map((h,k)=>J(h,n,{...o,path:[...o.path,a,k]})),c=r.rest?J(r.rest,n,{...o,path:[...o.path,s,...n.target==="openapi-3.0"?[r.items.length]:[]]}):null,l=r.items.length;for(;l>0;){let h=r.items[l-1];if(!(n.io==="input"?ur(h)!==void 0:h._zod.optout==="optional"))break;l--}let p=r.items.length,m=!r.rest;n.target==="draft-2020-12"?(t.prefixItems=u,m?t.items=!1:c&&(t.items=c),l>0&&(t.minItems=l),m&&(t.maxItems=p)):n.target==="openapi-3.0"?(t.items={anyOf:u},c&&t.items.anyOf.push(c),l>0&&(t.minItems=l),m&&(t.maxItems=p)):(t.items=u,m?t.additionalItems=!1:c&&(t.additionalItems=c),l>0&&(t.minItems=l),m&&(t.maxItems=p));let{minimum:f,maximum:g}=ne(e);typeof f=="number"&&(t.minItems=f),typeof g=="number"&&(t.maxItems=g)};function Dc(e,n,i){if(n.$ref){if(i.has(n))return n;i.add(n);let g=e.get(n)?.def;if(!g)return n;let h=Dc(e,g,i);return h===g?n:h}for(let g of["anyOf","oneOf"]){let h=n[g];if(!Array.isArray(h))continue;let k=h.map(x=>Dc(e,x,i));k.some((x,I)=>x!==h[I])&&(n={...n,[g]:k})}let o=Array.isArray(n.type)?n.type:[n.type],t=!o.includes("string")&&o.some(g=>g==="number"||g==="integer"),r=n.enum??(n.const!==void 0?[n.const]:void 0);if(!t&&!r?.some(g=>typeof g=="number"))return n;let{minimum:a,maximum:s,exclusiveMinimum:u,exclusiveMaximum:c,multipleOf:l,format:p,id:m,...f}=n;return f.enum?f.enum=f.enum.map(g=>typeof g=="number"?String(g):g):typeof f.const=="number"&&(f.const=String(f.const)),t&&(f.type="string",r||(f.pattern=(o.includes("number")?Me:Rn).source)),f}var jc=new WeakMap;function lk(e){let n=new Map;for(let o of e.seen.values())o.def&&!n.has(o.schema)&&n.set(o.schema,o);let i=new Map;for(let o of jc.get(e)??[]){let t=e.seen.get(o),r=(t?.def??t?.schema)?.propertyNames;if(!r||r===!0||i.has(r))continue;let a=Dc(n,r,new Set);a!==r&&i.set(r,a)}if(i.size)for(let o of e.seen.values())for(let t of[o.schema,o.def]){let r=t&&i.get(t.propertyNames);r&&(t.propertyNames=r)}}var cl=(e,n,i,o)=>{let t=i,r=e._zod.def;t.type="object";let a=r.keyType,s=ne(a).patterns;if(r.mode==="loose"&&s&&s.size>0){let l=J(r.valueType,n,{...o,path:[...o.path,"patternProperties","*"]});t.patternProperties={};for(let p of s)ie(t.patternProperties,xf(p).source,l)}else{if(n.target==="draft-07"||n.target==="draft-2020-12"){t.propertyNames=J(r.keyType,n,{...o,path:[...o.path,"propertyNames"]});let l=jc.get(n);l||(l=[],jc.set(n,l),n.deferred.push(()=>lk(n))),l.push(e)}t.additionalProperties=J(r.valueType,n,{...o,path:[...o.path,"additionalProperties"]})}let u=a._zod.values,c=n.io==="input"&&ur(r.valueType)!==void 0;if(u&&!r.partial&&!c){let l=[...u].filter(p=>typeof p=="string"||typeof p=="number");l.length>0&&(t.required=l.map(String))}},ll=(e,n,i,o)=>{let t=e._zod.def,r=J(t.innerType,n,o),a=n.seen.get(e);n.target==="openapi-3.0"?(a.ref=t.innerType,i.nullable=!0):i.anyOf=[r,{type:"null"}]},dl=(e,n,i,o)=>{let t=e._zod.def;J(t.innerType,n,o);let r=n.seen.get(e);r.ref=t.innerType},pl=Symbol();function If(e,n,i,o,t){let r=!1,a=JSON.stringify(e,(s,u)=>typeof u!="bigint"?u:(r=!0,null));return r?(te(n,i,o,t,"BigInt defaults cannot be represented in JSON Schema"),pl):JSON.parse(a)}var ml=(e,n,i,o)=>{let t=e._zod.def;J(t.innerType,n,o);let r=n.seen.get(e);r.ref=t.innerType;let a=If(t.defaultValue,e,n,i,o);a!==pl&&(i.default=a)},fl=(e,n,i,o)=>{let t=e._zod.def;J(t.innerType,n,o);let r=n.seen.get(e);if(r.ref=t.innerType,n.io!=="input")return;let a=If(t.defaultValue,e,n,i,o);a!==pl&&(i._prefault=a)},gl=(e,n,i,o)=>{let t=e._zod.def;J(t.innerType,n,o);let r=n.seen.get(e);r.ref=t.innerType;let a;try{a=t.catchValue(void 0)}catch{te(e,n,i,o,"Dynamic catch values are not supported in JSON Schema");return}i.default=a},vl=(e,n,i,o)=>{let t=e._zod.def,r=t.in._zod.traits.has("$ZodTransform"),a=n.io==="input"?r?t.out:t.in:t.out;J(a,n,o);let s=n.seen.get(e);s.ref=a},hl=(e,n,i,o)=>{let t=e._zod.def;J(t.innerType,n,o);let r=n.seen.get(e);r.ref=t.innerType,i.readOnly=!0},yl=(e,n,i,o)=>{let t=e._zod.def;J(t.innerType,n,o);let r=n.seen.get(e);r.ref=t.innerType},so=(e,n,i,o)=>{let t=e._zod.def;J(t.innerType,n,o);let r=n.seen.get(e);r.ref=t.innerType},bl=(e,n,i,o)=>{let t=e._zod.innerType;J(t,n,o);let r=n.seen.get(e);r.ref=t},oo={string:Uc,number:Cc,boolean:Lc,bigint:Rc,symbol:Mc,null:Zc,undefined:Vc,void:Fc,never:Gc,any:Bc,unknown:Jc,date:Kc,enum:Hc,literal:Wc,nan:Xc,template_literal:qc,file:Yc,success:Qc,custom:el,function:tl,transform:nl,map:rl,set:il,array:ol,object:al,union:ao,intersection:sl,tuple:ul,record:cl,nullable:ll,nonoptional:dl,default:ml,prefault:fl,catch:gl,pipe:vl,readonly:hl,promise:yl,optional:so,lazy:bl};function uo(e,n){if("_idmap"in e){let o=e,t=qe({...n,processors:oo}),r={};for(let u of o._idmap.entries()){let[c,l]=u;J(l,t)}let a={},s={registry:o,uri:n?.uri,defs:r};t.external=s;for(let u of o._idmap.entries()){let[c,l]=u;Ye(t,l),ie(a,c,Qe(t,l))}if(Object.keys(r).length>0){let u=t.target==="draft-2020-12"?"$defs":"definitions";a.__shared={[u]:r}}return{schemas:a}}let i=qe({...n,processors:oo});return J(e,i),Ye(i,e),Qe(i,e)}var co=class{get metadataRegistry(){return this.ctx.metadataRegistry}get target(){return this.ctx.target}get unrepresentable(){return this.ctx.unrepresentable}get override(){return this.ctx.override}get io(){return this.ctx.io}get counter(){return this.ctx.counter}set counter(n){this.ctx.counter=n}get seen(){return this.ctx.seen}constructor(n){let i=n?.target??"draft-2020-12";i==="draft-4"&&(i="draft-04"),i==="draft-7"&&(i="draft-07"),this.ctx=qe({processors:oo,target:i,...n?.metadata&&{metadata:n.metadata},...n?.unrepresentable&&{unrepresentable:n.unrepresentable},...n?.override&&{override:n.override},...n?.io&&{io:n.io}})}process(n,i={path:[],schemaPath:[]}){return J(n,this.ctx,i)}emit(n,i){i&&(i.cycles&&(this.ctx.cycles=i.cycles),i.reused&&(this.ctx.reused=i.reused),i.external&&(this.ctx.external=i.external)),this.ctx.sharedDefsExtractedFor=void 0,this.ctx.sharedEmitDoneFor=void 0,Ye(this.ctx,n);let o=Qe(this.ctx,n),{"~standard":t,...r}=o;return r}};var wf={};var vn={};Ce(vn,{ZodAny:()=>Zl,ZodArray:()=>Bl,ZodBase64:()=>To,ZodBase64URL:()=>zo,ZodBigInt:()=>fn,ZodBigIntFormat:()=>Oo,ZodBoolean:()=>mn,ZodCIDRv4:()=>Po,ZodCIDRv6:()=>Ao,ZodCUID:()=>$o,ZodCUID2:()=>_o,ZodCatch:()=>pd,ZodCodec:()=>yr,ZodCreditCard:()=>Ol,ZodCustom:()=>br,ZodCustomStringFormat:()=>xt,ZodDate:()=>pr,ZodDefault:()=>ad,ZodDiscriminatedUnion:()=>Kl,ZodE164:()=>No,ZodEmail:()=>vo,ZodEmoji:()=>yo,ZodEnum:()=>ln,ZodExactOptional:()=>Co,ZodFile:()=>nd,ZodFunction:()=>kd,ZodGUID:()=>ho,ZodIBAN:()=>Dl,ZodIPv4:()=>wo,ZodIPv6:()=>So,ZodISODate:()=>tt,ZodISODateTime:()=>et,ZodISODuration:()=>rt,ZodISOTime:()=>nt,ZodInstanceOf:()=>wd,ZodIntersection:()=>Hl,ZodJWT:()=>Eo,ZodKSUID:()=>Io,ZodLazy:()=>bd,ZodLiteral:()=>td,ZodMAC:()=>El,ZodMap:()=>Ql,ZodNaN:()=>fd,ZodNanoID:()=>bo,ZodNever:()=>Fl,ZodNonOptional:()=>Lo,ZodNull:()=>Rl,ZodNullable:()=>od,ZodNumber:()=>pn,ZodNumberFormat:()=>It,ZodObject:()=>fr,ZodOptional:()=>vr,ZodPipe:()=>hr,ZodPrefault:()=>ud,ZodPreprocess:()=>gd,ZodPromise:()=>_d,ZodReadonly:()=>vd,ZodRecord:()=>cn,ZodSet:()=>ed,ZodString:()=>dn,ZodStringFormat:()=>H,ZodSuccess:()=>dd,ZodSymbol:()=>Cl,ZodTemplateLiteral:()=>yd,ZodTransform:()=>rd,ZodTuple:()=>Xl,ZodType:()=>L,ZodULID:()=>ko,ZodURL:()=>dr,ZodUUID:()=>Oe,ZodUndefined:()=>Ll,ZodUnion:()=>gr,ZodUnknown:()=>Vl,ZodVoid:()=>Gl,ZodXID:()=>xo,ZodXor:()=>Jl,_ZodString:()=>go,_default:()=>sd,_function:()=>Cg,any:()=>fg,array:()=>mr,base64:()=>Hf,base64url:()=>Wf,bigint:()=>cg,boolean:()=>Ul,catch:()=>md,check:()=>Lg,cidrv4:()=>Jf,cidrv6:()=>Kf,codec:()=>Og,creditCard:()=>qf,cuid:()=>Lf,cuid2:()=>Rf,currencyCode:()=>rg,custom:()=>Rg,date:()=>vg,describe:()=>Mg,discriminatedUnion:()=>kg,e164:()=>Xf,email:()=>Af,emoji:()=>Uf,enum:()=>jo,exactOptional:()=>id,file:()=>Tg,float32:()=>og,float64:()=>ag,function:()=>Cg,guid:()=>Tf,hash:()=>ig,hex:()=>ng,hostname:()=>tg,httpUrl:()=>jf,iban:()=>Yf,instanceof:()=>Vg,int:()=>mo,int32:()=>sg,int64:()=>lg,intersection:()=>Wl,invertCodec:()=>Dg,ipv4:()=>Ff,ipv6:()=>Bf,json:()=>Gg,jwt:()=>Qf,keyof:()=>hg,ksuid:()=>Vf,lazy:()=>$d,literal:()=>Ag,looseObject:()=>$g,looseRecord:()=>Ig,mac:()=>Gf,map:()=>wg,meta:()=>Zg,nan:()=>Eg,nanoid:()=>Cf,nativeEnum:()=>Pg,never:()=>Do,nonoptional:()=>ld,null:()=>Ml,nullable:()=>lr,nullish:()=>zg,number:()=>jl,object:()=>yg,optional:()=>_t,partialRecord:()=>xg,pipe:()=>fo,prefault:()=>cd,preprocess:()=>Bg,promise:()=>Ug,readonly:()=>hd,record:()=>Yl,refine:()=>xd,set:()=>Sg,strictObject:()=>bg,string:()=>cr,stringFormat:()=>eg,stringbool:()=>Fg,success:()=>Ng,superRefine:()=>Id,symbol:()=>pg,templateLiteral:()=>jg,transform:()=>Uo,tuple:()=>ql,uint32:()=>ug,uint64:()=>dg,ulid:()=>Mf,undefined:()=>mg,union:()=>gn,unknown:()=>$t,url:()=>Df,uuid:()=>zf,uuidv4:()=>Nf,uuidv6:()=>Ef,uuidv7:()=>Of,void:()=>gg,xid:()=>Zf,xor:()=>_g});var lo={};Ce(lo,{endsWith:()=>qt,gt:()=>Ne,gte:()=>$e,includes:()=>Wt,length:()=>yt,lowercase:()=>Kt,lt:()=>ze,lte:()=>be,maxLength:()=>ht,maxSize:()=>Xe,mime:()=>Qt,minLength:()=>Ze,minSize:()=>Ee,multipleOf:()=>We,negative:()=>to,nonnegative:()=>ro,nonpositive:()=>no,normalize:()=>en,overwrite:()=>Ae,positive:()=>eo,properties:()=>Yt,property:()=>io,regex:()=>Jt,size:()=>vt,slugify:()=>on,startsWith:()=>Xt,toLowerCase:()=>nn,toUpperCase:()=>rn,trim:()=>tn,uppercase:()=>Ht});var Sf=new WeakSet([Object.prototype,Error.prototype]);function po(e,n,i){Object.defineProperty(e,n,{configurable:!0,enumerable:!1,get(){let o=i(this);return Object.defineProperty(this,n,{value:o,configurable:!0,writable:!0}),o},set(o){Object.defineProperty(this,n,{value:o,configurable:!0,writable:!0})}})}var Pf=(e,n)=>{ba.init(e,n),e.name="ZodError";let i=Object.getPrototypeOf(e);Sf.has(i)||(Sf.add(i),po(i,"format",o=>t=>jn(o,t)),po(i,"flatten",o=>t=>Dn(o,t)),po(i,"addIssue",o=>t=>{o.issues.push(t),o.message=JSON.stringify(o.issues,Et,2)}),po(i,"addIssues",o=>t=>{o.issues.push(...t),o.message=JSON.stringify(o.issues,Et,2)}),Object.defineProperty(i,"isEmpty",{configurable:!0,enumerable:!1,get(){return this.issues.length===0}}))},pk=v("ZodError",Pf),ye=v("ZodError",Pf,void 0,{Parent:Error});var $l=Ct(ye),_l=Lt(ye),kl=Rt(ye),xl=Mt(ye),Il=Mr(ye),wl=Zr(ye),Sl=Vr(ye),Pl=Fr(ye),Al=Gr(ye),Tl=Br(ye),zl=Jr(ye),Nl=Kr(ye);function fk(){re.localeError||Y(wi())}function kt(){re.memoizer||Y({memoizer:Qn()})}var L=v("ZodType",(e,n)=>(fk(),j.init(e,n),e.def=n,e.type=n.type,e),{check(...e){let n=this.def;return this.clone(b.mergeDefs(n,{checks:[...n.checks??[],...e.map(i=>typeof i=="function"?{_zod:{check:i,def:{check:"custom"},onattach:[]}}:i)]}),{parent:!0})},with(...e){return this.check(...e)},clone(e,n){return G(this,e,n)},brand(){return this},register(e,n){return e.add(this,n),this},refine(e,n){return this.check(xd(e,n))},superRefine(e,n){return this.check(Id(e,n))},overwrite(e){return this.check(Ae(e))},optional(){return _t(this)},exactOptional(){return id(this)},nullable(){return lr(this)},nullish(){return _t(lr(this))},nonoptional(e){return ld(this,e)},array(){return mr(this)},or(e){return gn([this,e])},and(e){return Wl(this,e)},transform(e){return fo(this,Uo(e))},default(e){return sd(this,e)},prefault(e){return cd(this,e)},catch(e){return md(this,e)},pipe(e){return fo(this,e)},readonly(){return hd(this)},describe(e){let n=this.clone();return oe.add(n,{description:e}),n},meta(...e){if(e.length===0)return oe.get(this);let n=this.clone();return oe.add(n,e[0]),n},isOptional(){return this.safeParse(void 0).success},isNullable(){return this.safeParse(null).success},apply(e,...n){return n.length===0?e(this):e(this,...n)},get"~standard"(){return b.hide(this,"~standard",{...ii(this),jsonSchema:{input:an(this,"input"),output:an(this,"output")}})},set"~standard"(e){b.own(this,"~standard",e)},parse:function e(n,i){return $l(this,n,i,{callee:e})},parseAsync:async function e(n,i){return await _l(this,n,i,{callee:e})},safeParse(e,n){return kl(this,e,n)},async safeParseAsync(e,n){return xl(this,e,n)},get spa(){return this?.safeParseAsync},set spa(e){b.own(this,"spa",e)},validate(e,n){return Un(this,e,n)},validateAsync(e,n){return Cn(this,e,n)},encode:function e(n,i){return Il(this,n,i,{callee:e})},decode:function e(n,i){return wl(this,n,i,{callee:e})},encodeAsync:async function e(n,i){return await Sl(this,n,i,{callee:e})},decodeAsync:async function e(n,i){return await Pl(this,n,i,{callee:e})},safeEncode(e,n){return Al(this,e,n)},safeDecode(e,n){return Tl(this,e,n)},async safeEncodeAsync(e,n){return zl(this,e,n)},async safeDecodeAsync(e,n){return Nl(this,e,n)},toJSONSchema(e){return Oc(this,{})(e)},get description(){return oe.get(this)?.description},get _def(){return this._zod.def}}),go=v("_ZodString",(e,n)=>{pt.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Uc(e,i,o,t)},b.derived({format:e=>ne(e).format??null,minLength:e=>ne(e).minimum??null,maxLength:e=>ne(e).maximum??null},{regex(...e){return this.check(Jt(...e))},includes(...e){return this.check(Wt(...e))},startsWith(...e){return this.check(Xt(...e))},endsWith(...e){return this.check(qt(...e))},min(...e){return this.check(Ze(...e))},max(...e){return this.check(ht(...e))},length(...e){return this.check(yt(...e))},nonempty(...e){return this.check(Ze(1,...e))},lowercase(e){return this.check(Kt(e))},uppercase(e){return this.check(Ht(e))},trim(){return this.check(tn())},normalize(...e){return this.check(en(...e))},toLowerCase(){return this.check(nn())},toUpperCase(){return this.check(rn())},slugify(){return this.check(on())}})),dn=v("ZodString",(e,n)=>{pt.init(e,n),go.init(e,n)},{email(e){return this.check(Oi(vo,e))},url(e){return this.check(nr(dr,e))},jwt(e){return this.check(Qi(Eo,e))},emoji(e){return this.check(Ri(yo,e))},guid(e){return this.check(Di(ho,e))},uuid(e){return this.check(ji(Oe,e))},uuidv4(e){return this.check(Ui(Oe,e))},uuidv6(e){return this.check(Ci(Oe,e))},uuidv7(e){return this.check(Li(Oe,e))},nanoid(e){return this.check(Mi(bo,e))},cuid(e){return this.check(Zi($o,e))},cuid2(e){return this.check(Vi(_o,e))},ulid(e){return this.check(Fi(ko,e))},base64(e){return this.check(Xi(To,e))},base64url(e){return this.check(qi(zo,e))},xid(e){return this.check(Gi(xo,e))},ksuid(e){return this.check(Bi(Io,e))},ipv4(e){return this.check(Ji(wo,e))},ipv6(e){return this.check(Ki(So,e))},cidrv4(e){return this.check(Hi(Po,e))},cidrv6(e){return this.check(Wi(Ao,e))},e164(e){return this.check(Yi(No,e))},datetime(e){return this.check(rr(et,e))},date(e){return this.check(ir(tt,e))},time(e){return this.check(or(nt,e))},duration(e){return this.check(ar(rt,e))}});function cr(e){return Wu(dn,e)}var H=v("ZodStringFormat",(e,n)=>{B.init(e,n),go.init(e,n)}),et=v("ZodISODateTime",(e,n)=>{Rs.init(e,n),H.init(e,n)}),tt=v("ZodISODate",(e,n)=>{Ms.init(e,n),H.init(e,n)}),nt=v("ZodISOTime",(e,n)=>{Zs.init(e,n),H.init(e,n)}),rt=v("ZodISODuration",(e,n)=>{Vs.init(e,n),H.init(e,n)}),vo=v("ZodEmail",(e,n)=>{As.init(e,n),H.init(e,n)});function Af(e){return Oi(vo,e)}var ho=v("ZodGUID",(e,n)=>{Ss.init(e,n),H.init(e,n)});function Tf(e){return Di(ho,e)}var Oe=v("ZodUUID",(e,n)=>{Ps.init(e,n),H.init(e,n)});function zf(e){return ji(Oe,e)}function Nf(e){return Ui(Oe,e)}function Ef(e){return Ci(Oe,e)}function Of(e){return Li(Oe,e)}var dr=v("ZodURL",(e,n)=>{Ns.init(e,n),H.init(e,n)});function Df(e){return nr(dr,e)}function jf(e){return nr(dr,{protocol:Ln,hostname:Va,...b.normalizeParams(e)})}var yo=v("ZodEmoji",(e,n)=>{Es.init(e,n),H.init(e,n)});function Uf(e){return Ri(yo,e)}var bo=v("ZodNanoID",(e,n)=>{Os.init(e,n),H.init(e,n)});function Cf(e){return Mi(bo,e)}var $o=v("ZodCUID",(e,n)=>{Ds.init(e,n),H.init(e,n)});function Lf(e){return Zi($o,e)}var _o=v("ZodCUID2",(e,n)=>{js.init(e,n),H.init(e,n)});function Rf(e){return Vi(_o,e)}var ko=v("ZodULID",(e,n)=>{Us.init(e,n),H.init(e,n)});function Mf(e){return Fi(ko,e)}var xo=v("ZodXID",(e,n)=>{Cs.init(e,n),H.init(e,n)});function Zf(e){return Gi(xo,e)}var Io=v("ZodKSUID",(e,n)=>{Ls.init(e,n),H.init(e,n)});function Vf(e){return Bi(Io,e)}var wo=v("ZodIPv4",(e,n)=>{Fs.init(e,n),H.init(e,n)});function Ff(e){return Ji(wo,e)}var El=v("ZodMAC",(e,n)=>{Bs.init(e,n),H.init(e,n)});function Gf(e){return qu(El,e)}var So=v("ZodIPv6",(e,n)=>{Gs.init(e,n),H.init(e,n)});function Bf(e){return Ki(So,e)}var Po=v("ZodCIDRv4",(e,n)=>{Js.init(e,n),H.init(e,n)});function Jf(e){return Hi(Po,e)}var Ao=v("ZodCIDRv6",(e,n)=>{Ks.init(e,n),H.init(e,n)});function Kf(e){return Wi(Ao,e)}var To=v("ZodBase64",(e,n)=>{Hs.init(e,n),H.init(e,n)});function Hf(e){return Xi(To,e)}var zo=v("ZodBase64URL",(e,n)=>{Ws.init(e,n),H.init(e,n)});function Wf(e){return qi(zo,e)}var No=v("ZodE164",(e,n)=>{Xs.init(e,n),H.init(e,n)});function Xf(e){return Yi(No,e)}var Ol=v("ZodCreditCard",(e,n)=>{qs.init(e,n),H.init(e,n)});function qf(e){return Yu(Ol,e)}var Dl=v("ZodIBAN",(e,n)=>{Ys.init(e,n),H.init(e,n)});function Yf(e){return Qu(Dl,e)}var Eo=v("ZodJWT",(e,n)=>{Qs.init(e,n),H.init(e,n)});function Qf(e){return Qi(Eo,e)}var xt=v("ZodCustomStringFormat",(e,n)=>{eu.init(e,n),H.init(e,n)});function eg(e,n,i={}){return bt(xt,e,n,i)}function tg(e){return bt(xt,"hostname",Za,e)}function ng(e){return bt(xt,"hex",ns,e)}function rg(e){return bt(xt,"currency_code",Ga,e)}function ig(e,n){let i=n?.enc??"hex",o=`${e}_${i}`,t=xe[o];if(!t)throw new Error(`Unrecognized hash format: ${o}`);return bt(xt,o,t,n)}var pn=v("ZodNumber",(e,n)=>{fi.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Cc(e,i,o,t),e.isFinite=!0},b.derived({minValue:e=>{let{minimum:n,exclusiveMinimum:i}=ne(e);return Math.max(n??Number.NEGATIVE_INFINITY,i??Number.NEGATIVE_INFINITY)},maxValue:e=>{let{maximum:n,exclusiveMaximum:i}=ne(e);return Math.min(n??Number.POSITIVE_INFINITY,i??Number.POSITIVE_INFINITY)},isInt:e=>{let{isInt:n,multipleOf:i}=ne(e);return!!n||!!i?.some(Number.isSafeInteger)},format:e=>ne(e).format??null},{gt(e,n){return this.check(Ne(e,n))},gte(e,n){return this.check($e(e,n))},min(e,n){return this.check($e(e,n))},lt(e,n){return this.check(ze(e,n))},lte(e,n){return this.check(be(e,n))},max(e,n){return this.check(be(e,n))},int(e){return this.check(mo(e))},safe(e){return this.check(mo(e))},positive(e){return this.check(Ne(0,e))},nonnegative(e){return this.check($e(0,e))},negative(e){return this.check(ze(0,e))},nonpositive(e){return this.check(be(0,e))},multipleOf(e,n){return this.check(We(e,n))},step(e,n){return this.check(We(e,n))},finite(){return this}}));function jl(e){return tc(pn,e)}var It=v("ZodNumberFormat",(e,n)=>{tu.init(e,n),pn.init(e,n)});function mo(e){return rc(It,e)}function og(e){return ic(It,e)}function ag(e){return oc(It,e)}function sg(e){return ac(It,e)}function ug(e){return sc(It,e)}var mn=v("ZodBoolean",(e,n)=>{Kn.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Lc(e,i,o,t)});function Ul(e){return uc(mn,e)}var fn=v("ZodBigInt",(e,n)=>{gi.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Rc(e,i,o,t)},b.derived({minValue:e=>ne(e).minimum??null,maxValue:e=>ne(e).maximum??null,format:e=>ne(e).format??null},{gte(e,n){return this.check($e(e,n))},min(e,n){return this.check($e(e,n))},gt(e,n){return this.check(Ne(e,n))},lt(e,n){return this.check(ze(e,n))},lte(e,n){return this.check(be(e,n))},max(e,n){return this.check(be(e,n))},positive(e){return this.check(Ne(BigInt(0),e))},negative(e){return this.check(ze(BigInt(0),e))},nonpositive(e){return this.check(be(BigInt(0),e))},nonnegative(e){return this.check($e(BigInt(0),e))},multipleOf(e,n){return this.check(We(e,n))}}));function cg(e){return lc(fn,e)}var Oo=v("ZodBigIntFormat",(e,n)=>{nu.init(e,n),fn.init(e,n)});function lg(e){return pc(Oo,e)}function dg(e){return mc(Oo,e)}var Cl=v("ZodSymbol",(e,n)=>{ru.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Mc(e,i,o,t)});function pg(e){return fc(Cl,e)}var Ll=v("ZodUndefined",(e,n)=>{iu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Vc(e,i,o,t)});function mg(e){return gc(Ll,e)}var Rl=v("ZodNull",(e,n)=>{ou.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Zc(e,i,o,t)});function Ml(e){return vc(Rl,e)}var Zl=v("ZodAny",(e,n)=>{au.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Bc(e,i,o,t)});function fg(){return hc(Zl)}var Vl=v("ZodUnknown",(e,n)=>{su.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Jc(e,i,o,t)});function $t(){return yc(Vl)}var Fl=v("ZodNever",(e,n)=>{uu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Gc(e,i,o,t)});function Do(e){return bc(Fl,e)}var Gl=v("ZodVoid",(e,n)=>{cu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Fc(e,i,o,t)});function gg(e){return $c(Gl,e)}var pr=v("ZodDate",(e,n)=>{lu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Kc(e,i,o,t),e.min=(i,o)=>e.check($e(i,o)),e.max=(i,o)=>e.check(be(i,o))},b.derived({minDate:e=>{let{minimum:n}=ne(e);return n?new Date(n):null},maxDate:e=>{let{maximum:n}=ne(e);return n?new Date(n):null}},{}));function vg(e){return _c(pr,e)}var Bl=v("ZodArray",(e,n)=>{kt(),pu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>ol(e,i,o,t),e.element=n.element},{min(e,n){return this.check(Ze(e,n))},nonempty(e){return this.check(Ze(1,e))},max(e,n){return this.check(ht(e,n))},length(e,n){return this.check(yt(e,n))},unwrap(){return this.element}});function mr(e,n){return Ic(Bl,e,n)}function hg(e){let n=e._zod.def.shape;return jo(Object.keys(n))}var fr=v("ZodObject",(e,n)=>{kt(),mu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>al(e,i,o,t),b.installLazyProp(e,"shape",i=>i._zod.def.shape,!1)},{keyof(){return jo(Object.keys(this._zod.def.shape))},catchall(e){return this.clone(b.mergeDefs(this._zod.def,{catchall:e}))},passthrough(){return this.clone(b.mergeDefs(this._zod.def,{catchall:$t()}))},loose(){return this.clone(b.mergeDefs(this._zod.def,{catchall:$t()}))},strict(){return this.clone(b.mergeDefs(this._zod.def,{catchall:Do()}))},strip(){return this.clone(b.mergeDefs(this._zod.def,{catchall:void 0}))},extend(e){return b.extend(this,e)},safeExtend(e){return b.safeExtend(this,e)},merge(e){return b.merge(this,e)},pick(e){return b.pick(this,e)},omit(e){return b.omit(this,e)},partial(...e){return b.partial(vr,this,e[0])},exactPartial(...e){return b.partial(Co,this,e[0],"exactPartial")},required(...e){return b.required(Lo,this,e[0])}});function yg(e,n){let i={type:"object",shape:e??{},...b.normalizeParams(n)};return new fr(i)}function bg(e,n){return new fr({type:"object",shape:e,catchall:Do(),...b.normalizeParams(n)})}function $g(e,n){return new fr({type:"object",shape:e,catchall:$t(),...b.normalizeParams(n)})}var gr=v("ZodUnion",(e,n)=>{Hn.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>ao(e,i,o,t),e.options=n.options});function gn(e,n){return new gr({type:"union",options:e,...b.normalizeParams(n)})}var Jl=v("ZodXor",(e,n)=>{gr.init(e,n),fu.init(e,n),e._zod.processJSONSchema=(i,o,t)=>ao(e,i,o,t),e.options=n.options});function _g(e,n){return new Jl({type:"union",options:e,inclusive:!1,...b.normalizeParams(n)})}var Kl=v("ZodDiscriminatedUnion",(e,n)=>{gr.init(e,n),vu.init(e,n)});function kg(e,n,i){return new Kl({type:"union",options:n,discriminator:e,...b.normalizeParams(i)})}var Hl=v("ZodIntersection",(e,n)=>{hu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>sl(e,i,o,t)});function Wl(e,n){return new Hl({type:"intersection",left:e,right:n})}var Xl=v("ZodTuple",(e,n)=>{kt(),vi.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>ul(e,i,o,t)},{rest(e){return this.clone({...this._zod.def,rest:e})},partial(){let e=this._zod.def;if(e.checks?.length)throw new Error(".partial() cannot be used on tuple schemas containing refinements");return this.clone({...e,items:e.items.map(n=>new vr({type:"optional",innerType:n}))})}});function ql(e,n,i){let o=n instanceof j,t=o?i:n,r=o?n:null;return new Xl({type:"tuple",items:e,rest:r,...b.normalizeParams(t)})}var cn=v("ZodRecord",(e,n)=>{kt(),yu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>cl(e,i,o,t),e.keyType=n.keyType,e.valueType=n.valueType});function Yl(e,n,i){return!n||!n._zod?new cn({type:"record",keyType:cr(),valueType:e,...b.normalizeParams(n)}):new cn({type:"record",keyType:e,valueType:n,...b.normalizeParams(i)})}function xg(e,n,i){return new cn({type:"record",keyType:e,valueType:n,...b.normalizeParams(i),partial:!0})}function Ig(e,n,i){return new cn({type:"record",keyType:e,valueType:n,mode:"loose",...b.normalizeParams(i)})}var Ql=v("ZodMap",(e,n)=>{kt(),bu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>rl(e,i,o,t),e.keyType=n.keyType,e.valueType=n.valueType,e.min=(...i)=>e.check(Ee(...i)),e.nonempty=i=>e.check(Ee(1,i)),e.max=(...i)=>e.check(Xe(...i)),e.size=(...i)=>e.check(vt(...i))});function wg(e,n,i){return new Ql({type:"map",keyType:e,valueType:n,...b.normalizeParams(i)})}var ed=v("ZodSet",(e,n)=>{kt(),$u.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>il(e,i,o,t),e.min=(...i)=>e.check(Ee(...i)),e.nonempty=i=>e.check(Ee(1,i)),e.max=(...i)=>e.check(Xe(...i)),e.size=(...i)=>e.check(vt(...i))});function Sg(e,n){return new ed({type:"set",valueType:e,...b.normalizeParams(n)})}var ln=v("ZodEnum",(e,n)=>{_u.init(e,n),L.init(e,n),e._zod.processJSONSchema=(o,t,r)=>Hc(e,o,t,r),e.enum=n.entries,e.options=[...e._zod.values];let i=new Set(Object.keys(n.entries));e.extract=(o,t)=>{let r={};for(let a of o)if(i.has(a))r[a]=n.entries[a];else throw new Error(`Key ${a} not found in enum`);return new ln({...n,checks:[],...b.normalizeParams(t),entries:r})},e.exclude=(o,t)=>{let r={...n.entries};for(let a of o)if(i.has(a))delete r[a];else throw new Error(`Key ${a} not found in enum`);return new ln({...n,checks:[],...b.normalizeParams(t),entries:r})}});function jo(e,n){let i=Array.isArray(e)?Object.fromEntries(e.map(o=>[o,o])):e;return new ln({type:"enum",entries:i,...b.normalizeParams(n)})}function Pg(e,n){return new ln({type:"enum",entries:e,...b.normalizeParams(n)})}var td=v("ZodLiteral",(e,n)=>{ku.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Wc(e,i,o,t),e.values=new Set(n.values),Object.defineProperty(e,"value",{get(){if(n.values.length>1)throw new Error("This schema contains multiple valid literal values. Use `.values` instead.");return n.values[0]}})});function Ag(e,n){return new td({type:"literal",values:Array.isArray(e)?e:[e],...b.normalizeParams(n)})}var nd=v("ZodFile",(e,n)=>{xu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Yc(e,i,o,t),e.min=(i,o)=>e.check(Ee(i,o)),e.max=(i,o)=>e.check(Xe(i,o)),e.mime=(i,o)=>e.check(Qt(Array.isArray(i)?i:[i],o))});function Tg(e){return wc(nd,e)}var rd=v("ZodTransform",(e,n)=>{kt(),Iu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>nl(e,i,o,t),e._zod.parse=(i,o)=>{if(o.direction==="backward")throw new Ke(e.constructor.name);i.addIssue=r=>{if(typeof r=="string")i.issues.push(b.issue(r,i.value,n));else{let a=r;a.fatal&&(a.continue=!1),a.code??(a.code="custom"),"input"in a||(a.input=i.value),a.inst??(a.inst=e),i.issues.push(b.issue(a))}};let t=n.transform(i.value,i);return t instanceof Promise?t.then(r=>(i.value=r,i)):(i.value=t,i)}});function Uo(e){return new rd({type:"transform",transform:e})}var vr=v("ZodOptional",(e,n)=>{hi.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>so(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function _t(e){return new vr({type:"optional",innerType:e})}var Co=v("ZodExactOptional",(e,n)=>{wu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>so(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function id(e){return new Co({type:"optional",innerType:e})}var od=v("ZodNullable",(e,n)=>{Su.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>ll(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function lr(e){return new od({type:"nullable",innerType:e})}function zg(e){return _t(lr(e))}var ad=v("ZodDefault",(e,n)=>{Pu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>ml(e,i,o,t),e.unwrap=()=>e._zod.def.innerType,e.removeDefault=e.unwrap});function sd(e,n){return new ad({type:"default",innerType:e,get defaultValue(){return typeof n=="function"?n():b.shallowClone(n)}})}var ud=v("ZodPrefault",(e,n)=>{Au.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>fl(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function cd(e,n){return new ud({type:"prefault",innerType:e,get defaultValue(){return typeof n=="function"?n():b.shallowClone(n)}})}var Lo=v("ZodNonOptional",(e,n)=>{Tu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>dl(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function ld(e,n){return new Lo({type:"nonoptional",innerType:e,...b.normalizeParams(n)})}var dd=v("ZodSuccess",(e,n)=>{zu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Qc(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function Ng(e){return new dd({type:"success",innerType:e})}var pd=v("ZodCatch",(e,n)=>{Nu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>gl(e,i,o,t),e.unwrap=()=>e._zod.def.innerType,e.removeCatch=e.unwrap});function md(e,n){return new pd({type:"catch",innerType:e,catchValue:typeof n=="function"?n:b.constantCatch(n)})}var fd=v("ZodNaN",(e,n)=>{Eu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>Xc(e,i,o,t)});function Eg(e){return xc(fd,e)}var hr=v("ZodPipe",(e,n)=>{yi.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>vl(e,i,o,t),e.in=n.in,e.out=n.out});function fo(e,n){return new hr({type:"pipe",in:e,out:n})}var yr=v("ZodCodec",(e,n)=>{hr.init(e,n),Wn.init(e,n)});function Og(e,n,i){return new yr({type:"pipe",in:e,out:n,transform:i.decode,reverseTransform:i.encode})}function Dg(e){let n=e._zod.def;return new yr({type:"pipe",in:n.out,out:n.in,transform:n.reverseTransform,reverseTransform:n.transform})}var gd=v("ZodPreprocess",(e,n)=>{hr.init(e,n),Ou.init(e,n)}),vd=v("ZodReadonly",(e,n)=>{Du.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>hl(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function hd(e){return new vd({type:"readonly",innerType:e})}var yd=v("ZodTemplateLiteral",(e,n)=>{ju.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>qc(e,i,o,t)});function jg(e,n){return new yd({type:"template_literal",parts:e,...b.normalizeParams(n)})}var bd=v("ZodLazy",(e,n)=>{Xn.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>bl(e,i,o,t),e.unwrap=()=>e._zod.def.getter()});function $d(e){return new bd({type:"lazy",getter:e})}var _d=v("ZodPromise",(e,n)=>{Cu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>yl(e,i,o,t),e.unwrap=()=>e._zod.def.innerType});function Ug(e){return new _d({type:"promise",innerType:e})}var kd=v("ZodFunction",(e,n)=>{Uu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>tl(e,i,o,t)});function Cg(e){return new kd({type:"function",input:Array.isArray(e?.input)?ql(e?.input):e?.input??mr($t()),output:e?.output??$t()})}var br=v("ZodCustom",(e,n)=>{Lu.init(e,n),L.init(e,n),e._zod.processJSONSchema=(i,o,t)=>el(e,i,o,t)});function Lg(e){let n=new W({check:"custom"});return n._zod.check=e,n}function Rg(e,n){return Sc(br,e??(()=>!0),n)}function xd(e,n={}){return Pc(br,e,n)}function Id(e,n){return Ac(e,n)}var Mg=Tc,Zg=zc,wd=v("ZodInstanceOf",(e,n)=>{br.init(e,n)},{properties(e,n){return this.check(Yt(e,n))}});function Vg(e,n={}){let i=new wd({type:"custom",check:"custom",fn:o=>o instanceof e,abort:!0,...b.normalizeParams(n)});return i._zod.bag.Class=e,i._zod.check=o=>{o.value instanceof e||o.issues.push({code:"invalid_type",expected:e.name,input:o.value,inst:i,path:[...i._zod.def.path??[]]})},i}var Fg=(...e)=>Nc({Codec:yr,Boolean:mn,String:dn},...e);function Gg(e){let n=$d(()=>gn([cr(e),jl(),Ul(),Ml(),mr(n),Yl(cr(),n)]));return n}function Bg(e,n){return new gd({type:"pipe",in:Uo(e),out:n})}var gk={invalid_type:"invalid_type",too_big:"too_big",too_small:"too_small",invalid_format:"invalid_format",not_multiple_of:"not_multiple_of",unrecognized_keys:"unrecognized_keys",invalid_union:"invalid_union",invalid_key:"invalid_key",invalid_element:"invalid_element",invalid_value:"invalid_value",custom:"custom"};function vk(e){Y({customError:e})}function hk(){return Y().customError}var Sd;Sd||(Sd={});var $r={};Ce($r,{ZodISODate:()=>tt,ZodISODateTime:()=>et,ZodISODuration:()=>rt,ZodISOTime:()=>nt,date:()=>bk,datetime:()=>yk,duration:()=>_k,time:()=>$k});function yk(e){return rr(et,e)}function bk(e){return ir(tt,e)}function $k(e){return or(nt,e)}function _k(e){return ar(rt,e)}var P={...vn,...lo,iso:$r},kk=new Set(["$schema","$ref","$defs","definitions","$id","id","$comment","$anchor","$vocabulary","$dynamicRef","$dynamicAnchor","type","enum","const","anyOf","oneOf","allOf","not","properties","required","additionalProperties","patternProperties","propertyNames","minProperties","maxProperties","items","prefixItems","additionalItems","minItems","maxItems","uniqueItems","contains","minContains","maxContains","minLength","maxLength","pattern","format","minimum","maximum","exclusiveMinimum","exclusiveMaximum","multipleOf","description","default","contentEncoding","contentMediaType","contentSchema","unevaluatedItems","unevaluatedProperties","if","then","else","dependentSchemas","dependentRequired","nullable","readOnly"]);function xk(e,n){let i=e.$schema;return i==="https://json-schema.org/draft/2020-12/schema"?"draft-2020-12":i==="http://json-schema.org/draft-07/schema#"?"draft-7":i==="http://json-schema.org/draft-04/schema#"?"draft-4":n??"draft-2020-12"}function Jg(e,n){return e.map((i,o)=>oo).check(o=>{let t=o.value;if(typeof t!="object"||t===null||Array.isArray(t))return;let r=Object.getOwnPropertyNames(t);if(n.minProperties!==void 0&&r.length=${n.minProperties} properties`,input:t,inst:e,continue:!0}),n.maxProperties!==void 0&&r.length>n.maxProperties&&o.issues.push({origin:"object",code:"too_big",maximum:n.maxProperties,inclusive:!0,message:`Too big: expected object to have <=${n.maxProperties} properties`,input:t,inst:e,continue:!0}),n.keySchema)for(let a of r){let s=n.keySchema.safeParse(a);s.success||o.issues.push({code:"invalid_key",origin:"record",issues:s.error.issues,input:a,path:[a],continue:!0})}}).pipe(e)}function Pd(e,n){if(e===null)return"z";let i=typeof e;if(i!=="object"){if(i==="number"&&Number.isNaN(e))return null;let o=String(e);return`${i[0]}${o.length}:${o}`}if(n.has(e))return null;n.add(e);try{if(Array.isArray(e)){let r=[];for(let a of e){let s=Pd(a,n);if(s===null)return null;r.push(s)}return`a${r.length}:[${r.join(",")}]`}let o=Object.keys(e).sort(),t=[];for(let r of o){let a=Pd(e[r],n);if(a===null)return null;t.push(`${r.length}:${r}=${a}`)}return`o${t.length}:{${t.join(",")}}`}finally{n.delete(e)}}var Pk=new Set(["items","prefixItems","additionalItems","additionalProperties","contains","propertyNames","not","if","then","else","allOf","anyOf","oneOf","unevaluatedItems","unevaluatedProperties","contentSchema"]),Ak=new Set(["properties","patternProperties","dependentSchemas","dependencies","$defs","definitions"]);function _r(e){return typeof e!="object"||e===null?!1:Array.isArray(e)?e.some(_r):typeof e.$ref=="string"?!0:Object.entries(e).some(([n,i])=>Pk.has(n)?_r(i):!Ak.has(n)||typeof i!="object"||i===null?!1:Object.values(i).some(_r))}function Kg(e){return e===1?"element":"elements"}function Tk(e,n){return P.transform(o=>o).check(o=>{let t=o.value;if(Array.isArray(t)){if(n.uniqueItems===!0){let r=new Map;for(let a=0;a=a)break;sn.maxContains&&o.issues.push({code:"custom",message:`Array must contain at most ${n.maxContains} matching ${Kg(n.maxContains)}`,input:t,continue:!0})}}}).pipe(e)}function Hg(e,n){if(e!==!1)return e===void 0||e===!0?P.any():de(e,n)}var zk=/^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/;function Wg(e,n){if(e.not!==void 0){if(typeof e.not=="object"&&Object.keys(e.not).length===0)return P.never();throw new Error("not is not supported in Zod (except { not: {} } for never)")}if(e.unevaluatedItems!==void 0)throw new Error("unevaluatedItems is not supported");if(e.unevaluatedProperties!==void 0)throw new Error("unevaluatedProperties is not supported");if(e.if!==void 0||e.then!==void 0||e.else!==void 0)throw new Error("Conditional schemas (if/then/else) are not supported");if(e.dependentSchemas!==void 0||e.dependentRequired!==void 0)throw new Error("dependentSchemas and dependentRequired are not supported");if(e.$ref){let t=e.$ref;if(n.refs.has(t))return n.refs.get(t);if(n.processing.has(t))return P.lazy(()=>{if(!n.refs.has(t))throw new Error(`Circular reference not resolved: ${t}`);return n.refs.get(t)});n.processing.add(t);let r=wk(t,n),a=de(r,n);return n.refs.set(t,a),n.processing.delete(t),a}if(e.enum!==void 0){let t=e.enum;if(n.version==="openapi-3.0"&&e.nullable===!0&&t.length===1&&t[0]===null)return P.null();if(t.length===0)return P.never();if(t.length===1)return P.literal(t[0]);if(t.every(a=>typeof a=="string"))return P.enum(t);let r=t.map(a=>P.literal(a));return r.length<2?r[0]:P.union([r[0],r[1],...r.slice(2)])}if(e.const!==void 0)return P.literal(e.const);let i=e.type;if(Array.isArray(i)){let t=i.map(r=>{let a={...e,type:r};return Wg(a,n)});return t.length===0?P.never():t.length===1?t[0]:P.union(t)}if(!i)return P.any();let o;switch(i){case"string":{let t=P.string();if(e.format){let r=e.format;r==="email"?t=t.check(P.email()):r==="uri"||r==="uri-reference"?t=t.check(P.url()):r==="uuid"||r==="guid"?t=t.check(P.uuid()):r==="date-time"?t=t.check(P.iso.datetime({offset:!0})):r==="date"?t=t.check(P.iso.date()):r==="time"?t=t.check(P.regex(zk)):r==="duration"?t=t.check(P.iso.duration()):r==="hostname"?t=t.check(P.hostname()):r==="ipv4"?t=t.check(P.ipv4()):r==="ipv6"?t=t.check(P.ipv6()):r==="mac"?t=t.check(P.mac()):r==="cidr"?t=t.check(P.cidrv4()):r==="cidr-v6"?t=t.check(P.cidrv6()):r==="base64"?t=t.check(P.base64()):r==="base64url"?t=t.check(P.base64url()):r==="e164"?t=t.check(P.e164()):r==="credit_card"?t=t.check(P.creditCard()):r==="iban"?t=t.check(P.iban()):r==="jwt"?t=t.check(P.jwt()):r==="emoji"?t=t.check(P.emoji()):r==="nanoid"?t=t.check(P.nanoid()):r==="cuid"?t=t.check(P.cuid()):r==="cuid2"?t=t.check(P.cuid2()):r==="ulid"?t=t.check(P.ulid()):r==="xid"?t=t.check(P.xid()):r==="ksuid"&&(t=t.check(P.ksuid()))}typeof e.minLength=="number"&&(t=t.min(e.minLength)),typeof e.maxLength=="number"&&(t=t.max(e.maxLength)),e.pattern&&(t=t.regex(new RegExp(e.pattern))),o=t;break}case"number":case"integer":{let t=i==="integer"?P.number().int():P.number();typeof e.minimum=="number"&&e.exclusiveMinimum!==!0&&(t=t.min(e.minimum)),typeof e.maximum=="number"&&e.exclusiveMaximum!==!0&&(t=t.max(e.maximum)),typeof e.exclusiveMinimum=="number"?t=t.gt(e.exclusiveMinimum):e.exclusiveMinimum===!0&&typeof e.minimum=="number"&&(t=t.gt(e.minimum)),typeof e.exclusiveMaximum=="number"?t=t.lt(e.exclusiveMaximum):e.exclusiveMaximum===!0&&typeof e.maximum=="number"&&(t=t.lt(e.maximum)),typeof e.multipleOf=="number"&&(t=t.multipleOf(e.multipleOf)),o=t;break}case"boolean":{o=P.boolean();break}case"null":{o=P.null();break}case"object":{let t={},r=e.properties||{},a=new Set(e.required||[]),s=typeof e.additionalProperties=="object"?de(e.additionalProperties,n):void 0;for(let[p,m]of Object.entries(r)){let f=de(m,n);ie(t,p,a.has(p)?f:f.optional())}if(e.patternProperties){let p=e.patternProperties,m=Object.keys(p),f=[];for(let h of m){let k=de(p[h],n),x=P.string().regex(new RegExp(h));f.push(P.looseRecord(x,k))}let g=[];if(Object.keys(t).length>0&&g.push(P.object(t).passthrough()),g.push(...f),g.length===0)o=P.object({}).passthrough();else if(g.length===1)o=g[0];else{let h=P.intersection(g[0],g[1]);for(let k=2;knew RegExp(I)),x=o;o=o.check(I=>{if(!_e(I.value))return;let A=[];for(let C of Object.keys(I.value))h.includes(C)||k.some(V=>V.test(C))||A.push(C);A.length&&I.issues.push({code:"unrecognized_keys",keys:A,input:I.value,inst:x})})}}else{let p=P.object(t);e.additionalProperties===!1?o=p.strict():s?o=p.catchall(s):o=p.passthrough()}let u=e.propertyNames!==void 0&&e.propertyNames!==!0,c=typeof e.minProperties=="number"?e.minProperties:void 0,l=typeof e.maxProperties=="number"?e.maxProperties:void 0;if(u||c!==void 0||l!==void 0){let p;if(u){let m=typeof e.propertyNames=="object"&&e.propertyNames.type===void 0?{type:"string",...e.propertyNames}:e.propertyNames;p=de(m,n)}o=Sk(o,{keySchema:p,minProperties:c,maxProperties:l})}break}case"array":{let t=e.prefixItems,r=e.items;if(t&&Array.isArray(t)){let a=typeof e.minItems=="number"?e.minItems:0,s=t.map(p=>de(p,n)),u=Jg(s,a),c=Array.isArray(r)?void 0:Hg(r,n),l=P.tuple(u);o=c?l.rest(c):l,typeof e.minItems=="number"&&(o=o.check(P.minLength(e.minItems))),typeof e.maxItems=="number"&&(o=o.check(P.maxLength(e.maxItems)))}else if(Array.isArray(r)){let a=typeof e.minItems=="number"?e.minItems:0,s=r.map(p=>de(p,n)),u=Jg(s,a),c=Hg(e.additionalItems,n),l=P.tuple(u);o=c?l.rest(c):l,typeof e.minItems=="number"&&(o=o.check(P.minLength(e.minItems))),typeof e.maxItems=="number"&&(o=o.check(P.maxLength(e.maxItems)))}else if(r!==void 0){let a=de(r,n),s=P.array(a);typeof e.minItems=="number"&&(s=s.min(e.minItems)),typeof e.maxItems=="number"&&(s=s.max(e.maxItems)),o=s}else o=P.array(P.any());(e.uniqueItems===!0||e.contains!==void 0)&&(o=Tk(o,{uniqueItems:e.uniqueItems===!0,containsSchema:e.contains!==void 0?de(e.contains,n):void 0,minContains:typeof e.minContains=="number"?e.minContains:void 0,maxContains:typeof e.maxContains=="number"?e.maxContains:void 0}));break}default:throw new Error(`Unsupported type: ${i}`)}return o}function de(e,n){if(typeof e=="boolean")return e?P.any():P.never();let i=Wg(e,n),o=e.type||e.enum!==void 0||e.const!==void 0;if(e.anyOf&&Array.isArray(e.anyOf)){let s=e.anyOf.map(c=>de(c,n)),u=P.union(s);i=o?P.intersection(i,u):u}if(e.oneOf&&Array.isArray(e.oneOf)){let s=e.oneOf.map(c=>de(c,n)),u=P.xor(s);i=o?P.intersection(i,u):u}if(e.allOf&&Array.isArray(e.allOf))if(e.allOf.length===0)i=o?i:P.any();else{let s=o?i:de(e.allOf[0],n),u=o?0:1;for(let c=u;c0&&n.registry.add(i,t),e.description&&(i=i.describe(e.description)),i}function Xg(e,n){if(typeof e=="boolean")return e?P.any():P.never();let i;try{i=JSON.parse(JSON.stringify(e))}catch{throw new Error("fromJSONSchema input is not valid JSON (possibly cyclic); use $defs/$ref for recursive schemas")}let o=xk(i,n?.defaultTarget),t=i.$defs||i.definitions||{},r={version:o,defs:t,refs:new Map,processing:new Set,rootSchema:i,registry:n?.registry??oe};return de(i,r)}var qg=Symbol("z.visit/resolving");function kr(e,n){let i=typeof n=="function"?n:(a,s)=>{let u=n[a._zod.def.type];return u?u(a,s):a},o=new Map;function t(a){let s=o.get(a);if(s===qg)return new Xn({type:"lazy",getter:()=>o.get(a)});if(s!==void 0)return s;o.set(a,qg);let u=r(a),c=i(u,u!==a);return o.set(a,c),c}function r(a){let s=a._zod.def,u=s.type;switch(u){case"object":{let c=s.shape,l=Object.keys(c),p=!1,m={};for(let g of l){let h=t(c[g]);h!==c[g]&&(p=!0),m[g]=h}let f=s.catchall;return s.catchall&&(f=t(s.catchall),f!==s.catchall&&(p=!0)),p?G(a,{...s,shape:m,catchall:f}):a}case"array":{let c=t(s.element);return c===s.element?a:G(a,{...s,element:c})}case"tuple":{let c=s.items,l=!1,p=[];for(let f of c){let g=t(f);g!==f&&(l=!0),p.push(g)}let m=s.rest;return s.rest&&(m=t(s.rest),m!==s.rest&&(l=!0)),l?G(a,{...s,items:p,rest:m}):a}case"record":case"map":{let c=t(s.keyType),l=t(s.valueType);return c===s.keyType&&l===s.valueType?a:G(a,{...s,keyType:c,valueType:l})}case"set":{let c=t(s.valueType);return c===s.valueType?a:G(a,{...s,valueType:c})}case"union":{let c=s.options,l=!1,p=[];for(let m of c){let f=t(m);f!==m&&(l=!0),p.push(f)}return l?G(a,{...s,options:p}):a}case"intersection":{let c=t(s.left),l=t(s.right);return c===s.left&&l===s.right?a:G(a,{...s,left:c,right:l})}case"optional":case"nullable":case"default":case"prefault":case"catch":case"readonly":case"nonoptional":case"promise":case"success":{let c=t(s.innerType);return c===s.innerType?a:G(a,{...s,innerType:c})}case"pipe":{let c=t(s.in),l=t(s.out);return c===s.in&&l===s.out?a:G(a,{...s,in:c,out:l})}case"function":{let c=t(s.input),l=t(s.output);return c===s.input&&l===s.output?a:G(a,{...s,input:c,output:l})}case"lazy":{let c=s.getter,{_cachedInner:l,...p}=s;return G(a,{...p,getter:()=>t(c())})}case"template_literal":case"string":case"number":case"int":case"boolean":case"bigint":case"symbol":case"undefined":case"null":case"void":case"never":case"any":case"unknown":case"date":case"nan":case"enum":case"literal":case"file":case"transform":case"custom":return a;default:return a}}return t(e)}function Yg(e){return kr(e,{object:n=>n.partial(),union:n=>{let i=n._zod.def;return i.discriminator===void 0?n:gn(i.options)}})}function Nk(e,n){if(!n?.length)return e;let i=e._zod.def;return G(e,Se(i,{checks:[...i.checks??[],...n]}),{parent:!0})}function Qg(e){return Nk(e.out,e.checks)}function Ek(e){return e.in._zod.traits.has("$ZodTransform")?Qg(e):e.in}function ev(e){return kr(e,{pipe:n=>Ek(n._zod.def),default:(n,i)=>i?_t(n._zod.def.innerType):n,catch:(n,i)=>i?n._zod.def.innerType:n})}function tv(e){return kr(e,{pipe:n=>Qg(n._zod.def),prefault:(n,i)=>i?n._zod.def.innerType:n})}var Ad={};Ce(Ad,{bigint:()=>Uk,boolean:()=>jk,date:()=>Ck,number:()=>Dk,string:()=>Ok});function Ok(e){return Xu(dn,e)}function Dk(e){return nc(pn,e)}function jk(e){return cc(mn,e)}function Uk(e){return dc(fn,e)}function Ck(e){return kc(pr,e)}var Lk=new Set(["__proto__","prototype","constructor"]),wt=d.string().min(1).max(256).refine(e=>!Lk.has(e),"reserved storage key"),Ro=d.json(),Mo=256*1024,Rk=5*1024*1024,nv=1024,rv=d.strictObject({key:wt}),iv=d.object({value:Ro}),ov=d.strictObject({key:wt,value:Ro}),av=d.object({ok:d.literal(!0)}),sv=d.strictObject({key:wt}),uv=d.object({ok:d.literal(!0)}),cv=d.strictObject({}).optional(),lv=d.object({keys:d.array(d.string()).max(nv)}),dv=d.strictObject({key:wt}),pv=d.object({value:d.string().nullable()}),mv=d.strictObject({key:wt,value:d.string().max(64*1024)}),fv=d.object({ok:d.literal(!0)}),gv=d.strictObject({key:wt}),vv=d.object({ok:d.literal(!0)}),hv=d.strictObject({}).optional(),yv=d.object({status:d.enum(["os-keyring","unavailable"])}),bv=d.strictObject({}).optional(),$v=d.object({settings:d.record(d.string(),Ro)}),_v=d.strictObject({key:wt,value:Ro}),kv=d.object({ok:d.literal(!0)});var Zo="x-orca-enum-since";var it="1.4.160",Td="1.4.245";var xr="1.4.246";var xv=xr,Iv=xr,Zk="Relative to the plugin root; `..` segments and Windows device names such as `CON` are refused.";function wv(e,n,i){return ot(`${e} ${Zk}`,n,i)}function ot(e,n,i){return i?{description:e,"x-orca-since":n,examples:[...i]}:{description:e,"x-orca-since":n}}var hn=["workspace.created","workspace.removed","agent.status.changed","workspace.changed"],nT=hn.length,Vk={"workspace.created":Td,"workspace.removed":Td,"agent.status.changed":it,"workspace.changed":Iv},Vo=new Map([["worktree.created","workspace.created"],["worktree.removed","workspace.removed"]]);var rT=d.object({on:d.enum(hn).meta({...ot("Event delivered to the plugin worker.",it),[Zo]:Vk})}).strict().meta({id:"EventContribution",description:"An event subscription. Requires `main`, the `trusted-worker` execution profile and the capability of the event's domain: `workspace:read` for workspace events, `agent:read` for agent events."});var pe=["worker","panel","editor"],Sv=["worker"],yn=["panel","editor"],ee=e=>e;function Pv(e,n){return n==="worker"?e.since:Math.max(e.since,e.framesSince??0)}var Fk=["success","failure","cancellation","superseded"],Av=[...Fk,"interruption","unconfirmed"];var bn=["working","blocked","waiting","done"];var CT=new Set(bn);var at=d.string().regex(/^[A-Za-z0-9_.:-]{1,128}$/,"is 1-128 letters, digits, or . _ : -");var Ev=12e4,JT=1024*1024,KT=256*1024;var Bk=d.object({id:d.string().min(1).max(64),surface:d.enum(["panel","editor"]),contributionId:d.string().min(1).max(256)}),HT=d.object({name:at,input:d.unknown(),panel:Bk}),WT=d.object({event:at,payload:d.unknown(),panel:d.string().min(1).max(64).optional()}),Ov=["storage","settings"],XT=d.object({area:d.enum(Ov),key:d.string().min(1).max(256)}),qT=d.discriminatedUnion("kind",[d.object({kind:d.literal("message"),event:at,payload:d.unknown()}),d.object({kind:d.literal("event"),event:d.enum(hn),payload:d.unknown()}),d.object({kind:d.literal("changed"),area:d.enum(Ov),key:d.string()})]);var Jk=d.strictObject({name:at,input:d.json().optional(),timeoutMs:d.number().int().min(1).max(Ev).optional()}),Kk=d.object({output:d.json()}),Hk=50,Wk=d.strictObject({}).optional(),Xk=d.object({agents:d.array(d.object({terminalId:d.string().min(1).max(1024).nullable(),title:d.string().max(512).nullable(),agent:d.string().max(128).nullable(),state:d.enum(bn),stateStartedAt:d.number().finite()})).max(Hk)}),qk=d.strictObject({event:d.enum(hn)}),Yk=d.object({ok:d.literal(!0)}),Dv={"plugin.request":ee({summary:"Asks the plugin's own worker to run the handler it registered with `orca.panels.handle(name)`, starting the worker if needed; resolves with what the handler returned. `unknown_method` when no handler has that name.",since:2,scope:"plugin-private",capability:null,mutation:!1,surfaces:yn,params:Jk,result:Kk}),"agents.list":ee({summary:"The agents in the focused workspace: their terminal, title, agent kind and status. `agent.status.changed` reports each change after.",since:2,scope:"active-workspace",capability:"agent:read",mutation:!1,surfaces:pe,params:Wk,result:Xk}),"events.subscribe":ee({summary:"Delivers a workspace or agent event to this panel as `orca.on(event)`; needs the event's read capability. The frame APIs call it for you.",since:2,scope:"plugin-private",capability:null,mutation:!1,surfaces:yn,params:qk,result:Yk})};var Qk=4096,ex=50,Ir=512,Fo=1024,tx=d.strictObject({}).optional(),zd=d.object({branch:d.string().max(Ir),displayName:d.string().max(Ir),terminals:d.array(d.object({id:d.string().min(1).max(Fo),title:d.string().max(Ir).optional()}).strict()).max(ex)}).strict().nullable(),nx=zd,rx=d.strictObject({terminalId:d.string().min(1).max(Fo),text:d.string().min(1).max(Qk),enter:d.boolean().default(!1)}),ix=d.object({accepted:d.boolean()}),ox=d.strictObject({title:d.string().min(1).max(120),body:d.string().max(1e3).optional()}),ax=d.object({delivered:d.boolean()});var sx=8192,ux=["http:","https:","mailto:"],jv=64*1024*1024,cx=d.strictObject({url:d.string().min(1).max(sx).refine(fx,"url must be an http:, https: or mailto: URL")}),lx=d.object({opened:d.boolean(),reason:d.enum(["cancelled","consent-unavailable"]).optional()}),dx=d.union([d.string().max(jv),d.custom(e=>e instanceof ArrayBuffer||e instanceof Uint8Array,"data must be a string or ArrayBuffer").refine(e=>e.byteLength<=jv,"data exceeds 64 MiB").meta({type:"ArrayBuffer"})]),px=d.strictObject({suggestedName:d.string().min(1).max(255).optional(),mimeType:d.string().min(1).max(255).optional(),data:dx}),mx=d.object({status:d.enum(["saved","cancelled"])});function fx(e){try{return ux.includes(new URL(e).protocol)}catch{return!1}}var St={"workspace.readContext":ee({summary:"Branch, name and terminal ids of the focused workspace, or null when none is focused.",since:0,scope:"active-workspace",capability:"workspace:read",mutation:!1,surfaces:pe,params:tx,result:nx}),"terminal.sendText":ee({summary:"Types text into one terminal named by id, optionally pressing Enter.",since:0,scope:"explicit-terminal",capability:"terminal:send",mutation:!0,surfaces:Sv,params:rx,result:ix}),"notifications.show":ee({summary:"Shows a desktop notification.",since:0,scope:"desktop",capability:"notifications:show",mutation:!0,surfaces:pe,params:ox,result:ax}),"storage.get":ee({summary:"Reads a JSON value from the plugin's private store; null when absent.",since:0,scope:"plugin-private",capability:"storage:own",mutation:!1,framesSince:2,surfaces:pe,params:rv,result:iv}),"storage.set":ee({summary:"Writes a JSON value to the plugin's private store.",since:0,scope:"plugin-private",capability:"storage:own",mutation:!0,framesSince:2,surfaces:pe,params:ov,result:av}),"storage.delete":ee({summary:"Removes a key from the plugin's private store.",since:0,scope:"plugin-private",capability:"storage:own",mutation:!0,framesSince:2,surfaces:pe,params:sv,result:uv}),"storage.keys":ee({summary:"Lists the keys in the plugin's private store.",since:0,scope:"plugin-private",capability:"storage:own",mutation:!1,framesSince:2,surfaces:pe,params:cv,result:lv}),"secrets.get":ee({summary:"Reads a secret from the plugin's encrypted secrets file; null when absent.",since:0,scope:"plugin-private",capability:"secrets:own",mutation:!1,framesSince:2,surfaces:pe,params:dv,result:pv}),"secrets.set":ee({summary:"Stores a secret in the plugin's encrypted secrets file.",since:0,scope:"plugin-private",capability:"secrets:own",mutation:!0,framesSince:2,surfaces:pe,params:mv,result:fv}),"secrets.delete":ee({summary:"Removes a secret from the plugin's encrypted secrets file.",since:0,scope:"plugin-private",capability:"secrets:own",mutation:!0,framesSince:2,surfaces:pe,params:gv,result:vv}),"secrets.protection":ee({summary:"How secrets are protected at rest: `os-keyring`, or `unavailable` (no OS key store, or Linux `basic_text`), where `secrets.set` fails.",since:1,scope:"plugin-private",capability:"secrets:own",mutation:!1,framesSince:2,surfaces:pe,params:hv,result:yv}),"settings.get":ee({summary:"Reads every setting the plugin owns.",since:0,scope:"plugin-private",capability:"settings:own",mutation:!1,framesSince:2,surfaces:pe,params:bv,result:$v}),"settings.set":ee({summary:"Writes one setting the plugin owns.",since:0,scope:"plugin-private",capability:"settings:own",mutation:!0,framesSince:2,surfaces:pe,params:_v,result:kv}),"shell.openExternal":ee({summary:"Opens an http:, https: or mailto: URL in the default browser. Needs a click or key press in the frame; desktop app only. Orca asks the person before an http(s) host the plugin was not allowed; `opened` is false if they cancel.",since:1,scope:"desktop",capability:null,userActivation:!0,mutation:!1,surfaces:yn,params:cx,result:lx}),"files.saveAs":ee({summary:"Offers data (a string or ArrayBuffer, up to 64 MiB) in Orca's save dialog; the plugin never learns the path. Needs a click or key press in the frame; desktop app only.",since:1,scope:"desktop",capability:null,userActivation:!0,mutation:!0,surfaces:yn,params:px,result:mx}),...Dv},Uv=Object.keys(St).filter(Cv);function Cv(e){return Object.hasOwn(St,e)}function Nd(e){return Cv(e)?St[e]:null}var Lv=Math.max(...Uv.map(e=>St[e].since));function wr(e){return Uv.filter(n=>St[n].surfaces.includes(e))}function Rv(e,n){return wr(e).filter(i=>n||St[i].userActivation!==!0)}function Mv(e,n="panel"){return Math.max(0,...e.map(i=>Pv(St[i],n)))}var Fe=1,dz=d.number().refine(e=>e===Fe,{error:e=>typeof e.input=="number"&&e.input>Fe?`targets host API ${e.input}, but this Orca supports only ${Fe}; update Orca`:`must be ${Fe}`}).meta({const:Fe});var gx=new Set(["rate_limited","unavailable","timeout","conflict"]);function De(e,n=e,i){return Object.assign(new Error(n),{code:e,retryable:gx.has(e),...i===void 0?{}:{retryAfterMs:i}})}var vx=new Set(["plugin.request","events.subscribe","storage.get","storage.set","storage.delete","storage.keys","settings.get","settings.set","secrets.get","secrets.set","secrets.delete","secrets.protection"]);function Go(e,n){return typeof e=="object"&&e!==null&&n in e?Object.getOwnPropertyDescriptor(e,n)?.value:void 0}function Zv(e){let n={storage:new Map(Object.entries(e.storage??{})),settings:new Map(Object.entries(e.settings??{})),secrets:new Map(Object.entries(e.secrets??{}))},i=new Set,o=(a,s,u)=>{if(u===void 0?n[a].delete(s):n[a].set(s,u),a!=="secrets")for(let c of i)c(a,s);return{ok:!0}},t=null;async function r(a){let s=String(Go(a,"name")),u=Go(a,"input");if(!e.requests||!Object.hasOwn(e.requests,s)){if(t)return{output:await t(s,u)??null};throw De("unknown_method",`no panel handler named ${s}`)}let c=e.requests[s];return{output:(typeof c=="function"?await c(u):c)??null}}return{handles:a=>vx.has(a),async answer(a,s){let u=String(Go(s,"key")),c=Go(s,"value");switch(a){case"plugin.request":return r(s);case"storage.get":return{value:n.storage.get(u)??null};case"storage.keys":return{keys:[...n.storage.keys()]};case"settings.get":return{settings:Object.fromEntries(n.settings)};case"secrets.get":return{value:n.secrets.get(u)??null};case"secrets.protection":return{status:"os-keyring"};case"storage.set":return o("storage",u,c);case"settings.set":return o("settings",u,c);case"secrets.set":return o("secrets",u,c);case"storage.delete":return o("storage",u,void 0);case"secrets.delete":return o("secrets",u,void 0);default:return{ok:!0}}},routeRequests(a){return t=a,()=>{t===a&&(t=null)}},onChange(a){return i.add(a),()=>i.delete(a)},snapshot:()=>({storage:Object.fromEntries(n.storage),settings:Object.fromEntries(n.settings),secrets:Object.fromEntries(n.secrets)})}}var Bo=class extends Error{constructor(i,o){super(o);this.code=i}code};function hx(e){return typeof e=="function"}var Vv={"workspace.readContext":null,"notifications.show":{delivered:!0},"shell.openExternal":{opened:!0},"files.saveAs":{status:"saved"},"agents.list":{agents:[]}};function Fv(e,n){let i=new Set(e.capabilities??n),o=new Map(Object.entries(e.results??{})),t=Zv(e),r={panel:Rv("panel",!0),worker:wr("worker")},a=[],s=[],u=new Set,c=0,l=(g,h)=>{throw new Bo(g,h)};async function p(g,h,k){let x=Nd(g);if(!x)return l("unknown_method",`${g} does not exist in this Orca`);if(!x.surfaces.includes(k))return l("not_permitted",`${g} is not available to ${k}s`);if(x.userActivation===!0){if(c===0)return l("not_permitted",`${g} needs a click or key press in the frame`);c-=1}if(x.capability&&!i.has(x.capability))return l("capability_denied",`${g} needs the ${x.capability} capability`);let I=x.params.safeParse(h);return I.success?I.data:l("invalid_params",I.error.issues[0]?.message??"invalid params")}async function m(g,h,k){let x;try{x=await p(g,h,k)}catch(T){throw T instanceof Bo?(s.push({method:g,code:T.code,message:T.message}),De(T.code,T.message)):T}let I=Nd(g);if(!I)throw De("unknown_method",g);let A=!o.has(g)&&t.handles(g);if(!o.has(g)&&!A&&!Object.hasOwn(Vv,g))throw De("unavailable",`the test configured no result for ${g}`);let C=o.has(g)?o.get(g):Vv[g],V=A?await t.answer(g,x):hx(C)?await C(x):C,w=I.result.safeParse(V);if(!w.success)throw new TypeError(`mockHost: the result configured for ${g} does not match the host API: ${w.error.issues[0]?.message??"invalid result"}`);return w.data}let f=g=>({api:{major:Fe,minor:Mv(r[g])},call(h,k){a.push({method:h,params:k});let x=m(h,k,g);return u.add(x),x.catch(()=>{}).finally(()=>u.delete(x)),x},has:h=>r[g].some(k=>k===h)});return{calls:a,refusals:s,capabilities:[...i],callsOf:g=>a.filter(h=>h.method===g).map(h=>h.params),respond:(g,h)=>o.set(g,h),grantGesture:()=>{c=1},data:()=>t.snapshot(),onDataChange:g=>t.onChange(g),routeRequests:g=>t.routeRequests(g),async idle(){for(;u.size>0;)await Promise.allSettled(u)},bridge:f("panel"),worker:f("worker")}}var je={render:"ui.render",event:"ui.event",error:"ui.error",ack:"ui.ack",ready:"ui.ready",hydrate:"ui.hydrate",visibility:"ui.visibility",persist:"ui.persist",retain:"ui.retain",snapshot:"ui.snapshot",restore:"ui.restore"};var yx={Input:{value:"value",change:"onChange"},Textarea:{value:"value",change:"onChange"},Switch:{value:"checked",change:"onChange"},Checkbox:{value:"checked",change:"onChange"},Select:{value:"value",change:"onChange"},RadioGroup:{value:"value",change:"onChange"},Slider:{value:"value",change:"onChange"},Tabs:{value:"value",change:"onChange"},Collapsible:{value:"open",change:"onChange"},Table:{value:"selected",change:"onSelectionChange"},Tree:{value:"selected",change:"onSelect"}},bx=new Map(Object.entries(yx));function Ed(e){return bx.get(e)??null}var Jo="$edit";var $x=/[\p{Cc}\p{Cf}\p{Cs}\p{Zl}\p{Zp}]/u,_x=new Set(["‌","‍"]);function kx(e){return _x.has(e)||!$x.test(e)}function Gv(e){return[...e].filter(kx).join("")}var xx=/[\t\n\v\f\r\u0085\u2028\u2029]+/g;function Ix(e){return Gv(e.replace(xx," "))}function Bv(e){let n=e.overwrite(Ix);return e.minLength?n.min(e.minLength,"must contain visible characters"):n}var wx=/^(?:con|prn|aux|nul|clock\$|conin\$|conout\$|com[1-9\u00B9\u00B2\u00B3]|lpt[1-9\u00B9\u00B2\u00B3])(?:\..*)?$/i,Sx=/[<>:"|?*]/,Ko=String.raw`[^<>:"|?*\x00-\x1f\\/]*[^<>:"|?*\x00-\x1f\\/. ]`,Od=new RegExp(`^${Ko}(?:[\\\\/]${Ko})*$`),Sz=new RegExp(`^${Ko}(?:/${Ko})*$`);function Px(e){return e.length===0||e==="."||e===".."?"empty and dot path segments are not allowed":e.endsWith(".")||e.endsWith(" ")?"path segments may not end with a dot or space":Sx.test(e)||[...e].some(n=>n.charCodeAt(0)<=31)?"path segment contains a Windows-forbidden character or alternate-data-stream colon":wx.test(e)?"path segment is a Windows reserved device name":null}function Ax(e){if(e.length===0||e.startsWith("/")||e.startsWith("\\"))return"must be a non-empty relative path";let n=e.split(/[\\/]/);for(let i of n){let o=Px(i);if(o)return o}return null}function Dd(e){return Ax(e)===null}var Jv=/^[a-z0-9]+(?:-[a-z0-9]+)*$/,Tx=new Set(["__proto__","prototype","constructor"]),jd=64;function Kv(e){return Tx.has(e)}var Ud="must be a portable relative path inside the plugin directory",Hv=d.string().max(jd).regex(Jv,"must be kebab-case (a-z, 0-9, dashes)").refine(e=>!Kv(e),"must not be a reserved name"),Wv=d.string().min(1).max(1024).regex(Od,Ud).refine(e=>!Od.test(e)||Dd(e),Ud),Dz=d.string().min(1).max(1024).transform(e=>e.replace(/[\\/]+$/,"")).refine(Dd,Ud),jz=d.string().min(1).max(256).regex(/^[A-Za-z0-9]+(?:[._-][A-Za-z0-9]+)*$/,"must be a portable command id");var $n=["activity","bar-chart-3","bell","blocks","book","bot","bug","calendar","cloud","code","database","file-text","flag","folder","gauge","globe","hammer","layers","lightbulb","package","plug","puzzle","rocket","star","terminal","wrench","zap","add","remove","delete","edit","refresh","search","settings","check","close","info","warning","error","open-external","copy","download","upload","play","pause","stop","more","expand","collapse","next","filter","branch","file","agent","link"],zx=Object.fromEntries($n.slice($n.indexOf("add")).map(e=>[e,xr])),Fz=new Map($n.map(e=>[e.replaceAll("-",""),e]));var Nx=["html","components"],Ex=/\.(?:m?js|tsx?|mts|jsx)$/i,Gz=d.object({id:Hv.meta(ot("Panel id, unique among this plugin's panels. The reserved names `constructor` and `prototype` are refused.",it,["dashboard"])),title:Bv(d.string().min(1).max(256)).meta(ot("Title shown on the panel tab and its tooltip.",it,["Dashboard"])),icon:d.enum($n).optional().meta({...ot("Icon shown in the right-sidebar activity bar. Defaults to `plug`.",it,["database"]),[Zo]:zx}),entry:Wv.meta(wv(`What the panel runs: an HTML page for \`ui: "html"\`, a \`.js\`/\`.mjs\` module for \`ui: "components"\`. Either may instead be a \`.ts\`/\`.tsx\`/\`.mts\`/\`.jsx\` file, which Orca transpiles when it loads (needs \`engines.orca\` \`>=${xv}\`; an \`html\` panel then gets a generated page around it). It is trusted code: install panels you trust.`,it,["dist/panel.html"])),ui:d.enum(Nx).optional().meta(ot("How the panel draws its UI. `html` (default) shows `entry` as a web page in an isolated frame; `components` runs `entry` as a hidden module and Orca draws the component tree it returns with its own controls.",xr,["components"]))}).strict().refine(e=>e.ui!=="components"||Ex.test(e.entry),{path:["entry"],message:"a components panel entry must be a .js, .mjs, .ts, .tsx, .mts or .jsx module"}).meta({id:"PanelContribution",description:"A sidebar panel. Requires the `sandboxed-ui` execution profile or higher."});var O={maxNodes:5e3,maxDepth:64,maxTreeBytes:524288,maxTextLength:16384,maxLabelLength:1024,maxPropsPerNode:32,maxSelectOptions:500,maxEventArgs:8,maxCallbackIdLength:64,maxRadioOptions:50,maxTableColumns:32,maxTableRows:5e3,maxTreeItems:2e3,maxTreeItemDepth:16,maxKeyValueItems:200,maxDocumentLength:65536,maxEventArgItems:5e3},Jz={maxBytes:640*1024,maxMessages:200,perMs:1e4,maxDepth:O.maxDepth*2+24,maxObjects:O.maxNodes*8+1024};var Ho=/^[A-Za-z0-9_.:-]+$/,Xv=d.object({$callback:d.string().min(1).max(O.maxCallbackIdLength).regex(Ho)}).strict(),qv=["neutral","accent","success","warning","danger"],Z=d.string().max(O.maxLabelLength),F=Z.min(1),X=Xv.optional(),Te=d.string().regex(/^[a-z0-9-]{1,64}$/),_n=d.enum(["none","xs","sm","md","lg"]).optional(),Cd=d.enum(["start","center","end","stretch"]).optional(),Ge=d.enum(qv).optional(),Wo=d.enum(["xs","sm","md"]).optional(),Ld=d.enum(["solid","outline","ghost"]).optional(),N=d.boolean().optional(),kn=d.string().max(O.maxTextLength),Sr=d.enum(["sm","md","lg","none"]).optional(),Pt=d.string().min(1).max(O.maxLabelLength),me={[Jo]:d.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).optional()};function U(e,n){return{props:e,children:n}}var Ox=d.object({label:F,labelHidden:N,value:kn.optional(),defaultValue:kn.optional(),placeholder:Z.optional(),rows:d.number().int().min(2).max(20).optional(),maxLength:d.number().int().positive().max(O.maxTextLength).optional(),invalid:N,disabled:N,onChange:X,onSubmit:X,...me}).strict(),Dx=d.object({label:F,description:Z.optional(),checked:N,defaultChecked:N,disabled:N,onChange:X,...me}).strict(),jx=d.object({label:F,labelHidden:N,value:Z.optional(),defaultValue:Z.optional(),options:d.array(d.object({value:F,label:F,description:Z.optional(),disabled:N}).strict()).max(O.maxRadioOptions),orientation:d.enum(["vertical","horizontal"]).optional(),disabled:N,onChange:X,...me}).strict(),Xo=d.number().refine(Number.isFinite,"must be finite"),Ux=d.object({label:F,labelHidden:N,value:Xo.optional(),defaultValue:Xo.optional(),min:Xo.optional(),max:Xo.optional(),step:d.number().positive().refine(Number.isFinite).optional(),showValue:N,disabled:N,onChange:X,...me}).strict(),Cx=d.object({label:F,description:Z.optional(),error:Z.optional(),required:N}).strict(),Yv={Textarea:U(Ox,"none"),Checkbox:U(Dx,"none"),RadioGroup:U(jx,"none"),Slider:U(Ux,"none"),Field:U(Cx,"any")};var Lx=d.object({label:F,value:Z.optional(),defaultValue:Z.optional(),onChange:X,...me}).strict(),Rx=d.object({value:F,label:F,icon:Te.optional(),disabled:N}).strict(),Mx=d.object({title:F,description:Z.optional(),open:N,defaultOpen:N,disabled:N,onChange:X,...me}).strict(),Zx=d.object({label:F,gap:_n}).strict(),Vx=d.object({columns:d.number().int().min(1).max(6).optional(),minItemWidth:d.enum(["xs","sm","md","lg"]).optional(),gap:_n}).strict(),Qv={Tabs:U(Lx,"tabs"),Tab:U(Rx,"any"),Collapsible:U(Mx,"any"),Toolbar:U(Zx,"any"),Grid:U(Vx,"any")};function Pr(e){return typeof e=="object"&&e!==null}var Ar=["long","short","duration"],Rd=d.number().refine(Number.isFinite,"must be a finite time in milliseconds"),eh=d.object({type:d.literal("relative"),at:Rd,format:d.enum(Ar).optional()}).strict(),Fx=[["day",864e5],["hour",36e5],["minute",6e4],["second",1e3]];function Gx(e){let n=Math.abs(e),[i,o]=Fx.find(([,t])=>n>=t)??["second",1e3];return{value:Math.trunc(e/o),unit:i}}function th(e,n,i,o){let{value:t,unit:r}=Gx(e-n);return i==="duration"?new Intl.NumberFormat(o,{style:"unit",unit:r,unitDisplay:"narrow"}).format(Math.abs(t)):new Intl.RelativeTimeFormat(o,{numeric:i==="long"?"auto":"always",style:i==="long"?"long":"narrow"}).format(t,r)}var Md=d.string().min(1).max(64),Bx=d.union([d.string().max(O.maxLabelLength),d.number(),d.boolean(),d.null(),eh]),nh=e=>new Set(e.map(n=>n.key)).size===e.length,Jx=d.object({label:F,columns:d.array(d.object({key:Md,label:F,align:d.enum(["start","center","end"]).optional(),width:d.enum(["auto","xs","sm","md","lg"]).optional(),minWidth:d.enum(["auto","xs","sm","md"]).optional(),hideBelow:d.enum(["sm","md"]).optional(),sortable:N}).strict()).min(1).max(O.maxTableColumns).refine(nh,"column keys must be unique"),rows:d.array(d.object({key:Pt,cells:d.record(Md,Bx.refine(e=>typeof e!="number"||Number.isFinite(e))).refine(e=>Object.keys(e).length<=O.maxTableColumns),disabled:N}).strict()).max(O.maxTableRows).refine(nh,"row keys must be unique"),sort:d.object({column:Md,direction:d.enum(["asc","desc"])}).strict().optional(),selectionMode:d.enum(["none","single","multiple"]).optional(),selected:d.array(Pt).max(O.maxTableRows).optional(),defaultSelected:d.array(Pt).max(O.maxTableRows).optional(),hasMore:N,loading:N,emptyText:Z.optional(),maxHeight:Sr,onSortChange:X,onSelectionChange:X,onRowAction:X,onLoadMore:X,...me}).strict(),Kx=d.object({key:Pt,label:F,description:Z.optional(),icon:Te.optional(),disabled:N,hasChildren:N,children:d.array(d.unknown()).optional()}).strict();function Hx(e){let n=[],i=new Set,o=[{raw:e,out:n,depth:1}],t=0;for(let r=o.pop();r;r=o.pop()){if(r.depth>O.maxTreeItemDepth)return`items nest deeper than ${O.maxTreeItemDepth}`;for(let a of r.raw){if(++t>O.maxTreeItems)return`more than ${O.maxTreeItems} items`;let s=Kx.safeParse(Pr(a)?a:null);if(!s.success)return"each item needs a key and a label";let{children:u,...c}=s.data;if(i.has(c.key))return`duplicate item key ${JSON.stringify(c.key.slice(0,64))}`;i.add(c.key);let l=c;r.out.push(l),u&&(l.children=[],o.push({raw:u,out:l.children,depth:r.depth+1}))}}return n}var Wx=d.array(d.unknown()).transform((e,n)=>{let i=Hx(e);return typeof i=="string"?(n.addIssue({code:"custom",message:i}),d.NEVER):i}),Xx=d.object({label:F,items:Wx,selected:Z.optional(),defaultSelected:Z.optional(),expanded:d.array(Pt).max(O.maxTreeItems).optional(),defaultExpanded:d.array(Pt).max(O.maxTreeItems).optional(),maxHeight:Sr,onSelect:X,onToggle:X,onAction:X,...me}).strict(),rh={Table:U(Jx,"none"),Tree:U(Xx,"none")};var ih=d.string().max(O.maxDocumentLength),qx=/\.(?:png|jpe?g|webp)$/i;function Yx(e){return qx.test(e)&&!/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(e)&&!/[\\\0?#]/.test(e)&&e.split("/").every(n=>n!==""&&n!=="."&&n!=="..")}var Qx=d.object({content:ih}).strict(),eI=d.object({code:ih,language:d.string().regex(/^[A-Za-z0-9_+#.-]{1,64}$/).optional(),label:Z.optional(),lineNumbers:N,wrap:N,maxHeight:Sr}).strict(),tI=d.object({src:d.string().max(512).refine(Yx,"must be an image file in the plugin"),alt:Z,size:d.enum(["xs","sm","md","lg","full"]).optional(),fit:d.enum(["contain","cover"]).optional(),rounded:N}).strict(),nI=d.object({label:Z.optional(),items:d.array(d.object({label:F,value:d.union([Z,d.number().refine(Number.isFinite),d.boolean(),d.null()]),tone:Ge,code:N}).strict()).max(O.maxKeyValueItems)}).strict(),rI=d.object({tone:Ge,title:Z.optional(),icon:Te.optional()}).strict(),iI=d.object({at:Rd,format:d.enum(Ar).optional(),tone:Ge,muted:N}).strict(),oI=d.object({shape:d.enum(["text","block","circle"]).optional(),lines:d.number().int().min(1).max(10).optional(),label:Z.optional()}).strict(),oh={Markdown:U(Qx,"none"),CodeView:U(eI,"none"),Image:U(tI,"none"),KeyValue:U(nI,"none"),Callout:U(rI,"any"),Skeleton:U(oI,"none"),RelativeTime:U(iI,"none")};var aI=$n,ah=new Set(aI),sI=d.object({gap:_n,align:Cd}).strict(),uI=d.object({gap:_n,align:Cd,justify:d.enum(["start","center","end","between"]).optional(),wrap:N}).strict(),cI=d.object({tone:Ge,muted:N,size:Wo,weight:d.enum(["regular","medium","semibold"]).optional(),truncate:N}).strict(),lI=d.object({level:d.union([d.literal(1),d.literal(2),d.literal(3)]).optional()}).strict(),dI=d.object({variant:Ld,tone:Ge,size:Wo,icon:Te.optional(),tooltip:Z.optional(),disabled:N,onPress:X}).strict(),pI=d.object({icon:Te,label:F,tooltip:Z.optional(),variant:Ld,tone:Ge,size:Wo,disabled:N,onPress:X}).strict(),mI=d.object({tone:Ge}).strict(),fI=d.object({title:Z.optional(),description:Z.optional()}).strict(),gI=d.object({label:Z.optional()}).strict(),vI=d.object({title:Z.optional(),description:Z.optional(),icon:Te.optional(),current:N,disabled:N,onPress:X}).strict(),hI=d.object({label:F,labelHidden:N,value:kn.optional(),defaultValue:kn.optional(),placeholder:Z.optional(),type:d.enum(["text","search","password"]).optional(),maxLength:d.number().int().positive().max(O.maxTextLength).optional(),invalid:N,disabled:N,onChange:X,onSubmit:X,...me}).strict(),yI=d.object({label:F,checked:N,defaultChecked:N,disabled:N,onChange:X,...me}).strict(),bI=d.object({label:F,labelHidden:N,value:Z.optional(),defaultValue:Z.optional(),placeholder:Z.optional(),options:d.array(d.object({value:F,label:F,disabled:N}).strict()).max(O.maxSelectOptions),disabled:N,onChange:X,...me}).strict(),$I=d.object({orientation:d.enum(["horizontal","vertical"]).optional()}).strict(),_I=d.object({label:F,labelHidden:N,value:d.number().min(0).max(100).optional()}).strict(),kI=d.object({label:F,labelHidden:N}).strict(),xI=d.object({title:F,description:Z.optional(),icon:Te.optional()}).strict(),II=d.object({href:d.string().max(2048).regex(/^(https?:\/\/|mailto:)/i).optional(),onPress:X}).strict(),wI=d.object({block:N}).strict(),Tr={Stack:U(sI,"any"),Row:U(uI,"any"),Text:U(cI,"inline"),Heading:U(lI,"inline"),Button:U(dI,"text"),IconButton:U(pI,"none"),Badge:U(mI,"text"),Card:U(fI,"any"),List:U(gI,"items"),ListItem:U(vI,"any"),Input:U(hI,"none"),Switch:U(yI,"none"),Select:U(bI,"none"),Separator:U($I,"none"),Progress:U(_I,"none"),Spinner:U(kI,"none"),EmptyState:U(xI,"any"),Link:U(II,"text"),Code:U(wI,"text"),...Yv,...Qv,...rh,...oh};function Zd(e){return typeof e=="string"&&Object.hasOwn(Tr,e)}var PN=Object.keys(Tr).filter(Zd),sh=new Set(["Text","Link","Code","Badge","RelativeTime"]),uh=new Set(["Button","IconButton","Input","Switch","Select","Link","ListItem","Textarea","Checkbox","RadioGroup","Slider","Tabs","Collapsible","Table","Tree","Markdown"]),qo={items:"ListItem",tabs:"Tab"};var SI=new Set(["type","key","props","children"]),Vd=32,PI=8,AI=/^[A-Z][A-Za-z0-9]{0,63}$/,TI=20,zI=new Map([[qo.items,"items"],[qo.tabs,"tabs"]]),NI={ListItem:"List",Tab:"Tabs"};function ch(e){return e==="items"||e==="tabs"?qo[e]:void 0}var Yo=class extends Error{};function Q(e,n){throw new Yo(`${e}: ${n}`)}function EI(e,n){return e===void 0?[]:(Array.isArray(e)||Q(n,"children must be an array"),e)}function OI(e,n,i){let o=Tr[e].props.shape,t={};for(let[r,a]of Object.entries(n)){if(a===void 0)continue;if(!Object.hasOwn(o,r)){i(`${e}: ignored unknown prop "${r.slice(0,64)}"`);continue}let s=o[r].safeParse(a);if(!s.success){i(`${e}: ignored invalid ${r}`);continue}t[r]=s.data}for(let[r,a]of Object.entries(o))if(!Object.hasOwn(t,r)&&!a.safeParse(void 0).success)return i(`${e}: missing required ${r}; showing a placeholder`),null;return typeof t.icon=="string"&&!ah.has(t.icon)&&i(`${e}: unknown icon "${t.icon}"; showing a fallback glyph`),t}function lh(e){if(e===null)return{ok:!0,tree:null,nodes:0,warnings:[]};let n=new Set,i=c=>{n.sizeO.maxTextLength&&Q(x,"text is too long"),r+ ++a>O.maxNodes&&Q(x,`more than ${O.maxNodes} nodes`),s+=PI+we.length,s>O.maxTreeBytes&&Q(x,`tree exceeds ${O.maxTreeBytes} bytes`),k.push(we);continue}Pr(l)||Q(x,"expected a node, string or number");let I=l.type,A=Zd(I);!A&&(typeof I!="string"||!AI.test(I))&&Q(x,`invalid component name ${JSON.stringify(String(I)).slice(0,80)}`),(f==="none"||f==="text")&&Q(x,`${m} accepts only text`),f==="inline"&&A&&!sh.has(I)&&Q(x,`${m} accepts only text, Text, Link, Code, Badge and RelativeTime`);let C=ch(f),V=typeof I=="string"?zI.get(I):void 0;C!==void 0&&I!==C&&Q(x,`${m} holds only ${C}`),V!==void 0&&V!==f&&Q(x,`${I} must be a direct child of ${NI[I]??"its container"}`),g&&uh.has(I)&&Q(x,`a ListItem with onPress cannot contain a ${I}`),++r+a>O.maxNodes&&Q(x,`more than ${O.maxNodes} nodes`),p>O.maxDepth&&Q(x,`deeper than ${O.maxDepth}`);for(let we of Object.keys(l))SI.has(we)||Q(x,`unknown node field ${we.slice(0,64)}`);let w=l.key;w!==void 0&&((typeof w!="string"||w.length>O.maxLabelLength)&&Q(x,"key must be a short string"),h.has(w)&&Q(x,`duplicate key ${JSON.stringify(w.slice(0,64))} among siblings`),h.add(w));let T=w===void 0?{}:{key:w};if(!A){i(`unknown component ${I}; showing a placeholder`),k.push({type:"Unsupported",...T,props:{name:I},children:[]}),s+=Vd+I.length;continue}let E=l.props??{};(!Pr(E)||Object.keys(E).length>O.maxPropsPerNode)&&Q(x,"props must be an object with few fields");let K=OI(I,E,i);if(!K){k.push({type:"Unsupported",...T,props:{name:I},children:[]}),s+=Vd+I.length;continue}s+=Vd+JSON.stringify(K).length,s>O.maxTreeBytes&&Q(x,`tree exceeds ${O.maxTreeBytes} bytes`);let Tt=[],Er={type:I,...T,props:K,children:Tt};k.push(Er);let xn=EI(l.children,x);xn.length>O.maxNodes&&Q(x,`more than ${O.maxNodes} children`);let na=new Set,Jh=g||I==="ListItem"&&K.onPress!==void 0;for(let we=xn.length-1;we>=0;we--)t.push({raw:xn[we],depth:p+1,parentType:I,policy:Tr[I].children,inPressable:Jh,siblingKeys:na,out:Tt,path:`${x}.children.${we}`})}}catch(c){if(c instanceof Yo)return{ok:!1,error:c.message};throw c}let u=o[0];return typeof u=="object"?{ok:!0,tree:u,nodes:r,warnings:[...n]}:{ok:!1,error:"tree: expected a node"}}var zr=d.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),At=d.string().min(1).max(64),Fd=d.union([d.string().max(O.maxTextLength),d.number().refine(Number.isFinite),d.boolean(),d.null()]),dh=d.array(Fd).max(O.maxEventArgItems),DI=d.union([Fd,dh,d.record(d.string().max(64),d.union([Fd,dh])).refine(e=>Object.keys(e).length<=16,"too many fields")]),RN=d.object({document:At,revision:zr,callback:d.string().min(1).max(O.maxCallbackIdLength).regex(Ho),args:d.array(DI).max(O.maxEventArgs),edit:zr.optional()}).strict(),jI=d.object({document:At,revision:zr,tree:d.unknown()}).strict(),ph=d.object({document:At.optional(),revision:zr,message:d.string().max(O.maxLabelLength*4),stack:d.string().max(8192).optional()}).strict();function mh(e){let n=jI.safeParse(e);if(!n.success)return{ok:!1,document:null,revision:null,error:"malformed render"};let{document:i,revision:o}=n.data,t=lh(n.data.tree);return t.ok?{...t,document:i,revision:o}:{ok:!1,document:i,revision:o,error:t.error}}var MN=d.object({document:At,revision:zr,accepted:d.boolean(),retryAfterMs:d.number().int().nonnegative().max(6e4).optional()}).strict(),ZN=d.object({document:At}).strict(),fh=/^[A-Za-z0-9_.:-]{1,128}$/,UI=["plugin","workspace"],Gd=d.number().int().min(0).max(1e6),VN=d.object({version:Gd,value:d.json()}).strict().refine(e=>JSON.stringify(e.value).length<=Mo,"persisted value is too large"),gh=d.object({document:At,entries:d.array(d.object({scope:d.enum(UI),key:d.string().regex(fh),version:Gd,value:d.json()}).strict()).min(1).max(64)}).strict(),FN=d.object({document:At,entries:d.array(d.object({key:d.string().regex(fh),version:Gd,value:d.json().optional()}).strict().refine(e=>JSON.stringify(e.value??null).length<=Mo,"retained value is too large")).min(1).max(64)}).strict();import{installOrcaDeclarativeRuntime as WI}from"./orca-runtime.mjs";var CI={Stack:"group",Row:"group",Card:"region",Text:"text",Heading:"heading",Button:"button",IconButton:"button",Badge:"status",List:"list",ListItem:"listitem",Input:"textbox",Switch:"switch",Select:"combobox",Separator:"separator",Progress:"progressbar",Spinner:"status",EmptyState:"group",Link:"link",Code:"code",Textarea:"textbox",Checkbox:"checkbox",RadioGroup:"radiogroup",Slider:"slider",Field:"group",Tabs:"tablist",Tab:"tab",Collapsible:"group",Toolbar:"toolbar",Grid:"group",Table:"grid",Tree:"tree",Markdown:"document",CodeView:"code",Image:"img",KeyValue:"list",Callout:"note",Skeleton:"status",RelativeTime:"time",Unsupported:"unsupported"};function hh(e,n){if(typeof e!="number")return"";let i=Ar.find(o=>o===n)??"short";return th(e,Date.now(),i,"en")}function LI(e){return typeof e=="object"&&e!==null&&"at"in e?hh(e.at,"format"in e?e.format:void 0):String(e??"")}var RI=["title","description","content","code","error","alt"];function MI(e){let n=[],i=[e.rows,e.items].flatMap(o=>Array.isArray(o)?o:[]);for(let o=i.shift();o!==void 0;o=i.shift()){if(typeof o!="object"||o===null)continue;let t={...o};typeof t.cells=="object"&&t.cells!==null&&n.push(...Object.values(t.cells).map(LI));for(let r of["label","value"])t[r]!==void 0&&t[r]!==null&&n.push(String(t[r]));Array.isArray(t.children)&&i.push(...t.children)}return n}function yh(e){if(typeof e=="string")return e;let n=e.props,i=RI.map(o=>n[o]).filter(o=>typeof o=="string");return e.type==="RelativeTime"?hh(n.at,n.format):e.type==="Tab"?typeof n.label=="string"?n.label:"":[...i,...MI(n),...e.children.map(yh)].join(" ")}var Bd=e=>e.replace(/\s+/g," ").trim();function ZI(e){let n=e.props,i=n.label??n.title;return typeof i=="string"?i:void 0}function VI(e,n){let i=e.props,o=e.type==="ListItem"&&i.onPress!==void 0;return{type:e.type,key:e.key?.startsWith("#")?void 0:e.key,role:o?"button":CI[e.type]??"generic",label:ZI(e),text:Bd(yh(e)),props:i,disabled:i.disabled===!0,path:n}}function Qo(e){let n=[],i=(o,t)=>{n.push(VI(o,t)),o.children.forEach((r,a)=>{typeof r!="string"&&i(r,`${t}/${r.key??`#${a}`}`)})};return e&&i(e,e.key??"#0"),n}function vh(e,n){return e===void 0?!1:typeof n=="string"?Bd(e)===Bd(n):n.test(e)}function bh(e,n){return(n.type===void 0||e.type===n.type)&&(n.role===void 0||e.role===n.role)&&(n.text===void 0||vh(e.text,n.text))&&(n.label===void 0||vh(e.label,n.label))&&(n.testId===void 0||e.key===n.testId)}function $h(e){return e.filter(n=>!e.some(i=>i.path.startsWith(`${n.path}/`)))}function _h(e){return Object.entries(e).map(([n,i])=>`${n}: ${i instanceof RegExp?String(i):JSON.stringify(i)}`).join(", ")}function Jd(e){if(typeof e=="string")return e;let n={};for(let[i,o]of Object.entries(e.props)){if(i.startsWith("$"))continue;let t=typeof o=="object"&&o!==null&&"$callback"in o;n[i]=t?"[handler]":o}return{type:e.type,...e.key&&!e.key.startsWith("#")?{key:e.key}:{},...Object.keys(n).length>0?{props:n}:{},...e.children.length>0?{children:e.children.map(Jd)}:{}}}var FI={value:"defaultValue",checked:"defaultChecked",open:"defaultOpen",selected:"defaultSelected"};function Kd(e){return typeof e=="string"||typeof e=="boolean"||typeof e=="number"||Array.isArray(e)&&e.every(n=>typeof n=="string")}function GI(e){switch(e.type){case"Switch":case"Checkbox":case"Collapsible":return!1;case"Slider":return typeof e.props.min=="number"?e.props.min:0;case"Table":return[];default:return""}}function kh(){let e=new Map;function n(t){let r=Ed(t.type);if(!r)throw new Error(`a ${t.type} has no value; expected a form control, Tabs or Table`);return r}function i(t){let r=e.get(t.path);if(r)return r;let{value:a}=n(t),s=t.props[a],u=t.props[FI[a]??""],l={value:Kd(s)?s:Kd(u)?u:GI(t),sent:0};return e.set(t.path,l),l}function o(t,r){let{value:a,change:s}=n(t);if(t.props[a]!==void 0&&t.props[s]===void 0)throw new Error(`the ${t.type} is read-only: it has a ${a} and no ${s}`);let u=i(t);return u.sent+=1,u.value=r,{value:r,id:u.sent}}return{observe(t){let r=new Map;for(let a of t){let s=Ed(a.type);if(!s)continue;let u=e.get(a.path)??i(a),c=a.props[s.value],l=a.props[Jo];Kd(c)&&(typeof l=="number"?l:0)>=u.sent&&(u.value=c),r.set(a.path,u)}e=r},valueOf:t=>i(t).value,edit:o,typeInto(t,r,a){if(t.type!=="Input"&&t.type!=="Textarea")throw new Error(`type: a ${t.type} takes no text; expected an Input or Textarea`);let s=a?"":String(i(t).value),u=[];a&&u.push(o(t,s));for(let c of r)s+=c,u.push(o(t,s));return u},toggle(t){if(!["Switch","Checkbox","Collapsible"].includes(t.type))throw new Error(`toggle: expected a Switch, Checkbox or Collapsible, not a ${t.type}`);return o(t,!i(t).value)}}}function xh(e){let n=new Map,i=(s,u)=>{let c=n.get(s)??new Set;return c.add(u),n.set(s,c),{dispose:()=>c.delete(u)}},o=(s,u)=>{for(let c of n.get(s)??[])c(u)},t=s=>u=>typeof u=="object"&&u!==null&&s in u?Object.getOwnPropertyDescriptor(u,s)?.value:void 0,r=()=>{};return{facades:{plugin:{request:(s,u,c)=>{let l=typeof c=="object"&&c!==null&&"timeoutMs"in c?c.timeoutMs:void 0;return e("plugin.request",{name:s,...u===void 0?{}:{input:u},...typeof l=="number"?{timeoutMs:l}:{}}).then(t("output"))},on:(s,u)=>i(`message:${s}`,u)},storage:{get:s=>e("storage.get",{key:s}).then(u=>t("value")(u)??null),set:(s,u)=>e("storage.set",{key:s,value:u}).then(r),delete:s=>e("storage.delete",{key:s}).then(r),keys:async()=>{let s=t("keys")(await e("storage.keys"));return Array.isArray(s)?s.map(String):[]},onDidChange:s=>i("changed:storage",u=>s({key:String(u)}))},settings:{get:async s=>{let u=t("settings")(await e("settings.get"));return s===void 0?u:t(s)(u)},set:(s,u)=>e("settings.set",{key:s,value:u}).then(r),onDidChange:s=>i("changed:settings",u=>s({key:String(u)}))},secrets:{get:async s=>{let u=t("value")(await e("secrets.get",{key:s}));return typeof u=="string"?u:null},set:(s,u)=>e("secrets.set",{key:s,value:u}).then(r),delete:s=>e("secrets.delete",{key:s}).then(r)}},post:(s,u)=>o(`message:${s}`,u),changed:(s,u)=>o(`changed:${s}`,u)}}var Ih=Symbol.for("orca.testing.stored");function wh(e,n){return Object.freeze({[Ih]:!0,version:n,value:e})}function BI(e){return typeof e=="object"&&e!==null&&Ih in e}function Sh(e,n){for(let i of["plugin","workspace"])for(let[o,t]of Object.entries(n?.[i]??{}))e[i].set(o,BI(t)?{version:t.version,value:t.value}:{version:1,value:t})}var JI={sm:360,md:480};function Ph(e,n){let i=e.filter(o=>!o.hideBelow||n>=JI[o.hideBelow]);return i.length>0?i:e.slice(0,1)}var Hd=(e,n)=>e.path.startsWith(`${n.path}/`);function ea(e,n){return n.filter(i=>i.type==="Tab"&&Hd(i,e)&&!i.path.slice(e.path.length+1).includes("/"))}function Wd(e,n,i){let o=ea(e,n);return o.find(t=>t.props.value===i)??o.find(t=>!t.disabled)}function Ah(e,n){let i=[];for(let o of e)if(!i.some(t=>Hd(o,t))&&(o.type==="Collapsible"&&n(o)!==!0&&i.push(o),o.type==="Tabs")){let t=Wd(o,e,n(o));i.push(...ea(o,e).filter(r=>r!==t))}return e.filter(o=>!i.some(t=>Hd(o,t)))}function Th(e){return typeof e=="object"&&e!==null&&"key"in e&&typeof e.key=="string"}function Xd(e){return Array.isArray(e.props.rows)?e.props.rows.filter(Th):[]}function qd(e){let n=[],i=Array.isArray(e.props.items)?[...e.props.items]:[];for(let o=i.shift();o!==void 0;o=i.shift())if(Th(o)){n.push(o);let t="children"in o?o.children:void 0;Array.isArray(t)&&i.push(...t)}return n}function Ie(e,n,i){if(e.type!==n)throw new Error(`${i}: expected a ${n}, not a ${e.type}`)}function Yd(e,n,i){let o=Xd(e).find(t=>t.key===n);if(!o||o.disabled===!0)throw new Error(`${i}: the Table has no enabled row "${n}"`);return o}function ta(e,n,i){let o=qd(e).find(t=>t.key===n);if(!o)throw new Error(`${i}: the Tree has no item "${n}"`);return o}function zh(e){return e.hasChildren===!0||Array.isArray(e.children)&&e.children.length>0}function Nh(e,n){let o=(Array.isArray(e.props.columns)?e.props.columns:[]).find(a=>typeof a=="object"&&a!==null&&"key"in a&&a.key===n);if(!o||typeof o!="object"||!("sortable"in o)||o.sortable!==!0)throw new Error(`sort: the Table has no sortable column "${n}"`);let t=e.props.sort,r=typeof t=="object"&&t!==null&&"column"in t&&t.column===n&&"direction"in t&&t.direction==="asc";return{column:n,direction:r?"desc":"asc"}}function KI(e,n){return e.type==="Tabs"?ea(e,n).map(o=>({value:o.props.value,disabled:o.disabled})):(Array.isArray(e.props.options)?e.props.options:[]).map(o=>typeof o=="object"&&o!==null&&"value"in o?{value:o.value,disabled:"disabled"in o&&o.disabled===!0}:{value:void 0,disabled:!0})}function Eh({host:e,controls:n,resolve:i,elements:o,dispatch:t,settled:r}){let a=new Map,s=l=>{let p=a.get(l.path);if(!p){let m=l.props.expanded??l.props.defaultExpanded;p=new Set(Array.isArray(m)?m.filter(f=>typeof f=="string"):[]),a.set(l.path,p)}return p},u=async(l,p,m,f)=>{let g=n.edit(l,m);t(p,[f],g.id),await r()},c=async(l,p,m,f)=>{let g=i(l,f);if(Ie(g,"Tree",f),!zh(ta(g,p,f)))throw new Error(`${f}: the Tree item "${p}" has no children`);let h=s(g);h.has(p)!==m&&(m?h.add(p):h.delete(p),t(g.props.onToggle,[{key:p,expanded:m}]),await r())};return{async press(l){let p=i(l,"press"),{href:m,onPress:f}=p.props;if(p.type==="Link"&&typeof m=="string")e.grantGesture(),e.bridge.call("shell.openExternal",{url:m}).catch(()=>{});else{if(f===void 0)throw new Error(`press: the ${p.type} has no onPress`);e.grantGesture()}t(f,[]),await r()},async type(l,p,m={}){let f=i(l,"type");for(let g of n.typeInto(f,p,m.replace===!0))t(f.props.onChange,[g.value],g.id),await r();m.submit&&(t(f.props.onSubmit,[n.valueOf(f)]),await r())},async submit(l){let p=i(l,"submit");t(p.props.onSubmit,[n.valueOf(p)]),await r()},async toggle(l){let p=i(l,"toggle"),m=n.toggle(p);t(p.props.onChange,[m.value],m.id),await r()},async select(l,p){let m=i(l,"select");if(!["Select","RadioGroup","Tabs"].includes(m.type))throw new Error(`select: expected a Select, RadioGroup or Tabs, not a ${m.type}`);let f=KI(m,o()).find(g=>g.value===p);if(!f||f.disabled)throw new Error(`select: the ${m.type} has no enabled option "${p}"`);await u(m,m.props.onChange,p,p)},async slide(l,p){let m=i(l,"slide");Ie(m,"Slider","slide");let f=typeof m.props.min=="number"?m.props.min:0,g=typeof m.props.max=="number"?m.props.max:100;if(!Number.isFinite(p)||pg)throw new Error(`slide: ${p} is outside the Slider's ${f} to ${g}`);await u(m,m.props.onChange,p,p)},async sort(l,p){let m=i(l,"sort");if(Ie(m,"Table","sort"),m.props.onSortChange===void 0)throw new Error("sort: the Table has no onSortChange");t(m.props.onSortChange,[Nh(m,p)]),await r()},async selectRows(l,p){let m=i(l,"selectRows");Ie(m,"Table","selectRows");let f=m.props.selectionMode??"none";if(f==="none"||f==="single"&&p.length>1)throw new Error(`selectRows: the Table's selectionMode is ${String(f)}`);p.forEach(g=>Yd(m,g,"selectRows")),await u(m,m.props.onSelectionChange,[...p],{keys:[...p]})},async activateRow(l,p){let m=i(l,"activateRow");if(Ie(m,"Table","activateRow"),Yd(m,p,"activateRow"),m.props.onRowAction===void 0)throw new Error("activateRow: the Table has no onRowAction");t(m.props.onRowAction,[{key:p}]),await r()},async loadMore(l){let p=i(l,"loadMore");if(Ie(p,"Table","loadMore"),p.props.hasMore!==!0||p.props.onLoadMore===void 0)throw new Error("loadMore: the Table has no more rows (hasMore and onLoadMore)");t(p.props.onLoadMore,[]),await r()},expand:(l,p)=>c(l,p,!0,"expand"),collapse:(l,p)=>c(l,p,!1,"collapse"),async selectItem(l,p){let m=i(l,"selectItem");if(Ie(m,"Tree","selectItem"),ta(m,p,"selectItem").disabled===!0)throw new Error(`selectItem: the Tree item "${p}" is disabled`);await u(m,m.props.onSelect,p,{key:p})},async activateItem(l,p){let m=i(l,"activateItem");if(Ie(m,"Tree","activateItem"),ta(m,p,"activateItem").disabled===!0||!m.props.onAction)throw new Error(`activateItem: the Tree item "${p}" cannot be activated`);t(m.props.onAction,[{key:p}]),await r()},expandedOf:l=>{let p=i(l,"expandedOf");return Ie(p,"Tree","expandedOf"),qd(p).map(m=>m.key).filter(m=>s(p).has(m))},columnsOf:(l,p={})=>{let m=i(l,"columnsOf");Ie(m,"Table","columnsOf");let g=(Array.isArray(m.props.columns)?m.props.columns:[]).flatMap(h=>{if(typeof h!="object"||h===null||!("key"in h))return[];let k="hideBelow"in h?h.hideBelow:void 0;return typeof h.key=="string"?[{key:h.key,hideBelow:k==="sm"||k==="md"?k:void 0}]:[]});return Ph(g,p.width??Number.POSITIVE_INFINITY).map(h=>h.key)},rowsOf:l=>{let p=i(l,"rowsOf");return Ie(p,"Table","rowsOf"),Xd(p).map(m=>m.key)}}}var Ue=e=>{let n=(e??"").replace(/\s+/g," ").trim();return JSON.stringify(n.length>60?`${n.slice(0,59)}…`:n)},Oh=e=>Array.isArray(e)?e.length:0;function HI(e,n){let{props:i}=e;switch(e.type){case"Heading":return`Heading ${Ue(e.text)}`;case"Callout":return`Callout ${String(i.tone??"neutral")} ${Ue(e.label??e.text)}`;case"EmptyState":return`EmptyState ${Ue(e.label)}`;case"Table":return`Table ${Ue(e.label)}: ${Oh(i.rows)} row(s)${i.hasMore===!0?", more":""}`;case"Tree":return`Tree ${Ue(e.label)}: ${Oh(i.items)} top-level item(s)`;case"Tabs":return`Tabs ${Ue(e.label)}: ${Ue(n.get(e.path))} selected`;case"Skeleton":case"Spinner":return`${e.type} ${Ue(e.label??"Loading")}`;case"Text":return i.tone==="danger"||i.tone==="warning"?`Text ${String(i.tone)} ${Ue(e.text)}`:null;default:return null}}function Dh(e,n){let i=[];for(let o of e){if(o.type==="List"){let r=e.filter(a=>a.type==="ListItem"&&a.path.startsWith(`${o.path}/`)).length;i.push(`List ${Ue(o.label)}: ${r} item(s)`);continue}let t=HI(o,n);t&&i.push(t)}return i.length>12?[...i.slice(0,12),`… ${i.length-12} more`]:i}function jh(e){return"path"in e}var XI=100,qI=()=>new Promise(e=>typeof setImmediate=="function"?setImmediate(e):setTimeout(e,0));async function Uh(e,n){let i=n.host,o=new Map,t=(w,T)=>{for(let E of o.get(w)??[])E(T)},r=[],a=[],s=[],u={plugin:new Map,workspace:new Map};Sh(u,n.persisted);let c=n.visible??!0,l={document:"",revision:0,tree:null},p=kh(),m=xh(i.bridge.call),f=i.onDataChange(m.changed);function g(w,T){if(w===je.ready)t(je.hydrate,{panel:{id:n.panelId??"panel"},visible:c,plugin:Object.fromEntries(u.plugin),workspace:Object.fromEntries(u.workspace)});else if(w===je.render){let E=mh(T);if(!E.ok){a.push({kind:"refused",message:E.error}),E.document!==null&&E.revision!==null&&t(je.ack,{document:E.document,revision:E.revision,accepted:!1});return}s.push(...E.warnings.filter(K=>!s.includes(K))),l={document:E.document,revision:E.revision,tree:E.tree},p.observe(Qo(E.tree)),t(je.ack,{document:E.document,revision:E.revision,accepted:!0})}else if(w===je.error){let E=ph.safeParse(T);a.push(E.success?{kind:"plugin",message:E.data.message,...E.data.stack?{stack:E.data.stack}:{}}:{kind:"plugin",message:String(T)})}else if(w===je.persist){let E=gh.safeParse(T);if(!E.success){a.push({kind:"refused",message:"persisted state Orca would not store"});return}for(let K of E.data.entries)u[K.scope].set(K.key,{version:K.version,value:K.value})}}let h=WI({post:g,awaitHydration:!0,colorScheme:n.theme??"dark",schedule:w=>r.push(w),bridge:{api:i.bridge.api,locale:n.locale??"en",host:{call:i.bridge.call,has:i.bridge.has},...m.facades,on(w,T){let E=o.get(w)??new Set;return E.add(T),o.set(w,E),{dispose:()=>E.delete(T)}}}});async function k(){for(let w=0;wAh(Qo(l.tree),w=>p.valueOf(w)),I=w=>$h(x().filter(T=>bh(T,w)));function A(w,T){let E=jh(w)?x().find(K=>K.path===w.path):I(w)[0];if(!E)throw new Error(jh(w)?`${T}: the element is no longer in the panel`:`${T}: nothing in the panel matches { ${_h(w)} }`);if(E.disabled)throw new Error(`${T}: the ${E.type} is disabled`);return E}function C(w,T,E){let K=typeof w=="object"&&w!==null&&"$callback"in w?w.$callback:null;typeof K=="string"&&t(je.event,{document:l.document,revision:l.revision,callback:K,args:T,...E===void 0?{}:{edit:E}})}await Promise.resolve(typeof e=="function"?{default:e}:e).then(w=>h.boot(w)).catch(w=>a.push({kind:"plugin",message:w instanceof Error?w.message:String(w),...w instanceof Error&&w.stack?{stack:w.stack}:{}})),await k();let V=Eh({host:i,controls:p,resolve:A,elements:x,dispatch:C,settled:k});return{host:i,errors:a,warnings:s,get refusals(){return i.refusals},find:w=>I(w)[0]??null,findAll:I,tree:()=>l.tree?Jd(l.tree):null,drawnTree:()=>l.tree,summary:()=>{let w=Qo(l.tree),T=x(),E=new Map(T.filter(K=>K.type==="Tabs").map(K=>[K.path,Wd(K,w,p.valueOf(K))?.label??""]));return Dh(T,E)},get persisted(){let w=T=>Object.fromEntries([...u[T]].map(([E,K])=>[E,K.value]));return{plugin:w("plugin"),workspace:w("workspace"),storage:i.data().storage}},settled:k,...V,valueOf:w=>p.valueOf(A(w,"valueOf")),async emit(w,T){t(w,T),await k()},async post(w,T){m.post(w,T),await k()},async setVisible(w){c=w,t(je.visibility,{visible:w}),await k()},async rerender(){h.rerender(),await k()},async unmount(){h.dispose(),o.clear(),f()}}}var Ch={workspaceId:d.string().min(1).max(2048),kind:d.enum(["worktree","folder"])},YI=d.object({...Ch,path:d.string().min(1).max(32*1024),branch:d.string().max(1024)}),QI=d.object({...Ch,path:d.string().min(1).max(32*1024)}),ew=d.object({workspaceId:d.string().min(1).max(2048).nullable(),paneKey:d.string().min(1).max(2048),terminalId:d.string().min(1).max(Fo).optional(),title:d.string().max(Ir).optional(),state:d.enum(bn),receivedAt:d.number().finite().positive(),mainAgent:d.object({state:d.enum(bn),outcome:d.enum(Av).optional(),stateStartedAt:d.number().finite()}).optional()}),tw=d.object({context:zd}),Qd={"workspace.created":YI,"workspace.removed":QI,"agent.status.changed":ew,"workspace.changed":tw};function nw(e){return typeof e!="object"||e===null||!("workspaceId"in e)||"worktreeId"in e?e:{...e,worktreeId:e.workspaceId}}function Nr(e,n){return typeof e=="object"&&e!==null&&n in e?Object.getOwnPropertyDescriptor(e,n)?.value:void 0}function ep(e,n){return e.add(n),{dispose:()=>{e.delete(n)}}}var rw=new Set(wr("worker"));function Lh(){return{commands:new Map,events:new Map,panelRequests:new Map,dataListeners:{storage:new Set,settings:new Set}}}function Rh(e){let{tables:n,hostCall:i}=e,o=async(t,r)=>{await i(t,r)};return Object.freeze({api:Object.freeze({major:Fe,minor:Lv}),commands:Object.freeze({register(t,r){return n.commands.set(t,r),{dispose:()=>{n.commands.delete(t)}}}}),events:Object.freeze({on(t,r){let a=Vo.get(t)??t,s=n.events.get(a)??new Set;n.events.set(a,s);let u=a!==t||t==="agent.status.changed",c=ep(s,p=>r(u?nw(p):p));if(t!=="workspace.changed")return c;let l=!0;return i("workspace.readContext").then(p=>l&&r({context:p})).catch(()=>{}),{dispose:()=>{l=!1,c.dispose()}}}}),host:Object.freeze({call:(t,r,a)=>i(t,r,a),has:t=>rw.has(t)}),panels:Object.freeze({handle(t,r){if(at.parse(t),typeof r!="function")throw new TypeError("orca.panels.handle needs a handler function");return n.panelRequests.set(t,r),{dispose:()=>{n.panelRequests.get(t)===r&&n.panelRequests.delete(t)}}},post(t,r,a){at.parse(t),e.postToPanels({event:t,payload:r,...a?.panel?{panel:a.panel}:{}})}}),storage:Object.freeze({get:async t=>Nr(await i("storage.get",{key:t}),"value")??null,set:(t,r)=>o("storage.set",{key:t,value:r}),delete:t=>o("storage.delete",{key:t}),keys:async()=>{let t=Nr(await i("storage.keys"),"keys");return Array.isArray(t)?t.filter(r=>typeof r=="string"):[]},onDidChange:t=>ep(n.dataListeners.storage,t)}),settings:Object.freeze({get:async t=>{let r=Nr(await i("settings.get"),"settings"),a=typeof r=="object"&&r!==null?{...r}:{};return t===void 0?a:Nr(a,t)},set:(t,r)=>o("settings.set",{key:t,value:r}),onDidChange:t=>ep(n.dataListeners.settings,t)}),secrets:Object.freeze({get:async t=>{let r=Nr(await i("secrets.get",{key:t}),"value");return typeof r=="string"?r:null},set:(t,r)=>o("secrets.set",{key:t,value:r}),delete:t=>o("secrets.delete",{key:t})}),grantedCapabilities:Object.freeze([...e.grantedCapabilities]),log:t=>e.log(String(t))})}var Mh={id:"test-panel",surface:"panel",contributionId:"panel"};function iw(e){return Object.hasOwn(Qd,e)}function ow(e){return e instanceof Error?e.message:String(e)}async function Zh(e,n){let{host:i}=n,o=new Set(n.events),t=Lh(),r=[],a=[],s=!0,u=e.default;if(typeof u!="function")throw new TypeError(typeof e.activate=="function"?"mountWorker: the module exports activate by name, but Orca calls the default export: write `export default function activate(orca)`":"mountWorker: the module has no default-exported activate(orca) function");let c=e.deactivate;if(c!==void 0&&typeof c!="function")throw new TypeError("mountWorker: the module exports a deactivate that is not a function");let l=Rh({tables:t,hostCall:(h,k)=>i.worker.call(h,k),postToPanels:h=>{a.push(h)},log:h=>{r.push(h)},grantedCapabilities:i.capabilities}),p=i.onDataChange((h,k)=>{for(let x of t.dataListeners[h])x({key:k})});await u(l);let m=n.commands?[...t.commands.keys()].find(h=>!n.commands?.includes(h)):void 0;if(m!==void 0)throw new Error(`registered undeclared command ${m}: list it in contributes.commands`);async function f(h,k,x){let I=t.panelRequests.get(h);if(!I)throw De("unknown_method",`no panel handler named ${h}`);let A={...Mh,contributionId:x??Mh.contributionId};return I(k,{panel:A,signal:new AbortController().signal})}let g=i.routeRequests((h,k)=>f(h,k));return{host:i,logs:r,posts:a,get refusals(){return i.refusals},async emit(h,k){if(!iw(h))throw new Error(`emit: "${h}" is not an event Orca sends to workers`);if(!o.has(h))throw new Error(`emit: "${h}" never arrives: it is not in contributes.events`);let x=Qd[h].safeParse(k);if(!x.success)throw new TypeError(`emit: that ${h} payload is not one Orca sends: ${x.error.issues[0]?.message??""}`);let I=t.events.get(Vo.get(h)??h)??[];await Promise.all([...I].map(async A=>A(x.data))),await i.idle()},async command(h,k){let x=t.commands.get(h);if(!x)throw new Error(`command: the worker registered no "${h}"`);let I=await x(k,{signal:new AbortController().signal});return await i.idle(),I},async request(h,k,x={}){let I=await f(h,k,x.panel);return await i.idle(),I},async deactivate(){if(s){s=!1,p(),g(),t.events.clear(),t.commands.clear(),t.panelRequests.clear();try{await(typeof c=="function"?c():void 0)}catch(h){throw new Error(`deactivate threw: ${ow(h)}`,{cause:h})}await i.idle()}}}}import{test as FE,describe as GE,beforeEach as BE,afterEach as JE}from"node:test";import{default as HE}from"node:assert/strict";function Gh(){for(let e=process.cwd();;e=Vh(e))try{let n=JSON.parse(aw(sw(e,"orca-plugin.json"),"utf8"));return np(n)?n:null}catch{if(Vh(e)===e)return null}}function np(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function tp(e,n){return Array.isArray(e)?e.flatMap(i=>np(i)&&typeof i[n]=="string"?[i[n]]:[]):[]}function Fh(e){return e&&np(e.contributes)?e.contributes:{}}function Bh(e={}){return Fv(e,tp(Gh()?.capabilities,"kind"))}function CE(e,n={}){let i=Gh();return Zh(e,{host:n.host??Bh(),events:n.events??tp(Fh(i).events,"on"),commands:n.commands??(i?tp(Fh(i).commands,"id"):null)})}function LE(e,n={}){return Uh(e,{...n,host:n.host??Bh()})}function RE(e){return e}export{JE as afterEach,HE as assert,BE as beforeEach,RE as defineCheck,GE as describe,De as hostError,Bh as mockHost,LE as mount,CE as mountWorker,wh as stored,FE as test}; diff --git a/skill-guides/orca-cli/references/plugins.md b/skill-guides/orca-cli/references/plugins.md index fd929296b37..c20e3566149 100644 --- a/skill-guides/orca-cli/references/plugins.md +++ b/skill-guides/orca-cli/references/plugins.md @@ -66,10 +66,14 @@ Exit codes: `0` ok, `1` error, `2` `plugin_invalid`, `3` `approval_required` or draws it (default `.orca/shots/-.png`, in the plugin folder when run inside one; `--width` applies to that capture only, and `--theme` too but only while Orca's window is hidden or minimized, else `themeApplied: false` with a `themeReason`) and lists the errors the - panel showed or logged; read the image file. `--act '[{"type":{"label":"New task"},"text":"Ship"},{"press":{"text":"Add"}}]'` + panel showed or logged; read the image file. A components panel's shot also waits for its + host calls (`plugin.request`) to answer, at most 3s; `pendingRequests` counts any still out. + `--act '[{"type":{"label":"New task"},"text":"Ship"},{"press":{"text":"Add"}}]'` first drives a components panel with the test kit's verbs (`press`, `type`, `select`, - `toggle`; at most 20) and reports `actions: [{ ok, error? }]`; it needs Orca's window hidden - or minimized and never counts as a user gesture. `plugin dev watch --shot ` opens one panel once (the + `toggle`, `slide`, Table `sort`/`selectRows`/`activateRow`/`loadMore`, Tree + `expand`/`collapse`/`selectItem`/`activateItem`; at most 20) and reports + `actions: [{ ok, error? }]`; it needs Orca's window hidden or minimized and never counts as a + user gesture. Afterwards the panel's atoms are put back (`restored`); worker-side effects stay. `plugin dev watch --shot ` opens one panel once (the first, or `--shot-panel `) and captures it after every reload while it stays on screen; when the user shows something else it skips (`shot_skipped`) and never switches back. `plugin open ` shows a panel to the user (`--editor ` opens a file in its custom editor). diff --git a/skill-guides/orca-plugin-authoring/references/workflow.md b/skill-guides/orca-plugin-authoring/references/workflow.md index 4a0a0495446..25ff760f5c8 100644 --- a/skill-guides/orca-plugin-authoring/references/workflow.md +++ b/skill-guides/orca-plugin-authoring/references/workflow.md @@ -35,18 +35,26 @@ re-checks changed commands and shortcuts), `ORCA plugin dev unload `. ## Seeing and showing the panel - `ORCA plugin shot [--panel ] [--theme light|dark] [--width ] [--out ] --json` - waits for the panel's current code to draw, then writes a PNG cropped to it (default - `.orca/shots/-.png` in the plugin folder when run inside one, else in - ``) and returns `{ path, width, height, theme, themeApplied, themeReason?, settled, errors, - actions? }`. Check a narrow `--width` and both themes. `--theme` applies only while Orca's + waits for the panel's current code to draw and, for a components panel, for its host calls + (`plugin.request` included) to answer and redraw (at most 3s more), then writes a PNG cropped to + it (default `.orca/shots/-.png` in the plugin folder when run inside one, else + in ``) and returns `{ path, width, height, theme, themeApplied, themeReason?, settled, + errors, pendingRequests?, actions?, restored? }`. `pendingRequests` above 0 means a worker had + not answered, so the PNG may show the loading state. Check a narrow `--width` and both themes. `--theme` applies only while Orca's window is hidden or minimized; otherwise `themeApplied` is false with a `themeReason`, so nothing on the user's screen repaints. - `--act ''` drives a components panel before the capture, in the test kit's verbs: `[{"type":{"label":"New task"},"text":"Ship","submit":true},{"press":{"text":"Add"}}, {"select":{"label":"View"},"value":"done"},{"toggle":{"label":"Hide done"}}]` (at most 20; - queries take `text`, `label`, `testId`, `type`, `role`). Each act goes through Orca's own - control, then waits for the panel to redraw; `actions` has one `{ ok, error? }` each, the first - failure skips the rest and exits 1. It needs Orca's window hidden or minimized, so it never + queries take `text`, `label`, `testId`, `type`, `role`). Also `{"slide":Q,"value":7}`, for a + Table `{"sort":Q,"column":"name"}`, `{"selectRows":Q,"keys":["a"]}`, + `{"activateRow":Q,"key":"a"}`, `{"loadMore":Q}`, and for a Tree `{"expand":Q,"key":"src"}`, + `collapse`, `selectItem`, `activateItem` (same `key`). Each act goes through Orca's own control, + then waits for the panel to redraw and its host calls to answer; `actions` has one + `{ ok, error? }` each, the first failure skips the rest and exits 1. After the capture the + panel's atoms are put back, persisted ones included (`restored`; false if it reloaded + meanwhile), but not what handlers changed elsewhere: a `plugin.request` that wrote worker + storage stays written. It needs Orca's window hidden or minimized, so it never clicks under the user, and refuses html panels. Acts are not a person's press: a Link's href stays closed and `shell.openExternal` / `files.saveAs` are refused. - `ORCA plugin open [--panel | --editor ]` shows the panel in the right diff --git a/src/cli/bundled-skill-guides.ts b/src/cli/bundled-skill-guides.ts index 8024dc5b55e..5b6a91cd27f 100644 --- a/src/cli/bundled-skill-guides.ts +++ b/src/cli/bundled-skill-guides.ts @@ -984,10 +984,14 @@ const ORCA_CLI_PLUGINS_REFERENCE_MARKDOWN = [ " draws it (default `.orca/shots/-.png`, in the plugin folder when run inside", " one; `--width` applies to that capture only, and `--theme` too but only while Orca's window is", " hidden or minimized, else `themeApplied: false` with a `themeReason`) and lists the errors the", - " panel showed or logged; read the image file. `--act '[{\"type\":{\"label\":\"New task\"},\"text\":\"Ship\"},{\"press\":{\"text\":\"Add\"}}]'`", + " panel showed or logged; read the image file. A components panel's shot also waits for its", + " host calls (`plugin.request`) to answer, at most 3s; `pendingRequests` counts any still out.", + " `--act '[{\"type\":{\"label\":\"New task\"},\"text\":\"Ship\"},{\"press\":{\"text\":\"Add\"}}]'`", " first drives a components panel with the test kit's verbs (`press`, `type`, `select`,", - " `toggle`; at most 20) and reports `actions: [{ ok, error? }]`; it needs Orca's window hidden", - " or minimized and never counts as a user gesture. `plugin dev watch --shot ` opens one panel once (the", + " `toggle`, `slide`, Table `sort`/`selectRows`/`activateRow`/`loadMore`, Tree", + " `expand`/`collapse`/`selectItem`/`activateItem`; at most 20) and reports", + " `actions: [{ ok, error? }]`; it needs Orca's window hidden or minimized and never counts as a", + " user gesture. Afterwards the panel's atoms are put back (`restored`); worker-side effects stay. `plugin dev watch --shot ` opens one panel once (the", " first, or `--shot-panel `) and captures it after every reload while it stays on screen;", " when the user shows something else it skips (`shot_skipped`) and never switches back. `plugin open", " ` shows a panel to the user (`--editor ` opens a file in its custom editor).", @@ -3316,18 +3320,26 @@ const ORCA_PLUGIN_AUTHORING_WORKFLOW_REFERENCE_MARKDOWN = [ "## Seeing and showing the panel", "", "- `ORCA plugin shot [--panel ] [--theme light|dark] [--width ] [--out ] --json`", - " waits for the panel's current code to draw, then writes a PNG cropped to it (default", - " `.orca/shots/-.png` in the plugin folder when run inside one, else in", - " ``) and returns `{ path, width, height, theme, themeApplied, themeReason?, settled, errors,", - " actions? }`. Check a narrow `--width` and both themes. `--theme` applies only while Orca's", + " waits for the panel's current code to draw and, for a components panel, for its host calls", + " (`plugin.request` included) to answer and redraw (at most 3s more), then writes a PNG cropped to", + " it (default `.orca/shots/-.png` in the plugin folder when run inside one, else", + " in ``) and returns `{ path, width, height, theme, themeApplied, themeReason?, settled,", + " errors, pendingRequests?, actions?, restored? }`. `pendingRequests` above 0 means a worker had", + " not answered, so the PNG may show the loading state. Check a narrow `--width` and both themes. `--theme` applies only while Orca's", " window is hidden or minimized; otherwise `themeApplied` is false with a `themeReason`, so", " nothing on the user's screen repaints.", "- `--act ''` drives a components panel before the capture, in the test kit's verbs:", " `[{\"type\":{\"label\":\"New task\"},\"text\":\"Ship\",\"submit\":true},{\"press\":{\"text\":\"Add\"}},", " {\"select\":{\"label\":\"View\"},\"value\":\"done\"},{\"toggle\":{\"label\":\"Hide done\"}}]` (at most 20;", - " queries take `text`, `label`, `testId`, `type`, `role`). Each act goes through Orca's own", - " control, then waits for the panel to redraw; `actions` has one `{ ok, error? }` each, the first", - " failure skips the rest and exits 1. It needs Orca's window hidden or minimized, so it never", + " queries take `text`, `label`, `testId`, `type`, `role`). Also `{\"slide\":Q,\"value\":7}`, for a", + " Table `{\"sort\":Q,\"column\":\"name\"}`, `{\"selectRows\":Q,\"keys\":[\"a\"]}`,", + " `{\"activateRow\":Q,\"key\":\"a\"}`, `{\"loadMore\":Q}`, and for a Tree `{\"expand\":Q,\"key\":\"src\"}`,", + " `collapse`, `selectItem`, `activateItem` (same `key`). Each act goes through Orca's own control,", + " then waits for the panel to redraw and its host calls to answer; `actions` has one", + " `{ ok, error? }` each, the first failure skips the rest and exits 1. After the capture the", + " panel's atoms are put back, persisted ones included (`restored`; false if it reloaded", + " meanwhile), but not what handlers changed elsewhere: a `plugin.request` that wrote worker", + " storage stays written. It needs Orca's window hidden or minimized, so it never", " clicks under the user, and refuses html panels. Acts are not a person's press: a Link's href", " stays closed and `shell.openExternal` / `files.saveAs` are refused.", "- `ORCA plugin open [--panel | --editor ]` shows the panel in the right", diff --git a/src/cli/handlers/plugin-authoring.ts b/src/cli/handlers/plugin-authoring.ts index 20d82c3fc50..cabd2d8d3cf 100644 --- a/src/cli/handlers/plugin-authoring.ts +++ b/src/cli/handlers/plugin-authoring.ts @@ -24,6 +24,7 @@ import { findPluginTestFiles, runPluginTests } from '../plugin-authoring/plugin- import { checkPluginPanels, formatPluginPanelCheck } from '../plugin-authoring/plugin-panel-check' import { RuntimeClientError } from '../runtime/types' import { PLUGIN_INVALID_CODE } from '../../shared/plugins/approval/plugin-cli-approval' +import { formatPluginGrantLines } from '../plugin-authoring/plugin-grant-lines' function optionalString(flags: Map, name: string): string | undefined { const value = flags.get(name) @@ -36,10 +37,7 @@ function formatGrants(report: PluginValidationReport): string[] { return [] } return [ - `${plugin.pluginKey} ${plugin.version} (${plugin.grants.execution})`, - ` ${plugin.grants.executionDescription}`, - ...plugin.grants.capabilities.map((capability) => ` - ${capability.description}`), - ...plugin.grants.contributions.map((item) => ` adds ${item.kind}: ${item.name}`), + ...formatPluginGrantLines(plugin), plugin.needsApproval ? ' Loading or enabling it needs --approve ; Orca prints the fingerprint.' : ' Content only: loads without approval.' diff --git a/src/cli/handlers/plugin-dev-watch.ts b/src/cli/handlers/plugin-dev-watch.ts index a4b94b92fe7..0af2df68ef0 100644 --- a/src/cli/handlers/plugin-dev-watch.ts +++ b/src/cli/handlers/plugin-dev-watch.ts @@ -17,6 +17,7 @@ import { writeStdoutLine } from '../stdout-line' import type { PluginHostListEntry } from '../../shared/plugins/plugin-list-entry' import { CLI_BOOLEAN_FLAGS } from '../../shared/cli-argument-boundary' import { checkPluginDevFolder } from '../plugin-dev-watch/plugin-dev-watch-check' +import { pluginDevWatchConfirmFor } from '../plugin-dev-watch/plugin-dev-watch-approval' import { pluginDevWatchShotPanel, type PluginDevWatchShotHost @@ -133,10 +134,11 @@ export function bindPluginDevWatchHost(ctx: HandlerContext, path: string): Plugi ...(check ? { check: () => checkPluginDevFolder(path) } : {}), ...(shotDir ? { shot: bindShotHost(ctx, shotDir, shotPanel) } : {}), refreshTypes: () => refreshDevTypes(ctx, path), - devLoad: () => + devLoad: (approvalFingerprint) => callPlugins(ctx, 'plugins.devLoad', { path, - approvalFingerprint: typeof approve === 'string' ? approve : undefined + approvalFingerprint: + approvalFingerprint ?? (typeof approve === 'string' ? approve : undefined) }), list: () => pollHost(ctx, 'plugins.list'), logs: (pluginKey, after) => @@ -170,7 +172,8 @@ export const PLUGIN_DEV_WATCH_HANDLERS: Record = { wait: waitUnlessAborted, onInterrupt: onPluginDevWatchInterrupt, exitNow: (code) => process.exit(code), - isConnectionLost: (error) => error instanceof PluginHostUnreachableError + isConnectionLost: (error) => error instanceof PluginHostUnreachableError, + confirm: pluginDevWatchConfirmFor(ctx.json) }) } } diff --git a/src/cli/handlers/plugin-view.test.ts b/src/cli/handlers/plugin-view.test.ts index 4ac18d196db..38174325eb0 100644 --- a/src/cli/handlers/plugin-view.test.ts +++ b/src/cli/handlers/plugin-view.test.ts @@ -277,4 +277,35 @@ describe('orca plugin shot', () => { ) ).rejects.toMatchObject({ code: 'runtime_unsupported' }) }) + + it('passes pendingRequests and restored on, and notes them in text', async () => { + const call = vi + .fn() + .mockResolvedValue( + shotReply({ pendingRequests: 2, actions: [{ ok: true }], restored: false }) + ) + await PLUGIN_VIEW_HANDLERS['plugin shot']( + context(['plugin', 'shot', 'acme.todos', '--act', '{"press":{"text":"Add"}}'], call, { cwd }) + ) + expect(JSON.parse(stdout.join('')).result).toMatchObject({ + pendingRequests: 2, + actions: [{ ok: true }], + restored: false + }) + const text = formatPluginShot({ + path: '/w/a.png', + pluginKey: 'acme.todos', + panelId: 'todos', + width: 300, + height: 600, + theme: 'dark', + themeApplied: false, + settled: true, + errors: [], + pendingRequests: 2, + restored: false + }) + expect(text).toContain('2 host call(s) (plugin.request included) were unanswered after 3s') + expect(text).toContain('its acted state was not put back') + }) }) diff --git a/src/cli/handlers/plugin-view.ts b/src/cli/handlers/plugin-view.ts index 9a26de5c2e9..025717b10c3 100644 --- a/src/cli/handlers/plugin-view.ts +++ b/src/cli/handlers/plugin-view.ts @@ -31,8 +31,12 @@ export type PluginShotReply = { themeReason?: string settled: boolean errors: string[] + /** Host calls still unanswered at the capture (components panels); absent on older hosts. */ + pendingRequests?: number /** Present when `acts` were sent; absent from hosts that predate --act. */ actions?: PluginShotActResult[] + /** With acts: the panel's atoms were put back after the capture; absent on older hosts. */ + restored?: boolean } /** `ifShown` and the panel was not on screen: the host opened, switched and captured nothing. */ @@ -49,7 +53,9 @@ export type PluginShotSaved = { themeReason?: string settled: boolean errors: string[] + pendingRequests?: number actions?: PluginShotActResult[] + restored?: boolean } type PluginOpenReply = @@ -139,7 +145,9 @@ async function shoot( ...(reply.themeReason ? { themeReason: reply.themeReason } : {}), settled: reply.settled, errors: reply.errors, - ...(reply.actions ? { actions: reply.actions } : {}) + ...(reply.pendingRequests === undefined ? {} : { pendingRequests: reply.pendingRequests }), + ...(reply.actions ? { actions: reply.actions } : {}), + ...(reply.restored === undefined ? {} : { restored: reply.restored }) } } @@ -174,9 +182,17 @@ export function formatPluginShot(shot: PluginShotSaved, requestedTheme?: string) ...(shot.settled ? [] : [' note: the panel had not finished drawing; this is what it showed.']), + ...(shot.pendingRequests + ? [ + ` note: ${shot.pendingRequests} host call(s) (plugin.request included) were unanswered after 3s; the panel may still show its loading state.` + ] + : []), ...(shot.actions ?? []).map((action, index) => action.ok ? ` act ${index + 1}: ok` : ` act ${index + 1} failed: ${action.error}` ), + ...(shot.restored === false + ? [' note: the panel reloaded during --act, so its acted state was not put back.'] + : []), ...shot.errors.map((error) => ` error: ${error}`) ].join('\n') } diff --git a/src/cli/plugin-authoring/plugin-create.ts b/src/cli/plugin-authoring/plugin-create.ts index fc314907e0a..bdc3c60a0c9 100644 --- a/src/cli/plugin-authoring/plugin-create.ts +++ b/src/cli/plugin-authoring/plugin-create.ts @@ -2,6 +2,7 @@ import { existsSync, readdirSync, statSync } from 'node:fs' import { mkdir, writeFile } from 'node:fs/promises' import { basename, dirname, join, resolve } from 'node:path' import { parsePluginManifest } from '../../shared/plugins/manifest/plugin-manifest' +import { pluginDisplayNameFromId } from './plugin-display-name' import { PLUGIN_TEMPLATE_NAMES, type PluginTemplateName } from './plugin-template-names' import { pluginTemplateKey } from './plugin-template-files' import { renderPluginTemplate } from './plugin-templates' @@ -26,14 +27,6 @@ export function pluginIdFromFolder(folder: string): string { .replace(/^-+|-+$/g, '') } -function titleFromId(id: string): string { - return id - .split('-') - .filter(Boolean) - .map((word) => word[0].toUpperCase() + word.slice(1)) - .join(' ') -} - function assertEmptyFolder(dir: string): void { if (!existsSync(dir)) { return @@ -58,7 +51,7 @@ export async function createPluginFromTemplate(input: { }): Promise { const dir = resolve(input.dir) const id = input.id ?? pluginIdFromFolder(dir) - const name = input.name ?? (titleFromId(id) || id) + const name = input.name ?? (pluginDisplayNameFromId(id) || id) const templateInput = { publisher: input.publisher, id, name } const pluginKey = pluginTemplateKey(templateInput) const template = renderPluginTemplate(input.template, templateInput) diff --git a/src/cli/plugin-authoring/plugin-display-name.test.ts b/src/cli/plugin-authoring/plugin-display-name.test.ts new file mode 100644 index 00000000000..d959966a529 --- /dev/null +++ b/src/cli/plugin-authoring/plugin-display-name.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, it } from 'vitest' +import { pluginDisplayNameFromId } from './plugin-display-name' + +describe('pluginDisplayNameFromId', () => { + it.each([ + ['pr-queue', 'PR Queue'], + ['api-explorer', 'API Explorer'], + ['ci-status', 'CI Status'], + ['github-pr-ui', 'Github PR UI'], + ['k8s-pods', 'K8s Pods'], + ['notes', 'Notes'], + ['prism', 'Prism'], + ['idle', 'Idle'], + ['url-shortener', 'URL Shortener'], + ['apis', 'Apis'], + ['my--tool-', 'My Tool'], + ['2fa-codes', '2fa Codes'] + ])('%s → %s', (id, name) => { + expect(pluginDisplayNameFromId(id)).toBe(name) + }) +}) diff --git a/src/cli/plugin-authoring/plugin-display-name.ts b/src/cli/plugin-authoring/plugin-display-name.ts new file mode 100644 index 00000000000..e082f0883fe --- /dev/null +++ b/src/cli/plugin-authoring/plugin-display-name.ts @@ -0,0 +1,15 @@ +// Why a short list: only words that read wrong title-cased ("Pr Queue"); a word must match whole. +const ACRONYMS = + 'AI API AWS CD CI CLI CPU CSS CSV DNS GCP GPU HTML HTTP HTTPS ID IO JS JSON K8s LLM MCP OS PDF PR SDK SQL SSH TS TSX UI URI URL VM XML YAML'.split( + ' ' + ) +const SPELLING = new Map(ACRONYMS.map((word) => [word.toLowerCase(), word])) + +/** `pr-queue` → "PR Queue": dash-separated words title-cased, known acronyms kept as written. */ +export function pluginDisplayNameFromId(id: string): string { + return id + .split('-') + .filter(Boolean) + .map((word) => SPELLING.get(word.toLowerCase()) ?? word[0].toUpperCase() + word.slice(1)) + .join(' ') +} diff --git a/src/cli/plugin-authoring/plugin-grant-lines.ts b/src/cli/plugin-authoring/plugin-grant-lines.ts new file mode 100644 index 00000000000..8d56580597e --- /dev/null +++ b/src/cli/plugin-authoring/plugin-grant-lines.ts @@ -0,0 +1,20 @@ +/** The displayed part of `PluginApprovalGrants`; also what a host's `approval_required` data carries. */ +export type PluginGrantSummary = { + execution: string + executionDescription: string + capabilities: { description: string }[] + contributions: { kind: string; name: string }[] +} + +type GrantSubject = { pluginKey: string; version: string; grants: PluginGrantSummary } + +/** What a plugin would be granted, as `orca plugin inspect` and the dev watch prompt print it. */ +export function formatPluginGrantLines(subject: GrantSubject): string[] { + const { grants } = subject + return [ + `${subject.pluginKey} ${subject.version} (${grants.execution})`, + ` ${grants.executionDescription}`, + ...grants.capabilities.map((capability) => ` - ${capability.description}`), + ...grants.contributions.map((item) => ` adds ${item.kind}: ${item.name}`) + ] +} diff --git a/src/cli/plugin-dev-watch/plugin-dev-watch-approval.test.ts b/src/cli/plugin-dev-watch/plugin-dev-watch-approval.test.ts new file mode 100644 index 00000000000..7346c94eca7 --- /dev/null +++ b/src/cli/plugin-dev-watch/plugin-dev-watch-approval.test.ts @@ -0,0 +1,183 @@ +import { PassThrough } from 'node:stream' +import { describe, expect, it, vi } from 'vitest' +import type { PluginHostListEntry } from '../../shared/plugins/plugin-list-entry' +import { RuntimeClientError } from '../runtime/types' +import { + createTerminalConfirm, + pluginDevWatchConfirmFor, + type PluginDevWatchConfirm +} from './plugin-dev-watch-approval' +import type { PluginDevWatchEvent } from './plugin-dev-watch-events' +import { runPluginDevWatch, type PluginDevWatchHost } from './plugin-dev-watch-loop' + +const KEY = 'acme.notes' +const PATH = '/work/notes' +const FINGERPRINT = 'ap1-0123456789abcdef' +const COMMAND = `orca plugin dev watch ${PATH} --approve ${FINGERPRINT}` + +const plugin: PluginHostListEntry = { + pluginKey: KEY, + consentFingerprint: 'sha256-x', + name: 'Notes', + version: '1.0.0', + publisher: 'acme', + status: 'running', + needsReconsent: false, + isDev: true, + devChangeCount: 0, + official: false, + bundled: false, + capabilities: [], + panels: [], + commands: [], + hasWorker: true, + restarts: 0 +} + +function approvalRequired(): RuntimeClientError { + return new RuntimeClientError( + 'approval_required', + `${KEY} 1.0.0 needs approval before it can run.`, + { + pluginKey: KEY, + name: 'Notes', + version: '1.0.0', + action: 'dev-load', + approvalFingerprint: FINGERPRINT, + isDev: true, + grants: { + execution: 'trusted-worker', + executionDescription: 'Runs its own code in a separate Node.js process on the Orca host.', + capabilities: [{ kind: 'git.read', description: 'Read git status.' }], + contributions: [{ kind: 'panels', name: 'Notes' }] + }, + why: 'It can run code.', + command: COMMAND, + nextSteps: [`To approve, run: ${COMMAND}`] + } + ) +} + +/** The first devLoad needs approval; one with the fingerprint loads. Ctrl-C after the first poll. */ +function watch(confirm: PluginDevWatchConfirm | undefined) { + const events: PluginDevWatchEvent[] = [] + let interrupt: () => void = () => {} + const devLoad = vi.fn(async (fingerprint?: string) => { + if (fingerprint !== FINGERPRINT) { + throw approvalRequired() + } + return { path: PATH, pluginKey: KEY, added: true, approval: 'approve-flag' as const, plugin } + }) + const host: PluginDevWatchHost = { + refreshTypes: async () => [], + devLoad, + list: async () => [plugin], + logs: async () => ({ pluginKey: KEY, lines: [] }), + approvalNeeded: async () => null, + devUnload: vi.fn(async () => {}) + } + const run = runPluginDevWatch({ + host, + emit: (event) => events.push(event), + wait: async () => interrupt(), + onInterrupt: (listener) => { + interrupt = listener + return () => {} + }, + exitNow: vi.fn(), + isConnectionLost: () => false, + ...(confirm ? { confirm } : {}) + }) + return { run, events, devLoad, host } +} + +describe('first-load approval prompt', () => { + it('on yes, loads again with the host fingerprint and keeps watching', async () => { + const confirm = vi.fn(async (_question: string) => true) + const { run, events, devLoad, host } = watch(confirm) + await expect(run).resolves.toBe(0) + expect(devLoad.mock.calls).toEqual([[undefined], [FINGERPRINT]]) + const question = confirm.mock.calls[0]?.[0] ?? '' + expect(question).toContain('Approving grants:') + expect(question).toContain(`${KEY} 1.0.0 (trusted-worker)`) + expect(question).toContain(' - Read git status.') + expect(question).toContain(' adds panels: Notes') + expect(question.endsWith('Approve and load? [y/N] ')).toBe(true) + expect(events.map((event) => event.type)).toEqual(['loaded', 'unloaded']) + expect(host.devUnload).toHaveBeenCalledTimes(1) + }) + + it('on no or no answer, fails approval_required with only the re-run command', async () => { + const confirm = vi.fn(async () => false) + const { run, devLoad } = watch(confirm) + await expect(run).rejects.toMatchObject({ + code: 'approval_required', + message: `Not approved. To approve later, run: ${COMMAND}`, + data: { command: COMMAND, nextSteps: [] } + }) + // The grants were just on screen; the error does not print them again. + await expect(run).rejects.not.toHaveProperty('data.grants') + expect(confirm).toHaveBeenCalledTimes(1) + expect(devLoad).toHaveBeenCalledTimes(1) + }) + + it('without a prompt (--json or no terminal) fails as before', async () => { + const { run, devLoad } = watch(undefined) + await expect(run).rejects.toMatchObject({ code: 'approval_required' }) + expect(devLoad).toHaveBeenCalledTimes(1) + }) + + it('never prompts for a stale fingerprint passed with --approve', async () => { + const confirm = vi.fn(async () => true) + const { run, host } = watch(confirm) + const stale = new RuntimeClientError('approval_stale', 'changed', approvalRequired().data) + vi.mocked(host.devLoad).mockRejectedValueOnce(stale) + await expect(run).rejects.toBe(stale) + expect(confirm).not.toHaveBeenCalled() + }) +}) + +function terminal(isTTY = true) { + const input = Object.assign(new PassThrough(), { isTTY }) + const output = Object.assign(new PassThrough(), { isTTY }) + let printed = '' + output.on('data', (chunk: Buffer) => { + printed += chunk.toString() + }) + return { input, output, printed: () => printed } +} + +describe('pluginDevWatchConfirmFor', () => { + it('prompts only when both streams are terminals and --json is off', () => { + expect(pluginDevWatchConfirmFor(false, terminal())).toBeTypeOf('function') + expect(pluginDevWatchConfirmFor(true, terminal())).toBeUndefined() + expect(pluginDevWatchConfirmFor(false, terminal(false))).toBeUndefined() + const { input } = terminal(false) + expect(pluginDevWatchConfirmFor(false, { input, output: terminal().output })).toBeUndefined() + }) + + it.each([ + ['y\n', true], + ['YES\n', true], + [' yes \n', true], + ['n\n', false], + ['\n', false], + ['sure\n', false] + ])('reads %j as %s', async (typed, expected) => { + const streams = terminal() + const answer = createTerminalConfirm(streams)('Approve and load? [y/N] ') + streams.input.write(typed) + await expect(answer).resolves.toBe(expected) + expect(streams.printed()).toContain('Approve and load? [y/N] ') + }) + + it.each([ + ['end of input', (input: PassThrough) => input.end()], + ['Ctrl-C', (input: PassThrough) => input.write('\u0003')] + ])('reads %s as no', async (_name, stop) => { + const streams = terminal() + const answer = createTerminalConfirm(streams)('Approve and load? [y/N] ') + stop(streams.input) + await expect(answer).resolves.toBe(false) + }) +}) diff --git a/src/cli/plugin-dev-watch/plugin-dev-watch-approval.ts b/src/cli/plugin-dev-watch/plugin-dev-watch-approval.ts new file mode 100644 index 00000000000..0c629229830 --- /dev/null +++ b/src/cli/plugin-dev-watch/plugin-dev-watch-approval.ts @@ -0,0 +1,128 @@ +import { createInterface } from 'node:readline' +import { z } from 'zod' +import { formatPluginGrantLines } from '../plugin-authoring/plugin-grant-lines' +import { RuntimeClientError } from '../runtime/types' +import type { DevLoadResult } from '../handlers/plugin-runtime' + +/** Asks a yes/no question; false on anything but yes, end of input or Ctrl-C. */ +export type PluginDevWatchConfirm = (question: string) => Promise + +const firstLoadApprovalSchema = z.object({ + pluginKey: z.string(), + name: z.string(), + version: z.string(), + approvalFingerprint: z.string(), + why: z.string().optional(), + grants: z.object({ + execution: z.string(), + executionDescription: z.string(), + capabilities: z.array(z.object({ description: z.string() })), + contributions: z.array(z.object({ kind: z.string(), name: z.string() })) + }) +}) + +type FirstLoadApproval = z.infer + +function firstLoadApprovalOf(error: unknown): FirstLoadApproval | null { + // Why not `approval_stale`: it answers a fingerprint passed with --approve, which stays explicit. + if (!(error instanceof RuntimeClientError) || error.code !== 'approval_required') { + return null + } + const parsed = firstLoadApprovalSchema.safeParse(error.data) + return parsed.success ? parsed.data : null +} + +export function pluginDevWatchApprovalQuestion(approval: FirstLoadApproval): string { + return [ + `${approval.name} needs your approval before Orca runs it. Approving grants:`, + ...formatPluginGrantLines(approval), + ...(approval.why ? [approval.why] : []), + 'Approve and load? [y/N] ' + ].join('\n') +} + +/** The first dev load; with `confirm` (a person at a terminal) an approval is asked, never assumed. + * A declined or unanswered ask fails with approval_required (exit 3) and only the re-run command. */ +export async function devLoadWithApproval( + devLoad: (approvalFingerprint?: string) => Promise, + confirm: PluginDevWatchConfirm | undefined +): Promise { + try { + return await devLoad() + } catch (error) { + const approval = confirm ? firstLoadApprovalOf(error) : null + if (!confirm || !approval) { + throw error + } + if (!(await confirm(pluginDevWatchApprovalQuestion(approval)))) { + throw declinedApprovalError(error, approval) + } + return devLoad(approval.approvalFingerprint) + } +} + +/** Why trimmed: the person just read the grants; repeating them buries the re-run command. */ +function declinedApprovalError(error: unknown, approval: FirstLoadApproval): RuntimeClientError { + const data = error instanceof RuntimeClientError ? error.data : undefined + const command = + typeof data === 'object' && + data !== null && + 'command' in data && + typeof data.command === 'string' + ? data.command + : null + return new RuntimeClientError( + 'approval_required', + command ? `Not approved. To approve later, run: ${command}` : 'Not approved.', + { + pluginKey: approval.pluginKey, + approvalFingerprint: approval.approvalFingerprint, + command, + nextSteps: [] + } + ) +} + +type PromptStreams = { + input: NodeJS.ReadableStream & { isTTY?: boolean } + output: NodeJS.WritableStream & { isTTY?: boolean } +} + +/** A prompt only for a person at a terminal; agents, pipes and `--json` keep the exit-3 error. */ +export function pluginDevWatchConfirmFor( + json: boolean, + streams: PromptStreams = { input: process.stdin, output: process.stdout } +): PluginDevWatchConfirm | undefined { + return !json && streams.input.isTTY && streams.output.isTTY + ? createTerminalConfirm(streams) + : undefined +} + +/** readline works the same in Windows cmd, PowerShell and Windows Terminal as on POSIX ttys. */ +export function createTerminalConfirm(streams: PromptStreams): PluginDevWatchConfirm { + return (question) => + new Promise((resolve) => { + const rl = createInterface({ input: streams.input, output: streams.output }) + let answered = false + const finish = (yes: boolean): void => { + if (answered) { + return + } + answered = true + rl.close() + resolve(yes) + } + // Why: with no SIGINT listener readline only pauses on Ctrl-C, leaving the prompt hanging. + rl.on('SIGINT', () => { + streams.output.write('\n') + finish(false) + }) + rl.on('close', () => { + if (!answered) { + streams.output.write('\n') + } + finish(false) + }) + rl.question(question, (answer) => finish(/^y(es)?$/i.test(answer.trim()))) + }) +} diff --git a/src/cli/plugin-dev-watch/plugin-dev-watch-loop.ts b/src/cli/plugin-dev-watch/plugin-dev-watch-loop.ts index 1eea30a55a3..c33786253c8 100644 --- a/src/cli/plugin-dev-watch/plugin-dev-watch-loop.ts +++ b/src/cli/plugin-dev-watch/plugin-dev-watch-loop.ts @@ -6,6 +6,7 @@ import type { PluginDevWatchStatus } from './plugin-dev-watch-events' import { PluginLogFollower } from './plugin-log-follower' +import { devLoadWithApproval, type PluginDevWatchConfirm } from './plugin-dev-watch-approval' import { PluginFrameLogDedupe, type PluginDevWatchLogLine } from './plugin-frame-log-dedupe' import { createPluginDevWatchCheckQueue, @@ -20,7 +21,8 @@ import { /** What the loop asks of the Orca host; the handler binds it to RPC for one folder. */ export type PluginDevWatchHost = { refreshTypes(): Promise - devLoad(): Promise + /** `approvalFingerprint` overrides `--approve` once the person approved at the prompt. */ + devLoad(approvalFingerprint?: string): Promise list(): Promise logs(pluginKey: string, after: string | undefined): Promise /** Re-checks the folder's approval; null when it needs none. */ @@ -41,6 +43,8 @@ export type PluginDevWatchDeps = { onInterrupt(listener: () => void): () => void exitNow(code: number): void isConnectionLost(error: unknown): boolean + /** Only for a person at a terminal without `--json`: asks to approve a first load that needs it. */ + confirm?: PluginDevWatchConfirm } // Why these rates: logs feel live at 500 ms, and the plugin list (a projection of every plugin) is @@ -131,11 +135,12 @@ async function startShooter( } /** Loads the folder, then streams its logs and reload status until interrupted. Returns the exit - * code. A failed first load throws (approval_required exits 3 like `orca plugin dev load`). */ + * code. A failed first load throws (approval_required exits 3 like `orca plugin dev load`) unless + * the person approves it at the `confirm` prompt. */ export async function runPluginDevWatch(deps: PluginDevWatchDeps): Promise { const { host, emit } = deps const typeFiles = await host.refreshTypes() - const loaded = await host.devLoad() + const loaded = await devLoadWithApproval((fingerprint) => host.devLoad(fingerprint), deps.confirm) const { pluginKey } = loaded let snapshot = snapshotOf(loaded.plugin) emit({ diff --git a/src/cli/specs/plugin-view.ts b/src/cli/specs/plugin-view.ts index 9acc415366f..42a1e6f5ca7 100644 --- a/src/cli/specs/plugin-view.ts +++ b/src/cli/specs/plugin-view.ts @@ -30,11 +30,11 @@ export const PLUGIN_VIEW_COMMAND_SPECS: CommandSpec[] = [ allowedFlags: [...GLOBAL_FLAGS, 'plugin', 'panel', 'theme', 'width', 'act', 'out'], positionalArgs: ['plugin'], notes: [ - 'Shows the panel like `orca plugin open`, waits until it has drawn (a components panel: its first tree from the current code; an html panel: its page loaded), then captures exactly the panel, with the window hidden or behind others. It never shows, raises or focuses the window, and it does not leave Settings or another full-page view.', + 'Shows the panel like `orca plugin open`, waits until it has drawn (a components panel: its first tree from the current code, then until no host call such as plugin.request is in flight and its answer has drawn, at most 3s more; an html panel: its page loaded), then captures exactly the panel, with the window hidden or behind others. It never shows, raises or focuses the window, and it does not leave Settings or another full-page view.', 'Writes .orca/shots/-.png unless --out names a file: in the plugin folder when run inside one (the nearest orca-plugin.json up to the repository root, as `dev watch --shot` does), else in . The image is in CSS pixels. Read the image file to see the panel.', '--width sets the panel width for this capture only. --theme paints Orca light or dark for this capture only, and only while its window is hidden or minimized, then puts your theme back; the setting never changes. With the window on screen it captures in the current theme rather than repaint the app in front of you. The result says which theme it shows, whether --theme took effect (themeApplied) and why not (themeReason).', - '--act runs input on a components panel before the capture, in the test kit\'s words: a JSON list (at most 20) of {"press":Q}, {"type":Q,"text":"…","replace"?:true,"submit"?:true}, {"select":Q,"value":"…"} and {"toggle":Q}, where Q matches like the kit\'s queries ({"text"|"label"|"testId"|"type"|"role":"…"}). Each act goes through Orca\'s own control and waits for the panel to redraw. It acts only on this panel and only while Orca\'s window is hidden or minimized; html panels refuse it. Acts are not a person\'s input: a Link\'s href stays unopened and gesture-only calls (shell.openExternal, files.saveAs) are refused. The first failed act stops the rest; the PNG shows the panel at that point and the command exits 1.', - '--json prints { path, width, height, theme, themeApplied, themeReason?, settled, errors, actions? }; actions has one { ok, error? } per act. errors lists the error banner the panel shows and the errors it logged (`orca plugin logs`) during the capture; settled is false when it had not finished drawing after 15s.', + '--act runs input on a components panel before the capture, in the test kit\'s words: a JSON list (at most 20) of {"press":Q}, {"type":Q,"text":"…","replace"?:true,"submit"?:true}, {"select":Q,"value":"…"}, {"toggle":Q}, {"slide":Q,"value":n}, and for a Table {"sort":Q,"column":"…"}, {"selectRows":Q,"keys":[…]}, {"activateRow":Q,"key":"…"}, {"loadMore":Q}, for a Tree {"expand"|"collapse"|"selectItem"|"activateItem":Q,"key":"…"}, where Q matches like the kit\'s queries ({"text"|"label"|"testId"|"type"|"role":"…"}). Each act goes through Orca\'s own control and waits for the panel to redraw and its host calls to answer. After the capture Orca puts the panel\'s atoms back (persisted ones included, so neither later shots nor the user keep the acted state); what handlers did elsewhere stays, such as a plugin.request that changed the worker\'s storage. It acts only on this panel and only while Orca\'s window is hidden or minimized; html panels refuse it. Acts are not a person\'s input: a Link\'s href stays unopened and gesture-only calls (shell.openExternal, files.saveAs) are refused. The first failed act stops the rest; the PNG shows the panel at that point and the command exits 1.', + '--json prints { path, width, height, theme, themeApplied, themeReason?, settled, errors, pendingRequests?, actions?, restored? }; pendingRequests counts host calls still unanswered at the capture (components panels), actions has one { ok, error? } per act, and restored is false when the panel reloaded during --act so its acted state stayed. errors lists the error banner the panel shows and the errors it logged (`orca plugin logs`) during the capture; settled is false when it had not finished drawing after 15s.', 'Desktop app only: a server with no window (`orca serve`) refuses it. With --environment the PNG (at most 5 MiB; it shows only the plugin panel) comes back to this machine and is written here.' ], examples: [ diff --git a/src/cli/specs/plugin.ts b/src/cli/specs/plugin.ts index c7c5d454e31..431d7c8f2a2 100644 --- a/src/cli/specs/plugin.ts +++ b/src/cli/specs/plugin.ts @@ -206,6 +206,7 @@ export const PLUGIN_RUNTIME_COMMAND_SPECS: CommandSpec[] = [ positionalArgs: ['dir'], notes: [ 'The inner loop: loads the folder like `orca plugin dev load` (refreshing its .orca/types), then prints each log line its panels, editors and worker write, every reload a save causes, and status changes such as errored or invalid with the error.', + 'A first load that needs approval, run in a terminal without --json, shows the grants and asks `Approve and load? [y/N]`; yes loads it with that fingerprint and keeps watching. Anything else, --json or no terminal (agents, pipes) fails like `orca plugin dev load` (exit 3, with the re-run command).', 'When an edit asks for new access it prints the `orca plugin dev reload --approve ` command to run from another shell; this one keeps watching.', 'Ctrl-C unloads the folder (unless it was loaded before this command) and exits 0; a second Ctrl-C exits at once. If the connection to Orca drops it says so and exits 1.', "--check runs `orca plugin check` after the load and after each reload and prints the result inline (one `check` event with --json; it fails while Orca does not run the plugin, such as pending approval, even if the panels render). Like `orca plugin check` it runs the plugin's code on this machine, unsandboxed, so use it on code you trust; it needs a local folder.", diff --git a/src/main/plugins/view/plugin-view-capture.test.ts b/src/main/plugins/view/plugin-view-capture.test.ts index 6fd93cc940d..ec063391658 100644 --- a/src/main/plugins/view/plugin-view-capture.test.ts +++ b/src/main/plugins/view/plugin-view-capture.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it, vi } from 'vitest' import { capturePluginPanelPng, compositeBitmap, + looksBlank, pluginPanelCaptureRect, PLUGIN_SHOT_MAX_PNG_BYTES, settlePluginFrameGuest, @@ -16,6 +17,8 @@ function image(size: { width: number; height: number }, png = Buffer.from('png') isEmpty: () => size.width === 0, getSize: () => size, resize: resized, + // A drawn panel: more than a background and a border. + toBitmap: () => Buffer.from([1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]), toPNG: () => png } as unknown as NativeImage } @@ -56,7 +59,10 @@ describe('capturePluginPanelPng', () => { it('captures the rect and scales a HiDPI image to one pixel per point', async () => { const target = contents() const shot = await capturePluginPanelPng(target, { x: 900, y: 40, width: 360, height: 700 }) - expect(target.capturePage).toHaveBeenCalledWith({ x: 900, y: 40, width: 360, height: 700 }) + expect(target.capturePage).toHaveBeenCalledWith( + { x: 900, y: 40, width: 360, height: 700 }, + { stayHidden: true } + ) expect(shot).toMatchObject({ width: 360, height: 700 }) expect(shot.png.toString()).toBe('png') }) @@ -158,3 +164,59 @@ describe('capturePluginPanelPng with an html guest', () => { expect(shot).toEqual({ png: Buffer.from('png-7'), width: 20, height: 10 }) }) }) + +describe('capturePluginPanelPng retries a bare-background capture', () => { + function solidImage(size: { width: number; height: number }, colors: number[]): NativeImage { + const bitmap = Buffer.alloc(size.width * size.height * 4) + for (let pixel = 0; pixel < size.width * size.height; pixel += 1) { + bitmap.writeUInt32LE(colors[pixel % colors.length], pixel * 4) + } + // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: capture reads only these NativeImage members. + return { + isEmpty: () => false, + getSize: () => size, + resize: () => solidImage(size, colors), + toBitmap: () => bitmap, + toPNG: () => Buffer.from(`png-${colors.length}`) + } as unknown as NativeImage + } + + it('recaptures until the panel has drawn, then stops', async () => { + const size = { width: 4, height: 4 } + const shots = [solidImage(size, [1]), solidImage(size, [1, 2]), solidImage(size, [1, 2, 3])] + const host = contents({ + capturePage: vi.fn(async () => shots.shift() ?? solidImage(size, [9])) + }) + const wait = vi.fn(async () => undefined) + const shot = await capturePluginPanelPng(host, { x: 0, y: 0, ...size }, undefined, wait) + expect(host.capturePage).toHaveBeenCalledTimes(3) + expect(wait).toHaveBeenCalledTimes(2) + expect(shot.png).toEqual(Buffer.from('png-3')) + }) + + it('gives up after its retries and returns the last capture of a truly plain panel', async () => { + const size = { width: 2, height: 2 } + const host = contents({ capturePage: vi.fn(async () => solidImage(size, [5])) }) + const shot = await capturePluginPanelPng( + host, + { x: 0, y: 0, ...size }, + undefined, + async () => {} + ) + expect(host.capturePage).toHaveBeenCalledTimes(9) + expect(shot.png).toEqual(Buffer.from('png-1')) + }) +}) + +describe('looksBlank', () => { + it('is true for one or two colors and false from three', () => { + const pixels = (...values: number[]) => { + const bitmap = Buffer.alloc(values.length * 4) + values.forEach((value, index) => bitmap.writeUInt32LE(value, index * 4)) + return bitmap + } + expect(looksBlank(pixels(7, 7, 7))).toBe(true) + expect(looksBlank(pixels(7, 8, 7))).toBe(true) + expect(looksBlank(pixels(7, 8, 9))).toBe(false) + }) +}) diff --git a/src/main/plugins/view/plugin-view-capture.ts b/src/main/plugins/view/plugin-view-capture.ts index 1e8cb9fe0b8..5bcf1e1d157 100644 --- a/src/main/plugins/view/plugin-view-capture.ts +++ b/src/main/plugins/view/plugin-view-capture.ts @@ -96,6 +96,46 @@ export function compositeBitmap( return out } +// Why retry as well: a fallback in case even a stayHidden capture returns a bare background (Linux CI). +// Why stayHidden: Electron's documented way to keep a hidden window rendering for the capture. +const HIDDEN_CAPTURE = { stayHidden: true } +const BLANK_RETRY_WAIT_MS = 150 +const BLANK_RETRIES = 8 + +/** Two colors or fewer: a background and maybe a border, i.e. nothing of the panel drawn yet. */ +export function looksBlank(bitmap: Buffer): boolean { + const seen = new Set() + for (let offset = 0; offset + 3 < bitmap.byteLength; offset += 4) { + seen.add(bitmap.readUInt32LE(offset)) + if (seen.size > 2) { + return false + } + } + return true +} + +async function captureUntilDrawn( + contents: WebContents, + target: CaptureRect, + wait: (ms: number) => Promise +): Promise { + const grab = async (): Promise => { + const shot = await contents.capturePage(target, HIDDEN_CAPTURE) + return shot.isEmpty() ? shot : atSize(shot, target.width, target.height) + } + let image = await grab() + for (let tries = 0; tries < BLANK_RETRIES && !image.isEmpty(); tries += 1) { + if (!looksBlank(image.toBitmap())) { + break + } + await wait(BLANK_RETRY_WAIT_MS) + image = await grab() + } + return image +} + +const sleep = (ms: number): Promise => new Promise((resolve) => setTimeout(resolve, ms)) + /** * The PNG of exactly that rect, at one image pixel per window point. Why the guest separately: * on Linux the window capture leaves a `` guest blank, so an html panel's guest is @@ -104,14 +144,18 @@ export function compositeBitmap( export async function capturePluginPanelPng( contents: WebContents, rect: PluginViewDrawnPanel['rect'], - guest?: { contents: WebContents; rect: CaptureRect; fromBitmap: BitmapImageFactory } + guest?: { contents: WebContents; rect: CaptureRect; fromBitmap: BitmapImageFactory }, + wait: (ms: number) => Promise = sleep ): Promise<{ png: Buffer; width: number; height: number }> { const zoom = contents.getZoomFactor() const target = pluginPanelCaptureRect(rect, zoom) if (target.width < 1 || target.height < 1) { throw new Error('The panel has no area to capture; is the right sidebar collapsed?') } - let image: NativeImage = await contents.capturePage(target) + // An html panel's guest is drawn over this capture below, so only a bare host is retried. + let image: NativeImage = guest + ? await contents.capturePage(target, HIDDEN_CAPTURE) + : await captureUntilDrawn(contents, target, wait) if (image.isEmpty()) { throw new Error('Orca drew nothing to capture; try again once its window has loaded.') } diff --git a/src/main/plugins/view/plugin-view-desktop.test.ts b/src/main/plugins/view/plugin-view-desktop.test.ts index 2fc149a68c7..24acba2c46c 100644 --- a/src/main/plugins/view/plugin-view-desktop.test.ts +++ b/src/main/plugins/view/plugin-view-desktop.test.ts @@ -26,6 +26,8 @@ const KEY = 'acme.todos' const CAPTURED = { isEmpty: () => false, getSize: () => ({ width: 300, height: 600 }), + // A drawn panel: more than a background and a border. + toBitmap: () => Buffer.from([1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]), toPNG: () => Buffer.from('png') } as unknown as NativeImage @@ -240,10 +242,10 @@ describe('plugins.shot on the desktop', () => { answer({ ...DRAWN, panel: { ...DRAWN.panel!, actions: [{ ok: true }] } }) ) const shot = await createPluginViewDesktop(deps()).shot({ pluginKey: KEY, acts }) - expect(shot).toMatchObject({ actions: [{ ok: true }] }) + expect(shot).toMatchObject({ actions: [{ ok: true }], restored: false }) const [, body, timeoutMs] = relay.requestPluginViewFromRenderer.mock.calls[0] ?? [] expect(body).toMatchObject({ capture: { acts } }) - expect(timeoutMs).toBe(24_000) + expect(timeoutMs).toBe(27_500) relay.requestPluginViewFromRenderer.mockClear() await expect( @@ -255,4 +257,18 @@ describe('plugins.shot on the desktop', () => { }) expect(relay.requestPluginViewFromRenderer).not.toHaveBeenCalled() }) + + it('reports unanswered host calls and whether --act was put back once the capture ended', async () => { + relay.requestPluginViewFromRenderer.mockImplementation(async (...args) => + args[1]?.kind === 'open-panel' + ? { ...DRAWN, panel: { ...DRAWN.panel!, pendingRequests: 1, actions: [{ ok: true }] } } + : { requestId: 'r', ok: true, restored: true } + ) + const view = createPluginViewDesktop(deps()) + await expect( + view.shot({ pluginKey: KEY, acts: [{ toggle: { label: 'Hide done' } }] }) + ).resolves.toMatchObject({ pendingRequests: 1, restored: true }) + // Without acts there is nothing to put back, so no `restored`. + expect(await view.shot({ pluginKey: KEY })).not.toHaveProperty('restored') + }) }) diff --git a/src/main/plugins/view/plugin-view-desktop.ts b/src/main/plugins/view/plugin-view-desktop.ts index 89dbd6f3077..d688654660b 100644 --- a/src/main/plugins/view/plugin-view-desktop.ts +++ b/src/main/plugins/view/plugin-view-desktop.ts @@ -46,8 +46,12 @@ export type PluginShotResult = { settled: boolean /** Errors the panel logged during the capture and the banner it shows, if any. */ errors: string[] + /** Host calls (`plugin.request` included) still unanswered at the capture; components only. */ + pendingRequests?: number /** One result per `acts` entry, when acts were asked for. */ actions?: PluginShotActResult[] + /** With acts: the panel's atoms were put back after the capture (false: its guest reloaded). */ + restored?: boolean } /** `ifShown` and the panel was not on screen: nothing was opened, switched or captured. */ @@ -95,6 +99,8 @@ const RENDER_TIMEOUT_MS = 15_000 const REPLY_GRACE_MS = 5_000 // Why: each act may wait up to 3s for the panel to settle, plus the frames that paint it. const ACT_TIMEOUT_MS = 4_000 +// Why: after drawing, a shot waits up to 3s more for the panel's worker to answer. +const SETTLE_TIMEOUT_MS = 3_500 const MAX_ERRORS = 20 function failed(reply: PluginViewReply): PluginCliError | null { @@ -166,78 +172,87 @@ export function createPluginViewDesktop(deps: PluginViewDesktopDeps): PluginView const { colorScheme, themeReason } = pluginShotThemeDecision(requested, deps.windowShown()) const { cursor } = deps.logsSince(pluginKey) return withPaintingWhileHidden([contents, ...deps.guestsOf(pluginKey)], async () => { - try { - const reply = await requestPluginViewFromRenderer( - contents, - { - kind: 'open-panel', - pluginKey, - panelId: panel.panelId, - capture: { - guestRevision: panel.guestRevision, - ...(width === undefined ? {} : { width }), - ...(colorScheme === undefined ? {} : { colorScheme }), - ...(ifShown ? { ifShown: true } : {}), - ...(acts ? { acts } : {}), - timeoutMs: RENDER_TIMEOUT_MS + let restored: boolean | undefined + const shot = await (async (): Promise => { + try { + const reply = await requestPluginViewFromRenderer( + contents, + { + kind: 'open-panel', + pluginKey, + panelId: panel.panelId, + capture: { + guestRevision: panel.guestRevision, + ...(width === undefined ? {} : { width }), + ...(colorScheme === undefined ? {} : { colorScheme }), + ...(ifShown ? { ifShown: true } : {}), + ...(acts ? { acts } : {}), + timeoutMs: RENDER_TIMEOUT_MS + } + }, + RENDER_TIMEOUT_MS + SETTLE_TIMEOUT_MS + actsTimeoutMs + REPLY_GRACE_MS + ) + if (ifShown && !reply.ok && reply.code === PLUGIN_VIEW_NOT_SHOWN_CODE) { + return { + pluginKey, + panelId: panel.panelId, + title: panel.title, + notShown: reply.message } - }, - RENDER_TIMEOUT_MS + actsTimeoutMs + REPLY_GRACE_MS - ) - if (ifShown && !reply.ok && reply.code === PLUGIN_VIEW_NOT_SHOWN_CODE) { + } + const error = failed(reply) + if (error) { + throw error + } + const drawn = reply.ok ? reply.panel : undefined + if (!drawn) { + throw new Error('Orca did not report where the panel is drawn.') + } + const guest = + drawn.ui === 'html' + ? deps.guestsOf(pluginKey).find((each) => each.getURL() === drawn.guestUrl) + : undefined + await settlePluginFrameGuest(guest) + const image = await capturePluginPanelPng( + contents, + drawn.rect, + guest && drawn.guestRect + ? { contents: guest, rect: drawn.guestRect, fromBitmap: deps.imageFromBitmap } + : undefined + ) + const logged = deps + .logsSince(pluginKey, cursor) + .lines.filter((line) => line.level === 'error') + .map((line) => line.line) return { pluginKey, panelId: panel.panelId, title: panel.title, - notShown: reply.message + ui: drawn.ui, + png: image.png.toString('base64'), + width: image.width, + height: image.height, + colorScheme: drawn.colorScheme, + themeApplied: drawn.themeApplied, + ...(themeReason ? { themeReason } : {}), + settled: drawn.settled, + errors: [...(drawn.issue ? [drawn.issue] : []), ...logged].slice(0, MAX_ERRORS), + ...(drawn.pendingRequests === undefined + ? {} + : { pendingRequests: drawn.pendingRequests }), + ...(drawn.actions ? { actions: drawn.actions } : {}) } + } finally { + const ended = await requestPluginViewFromRenderer( + contents, + { kind: 'end-capture' }, + OPEN_TIMEOUT_MS + ).catch(() => null) + restored = ended?.ok ? ended.restored : undefined } - const error = failed(reply) - if (error) { - throw error - } - const drawn = reply.ok ? reply.panel : undefined - if (!drawn) { - throw new Error('Orca did not report where the panel is drawn.') - } - const guest = - drawn.ui === 'html' - ? deps.guestsOf(pluginKey).find((each) => each.getURL() === drawn.guestUrl) - : undefined - await settlePluginFrameGuest(guest) - const image = await capturePluginPanelPng( - contents, - drawn.rect, - guest && drawn.guestRect - ? { contents: guest, rect: drawn.guestRect, fromBitmap: deps.imageFromBitmap } - : undefined - ) - const logged = deps - .logsSince(pluginKey, cursor) - .lines.filter((line) => line.level === 'error') - .map((line) => line.line) - return { - pluginKey, - panelId: panel.panelId, - title: panel.title, - ui: drawn.ui, - png: image.png.toString('base64'), - width: image.width, - height: image.height, - colorScheme: drawn.colorScheme, - themeApplied: drawn.themeApplied, - ...(themeReason ? { themeReason } : {}), - settled: drawn.settled, - errors: [...(drawn.issue ? [drawn.issue] : []), ...logged].slice(0, MAX_ERRORS), - ...(drawn.actions ? { actions: drawn.actions } : {}) - } - } finally { - await requestPluginViewFromRenderer( - contents, - { kind: 'end-capture' }, - OPEN_TIMEOUT_MS - ).catch(() => undefined) - } + })() + // After --act: whether the panel's atoms were put back once the capture ended. + return 'png' in shot && acts ? { ...shot, restored: restored === true } : shot }) } } diff --git a/src/main/plugins/view/plugin-view-reply-schema.ts b/src/main/plugins/view/plugin-view-reply-schema.ts index 34acb132827..9d30be21b7c 100644 --- a/src/main/plugins/view/plugin-view-reply-schema.ts +++ b/src/main/plugins/view/plugin-view-reply-schema.ts @@ -21,6 +21,7 @@ const drawnPanelSchema = z.object({ colorScheme: z.enum(['light', 'dark']), themeApplied: z.boolean(), settled: z.boolean(), + pendingRequests: z.number().int().nonnegative().optional(), actions: z.array(pluginShotActResultSchema).max(PLUGIN_SHOT_MAX_ACTS).optional() }) @@ -29,7 +30,8 @@ export const pluginViewReplySchema: z.ZodType = z.union([ z.object({ requestId: z.string().max(128), ok: z.literal(true), - panel: drawnPanelSchema.optional() + panel: drawnPanelSchema.optional(), + restored: z.boolean().optional() }), z.object({ requestId: z.string().max(128), diff --git a/src/renderer/src/components/plugins/declarative/PluginDeclarativeTable.tsx b/src/renderer/src/components/plugins/declarative/PluginDeclarativeTable.tsx index ac29ecec718..4769fd0b392 100644 --- a/src/renderer/src/components/plugins/declarative/PluginDeclarativeTable.tsx +++ b/src/renderer/src/components/plugins/declarative/PluginDeclarativeTable.tsx @@ -100,6 +100,7 @@ export function PluginDeclarativeTable({ defaultValue: props.defaultSelected, fallback: [], acked: props.$edit, + actTarget: props, callback: selectionCallback, send: (callback, value, edit) => emit(callback, [{ keys: [...value] }], { edit }) }) diff --git a/src/renderer/src/components/plugins/declarative/PluginDeclarativeTree.tsx b/src/renderer/src/components/plugins/declarative/PluginDeclarativeTree.tsx index 1fa0fee7ea3..8d9a06f28de 100644 --- a/src/renderer/src/components/plugins/declarative/PluginDeclarativeTree.tsx +++ b/src/renderer/src/components/plugins/declarative/PluginDeclarativeTree.tsx @@ -4,6 +4,7 @@ import { LoadingSpinner } from '@/components/LoadingSpinner' import { translate } from '@/i18n/i18n' import type { PluginDeclarativeProps } from '../../../../../shared/plugins/declarative/plugin-declarative-catalog' import { usePluginDeclarativeHostValue } from './plugin-declarative-host-value' +import { usePluginDeclarativeActExpansion } from './plugin-declarative-act-targets' import type { PluginDeclarativeEmit } from './PluginDeclarativeControls' import { PluginDeclarativeIconGlyph } from './plugin-declarative-icons' import { visibleTreeRows, type PluginDeclarativeTreeRow } from './plugin-declarative-tree-rows' @@ -35,6 +36,7 @@ export function PluginDeclarativeTree({ defaultValue: props.defaultSelected, fallback: '', acked: props.$edit, + actTarget: props, callback: props.onSelect?.$callback, send: (callback, key, edit) => emit(callback, [{ key }], { edit }) }) @@ -50,22 +52,25 @@ export function PluginDeclarativeTree({ elements.current.get(row.item.key)?.focus() } } - const toggle = (row: ItemRow, open: boolean): void => { - if (!row.expandable || row.expanded === open) { - return - } + const setExpanded = (key: string, open: boolean): void => { setOpenItems((previous) => { const keys = new Set(previous.keys) if (open) { - keys.add(row.item.key) + keys.add(key) } else { - keys.delete(row.item.key) + keys.delete(key) } return { ...previous, keys } }) const callback = props.onToggle?.$callback if (callback) { - emit(callback, [{ key: row.item.key, expanded: open }]) + emit(callback, [{ key, expanded: open }]) + } + } + usePluginDeclarativeActExpansion(props, { expanded: () => expanded, set: setExpanded }) + const toggle = (row: ItemRow, open: boolean): void => { + if (row.expandable && row.expanded !== open) { + setExpanded(row.item.key, open) } } const select = (row: ItemRow): void => { diff --git a/src/renderer/src/components/plugins/declarative/plugin-declarative-act-targets.ts b/src/renderer/src/components/plugins/declarative/plugin-declarative-act-targets.ts index 1ae3a87bf0a..94708b9faae 100644 --- a/src/renderer/src/components/plugins/declarative/plugin-declarative-act-targets.ts +++ b/src/renderer/src/components/plugins/declarative/plugin-declarative-act-targets.ts @@ -35,9 +35,10 @@ export function usePluginDeclarativeActTarget( fallback: T, live: { value: T; change: (next: T) => void; readOnly: boolean } ): void { - const liveRef = useRef(live) + // Why the fallback rides along: a Table's `[]` is a new array every render. + const liveRef = useRef({ ...live, fallback }) useLayoutEffect(() => { - liveRef.current = live + liveRef.current = { ...live, fallback } }) useLayoutEffect(() => { if (!props) { @@ -47,7 +48,7 @@ export function usePluginDeclarativeActTarget( value: () => liveRef.current.value, readOnly: () => liveRef.current.readOnly, change: (next) => { - if (!isSameKind(next, fallback)) { + if (!isSameKind(next, liveRef.current.fallback)) { return false } liveRef.current.change(next) @@ -60,5 +61,42 @@ export function usePluginDeclarativeActTarget( targets.delete(props) } } - }, [props, fallback]) + }, [props]) +} + +/** A mounted Tree's expanded items, which Orca holds while the person browses. */ +export type PluginDeclarativeActExpansion = { + expanded(): ReadonlySet + /** Opens or closes `key` as a click on its chevron would. */ + set(key: string, open: boolean): void +} + +const expansions = new WeakMap() + +export function pluginDeclarativeActExpansion( + props: PluginDeclarativeDrawnProps +): PluginDeclarativeActExpansion | null { + return expansions.get(props) ?? null +} + +export function usePluginDeclarativeActExpansion( + props: PluginDeclarativeDrawnProps, + live: PluginDeclarativeActExpansion +): void { + const liveRef = useRef(live) + useLayoutEffect(() => { + liveRef.current = live + }) + useLayoutEffect(() => { + const expansion: PluginDeclarativeActExpansion = { + expanded: () => liveRef.current.expanded(), + set: (key, open) => liveRef.current.set(key, open) + } + expansions.set(props, expansion) + return () => { + if (expansions.get(props) === expansion) { + expansions.delete(props) + } + } + }, [props]) } diff --git a/src/renderer/src/components/plugins/view/plugin-view-act-test-harness.tsx b/src/renderer/src/components/plugins/view/plugin-view-act-test-harness.tsx new file mode 100644 index 00000000000..b018390c240 --- /dev/null +++ b/src/renderer/src/components/plugins/view/plugin-view-act-test-harness.tsx @@ -0,0 +1,70 @@ +import { act, render } from '@testing-library/react' +import { TooltipProvider } from '@/components/ui/tooltip' +import { parsePluginDeclarativeTree } from '../../../../../shared/plugins/declarative/plugin-declarative-tree' +import type { PluginDeclarativeNode } from '../../../../../shared/plugins/declarative/plugin-declarative-catalog' +import type { PluginShotAct } from '../../../../../shared/plugins/view/plugin-shot-acts' +import { PluginDeclarativeView } from '../declarative/PluginDeclarativeView' +import type { PluginDeclarativeEmit } from '../declarative/PluginDeclarativeControls' +import { + pluginDeclarativeActExpansion, + pluginDeclarativeActTarget +} from '../declarative/plugin-declarative-act-targets' +import type { PluginPanelActDriver } from '../../right-sidebar/plugin-panel-act-driver' +import { runPluginPanelActs } from './plugin-view-acts' + +export const cb = (id: string) => ({ $callback: id }) +export const node = ( + type: string, + props: Record = {}, + children: unknown[] = [] +) => ({ type, props, children }) + +function parse(raw: unknown): PluginDeclarativeNode { + const parsed = parsePluginDeclarativeTree(raw) + if (!parsed.ok || !parsed.tree) { + throw new Error(parsed.ok ? 'empty tree' : parsed.error) + } + return parsed.tree +} + +export type SentEvent = { callback: string; args: unknown[]; edit?: number } + +/** + * A fake guest under Orca's real drawn view: `build` is its render, `handle` its callbacks, and + * each callback re-renders it, as a real guest's do. `run` drives it as `shot --act` would. + */ +export function mountActGuest(build: () => unknown, handle: (event: SentEvent) => void = () => {}) { + const sent: SentEvent[] = [] + let tree: PluginDeclarativeNode | null = null + const receive = (callback: string, args: unknown[], edit?: number): void => { + const event = { callback, args, ...(edit === undefined ? {} : { edit }) } + sent.push(event) + handle(event) + draw() + } + const onEvent: PluginDeclarativeEmit = (callback, args, options = {}) => + receive(callback, args, options.edit) + const view = () => ( + + + + ) + const result = render(view()) + function draw(): void { + tree = parse(build()) + result.rerender(view()) + } + act(() => draw()) + const driver: Pick = { + tree: () => tree, + send: (callback, args) => act(() => receive(callback, args)) + } + const run = (acts: PluginShotAct[]) => + runPluginPanelActs(acts, { + driver, + targetOf: pluginDeclarativeActTarget, + expansionOf: pluginDeclarativeActExpansion, + settle: () => act(async () => {}) + }) + return { sent, run } +} diff --git a/src/renderer/src/components/plugins/view/plugin-view-acts.test.tsx b/src/renderer/src/components/plugins/view/plugin-view-acts.test.tsx index 02732732990..65fe3472140 100644 --- a/src/renderer/src/components/plugins/view/plugin-view-acts.test.tsx +++ b/src/renderer/src/components/plugins/view/plugin-view-acts.test.tsx @@ -1,42 +1,17 @@ // @vitest-environment happy-dom -import { act, cleanup, render, screen } from '@testing-library/react' +import { cleanup, screen } from '@testing-library/react' import { afterEach, describe, expect, it } from 'vitest' -import { TooltipProvider } from '@/components/ui/tooltip' -import { parsePluginDeclarativeTree } from '../../../../../shared/plugins/declarative/plugin-declarative-tree' -import type { PluginDeclarativeNode } from '../../../../../shared/plugins/declarative/plugin-declarative-catalog' import type { PluginShotAct } from '../../../../../shared/plugins/view/plugin-shot-acts' -import { PluginDeclarativeView } from '../declarative/PluginDeclarativeView' -import type { PluginDeclarativeEmit } from '../declarative/PluginDeclarativeControls' -import { pluginDeclarativeActTarget } from '../declarative/plugin-declarative-act-targets' -import type { PluginPanelActDriver } from '../../right-sidebar/plugin-panel-act-driver' -import { runPluginPanelActs } from './plugin-view-acts' +import { cb, mountActGuest, node } from './plugin-view-act-test-harness' afterEach(cleanup) -const cb = (id: string) => ({ $callback: id }) -const node = (type: string, props: Record = {}, children: unknown[] = []) => ({ - type, - props, - children -}) - -function parse(raw: unknown): PluginDeclarativeNode { - const parsed = parsePluginDeclarativeTree(raw) - if (!parsed.ok || !parsed.tree) { - throw new Error(parsed.ok ? 'empty tree' : parsed.error) - } - return parsed.tree -} - -/** A tiny todo guest: Orca draws its tree, and its callbacks re-render it, as a real guest's do. */ +/** A tiny todo guest. */ function mountTodoGuest() { const tasks: string[] = [] const state = { draft: '', edit: 0, tasks, hideDone: false } - const sent: { callback: string; args: unknown[]; edit?: number }[] = [] - const listeners = new Set<() => void>() - let tree: PluginDeclarativeNode | null = null - const build = () => - parse( + const { sent, run } = mountActGuest( + () => node('Stack', {}, [ node('Input', { label: 'New task', @@ -60,51 +35,21 @@ function mountTodoGuest() { ]), node('Tab', { value: 'done', label: 'Done' }, [node('Text', {}, ['Nothing done yet'])]) ]) - ]) - ) - const handle = (callback: string, args: unknown[], edit?: number): void => { - sent.push({ callback, args, ...(edit === undefined ? {} : { edit }) }) - if (callback === 'draft' && typeof args[0] === 'string') { - state.draft = args[0] - state.edit = Math.max(state.edit, edit ?? 0) - } else if (callback === 'submit' || callback === 'add') { - if (state.draft) { - state.tasks.push(state.draft) + ]), + ({ callback, args, edit }) => { + if (callback === 'draft' && typeof args[0] === 'string') { + state.draft = args[0] + state.edit = Math.max(state.edit, edit ?? 0) + } else if (callback === 'submit' || callback === 'add') { + if (state.draft) { + state.tasks.push(state.draft) + } + state.draft = '' + } else if (callback === 'hide') { + state.hideDone = args[0] === true } - state.draft = '' - } else if (callback === 'hide') { - state.hideDone = args[0] === true } - draw() - } - const onEvent: PluginDeclarativeEmit = (callback, args, options = {}) => - handle(callback, args, options.edit) - const view = () => ( - - - ) - const result = render(view()) - function draw(): void { - tree = build() - result.rerender(view()) - listeners.forEach((listener) => listener()) - } - act(() => draw()) - const driver: PluginPanelActDriver = { - tree: () => tree, - send: (callback, args) => act(() => handle(callback, args)), - onDraw: (listener) => { - listeners.add(listener) - return () => listeners.delete(listener) - } - } - const run = (acts: PluginShotAct[]) => - runPluginPanelActs(acts, { - driver, - targetOf: pluginDeclarativeActTarget, - settle: () => act(async () => {}) - }) return { state, sent, run } } diff --git a/src/renderer/src/components/plugins/view/plugin-view-acts.ts b/src/renderer/src/components/plugins/view/plugin-view-acts.ts index b5dc56df7c3..b69522c21df 100644 --- a/src/renderer/src/components/plugins/view/plugin-view-acts.ts +++ b/src/renderer/src/components/plugins/view/plugin-view-acts.ts @@ -10,33 +10,20 @@ import { optionsOf } from '../../../../../shared/plugins/declarative/testing/tes import { isControlValue } from '../../../../../shared/plugins/declarative/testing/testing-value-controls' import type { PluginShotAct, - PluginShotActResult, - PluginShotQuery + PluginShotActResult } from '../../../../../shared/plugins/view/plugin-shot-acts' -import type { - PluginDeclarativeActTarget, - PluginDeclarativeDrawnProps -} from '../declarative/plugin-declarative-act-targets' -import type { PluginPanelActDriver } from '../../right-sidebar/plugin-panel-act-driver' +import type { PluginDeclarativeActTarget } from '../declarative/plugin-declarative-act-targets' +import { + callbackId, + runPluginPanelDataAct, + type PluginPanelActContext, + type PluginPanelActDeps +} from './plugin-view-data-acts' -export type PluginPanelActDeps = { - driver: PluginPanelActDriver - targetOf(props: PluginDeclarativeDrawnProps): PluginDeclarativeActTarget | null - /** Resolves once the panel has drawn what the last act caused. */ - settle(): Promise -} +export type { PluginPanelActDeps } from './plugin-view-data-acts' const NOT_RUN = 'not run: an earlier action failed' -function callbackId(value: unknown): string | null { - return typeof value === 'object' && - value !== null && - '$callback' in value && - typeof value.$callback === 'string' - ? value.$callback - : null -} - const TAKES = { type: { types: ['Input', 'Textarea'], words: 'an Input or Textarea' }, select: { types: ['Select', 'RadioGroup', 'Tabs'], words: 'a Select, RadioGroup or Tabs' }, @@ -52,103 +39,120 @@ function expectTaken(element: TestElement, verb: keyof typeof TAKES): void { } } -/** Runs each act on what Orca draws, as the test kit's verbs do; stops at the first failure. */ -export async function runPluginPanelActs( - acts: readonly PluginShotAct[], - { driver, targetOf, settle }: PluginPanelActDeps -): Promise { +function createActContext({ + driver, + targetOf, + expansionOf, + settle +}: PluginPanelActDeps): PluginPanelActContext { const valueOf = (element: TestElement) => { const value = targetOf(element.props)?.value() return isControlValue(value) ? value : '' } const elements = (): TestElement[] => visibleElements(listElements(driver.tree()), valueOf) - const resolve = (query: PluginShotQuery, verb: string): TestElement => { - const found = innermost(elements().filter((element) => matchesQuery(element, query)))[0] - if (!found) { - throw new Error(`${verb}: nothing in the panel matches { ${describeQuery(query)} }`) - } - if (found.disabled) { - throw new Error(`${verb}: the ${found.type} is disabled`) - } - return found - } - const editable = (element: TestElement, verb: string): PluginDeclarativeActTarget => { - const target = targetOf(element.props) - if (!target) { - throw new Error(`${verb}: the ${element.type} is not on screen`) - } - if (target.readOnly()) { - throw new Error(`${verb}: the ${element.type} is read-only (a value and no onChange)`) - } - return target - } - const change = (target: PluginDeclarativeActTarget, next: unknown, verb: string): void => { - if (!target.change(next)) { - throw new Error(`${verb}: the control does not take ${JSON.stringify(next)}`) + return { + elements, + settle, + expansionOf, + resolve: (query, verb) => { + const found = innermost(elements().filter((element) => matchesQuery(element, query)))[0] + if (!found) { + throw new Error(`${verb}: nothing in the panel matches { ${describeQuery(query)} }`) + } + if (found.disabled) { + throw new Error(`${verb}: the ${found.type} is disabled`) + } + return found + }, + editable: (element, verb) => { + const target = targetOf(element.props) + if (!target) { + throw new Error(`${verb}: the ${element.type} is not on screen`) + } + if (target.readOnly()) { + throw new Error(`${verb}: the ${element.type} is read-only (a value and no onChange)`) + } + return target + }, + change: (target: PluginDeclarativeActTarget, next, verb) => { + if (!target.change(next)) { + throw new Error(`${verb}: the control does not take ${JSON.stringify(next)}`) + } + }, + send: async (callback, args, missing) => { + if (callback === null) { + throw new Error(missing) + } + driver.send(callback, args) + await settle() } } - const send = async (callback: string | null, args: string[], missing: string) => { - if (callback === null) { - throw new Error(missing) - } - driver.send(callback, args) - await settle() - } +} - const run = async (act: PluginShotAct): Promise => { - if ('press' in act) { - const element = resolve(act.press, 'press') - const onPress = callbackId(element.props.onPress) - // Acts are not a person's input: a Link's href stays unopened and no gesture is granted. +async function runFormAct(act: PluginShotAct, context: PluginPanelActContext): Promise { + const { resolve, editable, change, send, settle } = context + if ('press' in act) { + const element = resolve(act.press, 'press') + // Acts are not a person's input: a Link's href stays unopened and no gesture is granted. + await send( + callbackId(element.props.onPress), + [], + element.type === 'Link' && typeof element.props.href === 'string' + ? "press: --act does not open a Link's href; only a person's click does" + : `press: the ${element.type} has no onPress` + ) + return true + } + if ('type' in act) { + const element = resolve(act.type, 'type') + expectTaken(element, 'type') + const target = editable(element, 'type') + let value = act.replace ? '' : String(target.value()) + if (act.replace) { + change(target, value, 'type') + } + for (const character of act.text) { + value += character + change(target, value, 'type') + } + await settle() + if (act.submit) { await send( - onPress, - [], - element.type === 'Link' && typeof element.props.href === 'string' - ? "press: --act does not open a Link's href; only a person's click does" - : `press: the ${element.type} has no onPress` + callbackId(element.props.onSubmit), + [String(target.value())], + `type: the ${element.type} has no onSubmit` ) - return } - if ('type' in act) { - const element = resolve(act.type, 'type') - expectTaken(element, 'type') - const target = editable(element, 'type') - let value = act.replace ? '' : String(target.value()) - if (act.replace) { - change(target, value, 'type') - } - for (const character of act.text) { - value += character - change(target, value, 'type') - } - await settle() - if (act.submit) { - await send( - callbackId(element.props.onSubmit), - [String(target.value())], - `type: the ${element.type} has no onSubmit` - ) - } - return - } - if ('select' in act) { - const element = resolve(act.select, 'select') - expectTaken(element, 'select') - const option = optionsOf(element, elements()).find((entry) => entry.value === act.value) - if (!option || option.disabled) { - throw new Error(`select: the ${element.type} has no enabled option "${act.value}"`) - } - change(editable(element, 'select'), act.value, 'select') - await settle() - return + return true + } + if ('select' in act) { + const element = resolve(act.select, 'select') + expectTaken(element, 'select') + const option = optionsOf(element, context.elements()).find((entry) => entry.value === act.value) + if (!option || option.disabled) { + throw new Error(`select: the ${element.type} has no enabled option "${act.value}"`) } + change(editable(element, 'select'), act.value, 'select') + await settle() + return true + } + if ('toggle' in act) { const element = resolve(act.toggle, 'toggle') expectTaken(element, 'toggle') const target = editable(element, 'toggle') change(target, target.value() !== true, 'toggle') await settle() + return true } + return false +} +/** Runs each act on what Orca draws, as the test kit's verbs do; stops at the first failure. */ +export async function runPluginPanelActs( + acts: readonly PluginShotAct[], + deps: PluginPanelActDeps +): Promise { + const context = createActContext(deps) const results: PluginShotActResult[] = [] for (const act of acts) { if (results.some((result) => !result.ok)) { @@ -156,7 +160,9 @@ export async function runPluginPanelActs( continue } try { - await run(act) + if (!(await runFormAct(act, context))) { + await runPluginPanelDataAct(act, context) + } results.push({ ok: true }) } catch (error) { results.push({ ok: false, error: error instanceof Error ? error.message : String(error) }) diff --git a/src/renderer/src/components/plugins/view/plugin-view-capture-acts.ts b/src/renderer/src/components/plugins/view/plugin-view-capture-acts.ts new file mode 100644 index 00000000000..3d91146ec3d --- /dev/null +++ b/src/renderer/src/components/plugins/view/plugin-view-capture-acts.ts @@ -0,0 +1,65 @@ +import type { + PluginShotAct, + PluginShotActResult +} from '../../../../../shared/plugins/view/plugin-shot-acts' +import { + pluginDeclarativeActExpansion, + pluginDeclarativeActTarget +} from '../declarative/plugin-declarative-act-targets' +import { + pluginPanelActDriver, + type PluginPanelActDriver +} from '../../right-sidebar/plugin-panel-act-driver' +import { runPluginPanelActs } from './plugin-view-acts' +import { + PLUGIN_PANEL_ACT_FIRST_DRAW_MS, + PLUGIN_PANEL_SHOT_FIRST_QUIET_MS, + settlePluginPanel +} from './plugin-view-panel-settle' + +// The panel `--act` changed, until `end-capture` puts its atoms back. +let acted: PluginPanelActDriver | null = null + +/** + * A drawn components panel before its capture: waits for its worker's answers, then runs `acts` + * (remembering the panel's atoms first). Not ok: acts for a panel that is not drawn components. + */ +export async function settleAndActOnPanel( + tabKey: string, + ui: 'components' | 'html' | undefined, + acts: readonly PluginShotAct[] | undefined +): Promise< + { ok: true; pendingRequests?: number; actions?: PluginShotActResult[] } | { ok: false } +> { + const driver = ui === 'components' ? pluginPanelActDriver(tabKey) : null + if (!driver) { + return acts ? { ok: false } : { ok: true } + } + await settlePluginPanel(driver, PLUGIN_PANEL_SHOT_FIRST_QUIET_MS) + if (!acts) { + return { ok: true, pendingRequests: driver.pending() } + } + acted = driver + driver.snapshot() + const actions = await runPluginPanelActs(acts, { + driver, + targetOf: pluginDeclarativeActTarget, + expansionOf: pluginDeclarativeActExpansion, + settle: () => settlePluginPanel(driver, PLUGIN_PANEL_ACT_FIRST_DRAW_MS) + }) + return { ok: true, pendingRequests: driver.pending(), actions } +} + +/** After the capture: the acted panel's atoms back, drawn; undefined when nothing acted. */ +export async function restoreActedPanel(): Promise { + const driver = acted + acted = null + if (!driver) { + return undefined + } + const restored = driver.restore() + if (restored) { + await settlePluginPanel(driver, PLUGIN_PANEL_ACT_FIRST_DRAW_MS) + } + return restored +} diff --git a/src/renderer/src/components/plugins/view/plugin-view-data-acts.test.tsx b/src/renderer/src/components/plugins/view/plugin-view-data-acts.test.tsx new file mode 100644 index 00000000000..ff61949f01a --- /dev/null +++ b/src/renderer/src/components/plugins/view/plugin-view-data-acts.test.tsx @@ -0,0 +1,164 @@ +// @vitest-environment happy-dom +import { cleanup, screen } from '@testing-library/react' +import { afterEach, describe, expect, it } from 'vitest' +import { cb, mountActGuest, node } from './plugin-view-act-test-harness' + +afterEach(cleanup) + +const FILES = ['b.ts', 'a.ts', 'c.ts'] + +/** A file browser guest: a sortable, selectable, paged Table, a lazy Tree and a Slider. */ +type FilesState = { + sort: { column: string; direction: string } + selected: readonly string[] + opened: string[] + pages: number + lazy: boolean + treeSelected: string + volume: number +} + +function mountFilesGuest() { + const state: FilesState = { + sort: { column: 'name', direction: 'asc' }, + selected: [], + opened: [], + pages: 1, + lazy: false, + treeSelected: '', + volume: 3 + } + const guest = mountActGuest( + () => + node('Stack', {}, [ + node('Table', { + label: 'Files', + columns: [ + { key: 'name', label: 'Name', sortable: true }, + { key: 'size', label: 'Size' } + ], + rows: FILES.map((name) => ({ key: name, cells: { name, size: 1 } })), + sort: state.sort, + selectionMode: 'multiple', + selected: [...state.selected], + hasMore: state.pages < 5, + onSortChange: cb('sort'), + onSelectionChange: cb('select'), + onRowAction: cb('open'), + onLoadMore: cb('more') + }), + node('Tree', { + label: 'Folders', + items: [ + { + key: 'src', + label: 'src', + hasChildren: true, + ...(state.lazy ? { children: [{ key: 'src/main.ts', label: 'main.ts' }] } : {}) + }, + { key: 'README.md', label: 'README.md' } + ], + selected: state.treeSelected, + onToggle: cb('toggle'), + onSelect: cb('pick'), + onAction: cb('run') + }), + node('Slider', { + label: 'Volume', + min: 0, + max: 10, + value: state.volume, + onChange: cb('vol') + }) + ]), + ({ callback, args }) => { + const arg = args[0] + const field = (name: string): unknown => + typeof arg === 'object' && arg !== null && name in arg + ? Object.entries(arg).find(([key]) => key === name)?.[1] + : undefined + if (callback === 'sort') { + state.sort = { column: String(field('column')), direction: String(field('direction')) } + } else if (callback === 'select') { + const keys = field('keys') + state.selected = Array.isArray(keys) ? keys.map(String) : [] + } else if (callback === 'open') { + state.opened.push(String(field('key'))) + } else if (callback === 'more') { + state.pages += 1 + } else if (callback === 'toggle') { + state.lazy = field('expanded') === true + } else if (callback === 'pick') { + state.treeSelected = String(field('key')) + } else if (callback === 'vol' && typeof arg === 'number') { + state.volume = arg + } + } + ) + return { ...guest, state } +} + +describe('shot --act Table, Tree and Slider verbs', () => { + it('sorts, selects, activates and pages a Table as its header, rows and scroll would', async () => { + const guest = mountFilesGuest() + const table = { type: 'Table' } + // Orca itself asks for more once the last row shows; the act asks once more on top. + const pagesBefore = guest.state.pages + expect( + await guest.run([ + { sort: table, column: 'name' }, + { selectRows: table, keys: ['a.ts', 'c.ts'] }, + { activateRow: table, key: 'b.ts' }, + { loadMore: table } + ]) + ).toEqual([{ ok: true }, { ok: true }, { ok: true }, { ok: true }]) + // Ascending was on, so the header flips it. + expect(guest.state.sort).toEqual({ column: 'name', direction: 'desc' }) + expect(guest.state.selected).toEqual(['a.ts', 'c.ts']) + expect(guest.state.opened).toEqual(['b.ts']) + expect(guest.state.pages).toBeGreaterThan(pagesBefore) + // The last page: the guest re-renders without hasMore on its next event. + guest.state.pages = 5 + await guest.run([{ activateRow: table, key: 'a.ts' }]) + expect(await guest.run([{ loadMore: table }])).toEqual([ + { ok: false, error: 'loadMore: the Table has no more rows (hasMore and onLoadMore)' } + ]) + expect(await guest.run([{ sort: table, column: 'size' }])).toEqual([ + { ok: false, error: 'sort: the Table has no sortable column "size"' } + ]) + expect(await guest.run([{ activateRow: table, key: 'z.ts' }])).toEqual([ + { ok: false, error: 'activateRow: the Table has no enabled row "z.ts"' } + ]) + }) + + it('expands a lazy Tree item, selects and activates what it loaded, then collapses it', async () => { + const guest = mountFilesGuest() + const tree = { label: 'Folders' } + expect( + await guest.run([ + { expand: tree, key: 'src' }, + { selectItem: tree, key: 'src/main.ts' }, + { activateItem: tree, key: 'src/main.ts' } + ]) + ).toEqual([{ ok: true }, { ok: true }, { ok: true }]) + expect(screen.getByRole('treeitem', { name: /main\.ts/ })).toBeTruthy() + expect(guest.state.treeSelected).toBe('src/main.ts') + // Already open: nothing more is sent, as the kit does. + await guest.run([{ expand: tree, key: 'src' }]) + expect(guest.sent.filter((event) => event.callback === 'toggle')).toHaveLength(1) + await guest.run([{ collapse: tree, key: 'src' }]) + expect(guest.state.lazy).toBe(false) + expect(await guest.run([{ expand: tree, key: 'README.md' }])).toEqual([ + { ok: false, error: 'expand: the Tree item "README.md" has no children' } + ]) + }) + + it('slides within the bounds only', async () => { + const guest = mountFilesGuest() + expect(await guest.run([{ slide: { label: 'Volume' }, value: 7 }])).toEqual([{ ok: true }]) + expect(guest.state.volume).toBe(7) + expect(await guest.run([{ slide: { label: 'Volume' }, value: 11 }])).toEqual([ + { ok: false, error: "slide: 11 is outside the Slider's 0 to 10" } + ]) + }) +}) diff --git a/src/renderer/src/components/plugins/view/plugin-view-data-acts.ts b/src/renderer/src/components/plugins/view/plugin-view-data-acts.ts new file mode 100644 index 00000000000..622665f449a --- /dev/null +++ b/src/renderer/src/components/plugins/view/plugin-view-data-acts.ts @@ -0,0 +1,137 @@ +import type { TestElement } from '../../../../../shared/plugins/declarative/testing/testing-tree' +import { + enabledRow, + expectType, + isExpandable, + nextSort, + treeItem +} from '../../../../../shared/plugins/declarative/testing/testing-data-controls' +import type { PluginDeclarativeEventArg } from '../../../../../shared/plugins/declarative/plugin-declarative-messages' +import type { + PluginShotAct, + PluginShotQuery +} from '../../../../../shared/plugins/view/plugin-shot-acts' +import type { + PluginDeclarativeActExpansion, + PluginDeclarativeActTarget, + PluginDeclarativeDrawnProps +} from '../declarative/plugin-declarative-act-targets' +import type { PluginPanelActDriver } from '../../right-sidebar/plugin-panel-act-driver' + +export type PluginPanelActDeps = { + driver: Pick + targetOf(props: PluginDeclarativeDrawnProps): PluginDeclarativeActTarget | null + expansionOf(props: PluginDeclarativeDrawnProps): PluginDeclarativeActExpansion | null + /** Resolves once the panel has drawn what the last act caused. */ + settle(): Promise +} + +/** What each verb needs of the drawn panel; built once per act list. */ +export type PluginPanelActContext = { + elements(): TestElement[] + resolve(query: PluginShotQuery, verb: string): TestElement + editable(element: TestElement, verb: string): PluginDeclarativeActTarget + change(target: PluginDeclarativeActTarget, next: unknown, verb: string): void + /** Sends `callback`, then settles; throws `missing` when the element has no such handler. */ + send(callback: string | null, args: PluginDeclarativeEventArg[], missing: string): Promise + expansionOf: PluginPanelActDeps['expansionOf'] + settle(): Promise +} + +export function callbackId(value: unknown): string | null { + return typeof value === 'object' && + value !== null && + '$callback' in value && + typeof value.$callback === 'string' + ? value.$callback + : null +} + +async function expandOrCollapse( + tree: TestElement, + key: string, + open: boolean, + context: PluginPanelActContext +): Promise { + const verb = open ? 'expand' : 'collapse' + expectType(tree, 'Tree', verb) + if (!isExpandable(treeItem(tree, key, verb))) { + throw new Error(`${verb}: the Tree item "${key}" has no children`) + } + const expansion = context.expansionOf(tree.props) + if (!expansion) { + throw new Error(`${verb}: the Tree is not on screen`) + } + if (expansion.expanded().has(key) !== open) { + expansion.set(key, open) + await context.settle() + } +} + +/** Slider, Table and Tree verbs, with the test kit's checks and messages. */ +export async function runPluginPanelDataAct( + act: PluginShotAct, + context: PluginPanelActContext +): Promise { + const { resolve, editable, change, send, settle } = context + if ('slide' in act) { + const slider = resolve(act.slide, 'slide') + expectType(slider, 'Slider', 'slide') + const min = typeof slider.props.min === 'number' ? slider.props.min : 0 + const max = typeof slider.props.max === 'number' ? slider.props.max : 100 + if (act.value < min || act.value > max) { + throw new Error(`slide: ${act.value} is outside the Slider's ${min} to ${max}`) + } + change(editable(slider, 'slide'), act.value, 'slide') + await settle() + } else if ('sort' in act) { + const table = resolve(act.sort, 'sort') + expectType(table, 'Table', 'sort') + const sort = nextSort(table, act.column) + await send(callbackId(table.props.onSortChange), [sort], 'sort: the Table has no onSortChange') + } else if ('selectRows' in act) { + const table = resolve(act.selectRows, 'selectRows') + expectType(table, 'Table', 'selectRows') + const mode = table.props.selectionMode ?? 'none' + if (mode === 'none' || (mode === 'single' && act.keys.length > 1)) { + throw new Error(`selectRows: the Table's selectionMode is ${String(mode)}`) + } + act.keys.forEach((key) => enabledRow(table, key, 'selectRows')) + change(editable(table, 'selectRows'), [...act.keys], 'selectRows') + await settle() + } else if ('activateRow' in act) { + const table = resolve(act.activateRow, 'activateRow') + expectType(table, 'Table', 'activateRow') + enabledRow(table, act.key, 'activateRow') + await send( + callbackId(table.props.onRowAction), + [{ key: act.key }], + 'activateRow: the Table has no onRowAction' + ) + } else if ('loadMore' in act) { + const table = resolve(act.loadMore, 'loadMore') + expectType(table, 'Table', 'loadMore') + const more = table.props.hasMore === true ? callbackId(table.props.onLoadMore) : null + await send(more, [], 'loadMore: the Table has no more rows (hasMore and onLoadMore)') + } else if ('expand' in act) { + await expandOrCollapse(resolve(act.expand, 'expand'), act.key, true, context) + } else if ('collapse' in act) { + await expandOrCollapse(resolve(act.collapse, 'collapse'), act.key, false, context) + } else if ('selectItem' in act) { + const tree = resolve(act.selectItem, 'selectItem') + expectType(tree, 'Tree', 'selectItem') + if (treeItem(tree, act.key, 'selectItem').disabled === true) { + throw new Error(`selectItem: the Tree item "${act.key}" is disabled`) + } + change(editable(tree, 'selectItem'), act.key, 'selectItem') + await settle() + } else if ('activateItem' in act) { + const tree = resolve(act.activateItem, 'activateItem') + expectType(tree, 'Tree', 'activateItem') + const action = callbackId(tree.props.onAction) + if (treeItem(tree, act.key, 'activateItem').disabled === true || action === null) { + throw new Error(`activateItem: the Tree item "${act.key}" cannot be activated`) + } + await send(action, [{ key: act.key }], '') + } +} diff --git a/src/renderer/src/components/plugins/view/plugin-view-panel-settle.test.ts b/src/renderer/src/components/plugins/view/plugin-view-panel-settle.test.ts new file mode 100644 index 00000000000..649aec8806a --- /dev/null +++ b/src/renderer/src/components/plugins/view/plugin-view-panel-settle.test.ts @@ -0,0 +1,85 @@ +// @vitest-environment happy-dom +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { + PLUGIN_PANEL_MAX_SETTLE_MS, + PLUGIN_PANEL_SHOT_FIRST_QUIET_MS, + settlePluginPanel +} from './plugin-view-panel-settle' + +function fakePanel() { + let pending = 0 + const listeners = new Set<() => void>() + const changed = (): void => listeners.forEach((listener) => listener()) + return { + driver: { + pending: () => pending, + onChange: (listener: () => void) => { + listeners.add(listener) + return () => listeners.delete(listener) + } + }, + start: () => { + pending += 1 + changed() + }, + answer: () => { + pending -= 1 + changed() + }, + draw: changed, + listening: () => listeners.size + } +} + +function track(promise: Promise): { done: () => boolean } { + let done = false + void promise.then(() => { + done = true + }) + return { done: () => done } +} + +// Past the two painted frames (their 100ms fallbacks) that follow the wait. +const FRAMES_MS = 250 + +beforeEach(() => vi.useFakeTimers()) +afterEach(() => vi.useRealTimers()) + +describe('settlePluginPanel', () => { + it('settles a quiet panel after the first quiet spell', async () => { + const panel = fakePanel() + const settled = track(settlePluginPanel(panel.driver, PLUGIN_PANEL_SHOT_FIRST_QUIET_MS)) + await vi.advanceTimersByTimeAsync(PLUGIN_PANEL_SHOT_FIRST_QUIET_MS - 1) + expect(settled.done()).toBe(false) + await vi.advanceTimersByTimeAsync(1 + FRAMES_MS) + expect(settled.done()).toBe(true) + expect(panel.listening()).toBe(0) + }) + + it("waits for the worker's answer and the tree it causes", async () => { + const panel = fakePanel() + panel.start() + const settled = track(settlePluginPanel(panel.driver, PLUGIN_PANEL_SHOT_FIRST_QUIET_MS)) + await vi.advanceTimersByTimeAsync(2_000) + expect(settled.done()).toBe(false) + panel.answer() + await vi.advanceTimersByTimeAsync(100) + // The answer's tree restarts the quiet spell. + panel.draw() + await vi.advanceTimersByTimeAsync(149) + expect(settled.done()).toBe(false) + await vi.advanceTimersByTimeAsync(1 + FRAMES_MS) + expect(settled.done()).toBe(true) + }) + + it('gives up on a request that never answers at the cap', async () => { + const panel = fakePanel() + panel.start() + const settled = track(settlePluginPanel(panel.driver, PLUGIN_PANEL_SHOT_FIRST_QUIET_MS)) + await vi.advanceTimersByTimeAsync(PLUGIN_PANEL_MAX_SETTLE_MS - 1) + expect(settled.done()).toBe(false) + await vi.advanceTimersByTimeAsync(1 + FRAMES_MS) + expect(settled.done()).toBe(true) + expect(panel.driver.pending()).toBe(1) + }) +}) diff --git a/src/renderer/src/components/plugins/view/plugin-view-panel-settle.ts b/src/renderer/src/components/plugins/view/plugin-view-panel-settle.ts index 160ada76e9c..b9e8ea9992d 100644 --- a/src/renderer/src/components/plugins/view/plugin-view-panel-settle.ts +++ b/src/renderer/src/components/plugins/view/plugin-view-panel-settle.ts @@ -4,6 +4,7 @@ import { subscribePluginPanelDraw, type PluginPanelDrawStatus } from '../../right-sidebar/plugin-panel-draw-status' +import type { PluginPanelActDriver } from '../../right-sidebar/plugin-panel-act-driver' // Why a fallback: a hidden window may not tick animation frames, and a capture must not hang. const FRAME_FALLBACK_MS = 100 @@ -77,27 +78,51 @@ export function measurePluginPanelGuest( } // Why these: a handler that awaits a host call draws well within 1s, a burst of renders ends within -// a quiet 150ms, and 3s caps an act whose panel keeps re-rendering. -const ACT_FIRST_DRAW_MS = 1_000 -const ACT_QUIET_MS = 150 -export const PLUGIN_PANEL_ACT_MAX_SETTLE_MS = 3_000 +// a quiet 150ms, a cold panel asks its worker within 300ms of its first tree, and 3s caps a panel +// that keeps re-rendering or a request that never answers. +export const PLUGIN_PANEL_ACT_FIRST_DRAW_MS = 1_000 +export const PLUGIN_PANEL_SHOT_FIRST_QUIET_MS = 300 +const QUIET_MS = 150 +export const PLUGIN_PANEL_MAX_SETTLE_MS = 3_000 -/** After an act: waits for the trees it causes to stop coming, then for them to paint. */ -export async function settlePluginPanelAfterAct(onDraw: (listener: () => void) => () => void) { +/** + * Waits until the panel has no host call in flight (its worker answered) and no new tree for a + * quiet spell (`firstQuietMs` at first), then for what it drew to paint; at most 3s. + */ +export async function settlePluginPanel( + driver: Pick, + firstQuietMs: number +): Promise { await new Promise((resolve) => { let quiet: ReturnType | undefined + let unsubscribe = (): void => {} const finish = (): void => { clearTimeout(quiet) clearTimeout(cap) unsubscribe() resolve() } - const cap = setTimeout(finish, PLUGIN_PANEL_ACT_MAX_SETTLE_MS) - quiet = setTimeout(finish, ACT_FIRST_DRAW_MS) - const unsubscribe = onDraw(() => { + const arm = (ms: number): void => { clearTimeout(quiet) - quiet = setTimeout(finish, ACT_QUIET_MS) - }) + quiet = driver.pending() > 0 ? undefined : setTimeout(finish, ms) + } + const cap = setTimeout(finish, PLUGIN_PANEL_MAX_SETTLE_MS) + arm(firstQuietMs) + unsubscribe = driver.onChange(() => arm(QUIET_MS)) }) await nextPaintedFrames() } + +// Why a cap: a theme Orca cannot apply must not hold the shot forever. +const COLOR_SCHEME_MAX_FRAMES = 60 + +/** Frames until the document shows the asked color scheme, so the capture is of that repaint. */ +export async function waitForColorScheme(wantDark: boolean | null): Promise { + for (let frame = 0; wantDark !== null && frame < COLOR_SCHEME_MAX_FRAMES; frame += 1) { + if (document.documentElement.classList.contains('dark') === wantDark) { + break + } + await nextFrame() + } + await nextPaintedFrames() +} diff --git a/src/renderer/src/components/plugins/view/plugin-view-request-handler.ts b/src/renderer/src/components/plugins/view/plugin-view-request-handler.ts index 8aaa389cf51..4e5831fb312 100644 --- a/src/renderer/src/components/plugins/view/plugin-view-request-handler.ts +++ b/src/renderer/src/components/plugins/view/plugin-view-request-handler.ts @@ -7,7 +7,6 @@ import { type PluginViewReply, type PluginViewRequest } from '../../../../../shared/plugins/view/plugin-view-protocol' -import type { PluginShotActResult } from '../../../../../shared/plugins/view/plugin-shot-acts' import { detectLanguage } from '@/lib/language-detect' import { canShowRightSidebarForView } from '@/lib/right-sidebar-visibility' import { useAppStore } from '@/store' @@ -23,12 +22,10 @@ import { measurePluginPanelGuest, measurePluginPanelSurface, nextPaintedFrames, - settlePluginPanelAfterAct, + waitForColorScheme, waitForPluginPanelDraw } from './plugin-view-panel-settle' -import { runPluginPanelActs } from './plugin-view-acts' -import { pluginPanelActDriver } from '../../right-sidebar/plugin-panel-act-driver' -import { pluginDeclarativeActTarget } from '../declarative/plugin-declarative-act-targets' +import { restoreActedPanel, settleAndActOnPanel } from './plugin-view-capture-acts' import { pluginPanelNotShownReason } from './plugin-view-shown' type Failure = Extract @@ -103,18 +100,10 @@ async function capturePanel( if (status.value?.failure) { return fail(requestId, 'panel_failed', `The plugin panel ${status.value.failure}.`) } - await nextPaintedFrames() - let actions: PluginShotActResult[] | undefined - if (capture.acts) { - const driver = status.value?.ui === 'components' ? pluginPanelActDriver(tabKey) : null - if (!driver) { - return fail(requestId, 'act_unsupported', 'Only a drawn components panel takes --act.') - } - actions = await runPluginPanelActs(capture.acts, { - driver, - targetOf: pluginDeclarativeActTarget, - settle: () => settlePluginPanelAfterAct(driver.onDraw) - }) + await waitForColorScheme(wantDark) + const prepared = await settleAndActOnPanel(tabKey, status.value?.ui, capture.acts) + if (!prepared.ok) { + return fail(requestId, 'act_unsupported', 'Only a drawn components panel takes --act.') } let rect = measurePluginPanelSurface(tabKey) // The panel sits inside the sidebar's border; one correction makes it exactly --width wide. @@ -122,6 +111,8 @@ async function capturePanel( usePluginViewCaptureStore .getState() .setPanelWidth(capture.width + (capture.width - Math.round(rect.width))) + // A resize relayouts the panel; let it paint before main captures. + await nextPaintedFrames() await nextPaintedFrames() rect = measurePluginPanelSurface(tabKey) } @@ -142,7 +133,10 @@ async function capturePanel( colorScheme: dark ? 'dark' : 'light', themeApplied: wantDark !== null && dark === wantDark, settled: status.settled, - ...(actions ? { actions } : {}) + ...(prepared.pendingRequests === undefined + ? {} + : { pendingRequests: prepared.pendingRequests }), + ...(prepared.actions ? { actions: prepared.actions } : {}) } } } @@ -193,9 +187,15 @@ export async function handlePluginViewRequest( return await openPanel(request) case 'open-editor': return await openEditor(request) - case 'end-capture': + case 'end-capture': { usePluginViewCaptureStore.getState().end() - return { requestId: request.requestId, ok: true } + const restored = await restoreActedPanel() + return { + requestId: request.requestId, + ok: true, + ...(restored === undefined ? {} : { restored }) + } + } } } catch (error) { return fail( diff --git a/src/renderer/src/components/right-sidebar/PluginDeclarativePanel.tsx b/src/renderer/src/components/right-sidebar/PluginDeclarativePanel.tsx index f92737e5549..29cdc2ccb84 100644 --- a/src/renderer/src/components/right-sidebar/PluginDeclarativePanel.tsx +++ b/src/renderer/src/components/right-sidebar/PluginDeclarativePanel.tsx @@ -101,16 +101,6 @@ export function PluginDeclarativePanel({ useReportDeclarativePanelDraw(tabKey, guest.url, rendered?.document ?? null, issue) - usePluginFrameHost({ - surface: 'panel', - frameRef, - frameKey, - sessionToken, - declarative: channel, - consumeHostActivation: consumePress, - onUnresponsive - }) - const shownDocument = rendered?.document ?? '' const revision = rendered?.revision ?? 0 const onEvent = useCallback( @@ -130,7 +120,23 @@ export function PluginDeclarativePanel({ }, [admitPress, revision, sendToGuest, shownDocument] ) - usePluginPanelActDriver(tabKey, rendered?.tree ?? null, onEvent) + const { viewEpoch, trackHostCall } = usePluginPanelActDriver({ + tabKey, + tree: rendered?.tree ?? null, + document: rendered?.document ?? null, + send: onEvent, + sendToGuest + }) + usePluginFrameHost({ + surface: 'panel', + frameRef, + frameKey, + sessionToken, + declarative: channel, + consumeHostActivation: consumePress, + trackHostCall, + onUnresponsive + }) // A click on Orca's own Link (or a Markdown link): no frame-activation check, but its control // must have settled, and main keeps the URL allowlist and rate limit. const onOpenLink = (href: string, gestureId: string): void => { @@ -167,8 +173,8 @@ export function PluginDeclarativePanel({ ) : null} {reloads > 0 ? : null} { await flush() expect(callHostMethod).toHaveBeenCalledOnce() }) + + it('tracks each relayed host call until it settles, so a shot can wait for the worker', async () => { + let answer = (_value: unknown): void => {} + const callHostMethod = vi + .fn() + .mockImplementationOnce(() => new Promise((resolve) => (answer = resolve))) + .mockRejectedValueOnce(new Error('ipc broke')) + let pending = 0 + const trackHostCall = () => { + pending += 1 + return () => { + pending -= 1 + } + } + const { handle } = declarativeGuest({ callHostMethod, trackHostCall }) + const request = (id: number, method: string) => ({ orca: 1, kind: 'req', id, method }) + handle(request(1, 'plugin.request'), guestContext) + handle(request(2, 'storage.get'), guestContext) + // Refused before it reaches main: nothing to wait for. + handle(request(3, 'shell.openExternal'), guestContext) + expect(pending).toBe(2) + await flush() + expect(pending).toBe(1) + answer({ ok: true, value: 1 }) + await flush() + expect(pending).toBe(0) + }) }) diff --git a/src/renderer/src/components/right-sidebar/plugin-frame-host.ts b/src/renderer/src/components/right-sidebar/plugin-frame-host.ts index 9928ac60879..815311c0e24 100644 --- a/src/renderer/src/components/right-sidebar/plugin-frame-host.ts +++ b/src/renderer/src/components/right-sidebar/plugin-frame-host.ts @@ -89,6 +89,8 @@ export type PluginFrameHostOptions = { renderBudget?: PanelMessageBudget /** One-shot activation from a press on Orca's own controls (declarative panels). */ consumeHostActivation?: () => boolean + /** Called as a host call (`plugin.request` included) starts; the result runs when it settles. */ + trackHostCall?: () => () => void now?: () => number } @@ -278,6 +280,7 @@ export function createPluginFrameEnvelopeHandler( respond(pluginFailure(request.id, pluginError('unavailable', 'plugin session is not ready'))) return } + const settled = options.trackHostCall?.() callHostMethod({ sessionToken, action: request.method, params: request.params }) .then((outcome) => respond(pluginOutcomeResponse(request.id, outcome))) .catch((error: unknown) => @@ -288,5 +291,6 @@ export function createPluginFrameEnvelopeHandler( ) ) ) + .finally(() => settled?.()) } } diff --git a/src/renderer/src/components/right-sidebar/plugin-panel-act-driver.test.ts b/src/renderer/src/components/right-sidebar/plugin-panel-act-driver.test.ts new file mode 100644 index 00000000000..416eac07cec --- /dev/null +++ b/src/renderer/src/components/right-sidebar/plugin-panel-act-driver.test.ts @@ -0,0 +1,74 @@ +// @vitest-environment happy-dom +import { act, cleanup, renderHook } from '@testing-library/react' +import { afterEach, describe, expect, it, vi } from 'vitest' +import { pluginPanelActDriver, usePluginPanelActDriver } from './plugin-panel-act-driver' + +afterEach(cleanup) + +function mount(document: string | null = 'doc-1') { + const sendToGuest = vi.fn() + const send = vi.fn() + const hook = renderHook( + (props: { document: string | null }) => + usePluginPanelActDriver({ + tabKey: 'plugin:acme.todos/todos', + tree: null, + document: props.document, + send, + sendToGuest + }), + { initialProps: { document } } + ) + const driver = pluginPanelActDriver('plugin:acme.todos/todos') + if (!driver) { + throw new Error('the panel did not register') + } + return { hook, driver, sendToGuest, send } +} + +describe('usePluginPanelActDriver', () => { + it('counts host calls in flight, telling listeners as each starts and settles', () => { + const { hook, driver } = mount() + const changes = vi.fn() + driver.onChange(changes) + const first = hook.result.current.trackHostCall() + const second = hook.result.current.trackHostCall() + expect(driver.pending()).toBe(2) + first() + first() + expect(driver.pending()).toBe(1) + second() + expect(driver.pending()).toBe(0) + expect(changes).toHaveBeenCalledTimes(4) + }) + + it("snapshots and restores the shown guest's atoms, then redraws Orca's controls", () => { + const { hook, driver, sendToGuest } = mount() + driver.snapshot() + expect(sendToGuest).toHaveBeenLastCalledWith('ui.snapshot', { document: 'doc-1' }) + let restored = false + act(() => { + restored = driver.restore() + }) + expect(restored).toBe(true) + expect(sendToGuest).toHaveBeenLastCalledWith('ui.restore', { document: 'doc-1' }) + expect(hook.result.current.viewEpoch).toBe(1) + // Once: a second restore has nothing to put back. + expect(driver.restore()).toBe(false) + }) + + it('does not restore into a guest that reloaded since the snapshot', () => { + const { hook, driver, sendToGuest } = mount() + driver.snapshot() + hook.rerender({ document: 'doc-2' }) + expect(driver.restore()).toBe(false) + expect(sendToGuest).toHaveBeenCalledTimes(1) + expect(hook.result.current.viewEpoch).toBe(0) + }) + + it('unregisters when the panel unmounts', () => { + const { hook } = mount() + hook.unmount() + expect(pluginPanelActDriver('plugin:acme.todos/todos')).toBeNull() + }) +}) diff --git a/src/renderer/src/components/right-sidebar/plugin-panel-act-driver.ts b/src/renderer/src/components/right-sidebar/plugin-panel-act-driver.ts index 62978a96b5a..62a1905f376 100644 --- a/src/renderer/src/components/right-sidebar/plugin-panel-act-driver.ts +++ b/src/renderer/src/components/right-sidebar/plugin-panel-act-driver.ts @@ -1,17 +1,25 @@ -import { useLayoutEffect, useRef } from 'react' +import { useLayoutEffect, useMemo, useRef, useState } from 'react' import type { PluginDeclarativeNode } from '../../../../shared/plugins/declarative/plugin-declarative-catalog' import type { PluginDeclarativeEventArg } from '../../../../shared/plugins/declarative/plugin-declarative-messages' +import { PLUGIN_DECLARATIVE_MESSAGES } from '../../../../shared/plugins/declarative/plugin-declarative-message-names' /** - * What `orca plugin shot --act` drives on a mounted components panel: the tree on screen and the - * guest callbacks Orca's own controls fire. Sends carry no press, so they never grant a gesture. + * What `orca plugin shot` drives and waits on in a mounted components panel: the tree on screen, + * the guest callbacks Orca's own controls fire, and the host calls in flight. Sends carry no + * press, so they never grant a gesture. */ export type PluginPanelActDriver = { /** The tree React last committed for this panel. */ tree(): PluginDeclarativeNode | null send(callback: string, args: PluginDeclarativeEventArg[]): void - /** Called after each tree this panel commits. */ - onDraw(listener: () => void): () => void + /** Host calls (`plugin.request` included) the panel is still waiting on. */ + pending(): number + /** Called after each committed tree and each change in `pending()`. */ + onChange(listener: () => void): () => void + /** Asks the guest to remember its atoms before `--act`. */ + snapshot(): void + /** Puts them back and redraws Orca's controls; false when that guest is gone (a reload). */ + restore(): boolean } const drivers = new Map() @@ -20,32 +28,70 @@ export function pluginPanelActDriver(tabKey: string): PluginPanelActDriver | nul return drivers.get(tabKey) ?? null } -/** Registers the panel for `tabKey` while it is mounted. */ -export function usePluginPanelActDriver( - tabKey: string, - tree: PluginDeclarativeNode | null, +/** + * Registers the panel for `tabKey` while it is mounted. `viewEpoch` keys Orca's drawn view, so a + * restore also resets what its controls hold locally; `trackHostCall` goes to the frame host. + */ +export function usePluginPanelActDriver(options: { + tabKey: string + tree: PluginDeclarativeNode | null + document: string | null send: (callback: string, args: PluginDeclarativeEventArg[]) => void -): void { + sendToGuest: (event: string, payload: unknown) => void +}): { viewEpoch: number; trackHostCall: () => () => void } { + const { tabKey, tree } = options + const [viewEpoch, setViewEpoch] = useState(0) + const latest = useRef(options) const treeRef = useRef(tree) - const sendRef = useRef(send) - const listenersRef = useRef(new Set<() => void>()) + const [listeners] = useState(() => new Set<() => void>()) + const pendingRef = useRef(0) useLayoutEffect(() => { - sendRef.current = send + latest.current = options }) useLayoutEffect(() => { treeRef.current = tree - for (const listener of listenersRef.current) { - listener() - } - }, [tree]) + listeners.forEach((listener) => listener()) + }, [listeners, tree]) + const trackHostCall = useMemo( + () => () => { + pendingRef.current += 1 + listeners.forEach((listener) => listener()) + let done = false + return () => { + if (!done) { + done = true + pendingRef.current -= 1 + listeners.forEach((listener) => listener()) + } + } + }, + [listeners] + ) useLayoutEffect(() => { - const listeners = listenersRef.current + let snapshotOf: string | null = null const driver: PluginPanelActDriver = { tree: () => treeRef.current, - send: (callback, args) => sendRef.current(callback, args), - onDraw: (listener) => { + send: (callback, args) => latest.current.send(callback, args), + pending: () => pendingRef.current, + onChange: (listener) => { listeners.add(listener) return () => listeners.delete(listener) + }, + snapshot: () => { + snapshotOf = latest.current.document + if (snapshotOf) { + latest.current.sendToGuest(PLUGIN_DECLARATIVE_MESSAGES.snapshot, { document: snapshotOf }) + } + }, + restore: () => { + const document = snapshotOf + snapshotOf = null + if (!document || document !== latest.current.document) { + return false + } + latest.current.sendToGuest(PLUGIN_DECLARATIVE_MESSAGES.restore, { document }) + setViewEpoch((epoch) => epoch + 1) + return true } } drivers.set(tabKey, driver) @@ -54,5 +100,6 @@ export function usePluginPanelActDriver( drivers.delete(tabKey) } } - }, [tabKey]) + }, [listeners, tabKey]) + return { viewEpoch, trackHostCall } } diff --git a/src/renderer/src/components/right-sidebar/use-plugin-frame-host.ts b/src/renderer/src/components/right-sidebar/use-plugin-frame-host.ts index 89a2eab5cf8..5621f41e266 100644 --- a/src/renderer/src/components/right-sidebar/use-plugin-frame-host.ts +++ b/src/renderer/src/components/right-sidebar/use-plugin-frame-host.ts @@ -31,12 +31,22 @@ export function usePluginFrameHost(options: { declarative?: PluginFrameDeclarativeChannel /** Must be stable: a one-shot grant from presses on Orca's own controls. */ consumeHostActivation?: () => boolean + /** Must be stable: counts the panel's host calls in flight. */ + trackHostCall?: () => () => void onUnresponsive: () => void /** The guest's WebContents went away under an unchanged document (closed, crashed). */ onGuestGone?: () => void }): { onFrameLoad: () => void } { - const { surface, frameRef, frameKey, sessionToken, editor, declarative, consumeHostActivation } = - options + const { + surface, + frameRef, + frameKey, + sessionToken, + editor, + declarative, + consumeHostActivation, + trackHostCall + } = options const [loadedFrameKey, setLoadedFrameKey] = useState(null) const onUnresponsiveRef = useRef(options.onUnresponsive) const onGuestGoneRef = useRef(options.onGuestGone) @@ -75,7 +85,8 @@ export function usePluginFrameHost(options: { onPong: (pingId: number) => watchdog.handlePong(pingId), editor, declarative, - consumeHostActivation + consumeHostActivation, + trackHostCall } if (element instanceof HTMLIFrameElement) { const handler = createPluginFrameMessageHandler(hostOptions) @@ -128,6 +139,7 @@ export function usePluginFrameHost(options: { frameRef, getFrameWindow, surface, + trackHostCall, watchdog ]) diff --git a/src/shared/plugins/declarative/plugin-declarative-message-names.ts b/src/shared/plugins/declarative/plugin-declarative-message-names.ts index 728f0321d86..d9cc1e22bb0 100644 --- a/src/shared/plugins/declarative/plugin-declarative-message-names.ts +++ b/src/shared/plugins/declarative/plugin-declarative-message-names.ts @@ -24,7 +24,11 @@ export const PLUGIN_DECLARATIVE_MESSAGES = { /** guest → host, `{ entries: [{ scope, key, version, value }] }`: persisted atoms changed. */ persist: 'ui.persist', /** guest → host, `{ document, entries: [{ key, version, value? }] }`: keyed memory atoms changed. */ - retain: 'ui.retain' + retain: 'ui.retain', + /** host → guest, `{ document }`: remember every atom's value before `orca plugin shot --act`. */ + snapshot: 'ui.snapshot', + /** host → guest, `{ document }`: put the atoms back to the last `ui.snapshot`. */ + restore: 'ui.restore' } as const /** Grows with the component catalog, so plugins can feature-detect with `ui.catalog`. */ diff --git a/src/shared/plugins/declarative/runtime/declarative-act-snapshot.test.ts b/src/shared/plugins/declarative/runtime/declarative-act-snapshot.test.ts new file mode 100644 index 00000000000..4d8480ad7e9 --- /dev/null +++ b/src/shared/plugins/declarative/runtime/declarative-act-snapshot.test.ts @@ -0,0 +1,66 @@ +import { afterEach, describe, expect, it } from 'vitest' +import { + atom, + persistedEntry, + read, + resetAtoms, + set, + watchPersistedAtoms, + type OrcaAtom +} from './declarative-atoms' +import { actSnapshotSubscriptions } from './declarative-act-snapshot' + +function fakeBridge() { + const handlers = new Map void>() + return { + on: (event: string, handler: (payload: unknown) => void) => { + handlers.set(event, handler) + return { dispose: () => handlers.delete(event) } + }, + send: (event: string, payload: unknown) => handlers.get(event)?.(payload) + } +} + +afterEach(() => { + watchPersistedAtoms(null) + resetAtoms() +}) + +describe('shot --act atom snapshot', () => { + it('puts every plugin-written atom back, re-persisting the persisted ones', () => { + const tab = atom('snapshot.tab', 'all', { persist: 'plugin' }) + const draft = atom('snapshot.draft', '') + const count = atom(0) + const persisted: unknown[] = [] + watchPersistedAtoms((target: OrcaAtom) => persisted.push(persistedEntry(target))) + const bridge = fakeBridge() + actSnapshotSubscriptions(bridge.on, 'doc-1') + + bridge.send('ui.snapshot', { document: 'doc-1' }) + set(tab, 'done') + set(draft, 'Ship') + set(count, 3) + persisted.length = 0 + bridge.send('ui.restore', { document: 'doc-1' }) + + expect([read(tab), read(draft), read(count)]).toEqual(['all', '', 0]) + expect(persisted).toEqual([{ scope: 'plugin', key: 'snapshot.tab', version: 1, value: 'all' }]) + }) + + it("ignores another document's messages and restores at most once", () => { + const count = atom(1) + const bridge = fakeBridge() + actSnapshotSubscriptions(bridge.on, 'doc-1') + bridge.send('ui.snapshot', { document: 'doc-2' }) + set(count, 2) + bridge.send('ui.restore', { document: 'doc-1' }) + expect(read(count)).toBe(2) + + bridge.send('ui.snapshot', { document: 'doc-1' }) + set(count, 5) + bridge.send('ui.restore', { document: 'doc-1' }) + set(count, 6) + bridge.send('ui.restore', { document: 'doc-1' }) + expect(read(count)).toBe(6) + }) +}) diff --git a/src/shared/plugins/declarative/runtime/declarative-act-snapshot.ts b/src/shared/plugins/declarative/runtime/declarative-act-snapshot.ts new file mode 100644 index 00000000000..0456bc1726d --- /dev/null +++ b/src/shared/plugins/declarative/runtime/declarative-act-snapshot.ts @@ -0,0 +1,31 @@ +import { PLUGIN_DECLARATIVE_MESSAGES } from '../plugin-declarative-message-names' +import { captureAtomValues } from './declarative-atoms' +import { readHostMessage } from './declarative-host-messages' +import type { OrcaBridge, OrcaDisposable } from './declarative-runtime-types' + +/** + * `orca plugin shot --act` changes the live panel; Orca asks this guest to remember its atoms + * before acting (`ui.snapshot`) and to put them back after the capture (`ui.restore`). Only this + * guest's atoms: what handlers did elsewhere (worker requests, storage writes) stays. + */ +export function actSnapshotSubscriptions( + on: NonNullable, + document: string +): OrcaDisposable[] { + let restore: (() => void) | null = null + const ours = (payload: unknown): boolean => readHostMessage(payload).document === document + return [ + on(PLUGIN_DECLARATIVE_MESSAGES.snapshot, (payload) => { + if (ours(payload)) { + restore = captureAtomValues() + } + }), + on(PLUGIN_DECLARATIVE_MESSAGES.restore, (payload) => { + if (ours(payload) && restore) { + const pending = restore + restore = null + pending() + } + }) + ] +} diff --git a/src/shared/plugins/declarative/runtime/declarative-atoms.ts b/src/shared/plugins/declarative/runtime/declarative-atoms.ts index ec15d9a946f..81718188ff8 100644 --- a/src/shared/plugins/declarative/runtime/declarative-atoms.ts +++ b/src/shared/plugins/declarative/runtime/declarative-atoms.ts @@ -280,6 +280,22 @@ export function applyStorageValue(key: string, value: unknown): void { } } +/** + * `orca plugin shot --act`: remembers every plugin-written atom's value; the returned function + * sets them back as plugin code would, so persisted atoms store their old values again. + */ +export function captureAtomValues(): () => void { + const values = new Map, unknown>() + for (const inner of writableAtoms) { + values.set(inner, inner.value) + } + return () => { + for (const [inner, value] of values) { + assign(inner, value, true) + } + } +} + /** Applies stored values for a scope (on boot, or the workspace's after a workspace switch). */ export function hydrateAtoms( scope: SnapshotScope, diff --git a/src/shared/plugins/declarative/runtime/declarative-renderer.test.ts b/src/shared/plugins/declarative/runtime/declarative-renderer.test.ts index d92eeae2006..f9a965a9dc8 100644 --- a/src/shared/plugins/declarative/runtime/declarative-renderer.test.ts +++ b/src/shared/plugins/declarative/runtime/declarative-renderer.test.ts @@ -335,6 +335,8 @@ describe('declarative runtime', () => { 'ui.ack', 'ui.event', 'ui.hydrate', + 'ui.restore', + 'ui.snapshot', 'ui.visibility' ]) runtime.dispose() diff --git a/src/shared/plugins/declarative/runtime/declarative-renderer.ts b/src/shared/plugins/declarative/runtime/declarative-renderer.ts index 4ed298e7772..674bea7ef7f 100644 --- a/src/shared/plugins/declarative/runtime/declarative-renderer.ts +++ b/src/shared/plugins/declarative/runtime/declarative-renderer.ts @@ -10,6 +10,7 @@ import type { } from './declarative-runtime-types' import { evaluateOrcaTree, type OrcaCallback } from './declarative-evaluate' import { createMemoryRetention } from './declarative-memory-retention' +import { actSnapshotSubscriptions } from './declarative-act-snapshot' import { defaultSchedule, errorMessage, @@ -199,6 +200,7 @@ export function createOrcaDeclarativeRuntime(options: OrcaRuntimeOptions): OrcaD bridge.on(PLUGIN_DECLARATIVE_MESSAGES.ack, acknowledge), bridge.on(PLUGIN_DECLARATIVE_MESSAGES.hydrate, panel.hydrate), bridge.on(PLUGIN_DECLARATIVE_MESSAGES.visibility, panel.setVisibility), + ...actSnapshotSubscriptions(bridge.on.bind(bridge), document), bridge.on('theme', (payload) => { const { colorScheme } = readHostMessage(payload) if ( diff --git a/src/shared/plugins/view/plugin-shot-acts.test.ts b/src/shared/plugins/view/plugin-shot-acts.test.ts index 0ace7e4f8de..2c1b5752080 100644 --- a/src/shared/plugins/view/plugin-shot-acts.test.ts +++ b/src/shared/plugins/view/plugin-shot-acts.test.ts @@ -16,10 +16,36 @@ describe('parsePluginShotActs', () => { }) }) + it("takes the kit's Slider, Table and Tree verbs with their arguments", () => { + const table = { type: 'Table' } + const tree = { label: 'Folders' } + const json = JSON.stringify([ + { slide: { label: 'Volume' }, value: 7 }, + { sort: table, column: 'name' }, + { selectRows: table, keys: ['a', 'b'] }, + { activateRow: table, key: 'a' }, + { loadMore: table }, + { expand: tree, key: 'src' }, + { collapse: tree, key: 'src' }, + { selectItem: tree, key: 'src/main.ts' }, + { activateItem: tree, key: 'src/main.ts' } + ]) + expect(parsePluginShotActs(json)).toMatchObject({ ok: true, acts: { length: 9 } }) + expect(parsePluginShotActs('{"slide":{"label":"Volume"},"value":"7"}')).toMatchObject({ + ok: false, + error: expect.stringMatching(/^action 1 \(slide\) \(value\): /) + }) + expect(parsePluginShotActs('{"expand":{"label":"Folders"}}')).toMatchObject({ + ok: false, + error: expect.stringMatching(/^action 1 \(expand\) \(key\): /) + }) + }) + it('names the act and field that is wrong', () => { expect(parsePluginShotActs('[{"press":{"text":"A"}},{"click":{}}]')).toEqual({ ok: false, - error: 'action 2: expected an object with one of press, type, select, toggle' + error: + 'action 2: expected an object with one of press, type, select, toggle, slide, sort, selectRows, activateRow, loadMore, expand, collapse, selectItem, activateItem' }) expect(parsePluginShotActs('[{"type":{"label":"Name"}}]')).toMatchObject({ ok: false, diff --git a/src/shared/plugins/view/plugin-shot-acts.ts b/src/shared/plugins/view/plugin-shot-acts.ts index 5e4ab48e020..3691ac4b306 100644 --- a/src/shared/plugins/view/plugin-shot-acts.ts +++ b/src/shared/plugins/view/plugin-shot-acts.ts @@ -2,13 +2,17 @@ import { z } from 'zod' /** * `orca plugin shot --act`: input run against the live components panel before the capture, in - * the test kit's vocabulary (`press(query)`, `type(query, text, { replace, submit })`, - * `select(query, value)`, `toggle(query)`). Queries match as the kit's do, with plain strings. + * the test kit's vocabulary: `press(query)`, `type(query, text, { replace, submit })`, + * `select(query, value)`, `toggle(query)`, `slide(query, value)`, and the Table and Tree verbs + * (`sort`, `selectRows`, `activateRow`, `loadMore`, `expand`, `collapse`, `selectItem`, + * `activateItem`). Queries match as the kit's do, with plain strings. */ export const PLUGIN_SHOT_MAX_ACTS = 20 const QUERY_TEXT_MAX = 200 const TYPE_TEXT_MAX = 500 +// A Table's `selectRows`; well above a person's multi-select. +const PLUGIN_SHOT_MAX_ROW_KEYS = 200 const queryText = z.string().min(1).max(QUERY_TEXT_MAX) @@ -26,6 +30,8 @@ export const pluginShotQuerySchema = z export type PluginShotQuery = z.infer +const keyText = z.string().min(1).max(QUERY_TEXT_MAX) + const ACT_SCHEMAS = { press: z.strictObject({ press: pluginShotQuerySchema }), type: z.strictObject({ @@ -35,14 +41,35 @@ const ACT_SCHEMAS = { submit: z.boolean().optional() }), select: z.strictObject({ select: pluginShotQuerySchema, value: z.string().max(QUERY_TEXT_MAX) }), - toggle: z.strictObject({ toggle: pluginShotQuerySchema }) + toggle: z.strictObject({ toggle: pluginShotQuerySchema }), + slide: z.strictObject({ slide: pluginShotQuerySchema, value: z.number().finite() }), + sort: z.strictObject({ sort: pluginShotQuerySchema, column: keyText }), + selectRows: z.strictObject({ + selectRows: pluginShotQuerySchema, + keys: z.array(keyText).max(PLUGIN_SHOT_MAX_ROW_KEYS) + }), + activateRow: z.strictObject({ activateRow: pluginShotQuerySchema, key: keyText }), + loadMore: z.strictObject({ loadMore: pluginShotQuerySchema }), + expand: z.strictObject({ expand: pluginShotQuerySchema, key: keyText }), + collapse: z.strictObject({ collapse: pluginShotQuerySchema, key: keyText }), + selectItem: z.strictObject({ selectItem: pluginShotQuerySchema, key: keyText }), + activateItem: z.strictObject({ activateItem: pluginShotQuerySchema, key: keyText }) } export const pluginShotActSchema = z.union([ ACT_SCHEMAS.press, ACT_SCHEMAS.type, ACT_SCHEMAS.select, - ACT_SCHEMAS.toggle + ACT_SCHEMAS.toggle, + ACT_SCHEMAS.slide, + ACT_SCHEMAS.sort, + ACT_SCHEMAS.selectRows, + ACT_SCHEMAS.activateRow, + ACT_SCHEMAS.loadMore, + ACT_SCHEMAS.expand, + ACT_SCHEMAS.collapse, + ACT_SCHEMAS.selectItem, + ACT_SCHEMAS.activateItem ]) export type PluginShotAct = z.infer @@ -57,7 +84,21 @@ export const pluginShotActResultSchema: z.ZodType = z.union z.object({ ok: z.literal(false), error: z.string().max(2000) }) ]) -const VERBS = ['press', 'type', 'select', 'toggle'] as const +const VERBS = [ + 'press', + 'type', + 'select', + 'toggle', + 'slide', + 'sort', + 'selectRows', + 'activateRow', + 'loadMore', + 'expand', + 'collapse', + 'selectItem', + 'activateItem' +] as const satisfies readonly (keyof typeof ACT_SCHEMAS)[] function issueOf(index: number, value: unknown): string { const where = `action ${index + 1}` diff --git a/src/shared/plugins/view/plugin-view-protocol.ts b/src/shared/plugins/view/plugin-view-protocol.ts index 718b869cb55..32a3371eb93 100644 --- a/src/shared/plugins/view/plugin-view-protocol.ts +++ b/src/shared/plugins/view/plugin-view-protocol.ts @@ -46,12 +46,15 @@ export type PluginViewDrawnPanel = { themeApplied: boolean /** False when the wait timed out and the rect shows whatever was drawn by then. */ settled: boolean + /** Host calls (`plugin.request` included) still unanswered when it was measured. */ + pendingRequests?: number /** One result per requested act. */ actions?: PluginShotActResult[] } export type PluginViewReply = - | { requestId: string; ok: true; panel?: PluginViewDrawnPanel } + /** `restored`: on `end-capture` after `--act`, whether the panel's atoms were put back. */ + | { requestId: string; ok: true; panel?: PluginViewDrawnPanel; restored?: boolean } | { requestId: string; ok: false; code: string; message: string } /** The renderer could not show the view; `code` is a stable reason callers may branch on. */ diff --git a/tests/e2e/plugin-shot.spec.ts b/tests/e2e/plugin-shot.spec.ts index 1352cb2907b..b1b15b60981 100644 --- a/tests/e2e/plugin-shot.spec.ts +++ b/tests/e2e/plugin-shot.spec.ts @@ -13,6 +13,7 @@ import { expect, test } from './helpers/orca-app' import { orcaCliResult } from './helpers/compiled-orca-cli' import { RuntimeClient } from '../../src/cli/runtime/client' import { disablePluginSystem, enableDevPlugins } from './helpers/plugin-smoke' +import { createPluginFromTemplate } from '../../src/cli/plugin-authoring/plugin-create' import { ISOLATED_FRAMES_E2E } from './helpers/plugin-frame-guest' import { waitForActiveWorktree, waitForSessionReady } from './helpers/store' @@ -275,7 +276,12 @@ test('plugin shot --act types and presses on the hidden components panel before const userDataDir = await electronApp.evaluate(({ app }) => app.getPath('userData')) const shownBefore = await windowsShown(electronApp) const client = new RuntimeClient(userDataDir, 60_000, null, null) - type ActShot = { png: string; errors: string[]; actions?: { ok: boolean; error?: string }[] } + type ActShot = { + png: string + errors: string[] + actions?: { ok: boolean; error?: string }[] + restored?: boolean + } const before = await client.call('plugins.shot', { pluginKey, width: 360 }) // Orca's floating launcher parks over the sidebar; a capture hides it so it is never in a shot. @@ -308,11 +314,11 @@ test('plugin shot --act types and presses on the hidden components panel before { ok: false, error: 'not run: an earlier action failed' } ]) expect(acted.result.errors).toEqual([]) + // The shot shows the acted panel; afterwards the persisted list and the draft are put back. expect(acted.result.png).not.toBe(before.result.png) - // The guest ran the handlers: the task is listed and toggled done, as Orca draws it. - const task = orcaPage.getByRole('button', { name: /Ship the act/ }) - await expect(task).toBeVisible() - await expect(task).toContainText('Done') + expect(acted.result.restored).toBe(true) + await expect(orcaPage.getByRole('heading', { name: 'Tasks' })).toBeVisible() + await expect(orcaPage.getByRole('button', { name: /Ship the act/ })).toHaveCount(0) await expect(orcaPage.getByRole('textbox', { name: 'New task' })).toHaveValue('') // The launcher is back once the capture ended; the window never showed. await expect.poll(() => launcher.count()).toBe(launchers) @@ -322,3 +328,137 @@ test('plugin shot --act types and presses on the hidden components panel before await rm(tempRoot, { recursive: true, force: true }) } }) + +test('plugin shot waits for a cold worker, and --act state is put back after the capture', async ({ + electronApp, + orcaPage +}) => { + await waitForSessionReady(orcaPage) + await waitForActiveWorktree(orcaPage) + const tempRoot = await mkdtemp(join(tmpdir(), 'orca-plugin-shot-worker-')) + try { + const created = await createPluginFromTemplate({ + dir: join(tempRoot, 'shot-counter'), + template: 'worker-panel', + id: 'shot-counter', + name: 'Shot Counter' + }) + await enableDevPlugins(orcaPage, [created.path]) + const pluginKey = await devPluginKey(orcaPage, 'Shot Counter') + const userDataDir = await electronApp.evaluate(({ app }) => app.getPath('userData')) + const client = new RuntimeClient(userDataDir, 60_000, null, null) + type WorkerShot = { + panelId: string + pendingRequests?: number + actions?: { ok: boolean; error?: string }[] + restored?: boolean + } + + // The first shot starts the panel and its worker: it waits for counter.get's answer. + const cold = await client.call('plugins.shot', { pluginKey }) + expect(cold.result.pendingRequests).toBe(0) + const surface = orcaPage.locator( + `[data-plugin-panel-surface="plugin:${pluginKey}/${cold.result.panelId}"]` + ) + // Read at once, no retry: the capture already showed the worker's total, not the placeholder. + expect(await surface.innerText()).toMatch(/Counter\s+0\b/) + + // `step` is persisted ('plugin'): the act flips it for the shot only. + const acted = await client.call( + 'plugins.shot', + { pluginKey, acts: [{ press: { text: 'Step 10' } }] }, + { timeoutMs: 60_000 } + ) + expect(acted.result).toMatchObject({ actions: [{ ok: true }], restored: true }) + await expect(surface.getByRole('button', { name: 'Add 1' })).toBeVisible() + const later = await client.call('plugins.shot', { pluginKey }) + expect(later.result.pendingRequests).toBe(0) + await expect(surface.getByRole('button', { name: 'Add 1' })).toBeVisible() + await expect(surface.getByRole('button', { name: 'Step 10' })).toBeVisible() + } finally { + await disablePluginSystem(orcaPage).catch(() => undefined) + await rm(tempRoot, { recursive: true, force: true }) + } +}) + +test('plugin shot --act sorts and activates a Table row, then puts the panel back', async ({ + electronApp, + orcaPage +}) => { + await waitForSessionReady(orcaPage) + await waitForActiveWorktree(orcaPage) + const tempRoot = await mkdtemp(join(tmpdir(), 'orca-plugin-shot-table-')) + const pluginRoot = join(tempRoot, 'shot-table') + try { + await mkdir(join(pluginRoot, 'src'), { recursive: true }) + await writeFile( + join(pluginRoot, 'orca-plugin.json'), + JSON.stringify({ + manifestVersion: 2, + execution: 'sandboxed-ui', + id: 'shot-table', + name: 'Shot Table', + version: '1.0.0', + engines: { orca: '>=1.4.246' }, + pluginApi: 1, + contributes: { + panels: [{ id: 'files', title: 'Shot Table', entry: 'src/panel.tsx', ui: 'components' }] + }, + capabilities: [] + }) + ) + await writeFile( + join(pluginRoot, 'src', 'panel.tsx'), + [ + "import { atom, read, set, Stack, Table, Text } from 'orca'", + "const sort = atom({ column: 'name', direction: 'asc' })", + "const opened = atom('none')", + 'export default function Panel() {', + ' const by = read(sort)', + " const names = ['alpha', 'beta', 'gamma'].sort()", + " if (by.direction === 'desc') names.reverse()", + ' return (', + ' ', + ' {`Sorted ${by.direction}, opened ${read(opened)}`}', + ' ({ key: name, cells: { name } }))}', + ' sort={by}', + ' onSortChange={(next) => set(sort, next)}', + ' onRowAction={({ key }) => set(opened, key)}', + ' />', + ' ', + ' )', + '}', + '' + ].join('\n') + ) + await enableDevPlugins(orcaPage, [pluginRoot]) + const pluginKey = await devPluginKey(orcaPage, 'Shot Table') + const userDataDir = await electronApp.evaluate(({ app }) => app.getPath('userData')) + const client = new RuntimeClient(userDataDir, 60_000, null, null) + type TableShot = { png: string; actions?: { ok: boolean }[]; restored?: boolean } + + const before = await client.call('plugins.shot', { pluginKey }) + await expect(orcaPage.getByText('Sorted asc, opened none')).toBeVisible() + const table = { label: 'Files' } + const acted = await client.call( + 'plugins.shot', + { + pluginKey, + acts: [ + { sort: table, column: 'name' }, + { activateRow: table, key: 'gamma' } + ] + }, + { timeoutMs: 60_000 } + ) + expect(acted.result).toMatchObject({ actions: [{ ok: true }, { ok: true }], restored: true }) + expect(acted.result.png).not.toBe(before.result.png) + await expect(orcaPage.getByText('Sorted asc, opened none')).toBeVisible() + } finally { + await disablePluginSystem(orcaPage).catch(() => undefined) + await rm(tempRoot, { recursive: true, force: true }) + } +})