@happyvertical/smrt-web 0.51.39 → 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"file":"intents-BUTyN7YQ.js","names":[],"sources":["../../src/capability-classification.ts","../../src/intents.ts"],"sourcesContent":["/**\n * The one capability classification rule this package applies, extracted so\n * every declaration site in smrt-web shares a single implementation (#2587,\n * #2588).\n *\n * Two sites consume it today: `webmcp.ts` (canonical definitions trusted\n * through it directly, and its legacy CRUD switch's fail-closed default\n * branch) and `intents.ts` (a declared view intent, which is never a CRUD\n * verb and so resolves through the declaration rule alone). Keeping the rule\n * here rather than private to `webmcp.ts` is what lets the intent path be a\n * dependency-free module that never pulls the client-data engine.\n *\n * This module structurally mirrors `CapabilityEffect` / `CapabilityDeclaration`\n * / `CapabilityClassification` in `@happyvertical/smrt-types` rather than\n * importing them — this package's dependency-DAG guardrails keep it free of\n * every `@happyvertical/*` dependency (see AGENTS.md \"No inter-smrt\n * dependencies\"), the same reason `data-query.ts` mirrors that package's\n * bounded query envelope structurally instead of importing it.\n */\n\n/**\n * Browser/agent-visible effect classification for a capability. `'read'`\n * never mutates; `'write'` mutates within the application; `'destructive'`\n * may remove or irreversibly change data.\n */\nexport type WebMcpToolEffect = 'read' | 'write' | 'destructive';\n\n/** Every valid {@link WebMcpToolEffect}, in exposure-breadth order. */\nexport const WEBMCP_TOOL_EFFECTS: readonly WebMcpToolEffect[] = [\n 'read',\n 'write',\n 'destructive',\n];\n\n/**\n * An author-supplied, partial classification. Any omitted field resolves\n * through the fail-closed rule on {@link resolveDeclaredCapability}, never\n * through a CRUD- or name-based guess.\n */\nexport interface WebMcpCapabilityDeclaration {\n effect?: WebMcpToolEffect;\n idempotent?: boolean;\n openWorld?: boolean;\n}\n\n/** A fully resolved classification. */\nexport interface WebMcpCapabilityClassification {\n effect: WebMcpToolEffect;\n /**\n * Derived, never declared: every non-read effect is annotated destructive\n * to the browser, so a `write` capability cannot claim the MCP\n * additive-only guarantee.\n */\n destructive: boolean;\n idempotent: boolean;\n openWorld: boolean;\n}\n\n/** The MCP-shaped annotation set a resolved classification emits. */\nexport interface WebMcpCapabilityAnnotations {\n readOnlyHint: boolean;\n destructiveHint: boolean;\n idempotentHint: boolean;\n openWorldHint: boolean;\n untrustedContentHint: boolean;\n}\n\n/**\n * Resolve a declared capability with no CRUD/action-based guess — the shared\n * fail-closed default documented on `CapabilityClassification` in\n * `@happyvertical/smrt-types` (#2587): an omitted or invalid `effect`\n * resolves to `'destructive'`, an omitted `idempotent` to `false`, an\n * omitted `openWorld` to `true`. Each field defaults independently: a\n * declared `effect: 'read'` does NOT imply `idempotent: true`.\n */\nexport function resolveDeclaredCapability(\n declared: WebMcpCapabilityDeclaration,\n): WebMcpCapabilityClassification {\n const effect = WEBMCP_TOOL_EFFECTS.includes(\n declared.effect as WebMcpToolEffect,\n )\n ? (declared.effect as WebMcpToolEffect)\n : 'destructive';\n return {\n effect,\n destructive: effect !== 'read',\n idempotent: declared.idempotent ?? false,\n openWorld: declared.openWorld ?? true,\n };\n}\n\n/**\n * The browser annotations a resolved classification is finally registered\n * with. `destructiveHint` carries the DERIVED `destructive` flag, so a\n * `write` capability is annotated destructive exactly like a generated\n * custom model action declared `effect: 'write'`.\n */\nexport function capabilityAnnotations(\n classification: WebMcpCapabilityClassification,\n): WebMcpCapabilityAnnotations {\n return {\n readOnlyHint: classification.effect === 'read',\n destructiveHint: classification.destructive,\n idempotentHint: classification.idempotent,\n openWorldHint: classification.openWorld,\n untrustedContentHint: true,\n };\n}\n\n/**\n * Encode a resolved classification as the INPUT hints\n * `registerWebMcpBespokeTool` decodes (`bespokeDeclaredSemantics`), so a\n * capability resolved here survives that registrar's own re-resolution\n * unchanged.\n *\n * This is deliberately NOT {@link capabilityAnnotations}. That function emits\n * the derived `destructive` flag, and `destructiveHint: true` is the first\n * check the registrar makes — round-tripping it would silently upgrade every\n * `write` capability to `destructive`. On the input side `destructiveHint`\n * means \"the author declared the destructive EFFECT\", and `false` selects the\n * `write` bucket; the registrar re-emits it as `true` on its way to the\n * browser.\n */\nexport function capabilityDeclarationHints(\n classification: WebMcpCapabilityClassification,\n): WebMcpCapabilityAnnotations {\n return {\n readOnlyHint: classification.effect === 'read',\n destructiveHint: classification.effect === 'destructive',\n idempotentHint: classification.idempotent,\n openWorldHint: classification.openWorld,\n untrustedContentHint: true,\n };\n}\n","/**\n * Framework-agnostic declarative view intents (#2588).\n *\n * A view intent is an interaction a component owns that has no model\n * projection and never will — filter this list, advance the wizard, open the\n * archived tab. It is declared as a LITERAL object in a `.ts` module and\n * compiles into the mounted `ControlInteractionRegistry` /\n * `DataSurfaceRegistry` commands that `@happyvertical/smrt-ui` already\n * exposes, never around them.\n *\n * ## The hard invariant: an intent can never reach REST\n *\n * Enforced twice, structurally and at runtime.\n *\n * **Structurally**, {@link ViewIntentDeclaration} has no `execute`, `fetch`,\n * `url`, `route`, `endpoint`, or `method` field, and no field of function\n * type anywhere. Its `target` is a closed two-member union naming a browser\n * registry. There is no way to spell a network call in the type.\n *\n * **At runtime**, {@link defineIntent} rejects any key outside the declared\n * allowlist and any non-JSON value (functions included) anywhere in the\n * declaration, so a declaration cast through `as any` cannot smuggle one in\n * either. It reads every property exactly once and keeps a JSON COPY, so a\n * getter or Proxy cannot show the checker plain data and hand something else\n * to whoever reads the property next. The tool's `execute` is then CONSTRUCTED\n * by\n * {@link compileViewIntentToolSpec} from `intent.target` alone. An author\n * never supplies a callable, so there is no author-controlled code on the\n * execution path to place a `fetch` in.\n *\n * The decorator remains the sole authority on model-operation exposure\n * (epic #2585 invariant 1): a component may reference an operation\n * `@smrt({ api })` already exposes, through the generated model tools, but an\n * intent can only move browser state. And because intents dispatch registry\n * commands, `StagedControlReview` stays on the path unconditionally — an\n * agent-sourced `stage` is a proposal, and `apply` still requires the\n * registry's trusted local human gesture.\n *\n * ## Static form (the #2591 scanner contract)\n *\n * Declarations must be module-scope `defineIntent({ ... })` calls with a\n * single object literal argument, in a `.ts`/`.tsx` module — see\n * `packages/smrt-web/AGENTS.md` \"Declarative view intents\" for the contract\n * a scanner matcher implements against. Computed or conditional tool sets\n * keep using `useWebMcpTool`.\n *\n * This module imports nothing at runtime — not the client-data engine, not\n * `./index.js`, not `./webmcp.js` — so a `Foo.intents.ts` sidecar costs a\n * page nothing but its own declarations. Registration lives in `webmcp.ts`\n * (`registerViewIntent`), which is loaded lazily by every binding.\n */\n\nimport {\n capabilityDeclarationHints,\n resolveDeclaredCapability,\n WEBMCP_TOOL_EFFECTS,\n type WebMcpCapabilityAnnotations,\n type WebMcpCapabilityClassification,\n type WebMcpCapabilityDeclaration,\n} from './capability-classification.js';\n\n// ---------------------------------------------------------------------------\n// Declaration contract\n// ---------------------------------------------------------------------------\n\n/**\n * Control commands a view intent may dispatch. Structurally mirrors\n * `ControlCommandAction` in `@happyvertical/smrt-ui/forms`; this package\n * cannot import that one (see AGENTS.md \"No inter-smrt dependencies\").\n */\nexport type ViewIntentControlAction =\n | 'focus'\n | 'reveal'\n | 'highlight'\n | 'explain'\n | 'validate'\n | 'stage'\n | 'apply'\n | 'discard'\n | 'clear'\n | 'undo';\n\nconst VIEW_INTENT_CONTROL_ACTIONS: readonly ViewIntentControlAction[] = [\n 'focus',\n 'reveal',\n 'highlight',\n 'explain',\n 'validate',\n 'stage',\n 'apply',\n 'discard',\n 'clear',\n 'undo',\n];\n\n/** Mirrors `DataSurfaceIdentity['kind']` in `@happyvertical/smrt-ui/data`. */\nexport type ViewIntentDataSurfaceKind = 'table' | 'list' | 'report' | 'custom';\n\nconst VIEW_INTENT_DATA_SURFACE_KINDS: readonly ViewIntentDataSurfaceKind[] = [\n 'table',\n 'list',\n 'report',\n 'custom',\n];\n\n/**\n * The optional record a registry identity is qualified by. Rich forms use it\n * to tell apart controls that share a `formId`/`controlId` across records.\n * Structurally mirrors `ControlIdentity['subject']` /\n * `DataSurfaceIdentity['subject']` in `@happyvertical/smrt-ui`.\n */\nexport interface ViewIntentSubject {\n type: string;\n id: string;\n label?: string;\n}\n\n/**\n * A control-registry target: the intent dispatches exactly one\n * `ControlInteractionRegistry` command against a mounted control.\n *\n * `formId`/`controlId` are the statically declared half of the identity. A\n * binding supplies the mounted identity and must MATCH anything declared\n * here — a declaration is authority over a binding, never the other way\n * round.\n */\nexport interface ViewIntentControlTarget {\n registry: 'control';\n action: ViewIntentControlAction;\n formId?: string;\n controlId?: string;\n}\n\n/**\n * A data-surface target: the intent dispatches one\n * `DataSurfaceVisibleCommand` — a browser-visible state transition, never a\n * server-side query or mutation.\n */\nexport interface ViewIntentDataSurfaceTarget {\n registry: 'dataSurface';\n /** The visible-command `controlId` the mounted surface implements. */\n controlId: string;\n surfaceId?: string;\n kind?: ViewIntentDataSurfaceKind;\n}\n\nexport type ViewIntentTarget =\n | ViewIntentControlTarget\n | ViewIntentDataSurfaceTarget;\n\n/**\n * The literal object passed to {@link defineIntent}. Every field is data;\n * none is a function, a URL, or a route.\n */\nexport interface ViewIntentDeclaration {\n /**\n * Stable, namespaced identity — at least one dot, lowercase, e.g.\n * `orders.filter_by_status`. It is the intent's name in the manifest\n * (#2591) and in a playbook step (`{ kind: 'intent', id }`, #2589), so it\n * must not be derived from anything that can change (a namespace, a\n * generated tool name, a route).\n */\n id: string;\n /** Human/agent-readable description. Becomes the tool description. */\n description: string;\n /** JSON Schema for the tool's arguments. Must be plain JSON. */\n inputSchema?: Record<string, unknown>;\n /**\n * Partial capability declaration resolved by the shared fail-closed rule\n * (#2587). Omitted entirely, an intent classifies destructive,\n * non-idempotent, open-world.\n */\n capability?: WebMcpCapabilityDeclaration;\n /** Which registry this compiles into, and what it addresses there. */\n target: ViewIntentTarget;\n}\n\n/**\n * A validated, frozen intent.\n *\n * `kind: 'intent'` and `id` are the exported identity a `smrt-playbooks`\n * step reference (`{ kind: 'intent', id }`) names, and this object is\n * directly assignable to that package's `PlaybookIntentRecord` seam —\n * `{ id, classification, planes }` — so {@link resolveViewIntent} can be\n * passed as its `intents` resolver unchanged.\n */\nexport interface ViewIntent {\n readonly kind: 'intent';\n readonly id: string;\n readonly description: string;\n readonly inputSchema: Record<string, unknown>;\n /** Resolved through the shared fail-closed rule at declaration time. */\n readonly classification: WebMcpCapabilityClassification;\n readonly target: ViewIntentTarget;\n /**\n * An intent moves mounted browser state, so it is browser-valid only. A\n * server-side agent reaches one through the #2446 command/ack bridge, which\n * a playbook must declare explicitly.\n */\n readonly planes: readonly ['browser'];\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\nconst DECLARATION_KEYS = new Set([\n 'id',\n 'description',\n 'inputSchema',\n 'capability',\n 'target',\n]);\nconst CAPABILITY_KEYS = new Set(['effect', 'idempotent', 'openWorld']);\nconst CONTROL_TARGET_KEYS = new Set([\n 'registry',\n 'action',\n 'formId',\n 'controlId',\n]);\nconst DATA_SURFACE_TARGET_KEYS = new Set([\n 'registry',\n 'controlId',\n 'surfaceId',\n 'kind',\n]);\n\n/** Lowercase, dot-namespaced, at least two segments. */\nconst INTENT_ID_PATTERN = /^[a-z][a-z0-9]*(?:\\.[a-z0-9][a-z0-9_]*)+$/;\nconst IDENTIFIER_MAX_LENGTH = 256;\nconst INTENT_ID_MAX_LENGTH = 128;\nconst DESCRIPTION_MAX_LENGTH = 1024;\n\n/**\n * The six fixed `smrt_ui_*` tools are explicitly unchanged by this contract,\n * and intents sit above them rather than duplicating them. An intent whose\n * derived tool name would land in their namespace is rejected.\n */\nconst RESERVED_TOOL_NAME_PREFIX = 'smrt_ui_';\n\nfunction fail(message: string): never {\n throw new Error(`[smrt-web] invalid view intent declaration: ${message}`);\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nfunction assertNoUnknownKeys(\n value: Record<string, unknown>,\n allowed: ReadonlySet<string>,\n path: string,\n): void {\n for (const key of Object.keys(value)) {\n if (!allowed.has(key)) {\n fail(\n `unknown key '${key}' at ${path}. A declaration is data only — there is no field for an execute function, a URL, a route, or a fetch.`,\n );\n }\n }\n}\n\n/**\n * Validate that a value is JSON data and return a fresh deep COPY of it. This\n * is the runtime half of the no-REST invariant: a function value is the only\n * way author code could reach the execution path, and there is no legitimate\n * reason for one to appear in a static declaration.\n *\n * It copies rather than merely asserting because validate-then-store-by-\n * reference is a time-of-check/time-of-use gap: a getter (or a Proxy) can\n * return plain JSON to the checker and a function to whoever reads the\n * property next. Every property is read exactly once, here, and everything\n * downstream sees only this copy — so what was validated is precisely what is\n * kept, frozen, and handed to the browser.\n */\nfunction cloneJsonValue(value: unknown, path: string, depth = 0): unknown {\n if (depth > 32) fail(`${path} nests deeper than 32 levels`);\n if (value === null) return null;\n if (typeof value === 'function') {\n fail(\n `${path} is a function. A view intent declaration carries no code: its execute is constructed by the registry from 'target', so an intent has no path to REST.`,\n );\n }\n if (typeof value === 'string' || typeof value === 'boolean') return value;\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) fail(`${path} must be a finite number`);\n return value;\n }\n if (Array.isArray(value)) {\n return value.map((entry, index) =>\n cloneJsonValue(entry, `${path}[${index}]`, depth + 1),\n );\n }\n if (isPlainObject(value)) {\n const copy: Record<string, unknown> = {};\n // `Object.entries` reads each own enumerable property once. Symbol-keyed\n // properties are deliberately dropped: they are not JSON, they cannot be\n // named by a scanner, and nothing downstream reads them.\n for (const [key, entry] of Object.entries(value)) {\n const cloned = cloneJsonValue(entry, `${path}.${key}`, depth + 1);\n // `defineProperty`, not assignment: an own `__proto__` key (which\n // `JSON.parse` produces, so an agent argument can carry one) would\n // otherwise hit `Object.prototype`'s setter — silently dropping the key\n // AND swapping the copy's prototype for cloned input. This keeps the\n // copy exactly what was validated.\n Object.defineProperty(copy, key, {\n value: cloned,\n enumerable: true,\n writable: true,\n configurable: true,\n });\n }\n return copy;\n }\n fail(\n `${path} must be JSON data (got ${Object.prototype.toString.call(value)})`,\n );\n}\n\nfunction assertIdentifier(\n value: unknown,\n path: string,\n maxLength = IDENTIFIER_MAX_LENGTH,\n): string {\n if (typeof value !== 'string' || value.length === 0) {\n fail(`${path} must be a non-empty string`);\n }\n if (value.length > maxLength) {\n fail(`${path} must be at most ${maxLength} characters`);\n }\n for (const character of value) {\n const code = character.charCodeAt(0);\n if (code < 32 || code === 127) fail(`${path} contains a control character`);\n }\n return value;\n}\n\nfunction normalizeCapability(\n value: unknown,\n): WebMcpCapabilityDeclaration | undefined {\n if (value === undefined) return undefined;\n if (!isPlainObject(value)) fail('capability must be an object literal');\n assertNoUnknownKeys(value, CAPABILITY_KEYS, 'capability');\n const { effect, idempotent, openWorld } = value;\n if (effect !== undefined && !WEBMCP_TOOL_EFFECTS.includes(effect as never)) {\n fail(`capability.effect must be one of ${WEBMCP_TOOL_EFFECTS.join(', ')}`);\n }\n if (idempotent !== undefined && typeof idempotent !== 'boolean') {\n fail('capability.idempotent must be a boolean');\n }\n if (openWorld !== undefined && typeof openWorld !== 'boolean') {\n fail('capability.openWorld must be a boolean');\n }\n return {\n ...(effect === undefined ? {} : { effect: effect as never }),\n ...(idempotent === undefined ? {} : { idempotent }),\n ...(openWorld === undefined ? {} : { openWorld }),\n };\n}\n\nfunction normalizeTarget(value: unknown): ViewIntentTarget {\n if (!isPlainObject(value)) fail('target must be an object literal');\n const registry = value.registry;\n if (registry === 'control') {\n assertNoUnknownKeys(value, CONTROL_TARGET_KEYS, 'target');\n const action = value.action;\n if (!VIEW_INTENT_CONTROL_ACTIONS.includes(action as never)) {\n fail(\n `target.action must be one of ${VIEW_INTENT_CONTROL_ACTIONS.join(', ')}`,\n );\n }\n return {\n registry: 'control',\n action: action as ViewIntentControlAction,\n ...(value.formId === undefined\n ? {}\n : { formId: assertIdentifier(value.formId, 'target.formId') }),\n ...(value.controlId === undefined\n ? {}\n : { controlId: assertIdentifier(value.controlId, 'target.controlId') }),\n };\n }\n if (registry === 'dataSurface') {\n assertNoUnknownKeys(value, DATA_SURFACE_TARGET_KEYS, 'target');\n if (\n value.kind !== undefined &&\n !VIEW_INTENT_DATA_SURFACE_KINDS.includes(value.kind as never)\n ) {\n fail(\n `target.kind must be one of ${VIEW_INTENT_DATA_SURFACE_KINDS.join(', ')}`,\n );\n }\n return {\n registry: 'dataSurface',\n controlId: assertIdentifier(value.controlId, 'target.controlId'),\n ...(value.surfaceId === undefined\n ? {}\n : { surfaceId: assertIdentifier(value.surfaceId, 'target.surfaceId') }),\n ...(value.kind === undefined\n ? {}\n : { kind: value.kind as ViewIntentDataSurfaceKind }),\n };\n }\n fail(\"target.registry must be 'control' or 'dataSurface'\");\n}\n\n/** Derive the WebMCP tool name for an intent id. */\nexport function viewIntentToolName(id: string): string {\n return id.replace(/[.-]/g, '_');\n}\n\n// ---------------------------------------------------------------------------\n// The declaration registry\n// ---------------------------------------------------------------------------\n\nconst REGISTRY_KEY = Symbol.for('@happyvertical/smrt-web:view-intents');\n\ninterface ViewIntentRegistryState {\n intents: Map<string, ViewIntent>;\n}\n\nfunction registryState(): ViewIntentRegistryState {\n // A `globalThis` singleton, matching `ObjectRegistry` in smrt-core, so the\n // registry survives HMR and duplicate module instances in a dev bundle.\n const host = globalThis as Record<symbol, unknown>;\n const existing = host[REGISTRY_KEY] as ViewIntentRegistryState | undefined;\n if (existing) return existing;\n const created: ViewIntentRegistryState = { intents: new Map() };\n host[REGISTRY_KEY] = created;\n return created;\n}\n\n/**\n * Declare a view intent.\n *\n * Call this at MODULE SCOPE with a single object literal — no spreads, no\n * conditionals, no computed values — in a `.ts` module, conventionally a\n * `Foo.intents.ts` sidecar beside the component that binds it. That form is\n * the contract #2591's scanner matcher reads without evaluating the module.\n *\n * The returned intent is deeply frozen and registered under its `id`. A\n * byte-identical re-declaration returns the SAME frozen object. A\n * re-declaration that differs REPLACES the previous one and warns: editing a\n * sidecar is what an HMR update is for, and throwing there would break the\n * single most common dev action on these files. Two genuinely different\n * intents sharing an id is an authoring mistake the warning surfaces, and one\n * #2591's scanner catches statically, where both declarations are visible at\n * once.\n *\n * @throws if the declaration is not static JSON data, carries an unknown\n * key, carries a function anywhere, names a reserved tool namespace, or\n * derives a WebMCP tool name another intent already derives.\n */\nexport function defineIntent(declaration: ViewIntentDeclaration): ViewIntent {\n if (!isPlainObject(declaration)) {\n fail('defineIntent expects an object literal');\n }\n // `Object.keys` invokes no getter, so the allowlist check is safe to run on\n // the caller's object and gives the clearest message for a smuggled key.\n assertNoUnknownKeys(declaration, DECLARATION_KEYS, 'declaration');\n // Validate AND copy before any field-specific check, so a smuggled callable\n // is rejected wherever it sits — including inside `inputSchema` or `target`\n // — and every check below reads the copy rather than re-reading a property\n // that could answer differently the second time.\n const source = cloneJsonValue(declaration, 'declaration') as Record<\n string,\n unknown\n >;\n assertNoUnknownKeys(source, DECLARATION_KEYS, 'declaration');\n\n const id = assertIdentifier(source.id, 'id', INTENT_ID_MAX_LENGTH);\n if (!INTENT_ID_PATTERN.test(id)) {\n fail(\n `id '${id}' must be lowercase and namespaced with at least one dot, e.g. 'orders.filter_by_status'`,\n );\n }\n if (viewIntentToolName(id).startsWith(RESERVED_TOOL_NAME_PREFIX)) {\n fail(\n `id '${id}' resolves into the reserved '${RESERVED_TOOL_NAME_PREFIX}' namespace of the six fixed UI tools`,\n );\n }\n const description = assertIdentifier(\n source.description,\n 'description',\n DESCRIPTION_MAX_LENGTH,\n );\n if (source.inputSchema !== undefined && !isPlainObject(source.inputSchema)) {\n fail('inputSchema must be an object literal');\n }\n\n const intent: ViewIntent = deepFreeze({\n kind: 'intent',\n id,\n description,\n inputSchema: (source.inputSchema ?? {\n type: 'object',\n properties: {},\n }) as Record<string, unknown>,\n classification: resolveDeclaredCapability(\n normalizeCapability(source.capability) ?? {},\n ),\n target: normalizeTarget(source.target),\n planes: ['browser'] as const,\n });\n\n const state = registryState();\n // `viewIntentToolName` is not injective — `orders.foo_bar` and\n // `orders.foo.bar` both flatten to `orders_foo_bar` — and two intents that\n // collide there would fight over one WebMCP tool name at mount, where the\n // failure is a shadowed or rejected registration rather than a clear error.\n // Reject the second declaration instead, at the only place both are visible.\n const toolName = viewIntentToolName(id);\n for (const other of state.intents.values()) {\n if (other.id !== id && viewIntentToolName(other.id) === toolName) {\n fail(\n `id '${id}' derives the WebMCP tool name '${toolName}', which intent '${other.id}' already derives`,\n );\n }\n }\n const existing = state.intents.get(id);\n if (existing) {\n if (JSON.stringify(existing) === JSON.stringify(intent)) return existing;\n // biome-ignore lint/suspicious/noConsole: smrt-web has no logger dep (TanStack-only); a replaced intent declaration surfaces via console.warn by design (#2588)\n console.warn(\n `[smrt-web] view intent '${id}' was re-declared with a different definition; replacing it. In development this is an HMR update. In a built application it means two declarations share one id.`,\n );\n }\n state.intents.set(id, intent);\n return intent;\n}\n\nfunction deepFreeze<T>(value: T): T {\n if (value && typeof value === 'object') {\n for (const entry of Object.values(value)) deepFreeze(entry);\n Object.freeze(value);\n }\n return value;\n}\n\n/** Every intent declared in modules loaded so far, in declaration order. */\nexport function listViewIntents(): readonly ViewIntent[] {\n return [...registryState().intents.values()];\n}\n\n/**\n * Look up a declared intent by id.\n *\n * Directly usable as `smrt-playbooks`' `PlaybookIntentResolver` seam (#2589):\n * a {@link ViewIntent} satisfies its `PlaybookIntentRecord` shape, so an\n * intent step inherits this intent's classification and browser-only plane\n * validity rather than classifying itself.\n */\nexport function resolveViewIntent(id: string): ViewIntent | undefined {\n return registryState().intents.get(id);\n}\n\n/**\n * Drop every declared intent. For tests and HMR teardown; production code\n * has no reason to call it.\n */\nexport function clearViewIntentRegistry(): void {\n registryState().intents.clear();\n}\n\n// ---------------------------------------------------------------------------\n// Compilation to a bespoke tool spec\n// ---------------------------------------------------------------------------\n\n/**\n * The `ControlInteractionRegistry` surface an intent uses. Declared\n * structurally so this package takes no dependency on\n * `@happyvertical/smrt-ui`; the real registry satisfies it.\n */\nexport interface ViewIntentControlRegistryPort {\n execute(\n command: {\n action: ViewIntentControlAction;\n identity: ViewIntentControlIdentity;\n value?: unknown;\n durationMs?: number;\n revision?: number;\n },\n context?: { source: 'agent' },\n ): Promise<{ ok: boolean; reason?: string }>;\n}\n\n/** A mounted control's full registry key, subject included. */\nexport interface ViewIntentControlIdentity {\n formId: string;\n controlId: string;\n subject?: ViewIntentSubject;\n}\n\n/** A mounted data surface's full registry key, subject included. */\nexport interface ViewIntentDataSurfaceIdentity {\n surfaceId: string;\n kind: ViewIntentDataSurfaceKind;\n subject?: ViewIntentSubject;\n}\n\n/** The `DataSurfaceRegistry` surface an intent uses. */\nexport interface ViewIntentDataSurfaceRegistryPort {\n inspect(\n identity: ViewIntentDataSurfaceIdentity,\n ): { revision: number } | undefined;\n execute(command: {\n version: 1;\n commandId: string;\n identity: ViewIntentDataSurfaceIdentity;\n expectedRevision: number;\n controlId: string;\n payload?: unknown;\n }): Promise<{ ok: boolean; revision?: number; reason?: string }>;\n}\n\n/** The mounted identity a binding supplies for an intent's lifetime. */\nexport type ViewIntentBinding =\n | {\n registry: 'control';\n registryPort: ViewIntentControlRegistryPort;\n identity: ViewIntentControlIdentity;\n }\n | {\n registry: 'dataSurface';\n registryPort: ViewIntentDataSurfaceRegistryPort;\n identity: ViewIntentDataSurfaceIdentity;\n };\n\n/**\n * A bespoke tool spec, structurally identical to\n * `WebMcpBespokeToolSpec` in `./webmcp.js`. Declared here rather than\n * imported so this module stays free of even a type edge to the registrar\n * entry.\n */\nexport interface ViewIntentToolSpec {\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n annotations: WebMcpCapabilityAnnotations;\n execute: (args: Record<string, unknown>) => Promise<string>;\n}\n\n/**\n * Reasons an intent may report back to an agent. Anything else collapses to\n * `denied`, so a registry's internal reason never leaks through a tool\n * result. Mirrors the allowlist the fixed `smrt_ui_*` tools apply.\n */\nconst PUBLIC_REASONS = new Set([\n 'not_found',\n 'unsupported',\n 'consent_required',\n 'human_confirmation_required',\n 'sensitive_control',\n 'control_not_writable',\n 'control_not_editable',\n 'nothing_to_undo',\n 'stale_revision',\n 'idempotency_conflict',\n 'non_monotonic_revision',\n 'invalid_request',\n 'denied',\n]);\n\nfunction publicReason(reason: unknown): string {\n return typeof reason === 'string' && PUBLIC_REASONS.has(reason)\n ? reason\n : 'denied';\n}\n\nfunction ok(result: Record<string, unknown>): string {\n return JSON.stringify({ ok: true, ...result });\n}\n\nfunction denied(reason: string): string {\n return JSON.stringify({ ok: false, reason });\n}\n\n/**\n * WebMCP hands `execute` whatever the agent sent. Anything that is not a plain\n * object becomes an empty argument set, so a string or array argument fails\n * closed through the normal `invalid_request` path instead of throwing a\n * TypeError out of an `in` check.\n */\nfunction toolArguments(args: unknown): Record<string, unknown> {\n return isPlainObject(args) ? args : {};\n}\n\nlet commandCounter = 0;\n\nfunction newCommandId(): string {\n const cryptoLike = (globalThis as { crypto?: { randomUUID?: () => string } })\n .crypto;\n if (typeof cryptoLike?.randomUUID === 'function') {\n return cryptoLike.randomUUID();\n }\n commandCounter += 1;\n return `intent-${Date.now().toString(36)}-${commandCounter}`;\n}\n\nclass IntentArgumentError extends Error {}\n\n/**\n * Validate one agent-supplied argument and return a JSON copy of it. Copying\n * closes the same time-of-check gap `cloneJsonValue` closes for declarations:\n * the value handed to a registry command is the one that was validated, not\n * whatever a getter answers on the next read.\n */\nfunction jsonArg(args: Record<string, unknown>, key: string): unknown {\n try {\n return cloneJsonValue(args[key], key);\n } catch {\n throw new IntentArgumentError(key);\n }\n}\n\n/**\n * Read `revision` ONCE and keep the value that was type-checked, so a\n * two-faced getter cannot pass the `number` check and then land something\n * else on the command.\n */\nfunction optionalRevision(args: Record<string, unknown>): {\n revision?: number;\n} {\n const revision = args.revision;\n return typeof revision === 'number' && Number.isFinite(revision)\n ? { revision }\n : {};\n}\n\n/**\n * Collapse anything thrown on the execution path to an allowlisted reason.\n *\n * A registry does not only RETURN a rejection — `DataSurfaceRegistry` throws\n * for a payload that is too deep, too large, or carries a forbidden or\n * prototype-pollution key, and any registry can throw from a host handler. An\n * uncaught throw would escape both the `{ ok, reason }` contract and the\n * {@link publicReason} allowlist, handing the agent a raw internal message.\n * The six fixed `smrt_ui_*` tools guard the same way (`executeSafely` in\n * smrt-svelte's `webmcp-ui.ts`), collapsing anything unrecognized rather than\n * letting it out.\n */\nfunction intentErrorReason(error: unknown): string {\n return error instanceof IntentArgumentError ? 'invalid_request' : 'denied';\n}\n\nfunction buildControlCommand(\n target: ViewIntentControlTarget,\n identity: ViewIntentControlIdentity,\n args: Record<string, unknown>,\n): Parameters<ViewIntentControlRegistryPort['execute']>[0] {\n const base = { action: target.action, identity };\n switch (target.action) {\n case 'highlight': {\n const durationMs = args.durationMs;\n if (durationMs !== undefined) {\n if (typeof durationMs !== 'number' || !Number.isFinite(durationMs)) {\n throw new IntentArgumentError('durationMs');\n }\n return { ...base, durationMs };\n }\n return base;\n }\n case 'stage':\n if (!('value' in args)) throw new IntentArgumentError('value');\n return { ...base, value: jsonArg(args, 'value') };\n case 'apply':\n // `reviewedValueIsCanonical` is deliberately never set from intent\n // arguments: it is the staged-review surface's own marker, and an\n // agent-driven intent must not be able to claim a human review.\n return {\n ...base,\n ...('value' in args ? { value: jsonArg(args, 'value') } : {}),\n ...optionalRevision(args),\n };\n case 'discard':\n return { ...base, ...optionalRevision(args) };\n default:\n return base;\n }\n}\n\n/**\n * Compile a declared intent plus a mounted binding into a bespoke tool spec.\n *\n * The `execute` this returns is built here from `intent.target`; nothing an\n * author wrote is called. It dispatches exactly one registry command with\n * `source: 'agent'`, so every policy the registry enforces — staged review,\n * local-gesture proof, sensitivity, writability — applies unchanged.\n *\n * @throws if the binding does not match the intent's declared target.\n */\nexport function compileViewIntentToolSpec(\n intent: ViewIntent,\n binding: ViewIntentBinding,\n): ViewIntentToolSpec {\n if (binding.registry !== intent.target.registry) {\n throw new Error(\n `[smrt-web] intent '${intent.id}' targets the ${intent.target.registry} registry but was bound to ${binding.registry}`,\n );\n }\n\n const spec = {\n name: viewIntentToolName(intent.id),\n description: intent.description,\n inputSchema: intent.inputSchema,\n annotations: capabilityDeclarationHints(intent.classification),\n };\n\n if (binding.registry === 'control' && intent.target.registry === 'control') {\n const target = intent.target;\n const identity = binding.identity;\n assertBoundIdentity(intent.id, 'formId', target.formId, identity.formId);\n assertBoundIdentity(\n intent.id,\n 'controlId',\n target.controlId,\n identity.controlId,\n );\n const registry = binding.registryPort;\n return {\n ...spec,\n execute: async (args) => {\n try {\n const command = buildControlCommand(\n target,\n identity,\n toolArguments(args),\n );\n const result = await registry.execute(command, { source: 'agent' });\n return result.ok\n ? ok({ action: target.action, identity })\n : denied(publicReason(result.reason));\n } catch (error) {\n return denied(intentErrorReason(error));\n }\n },\n };\n }\n\n if (\n binding.registry === 'dataSurface' &&\n intent.target.registry === 'dataSurface'\n ) {\n const target = intent.target;\n const identity = binding.identity;\n assertBoundIdentity(\n intent.id,\n 'surfaceId',\n target.surfaceId,\n identity.surfaceId,\n );\n assertBoundIdentity(intent.id, 'kind', target.kind, identity.kind);\n const registry = binding.registryPort;\n return {\n ...spec,\n execute: async (args) => {\n try {\n const input = toolArguments(args);\n const payload =\n 'payload' in input ? jsonArg(input, 'payload') : undefined;\n const snapshot = registry.inspect(identity);\n if (!snapshot) return denied('not_found');\n const result = await registry.execute({\n version: 1,\n commandId: newCommandId(),\n identity,\n expectedRevision: snapshot.revision,\n controlId: target.controlId,\n ...(payload === undefined ? {} : { payload }),\n });\n return result.ok\n ? ok({\n controlId: target.controlId,\n identity,\n ...(result.revision === undefined\n ? {}\n : { revision: result.revision }),\n })\n : denied(publicReason(result.reason));\n } catch (error) {\n return denied(intentErrorReason(error));\n }\n },\n };\n }\n\n /* c8 ignore next 3 -- unreachable: registry equality is checked above */\n throw new Error(\n `[smrt-web] intent '${intent.id}' could not be compiled for its binding`,\n );\n}\n\nfunction assertBoundIdentity(\n id: string,\n field: string,\n declared: string | undefined,\n bound: string,\n): void {\n if (declared !== undefined && declared !== bound) {\n throw new Error(\n `[smrt-web] intent '${id}' declares ${field} '${declared}' but was bound to '${bound}'`,\n );\n }\n}\n"],"mappings":"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"}