@happyvertical/smrt-web 0.43.10 → 0.44.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -8,6 +8,18 @@
8
8
  */
9
9
  export declare function buildListQuery(params?: Record<string, unknown>): string;
10
10
 
11
+ /**
12
+ * Compile a declared intent plus a mounted binding into a bespoke tool spec.
13
+ *
14
+ * The `execute` this returns is built here from `intent.target`; nothing an
15
+ * author wrote is called. It dispatches exactly one registry command with
16
+ * `source: 'agent'`, so every policy the registry enforces — staged review,
17
+ * local-gesture proof, sensitivity, writability — applies unchanged.
18
+ *
19
+ * @throws if the binding does not match the intent's declared target.
20
+ */
21
+ export declare function compileViewIntentToolSpec(intent: ViewIntent, binding: ViewIntentBinding): ViewIntentToolSpec;
22
+
11
23
  /**
12
24
  * Build CRUD fetchers from a generated collection definition — the same URL
13
25
  * scheme and payload handling as the generated REST client
@@ -538,6 +550,51 @@ export declare interface PersistCollectionConfig<TData extends object = object>
538
550
  */
539
551
  export declare function registerDurableResource(namespace: string, resource: DurableResource): () => void;
540
552
 
553
+ /**
554
+ * Register one declared view intent (#2588) against a mounted registry
555
+ * binding, for as long as the returned disposer is not called.
556
+ *
557
+ * This is the ONLY way an intent reaches the browser, and it goes through
558
+ * {@link registerWebMcpBespokeTool}, so an intent inherits the same
559
+ * fail-closed `effects` exposure policy as a generated model tool. The
560
+ * intent's classification was resolved at declaration time by the shared
561
+ * rule, and the hints `compileViewIntentToolSpec` emits round-trip through
562
+ * the bespoke registrar's own re-resolution unchanged.
563
+ *
564
+ * The `execute` registered here is constructed by
565
+ * `compileViewIntentToolSpec` from `intent.target`. No author-supplied code
566
+ * runs, and the only thing it can do is dispatch one browser registry
567
+ * command — the runtime half of the no-REST invariant.
568
+ */
569
+ export declare function registerViewIntent(intent: ViewIntent, binding: ViewIntentBinding, options?: RegisterWebMcpBespokeToolOptions): WebMcpRegistrationDisposer;
570
+
571
+ /**
572
+ * Register one hand-written browser tool through the same fail-closed effect
573
+ * classification and `effects` exposure policy as {@link registerWebMcpTools}
574
+ * (#2586). A tool with no `annotations`, or with annotations that leave its
575
+ * effect undeclared, classifies destructive/non-idempotent/open-world — the
576
+ * same default `actionSemantics` gives an undeclared custom model action —
577
+ * and is excluded unless the policy allows `destructive`. `namespace` and
578
+ * `maxTools` are out of scope for a bespoke tool; see
579
+ * {@link RegisterWebMcpBespokeToolOptions}.
580
+ *
581
+ * @returns a disposer that deregisters the tool this call registered (a
582
+ * no-op double-call). On a browser without WebMCP, or when policy excludes
583
+ * the tool's effect, the call is a no-op and the disposer is inert.
584
+ */
585
+ export declare function registerWebMcpBespokeTool(spec: WebMcpBespokeToolSpec, options?: RegisterWebMcpBespokeToolOptions): WebMcpRegistrationDisposer;
586
+
587
+ export declare interface RegisterWebMcpBespokeToolOptions {
588
+ /**
589
+ * Allowed effects. Omitted means read-only exposure — the same default as
590
+ * {@link registerWebMcpTools}. `namespace` and `maxTools` deliberately do
591
+ * not apply to a bespoke tool (#2586): a component author already chose a
592
+ * stable name, and counting one intent against a shared budget could make
593
+ * an unrelated generated tool set fail to register.
594
+ */
595
+ effects?: readonly WebMcpToolEffect[];
596
+ }
597
+
541
598
  /**
542
599
  * Register every collection's generated tool descriptors with WebMCP.
543
600
  *
@@ -1304,6 +1361,245 @@ export declare interface UpdateStateConfig {
1304
1361
  /** Validate that an opaque cache handle came from {@link createSmrtWebClient}. */
1305
1362
  export declare function validateSmrtWebClient(client: SmrtWebClient): void;
1306
1363
 
1364
+ /**
1365
+ * A validated, frozen intent.
1366
+ *
1367
+ * `kind: 'intent'` and `id` are the exported identity a `smrt-playbooks`
1368
+ * step reference (`{ kind: 'intent', id }`) names, and this object is
1369
+ * directly assignable to that package's `PlaybookIntentRecord` seam —
1370
+ * `{ id, classification, planes }` — so {@link resolveViewIntent} can be
1371
+ * passed as its `intents` resolver unchanged.
1372
+ */
1373
+ export declare interface ViewIntent {
1374
+ readonly kind: 'intent';
1375
+ readonly id: string;
1376
+ readonly description: string;
1377
+ readonly inputSchema: Record<string, unknown>;
1378
+ /** Resolved through the shared fail-closed rule at declaration time. */
1379
+ readonly classification: WebMcpCapabilityClassification;
1380
+ readonly target: ViewIntentTarget;
1381
+ /**
1382
+ * An intent moves mounted browser state, so it is browser-valid only. A
1383
+ * server-side agent reaches one through the #2446 command/ack bridge, which
1384
+ * a playbook must declare explicitly.
1385
+ */
1386
+ readonly planes: readonly ['browser'];
1387
+ }
1388
+
1389
+ /** The mounted identity a binding supplies for an intent's lifetime. */
1390
+ export declare type ViewIntentBinding = {
1391
+ registry: 'control';
1392
+ registryPort: ViewIntentControlRegistryPort;
1393
+ identity: ViewIntentControlIdentity;
1394
+ } | {
1395
+ registry: 'dataSurface';
1396
+ registryPort: ViewIntentDataSurfaceRegistryPort;
1397
+ identity: ViewIntentDataSurfaceIdentity;
1398
+ };
1399
+
1400
+ /**
1401
+ * Control commands a view intent may dispatch. Structurally mirrors
1402
+ * `ControlCommandAction` in `@happyvertical/smrt-ui/forms`; this package
1403
+ * cannot import that one (see AGENTS.md "No inter-smrt dependencies").
1404
+ */
1405
+ export declare type ViewIntentControlAction = 'focus' | 'reveal' | 'highlight' | 'explain' | 'validate' | 'stage' | 'apply' | 'discard' | 'clear' | 'undo';
1406
+
1407
+ /** A mounted control's full registry key, subject included. */
1408
+ export declare interface ViewIntentControlIdentity {
1409
+ formId: string;
1410
+ controlId: string;
1411
+ subject?: ViewIntentSubject;
1412
+ }
1413
+
1414
+ /**
1415
+ * The `ControlInteractionRegistry` surface an intent uses. Declared
1416
+ * structurally so this package takes no dependency on
1417
+ * `@happyvertical/smrt-ui`; the real registry satisfies it.
1418
+ */
1419
+ export declare interface ViewIntentControlRegistryPort {
1420
+ execute(command: {
1421
+ action: ViewIntentControlAction;
1422
+ identity: ViewIntentControlIdentity;
1423
+ value?: unknown;
1424
+ durationMs?: number;
1425
+ revision?: number;
1426
+ }, context?: {
1427
+ source: 'agent';
1428
+ }): Promise<{
1429
+ ok: boolean;
1430
+ reason?: string;
1431
+ }>;
1432
+ }
1433
+
1434
+ /**
1435
+ * A control-registry target: the intent dispatches exactly one
1436
+ * `ControlInteractionRegistry` command against a mounted control.
1437
+ *
1438
+ * `formId`/`controlId` are the statically declared half of the identity. A
1439
+ * binding supplies the mounted identity and must MATCH anything declared
1440
+ * here — a declaration is authority over a binding, never the other way
1441
+ * round.
1442
+ */
1443
+ export declare interface ViewIntentControlTarget {
1444
+ registry: 'control';
1445
+ action: ViewIntentControlAction;
1446
+ formId?: string;
1447
+ controlId?: string;
1448
+ }
1449
+
1450
+ /** A mounted data surface's full registry key, subject included. */
1451
+ export declare interface ViewIntentDataSurfaceIdentity {
1452
+ surfaceId: string;
1453
+ kind: ViewIntentDataSurfaceKind;
1454
+ subject?: ViewIntentSubject;
1455
+ }
1456
+
1457
+ /** Mirrors `DataSurfaceIdentity['kind']` in `@happyvertical/smrt-ui/data`. */
1458
+ export declare type ViewIntentDataSurfaceKind = 'table' | 'list' | 'report' | 'custom';
1459
+
1460
+ /** The `DataSurfaceRegistry` surface an intent uses. */
1461
+ export declare interface ViewIntentDataSurfaceRegistryPort {
1462
+ inspect(identity: ViewIntentDataSurfaceIdentity): {
1463
+ revision: number;
1464
+ } | undefined;
1465
+ execute(command: {
1466
+ version: 1;
1467
+ commandId: string;
1468
+ identity: ViewIntentDataSurfaceIdentity;
1469
+ expectedRevision: number;
1470
+ controlId: string;
1471
+ payload?: unknown;
1472
+ }): Promise<{
1473
+ ok: boolean;
1474
+ revision?: number;
1475
+ reason?: string;
1476
+ }>;
1477
+ }
1478
+
1479
+ /**
1480
+ * A data-surface target: the intent dispatches one
1481
+ * `DataSurfaceVisibleCommand` — a browser-visible state transition, never a
1482
+ * server-side query or mutation.
1483
+ */
1484
+ export declare interface ViewIntentDataSurfaceTarget {
1485
+ registry: 'dataSurface';
1486
+ /** The visible-command `controlId` the mounted surface implements. */
1487
+ controlId: string;
1488
+ surfaceId?: string;
1489
+ kind?: ViewIntentDataSurfaceKind;
1490
+ }
1491
+
1492
+ /**
1493
+ * The literal object passed to {@link defineIntent}. Every field is data;
1494
+ * none is a function, a URL, or a route.
1495
+ */
1496
+ export declare interface ViewIntentDeclaration {
1497
+ /**
1498
+ * Stable, namespaced identity — at least one dot, lowercase, e.g.
1499
+ * `orders.filter_by_status`. It is the intent's name in the manifest
1500
+ * (#2591) and in a playbook step (`{ kind: 'intent', id }`, #2589), so it
1501
+ * must not be derived from anything that can change (a namespace, a
1502
+ * generated tool name, a route).
1503
+ */
1504
+ id: string;
1505
+ /** Human/agent-readable description. Becomes the tool description. */
1506
+ description: string;
1507
+ /** JSON Schema for the tool's arguments. Must be plain JSON. */
1508
+ inputSchema?: Record<string, unknown>;
1509
+ /**
1510
+ * Partial capability declaration resolved by the shared fail-closed rule
1511
+ * (#2587). Omitted entirely, an intent classifies destructive,
1512
+ * non-idempotent, open-world.
1513
+ */
1514
+ capability?: WebMcpCapabilityDeclaration;
1515
+ /** Which registry this compiles into, and what it addresses there. */
1516
+ target: ViewIntentTarget;
1517
+ }
1518
+
1519
+ /**
1520
+ * The optional record a registry identity is qualified by. Rich forms use it
1521
+ * to tell apart controls that share a `formId`/`controlId` across records.
1522
+ * Structurally mirrors `ControlIdentity['subject']` /
1523
+ * `DataSurfaceIdentity['subject']` in `@happyvertical/smrt-ui`.
1524
+ */
1525
+ export declare interface ViewIntentSubject {
1526
+ type: string;
1527
+ id: string;
1528
+ label?: string;
1529
+ }
1530
+
1531
+ export declare type ViewIntentTarget = ViewIntentControlTarget | ViewIntentDataSurfaceTarget;
1532
+
1533
+ /** Derive the WebMCP tool name for an intent id. */
1534
+ export declare function viewIntentToolName(id: string): string;
1535
+
1536
+ /**
1537
+ * A bespoke tool spec, structurally identical to
1538
+ * `WebMcpBespokeToolSpec` in `./webmcp.js`. Declared here rather than
1539
+ * imported so this module stays free of even a type edge to the registrar
1540
+ * entry.
1541
+ */
1542
+ export declare interface ViewIntentToolSpec {
1543
+ name: string;
1544
+ description: string;
1545
+ inputSchema: Record<string, unknown>;
1546
+ annotations: WebMcpCapabilityAnnotations;
1547
+ execute: (args: Record<string, unknown>) => Promise<string>;
1548
+ }
1549
+
1550
+ /**
1551
+ * A hand-written browser tool from application code — not generated from a
1552
+ * `@smrt()` model. Structurally identical to the WebMCP `registerTool` input;
1553
+ * kept as a separate type so this framework-agnostic module never depends on
1554
+ * a UI layer's tool-spec type.
1555
+ */
1556
+ export declare interface WebMcpBespokeToolSpec {
1557
+ name: string;
1558
+ description: string;
1559
+ inputSchema: Record<string, unknown>;
1560
+ annotations?: {
1561
+ readOnlyHint?: boolean;
1562
+ destructiveHint?: boolean;
1563
+ idempotentHint?: boolean;
1564
+ openWorldHint?: boolean;
1565
+ untrustedContentHint?: boolean;
1566
+ };
1567
+ execute: (args: Record<string, unknown>) => string | Promise<string>;
1568
+ }
1569
+
1570
+ /** The MCP-shaped annotation set a resolved classification emits. */
1571
+ declare interface WebMcpCapabilityAnnotations {
1572
+ readOnlyHint: boolean;
1573
+ destructiveHint: boolean;
1574
+ idempotentHint: boolean;
1575
+ openWorldHint: boolean;
1576
+ untrustedContentHint: boolean;
1577
+ }
1578
+
1579
+ /** A fully resolved classification. */
1580
+ declare interface WebMcpCapabilityClassification {
1581
+ effect: WebMcpToolEffect;
1582
+ /**
1583
+ * Derived, never declared: every non-read effect is annotated destructive
1584
+ * to the browser, so a `write` capability cannot claim the MCP
1585
+ * additive-only guarantee.
1586
+ */
1587
+ destructive: boolean;
1588
+ idempotent: boolean;
1589
+ openWorld: boolean;
1590
+ }
1591
+
1592
+ /**
1593
+ * An author-supplied, partial classification. Any omitted field resolves
1594
+ * through the fail-closed rule on {@link resolveDeclaredCapability}, never
1595
+ * through a CRUD- or name-based guess.
1596
+ */
1597
+ declare interface WebMcpCapabilityDeclaration {
1598
+ effect?: WebMcpToolEffect;
1599
+ idempotent?: boolean;
1600
+ openWorld?: boolean;
1601
+ }
1602
+
1307
1603
  export declare interface WebMcpExposurePolicy {
1308
1604
  /** Allowed effects. Omitted means read-only exposure. */
1309
1605
  effects?: readonly WebMcpToolEffect[];
@@ -1345,6 +1641,30 @@ export declare interface WebMcpToolDefinition extends WebToolDescriptor {
1345
1641
  relationships: SmrtWebRelationship[];
1346
1642
  }
1347
1643
 
1644
+ /**
1645
+ * The one capability classification rule this package applies, extracted so
1646
+ * every declaration site in smrt-web shares a single implementation (#2587,
1647
+ * #2588).
1648
+ *
1649
+ * Two sites consume it today: `webmcp.ts` (canonical definitions trusted
1650
+ * through it directly, and its legacy CRUD switch's fail-closed default
1651
+ * branch) and `intents.ts` (a declared view intent, which is never a CRUD
1652
+ * verb and so resolves through the declaration rule alone). Keeping the rule
1653
+ * here rather than private to `webmcp.ts` is what lets the intent path be a
1654
+ * dependency-free module that never pulls the client-data engine.
1655
+ *
1656
+ * This module structurally mirrors `CapabilityEffect` / `CapabilityDeclaration`
1657
+ * / `CapabilityClassification` in `@happyvertical/smrt-types` rather than
1658
+ * importing them — this package's dependency-DAG guardrails keep it free of
1659
+ * every `@happyvertical/*` dependency (see AGENTS.md "No inter-smrt
1660
+ * dependencies"), the same reason `data-query.ts` mirrors that package's
1661
+ * bounded query envelope structurally instead of importing it.
1662
+ */
1663
+ /**
1664
+ * Browser/agent-visible effect classification for a capability. `'read'`
1665
+ * never mutates; `'write'` mutates within the application; `'destructive'`
1666
+ * may remove or irreversibly change data.
1667
+ */
1348
1668
  export declare type WebMcpToolEffect = 'read' | 'write' | 'destructive';
1349
1669
 
1350
1670
  /**
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
- import { A as MAX_SMRT_WEB_DATA_QUERY_RESULT_BYTES, C as registerDurableResource, D as MAX_SMRT_WEB_DATA_QUERY_FACET_VALUES, E as MAX_SMRT_WEB_DATA_QUERY_FACETS, F as normalizeSmrtWebDataQueryResult, I as runWrapMutation, M as MAX_SMRT_WEB_DATA_QUERY_STRING_LENGTH, N as MAX_SMRT_WEB_DATA_QUERY_WARNINGS, O as MAX_SMRT_WEB_DATA_QUERY_OFFSET, P as executeSmrtWebDataQuery, S as durableStoreNamespace, T as MAX_SMRT_WEB_DATA_QUERY_CONTAINER_ITEMS, _ as createSmrtWebQuery, a as createSmrtWebClient, b as getOutboxHandle, c as newLocalId, d as unwrapListResult, f as validateSmrtWebClient, g as liveInvalidation, h as createSmrtWebEventSubscriber, i as createSmrtCollection, j as MAX_SMRT_WEB_DATA_QUERY_ROWS, k as MAX_SMRT_WEB_DATA_QUERY_PAGE_LIMIT, l as throwIfSmrtWebError, m as createUpdateState, n as buildListQuery, o as getEngineCollection, p as registerWebMcpTools, r as createDefinitionFetchers, s as invalidateSmrtWebCollections, t as SmrtWebRequestError, u as unwrapItemResult, v as DEFAULT_PERSIST_DEBOUNCE_MS, w as wipeDurableStore, x as offlineOutbox, y as persistCollection } from "./chunks/src-n14q6RHC.js";
2
- export { DEFAULT_PERSIST_DEBOUNCE_MS, MAX_SMRT_WEB_DATA_QUERY_CONTAINER_ITEMS, MAX_SMRT_WEB_DATA_QUERY_FACETS, MAX_SMRT_WEB_DATA_QUERY_FACET_VALUES, MAX_SMRT_WEB_DATA_QUERY_OFFSET, MAX_SMRT_WEB_DATA_QUERY_PAGE_LIMIT, MAX_SMRT_WEB_DATA_QUERY_RESULT_BYTES, MAX_SMRT_WEB_DATA_QUERY_ROWS, MAX_SMRT_WEB_DATA_QUERY_STRING_LENGTH, MAX_SMRT_WEB_DATA_QUERY_WARNINGS, SmrtWebRequestError, buildListQuery, createDefinitionFetchers, createSmrtCollection, createSmrtWebClient, createSmrtWebEventSubscriber, createSmrtWebQuery, createUpdateState, durableStoreNamespace, executeSmrtWebDataQuery, getEngineCollection, getOutboxHandle, invalidateSmrtWebCollections, liveInvalidation, newLocalId, normalizeSmrtWebDataQueryResult, offlineOutbox, persistCollection, registerDurableResource, registerWebMcpTools, runWrapMutation, throwIfSmrtWebError, unwrapItemResult, unwrapListResult, validateSmrtWebClient, wipeDurableStore };
1
+ import { A as MAX_SMRT_WEB_DATA_QUERY_OFFSET, C as offlineOutbox, D as MAX_SMRT_WEB_DATA_QUERY_CONTAINER_ITEMS, E as wipeDurableStore, F as MAX_SMRT_WEB_DATA_QUERY_WARNINGS, I as executeSmrtWebDataQuery, L as normalizeSmrtWebDataQueryResult, M as MAX_SMRT_WEB_DATA_QUERY_RESULT_BYTES, N as MAX_SMRT_WEB_DATA_QUERY_ROWS, O as MAX_SMRT_WEB_DATA_QUERY_FACETS, P as MAX_SMRT_WEB_DATA_QUERY_STRING_LENGTH, R as runWrapMutation, S as getOutboxHandle, T as registerDurableResource, _ as createSmrtWebEventSubscriber, a as createSmrtWebClient, b as DEFAULT_PERSIST_DEBOUNCE_MS, c as newLocalId, d as unwrapListResult, f as validateSmrtWebClient, g as createUpdateState, h as registerWebMcpTools, i as createSmrtCollection, j as MAX_SMRT_WEB_DATA_QUERY_PAGE_LIMIT, k as MAX_SMRT_WEB_DATA_QUERY_FACET_VALUES, l as throwIfSmrtWebError, m as registerWebMcpBespokeTool, n as buildListQuery, o as getEngineCollection, p as registerViewIntent, r as createDefinitionFetchers, s as invalidateSmrtWebCollections, t as SmrtWebRequestError, u as unwrapItemResult, v as liveInvalidation, w as durableStoreNamespace, x as persistCollection, y as createSmrtWebQuery } from "./chunks/src-D1ZtD6Bt.js";
2
+ import { n as compileViewIntentToolSpec, o as viewIntentToolName } from "./chunks/intents-BUTyN7YQ.js";
3
+ export { DEFAULT_PERSIST_DEBOUNCE_MS, MAX_SMRT_WEB_DATA_QUERY_CONTAINER_ITEMS, MAX_SMRT_WEB_DATA_QUERY_FACETS, MAX_SMRT_WEB_DATA_QUERY_FACET_VALUES, MAX_SMRT_WEB_DATA_QUERY_OFFSET, MAX_SMRT_WEB_DATA_QUERY_PAGE_LIMIT, MAX_SMRT_WEB_DATA_QUERY_RESULT_BYTES, MAX_SMRT_WEB_DATA_QUERY_ROWS, MAX_SMRT_WEB_DATA_QUERY_STRING_LENGTH, MAX_SMRT_WEB_DATA_QUERY_WARNINGS, SmrtWebRequestError, buildListQuery, compileViewIntentToolSpec, createDefinitionFetchers, createSmrtCollection, createSmrtWebClient, createSmrtWebEventSubscriber, createSmrtWebQuery, createUpdateState, durableStoreNamespace, executeSmrtWebDataQuery, getEngineCollection, getOutboxHandle, invalidateSmrtWebCollections, liveInvalidation, newLocalId, normalizeSmrtWebDataQueryResult, offlineOutbox, persistCollection, registerDurableResource, registerViewIntent, registerWebMcpBespokeTool, registerWebMcpTools, runWrapMutation, throwIfSmrtWebError, unwrapItemResult, unwrapListResult, validateSmrtWebClient, viewIntentToolName, wipeDurableStore };
@@ -0,0 +1,300 @@
1
+ /**
2
+ * Drop every declared intent. For tests and HMR teardown; production code
3
+ * has no reason to call it.
4
+ */
5
+ export declare function clearViewIntentRegistry(): void;
6
+
7
+ /**
8
+ * Compile a declared intent plus a mounted binding into a bespoke tool spec.
9
+ *
10
+ * The `execute` this returns is built here from `intent.target`; nothing an
11
+ * author wrote is called. It dispatches exactly one registry command with
12
+ * `source: 'agent'`, so every policy the registry enforces — staged review,
13
+ * local-gesture proof, sensitivity, writability — applies unchanged.
14
+ *
15
+ * @throws if the binding does not match the intent's declared target.
16
+ */
17
+ export declare function compileViewIntentToolSpec(intent: ViewIntent, binding: ViewIntentBinding): ViewIntentToolSpec;
18
+
19
+ /**
20
+ * Declare a view intent.
21
+ *
22
+ * Call this at MODULE SCOPE with a single object literal — no spreads, no
23
+ * conditionals, no computed values — in a `.ts` module, conventionally a
24
+ * `Foo.intents.ts` sidecar beside the component that binds it. That form is
25
+ * the contract #2591's scanner matcher reads without evaluating the module.
26
+ *
27
+ * The returned intent is deeply frozen and registered under its `id`. A
28
+ * byte-identical re-declaration returns the SAME frozen object. A
29
+ * re-declaration that differs REPLACES the previous one and warns: editing a
30
+ * sidecar is what an HMR update is for, and throwing there would break the
31
+ * single most common dev action on these files. Two genuinely different
32
+ * intents sharing an id is an authoring mistake the warning surfaces, and one
33
+ * #2591's scanner catches statically, where both declarations are visible at
34
+ * once.
35
+ *
36
+ * @throws if the declaration is not static JSON data, carries an unknown
37
+ * key, carries a function anywhere, names a reserved tool namespace, or
38
+ * derives a WebMCP tool name another intent already derives.
39
+ */
40
+ export declare function defineIntent(declaration: ViewIntentDeclaration): ViewIntent;
41
+
42
+ /** Every intent declared in modules loaded so far, in declaration order. */
43
+ export declare function listViewIntents(): readonly ViewIntent[];
44
+
45
+ /**
46
+ * Look up a declared intent by id.
47
+ *
48
+ * Directly usable as `smrt-playbooks`' `PlaybookIntentResolver` seam (#2589):
49
+ * a {@link ViewIntent} satisfies its `PlaybookIntentRecord` shape, so an
50
+ * intent step inherits this intent's classification and browser-only plane
51
+ * validity rather than classifying itself.
52
+ */
53
+ export declare function resolveViewIntent(id: string): ViewIntent | undefined;
54
+
55
+ /**
56
+ * A validated, frozen intent.
57
+ *
58
+ * `kind: 'intent'` and `id` are the exported identity a `smrt-playbooks`
59
+ * step reference (`{ kind: 'intent', id }`) names, and this object is
60
+ * directly assignable to that package's `PlaybookIntentRecord` seam —
61
+ * `{ id, classification, planes }` — so {@link resolveViewIntent} can be
62
+ * passed as its `intents` resolver unchanged.
63
+ */
64
+ export declare interface ViewIntent {
65
+ readonly kind: 'intent';
66
+ readonly id: string;
67
+ readonly description: string;
68
+ readonly inputSchema: Record<string, unknown>;
69
+ /** Resolved through the shared fail-closed rule at declaration time. */
70
+ readonly classification: WebMcpCapabilityClassification;
71
+ readonly target: ViewIntentTarget;
72
+ /**
73
+ * An intent moves mounted browser state, so it is browser-valid only. A
74
+ * server-side agent reaches one through the #2446 command/ack bridge, which
75
+ * a playbook must declare explicitly.
76
+ */
77
+ readonly planes: readonly ['browser'];
78
+ }
79
+
80
+ /** The mounted identity a binding supplies for an intent's lifetime. */
81
+ export declare type ViewIntentBinding = {
82
+ registry: 'control';
83
+ registryPort: ViewIntentControlRegistryPort;
84
+ identity: ViewIntentControlIdentity;
85
+ } | {
86
+ registry: 'dataSurface';
87
+ registryPort: ViewIntentDataSurfaceRegistryPort;
88
+ identity: ViewIntentDataSurfaceIdentity;
89
+ };
90
+
91
+ /**
92
+ * Control commands a view intent may dispatch. Structurally mirrors
93
+ * `ControlCommandAction` in `@happyvertical/smrt-ui/forms`; this package
94
+ * cannot import that one (see AGENTS.md "No inter-smrt dependencies").
95
+ */
96
+ export declare type ViewIntentControlAction = 'focus' | 'reveal' | 'highlight' | 'explain' | 'validate' | 'stage' | 'apply' | 'discard' | 'clear' | 'undo';
97
+
98
+ /** A mounted control's full registry key, subject included. */
99
+ export declare interface ViewIntentControlIdentity {
100
+ formId: string;
101
+ controlId: string;
102
+ subject?: ViewIntentSubject;
103
+ }
104
+
105
+ /**
106
+ * The `ControlInteractionRegistry` surface an intent uses. Declared
107
+ * structurally so this package takes no dependency on
108
+ * `@happyvertical/smrt-ui`; the real registry satisfies it.
109
+ */
110
+ export declare interface ViewIntentControlRegistryPort {
111
+ execute(command: {
112
+ action: ViewIntentControlAction;
113
+ identity: ViewIntentControlIdentity;
114
+ value?: unknown;
115
+ durationMs?: number;
116
+ revision?: number;
117
+ }, context?: {
118
+ source: 'agent';
119
+ }): Promise<{
120
+ ok: boolean;
121
+ reason?: string;
122
+ }>;
123
+ }
124
+
125
+ /**
126
+ * A control-registry target: the intent dispatches exactly one
127
+ * `ControlInteractionRegistry` command against a mounted control.
128
+ *
129
+ * `formId`/`controlId` are the statically declared half of the identity. A
130
+ * binding supplies the mounted identity and must MATCH anything declared
131
+ * here — a declaration is authority over a binding, never the other way
132
+ * round.
133
+ */
134
+ export declare interface ViewIntentControlTarget {
135
+ registry: 'control';
136
+ action: ViewIntentControlAction;
137
+ formId?: string;
138
+ controlId?: string;
139
+ }
140
+
141
+ /** A mounted data surface's full registry key, subject included. */
142
+ export declare interface ViewIntentDataSurfaceIdentity {
143
+ surfaceId: string;
144
+ kind: ViewIntentDataSurfaceKind;
145
+ subject?: ViewIntentSubject;
146
+ }
147
+
148
+ /** Mirrors `DataSurfaceIdentity['kind']` in `@happyvertical/smrt-ui/data`. */
149
+ export declare type ViewIntentDataSurfaceKind = 'table' | 'list' | 'report' | 'custom';
150
+
151
+ /** The `DataSurfaceRegistry` surface an intent uses. */
152
+ export declare interface ViewIntentDataSurfaceRegistryPort {
153
+ inspect(identity: ViewIntentDataSurfaceIdentity): {
154
+ revision: number;
155
+ } | undefined;
156
+ execute(command: {
157
+ version: 1;
158
+ commandId: string;
159
+ identity: ViewIntentDataSurfaceIdentity;
160
+ expectedRevision: number;
161
+ controlId: string;
162
+ payload?: unknown;
163
+ }): Promise<{
164
+ ok: boolean;
165
+ revision?: number;
166
+ reason?: string;
167
+ }>;
168
+ }
169
+
170
+ /**
171
+ * A data-surface target: the intent dispatches one
172
+ * `DataSurfaceVisibleCommand` — a browser-visible state transition, never a
173
+ * server-side query or mutation.
174
+ */
175
+ export declare interface ViewIntentDataSurfaceTarget {
176
+ registry: 'dataSurface';
177
+ /** The visible-command `controlId` the mounted surface implements. */
178
+ controlId: string;
179
+ surfaceId?: string;
180
+ kind?: ViewIntentDataSurfaceKind;
181
+ }
182
+
183
+ /**
184
+ * The literal object passed to {@link defineIntent}. Every field is data;
185
+ * none is a function, a URL, or a route.
186
+ */
187
+ export declare interface ViewIntentDeclaration {
188
+ /**
189
+ * Stable, namespaced identity — at least one dot, lowercase, e.g.
190
+ * `orders.filter_by_status`. It is the intent's name in the manifest
191
+ * (#2591) and in a playbook step (`{ kind: 'intent', id }`, #2589), so it
192
+ * must not be derived from anything that can change (a namespace, a
193
+ * generated tool name, a route).
194
+ */
195
+ id: string;
196
+ /** Human/agent-readable description. Becomes the tool description. */
197
+ description: string;
198
+ /** JSON Schema for the tool's arguments. Must be plain JSON. */
199
+ inputSchema?: Record<string, unknown>;
200
+ /**
201
+ * Partial capability declaration resolved by the shared fail-closed rule
202
+ * (#2587). Omitted entirely, an intent classifies destructive,
203
+ * non-idempotent, open-world.
204
+ */
205
+ capability?: WebMcpCapabilityDeclaration;
206
+ /** Which registry this compiles into, and what it addresses there. */
207
+ target: ViewIntentTarget;
208
+ }
209
+
210
+ /**
211
+ * The optional record a registry identity is qualified by. Rich forms use it
212
+ * to tell apart controls that share a `formId`/`controlId` across records.
213
+ * Structurally mirrors `ControlIdentity['subject']` /
214
+ * `DataSurfaceIdentity['subject']` in `@happyvertical/smrt-ui`.
215
+ */
216
+ export declare interface ViewIntentSubject {
217
+ type: string;
218
+ id: string;
219
+ label?: string;
220
+ }
221
+
222
+ export declare type ViewIntentTarget = ViewIntentControlTarget | ViewIntentDataSurfaceTarget;
223
+
224
+ /** Derive the WebMCP tool name for an intent id. */
225
+ export declare function viewIntentToolName(id: string): string;
226
+
227
+ /**
228
+ * A bespoke tool spec, structurally identical to
229
+ * `WebMcpBespokeToolSpec` in `./webmcp.js`. Declared here rather than
230
+ * imported so this module stays free of even a type edge to the registrar
231
+ * entry.
232
+ */
233
+ export declare interface ViewIntentToolSpec {
234
+ name: string;
235
+ description: string;
236
+ inputSchema: Record<string, unknown>;
237
+ annotations: WebMcpCapabilityAnnotations;
238
+ execute: (args: Record<string, unknown>) => Promise<string>;
239
+ }
240
+
241
+ /** The MCP-shaped annotation set a resolved classification emits. */
242
+ declare interface WebMcpCapabilityAnnotations {
243
+ readOnlyHint: boolean;
244
+ destructiveHint: boolean;
245
+ idempotentHint: boolean;
246
+ openWorldHint: boolean;
247
+ untrustedContentHint: boolean;
248
+ }
249
+
250
+ /** A fully resolved classification. */
251
+ declare interface WebMcpCapabilityClassification {
252
+ effect: WebMcpToolEffect;
253
+ /**
254
+ * Derived, never declared: every non-read effect is annotated destructive
255
+ * to the browser, so a `write` capability cannot claim the MCP
256
+ * additive-only guarantee.
257
+ */
258
+ destructive: boolean;
259
+ idempotent: boolean;
260
+ openWorld: boolean;
261
+ }
262
+
263
+ /**
264
+ * An author-supplied, partial classification. Any omitted field resolves
265
+ * through the fail-closed rule on {@link resolveDeclaredCapability}, never
266
+ * through a CRUD- or name-based guess.
267
+ */
268
+ declare interface WebMcpCapabilityDeclaration {
269
+ effect?: WebMcpToolEffect;
270
+ idempotent?: boolean;
271
+ openWorld?: boolean;
272
+ }
273
+
274
+ /**
275
+ * The one capability classification rule this package applies, extracted so
276
+ * every declaration site in smrt-web shares a single implementation (#2587,
277
+ * #2588).
278
+ *
279
+ * Two sites consume it today: `webmcp.ts` (canonical definitions trusted
280
+ * through it directly, and its legacy CRUD switch's fail-closed default
281
+ * branch) and `intents.ts` (a declared view intent, which is never a CRUD
282
+ * verb and so resolves through the declaration rule alone). Keeping the rule
283
+ * here rather than private to `webmcp.ts` is what lets the intent path be a
284
+ * dependency-free module that never pulls the client-data engine.
285
+ *
286
+ * This module structurally mirrors `CapabilityEffect` / `CapabilityDeclaration`
287
+ * / `CapabilityClassification` in `@happyvertical/smrt-types` rather than
288
+ * importing them — this package's dependency-DAG guardrails keep it free of
289
+ * every `@happyvertical/*` dependency (see AGENTS.md "No inter-smrt
290
+ * dependencies"), the same reason `data-query.ts` mirrors that package's
291
+ * bounded query envelope structurally instead of importing it.
292
+ */
293
+ /**
294
+ * Browser/agent-visible effect classification for a capability. `'read'`
295
+ * never mutates; `'write'` mutates within the application; `'destructive'`
296
+ * may remove or irreversibly change data.
297
+ */
298
+ declare type WebMcpToolEffect = 'read' | 'write' | 'destructive';
299
+
300
+ export { }
@@ -0,0 +1,2 @@
1
+ import { a as resolveViewIntent, i as listViewIntents, n as compileViewIntentToolSpec, o as viewIntentToolName, r as defineIntent, t as clearViewIntentRegistry } from "./chunks/intents-BUTyN7YQ.js";
2
+ export { clearViewIntentRegistry, compileViewIntentToolSpec, defineIntent, listViewIntents, resolveViewIntent, viewIntentToolName };