@contractspec/lib.surface-runtime 0.2.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.
Files changed (232) hide show
  1. package/README.md +164 -0
  2. package/dist/adapters/ai-sdk-stub.d.ts +5 -0
  3. package/dist/adapters/ai-sdk-stub.js +13 -0
  4. package/dist/adapters/blocknote-stub.d.ts +6 -0
  5. package/dist/adapters/blocknote-stub.js +31 -0
  6. package/dist/adapters/dnd-kit-adapter.d.ts +13 -0
  7. package/dist/adapters/dnd-kit-adapter.js +44 -0
  8. package/dist/adapters/dnd-kit-stub.d.ts +6 -0
  9. package/dist/adapters/dnd-kit-stub.js +8 -0
  10. package/dist/adapters/floating-ui-stub.d.ts +6 -0
  11. package/dist/adapters/floating-ui-stub.js +19 -0
  12. package/dist/adapters/index.d.ts +11 -0
  13. package/dist/adapters/index.js +176 -0
  14. package/dist/adapters/interfaces.d.ts +75 -0
  15. package/dist/adapters/interfaces.js +1 -0
  16. package/dist/adapters/motion-stub.d.ts +7 -0
  17. package/dist/adapters/motion-stub.js +27 -0
  18. package/dist/adapters/motion-stub.test.d.ts +1 -0
  19. package/dist/adapters/resizable-panels-stub.d.ts +6 -0
  20. package/dist/adapters/resizable-panels-stub.js +46 -0
  21. package/dist/adapters/resizable-panels-stub.test.d.ts +1 -0
  22. package/dist/browser/adapters/ai-sdk-stub.js +12 -0
  23. package/dist/browser/adapters/blocknote-stub.js +30 -0
  24. package/dist/browser/adapters/dnd-kit-adapter.js +43 -0
  25. package/dist/browser/adapters/dnd-kit-stub.js +7 -0
  26. package/dist/browser/adapters/floating-ui-stub.js +18 -0
  27. package/dist/browser/adapters/index.js +175 -0
  28. package/dist/browser/adapters/interfaces.js +0 -0
  29. package/dist/browser/adapters/motion-stub.js +26 -0
  30. package/dist/browser/adapters/resizable-panels-stub.js +45 -0
  31. package/dist/browser/evals/golden-context.js +0 -0
  32. package/dist/browser/evals/golden-harness.js +848 -0
  33. package/dist/browser/examples/pm-workbench.bundle.js +476 -0
  34. package/dist/browser/i18n/catalogs/en.js +71 -0
  35. package/dist/browser/i18n/catalogs/es.js +32 -0
  36. package/dist/browser/i18n/catalogs/fr.js +32 -0
  37. package/dist/browser/i18n/catalogs/index.js +133 -0
  38. package/dist/browser/i18n/index.js +173 -0
  39. package/dist/browser/i18n/keys.js +19 -0
  40. package/dist/browser/i18n/messages.js +143 -0
  41. package/dist/browser/index.js +2466 -0
  42. package/dist/browser/react/BundleProvider.js +47 -0
  43. package/dist/browser/react/BundleRenderer.js +726 -0
  44. package/dist/browser/react/OverlayConflictResolver.js +255 -0
  45. package/dist/browser/react/PatchProposalCard.js +255 -0
  46. package/dist/browser/react/RegionRenderer.js +128 -0
  47. package/dist/browser/react/SlotRenderer.js +118 -0
  48. package/dist/browser/react/WidgetPalette.js +59 -0
  49. package/dist/browser/react/index.js +792 -0
  50. package/dist/browser/runtime/apply-surface-patch.js +322 -0
  51. package/dist/browser/runtime/audit-events.js +137 -0
  52. package/dist/browser/runtime/build-context.js +55 -0
  53. package/dist/browser/runtime/extension-registry.js +58 -0
  54. package/dist/browser/runtime/field-renderer-registry.js +145 -0
  55. package/dist/browser/runtime/index.js +1496 -0
  56. package/dist/browser/runtime/overlay-alignment.js +83 -0
  57. package/dist/browser/runtime/overlay-signer.js +15 -0
  58. package/dist/browser/runtime/override-store.js +52 -0
  59. package/dist/browser/runtime/planner-prompt.js +67 -0
  60. package/dist/browser/runtime/planner-tools.js +77 -0
  61. package/dist/browser/runtime/policy-eval.js +155 -0
  62. package/dist/browser/runtime/preference-adapter.js +67 -0
  63. package/dist/browser/runtime/resolve-bundle.js +767 -0
  64. package/dist/browser/runtime/resolve-preferences.js +59 -0
  65. package/dist/browser/runtime/rollback.js +347 -0
  66. package/dist/browser/runtime/widget-registry.js +36 -0
  67. package/dist/browser/spec/define-module-bundle.js +113 -0
  68. package/dist/browser/spec/index.js +319 -0
  69. package/dist/browser/spec/types.js +0 -0
  70. package/dist/browser/spec/validate-bundle.js +65 -0
  71. package/dist/browser/spec/validate-surface-patch.js +206 -0
  72. package/dist/browser/spec/verification-snapshot-types.js +0 -0
  73. package/dist/browser/telemetry/index.js +20 -0
  74. package/dist/browser/telemetry/surface-metrics.js +20 -0
  75. package/dist/evals/golden-context.d.ts +24 -0
  76. package/dist/evals/golden-context.js +1 -0
  77. package/dist/evals/golden-harness.d.ts +29 -0
  78. package/dist/evals/golden-harness.js +849 -0
  79. package/dist/evals/golden-harness.test.d.ts +1 -0
  80. package/dist/examples/pm-workbench.bundle.d.ts +177 -0
  81. package/dist/examples/pm-workbench.bundle.js +477 -0
  82. package/dist/i18n/catalogs/en.d.ts +1 -0
  83. package/dist/i18n/catalogs/en.js +72 -0
  84. package/dist/i18n/catalogs/es.d.ts +1 -0
  85. package/dist/i18n/catalogs/es.js +33 -0
  86. package/dist/i18n/catalogs/fr.d.ts +1 -0
  87. package/dist/i18n/catalogs/fr.js +33 -0
  88. package/dist/i18n/catalogs/index.d.ts +3 -0
  89. package/dist/i18n/catalogs/index.js +134 -0
  90. package/dist/i18n/index.d.ts +5 -0
  91. package/dist/i18n/index.js +174 -0
  92. package/dist/i18n/keys.d.ts +20 -0
  93. package/dist/i18n/keys.js +20 -0
  94. package/dist/i18n/messages.d.ts +5 -0
  95. package/dist/i18n/messages.js +144 -0
  96. package/dist/index.d.ts +4 -0
  97. package/dist/index.js +2467 -0
  98. package/dist/node/adapters/ai-sdk-stub.js +12 -0
  99. package/dist/node/adapters/blocknote-stub.js +30 -0
  100. package/dist/node/adapters/dnd-kit-adapter.js +43 -0
  101. package/dist/node/adapters/dnd-kit-stub.js +7 -0
  102. package/dist/node/adapters/floating-ui-stub.js +18 -0
  103. package/dist/node/adapters/index.js +175 -0
  104. package/dist/node/adapters/interfaces.js +0 -0
  105. package/dist/node/adapters/motion-stub.js +26 -0
  106. package/dist/node/adapters/resizable-panels-stub.js +45 -0
  107. package/dist/node/evals/golden-context.js +0 -0
  108. package/dist/node/evals/golden-harness.js +848 -0
  109. package/dist/node/examples/pm-workbench.bundle.js +476 -0
  110. package/dist/node/i18n/catalogs/en.js +71 -0
  111. package/dist/node/i18n/catalogs/es.js +32 -0
  112. package/dist/node/i18n/catalogs/fr.js +32 -0
  113. package/dist/node/i18n/catalogs/index.js +133 -0
  114. package/dist/node/i18n/index.js +173 -0
  115. package/dist/node/i18n/keys.js +19 -0
  116. package/dist/node/i18n/messages.js +143 -0
  117. package/dist/node/index.js +2466 -0
  118. package/dist/node/react/BundleProvider.js +47 -0
  119. package/dist/node/react/BundleRenderer.js +726 -0
  120. package/dist/node/react/OverlayConflictResolver.js +255 -0
  121. package/dist/node/react/PatchProposalCard.js +255 -0
  122. package/dist/node/react/RegionRenderer.js +128 -0
  123. package/dist/node/react/SlotRenderer.js +118 -0
  124. package/dist/node/react/WidgetPalette.js +59 -0
  125. package/dist/node/react/index.js +792 -0
  126. package/dist/node/runtime/apply-surface-patch.js +322 -0
  127. package/dist/node/runtime/audit-events.js +137 -0
  128. package/dist/node/runtime/build-context.js +55 -0
  129. package/dist/node/runtime/extension-registry.js +58 -0
  130. package/dist/node/runtime/field-renderer-registry.js +145 -0
  131. package/dist/node/runtime/index.js +1496 -0
  132. package/dist/node/runtime/overlay-alignment.js +83 -0
  133. package/dist/node/runtime/overlay-signer.js +15 -0
  134. package/dist/node/runtime/override-store.js +52 -0
  135. package/dist/node/runtime/planner-prompt.js +67 -0
  136. package/dist/node/runtime/planner-tools.js +77 -0
  137. package/dist/node/runtime/policy-eval.js +155 -0
  138. package/dist/node/runtime/preference-adapter.js +67 -0
  139. package/dist/node/runtime/resolve-bundle.js +767 -0
  140. package/dist/node/runtime/resolve-preferences.js +59 -0
  141. package/dist/node/runtime/rollback.js +347 -0
  142. package/dist/node/runtime/widget-registry.js +36 -0
  143. package/dist/node/spec/define-module-bundle.js +113 -0
  144. package/dist/node/spec/index.js +319 -0
  145. package/dist/node/spec/types.js +0 -0
  146. package/dist/node/spec/validate-bundle.js +65 -0
  147. package/dist/node/spec/validate-surface-patch.js +206 -0
  148. package/dist/node/spec/verification-snapshot-types.js +0 -0
  149. package/dist/node/telemetry/index.js +20 -0
  150. package/dist/node/telemetry/surface-metrics.js +20 -0
  151. package/dist/react/BundleProvider.d.ts +13 -0
  152. package/dist/react/BundleProvider.js +48 -0
  153. package/dist/react/BundleRenderer.d.ts +22 -0
  154. package/dist/react/BundleRenderer.js +727 -0
  155. package/dist/react/OverlayConflictResolver.d.ts +15 -0
  156. package/dist/react/OverlayConflictResolver.js +256 -0
  157. package/dist/react/PatchProposalCard.d.ts +13 -0
  158. package/dist/react/PatchProposalCard.js +256 -0
  159. package/dist/react/RegionRenderer.d.ts +13 -0
  160. package/dist/react/RegionRenderer.js +129 -0
  161. package/dist/react/SlotRenderer.d.ts +13 -0
  162. package/dist/react/SlotRenderer.js +119 -0
  163. package/dist/react/WidgetPalette.d.ts +12 -0
  164. package/dist/react/WidgetPalette.js +60 -0
  165. package/dist/react/index.d.ts +7 -0
  166. package/dist/react/index.js +793 -0
  167. package/dist/runtime/apply-surface-patch.d.ts +15 -0
  168. package/dist/runtime/apply-surface-patch.js +323 -0
  169. package/dist/runtime/apply-surface-patch.test.d.ts +1 -0
  170. package/dist/runtime/audit-events.d.ts +70 -0
  171. package/dist/runtime/audit-events.js +138 -0
  172. package/dist/runtime/audit-events.test.d.ts +1 -0
  173. package/dist/runtime/build-context.d.ts +9 -0
  174. package/dist/runtime/build-context.js +56 -0
  175. package/dist/runtime/extension-registry.d.ts +39 -0
  176. package/dist/runtime/extension-registry.js +59 -0
  177. package/dist/runtime/field-renderer-registry.d.ts +23 -0
  178. package/dist/runtime/field-renderer-registry.js +146 -0
  179. package/dist/runtime/field-renderer-registry.test.d.ts +1 -0
  180. package/dist/runtime/index.d.ts +16 -0
  181. package/dist/runtime/index.js +1497 -0
  182. package/dist/runtime/overlay-alignment.d.ts +49 -0
  183. package/dist/runtime/overlay-alignment.js +84 -0
  184. package/dist/runtime/overlay-alignment.test.d.ts +1 -0
  185. package/dist/runtime/overlay-signer.d.ts +15 -0
  186. package/dist/runtime/overlay-signer.js +16 -0
  187. package/dist/runtime/override-store.d.ts +44 -0
  188. package/dist/runtime/override-store.js +53 -0
  189. package/dist/runtime/override-store.test.d.ts +1 -0
  190. package/dist/runtime/planner-prompt.d.ts +39 -0
  191. package/dist/runtime/planner-prompt.js +68 -0
  192. package/dist/runtime/planner-prompt.test.d.ts +1 -0
  193. package/dist/runtime/planner-tools.d.ts +106 -0
  194. package/dist/runtime/planner-tools.js +78 -0
  195. package/dist/runtime/planner-tools.test.d.ts +1 -0
  196. package/dist/runtime/policy-eval.d.ts +23 -0
  197. package/dist/runtime/policy-eval.js +156 -0
  198. package/dist/runtime/preference-adapter.d.ts +6 -0
  199. package/dist/runtime/preference-adapter.js +68 -0
  200. package/dist/runtime/resolve-bundle.d.ts +68 -0
  201. package/dist/runtime/resolve-bundle.js +768 -0
  202. package/dist/runtime/resolve-bundle.test.d.ts +1 -0
  203. package/dist/runtime/resolve-preferences.d.ts +9 -0
  204. package/dist/runtime/resolve-preferences.js +60 -0
  205. package/dist/runtime/resolve-preferences.test.d.ts +1 -0
  206. package/dist/runtime/rollback.d.ts +21 -0
  207. package/dist/runtime/rollback.js +348 -0
  208. package/dist/runtime/rollback.test.d.ts +1 -0
  209. package/dist/runtime/widget-registry.d.ts +26 -0
  210. package/dist/runtime/widget-registry.js +37 -0
  211. package/dist/runtime/widget-registry.test.d.ts +1 -0
  212. package/dist/spec/define-module-bundle.d.ts +17 -0
  213. package/dist/spec/define-module-bundle.js +114 -0
  214. package/dist/spec/define-module-bundle.test.d.ts +1 -0
  215. package/dist/spec/index.d.ts +5 -0
  216. package/dist/spec/index.js +320 -0
  217. package/dist/spec/types.d.ts +494 -0
  218. package/dist/spec/types.js +1 -0
  219. package/dist/spec/validate-bundle.d.ts +23 -0
  220. package/dist/spec/validate-bundle.js +66 -0
  221. package/dist/spec/validate-bundle.test.d.ts +1 -0
  222. package/dist/spec/validate-surface-patch.d.ts +39 -0
  223. package/dist/spec/validate-surface-patch.js +207 -0
  224. package/dist/spec/validate-surface-patch.test.d.ts +1 -0
  225. package/dist/spec/verification-snapshot-types.d.ts +23 -0
  226. package/dist/spec/verification-snapshot-types.js +1 -0
  227. package/dist/spec/verification-snapshot.test.d.ts +5 -0
  228. package/dist/telemetry/index.d.ts +5 -0
  229. package/dist/telemetry/index.js +21 -0
  230. package/dist/telemetry/surface-metrics.d.ts +17 -0
  231. package/dist/telemetry/surface-metrics.js +21 -0
  232. package/package.json +920 -0
@@ -0,0 +1,494 @@
1
+ /**
2
+ * Core bundle spec types for @contractspec/lib.surface-runtime.
3
+ * Aligns with 03_core_bundle_spec.md and 01_preference_dimensions.md.
4
+ */
5
+ export type BundleScope = 'system' | 'workspace' | 'team' | 'user' | 'session';
6
+ export type SurfaceKind = 'overview' | 'list' | 'detail' | 'editor' | 'workbench' | 'assistant' | 'board' | 'timeline' | 'canvas';
7
+ export interface PreferenceDimensions {
8
+ guidance: 'none' | 'hints' | 'tooltips' | 'walkthrough' | 'wizard';
9
+ density: 'minimal' | 'compact' | 'standard' | 'detailed' | 'dense';
10
+ dataDepth: 'summary' | 'standard' | 'detailed' | 'exhaustive';
11
+ control: 'restricted' | 'standard' | 'advanced' | 'full';
12
+ media: 'text' | 'visual' | 'voice' | 'hybrid';
13
+ pace: 'deliberate' | 'balanced' | 'rapid';
14
+ narrative: 'top-down' | 'bottom-up' | 'adaptive';
15
+ }
16
+ /** Scope from which a preference value was resolved. Order: user → workspace-user → bundle → surface → entity → session. */
17
+ export type PreferenceScope = 'user' | 'workspace-user' | 'bundle' | 'surface' | 'entity' | 'session';
18
+ /** Resolved preference profile with source attribution and constraint notes per dimension. */
19
+ export interface ResolvedPreferenceProfile {
20
+ /** Canonical values after scope merge and constraint resolution. */
21
+ canonical: PreferenceDimensions;
22
+ /** Source scope per dimension (which layer provided the value). */
23
+ sourceByDimension: Partial<Record<keyof PreferenceDimensions, PreferenceScope>>;
24
+ /** Dimensions that were constrained (requested value not applied); value = reason. */
25
+ constrained: Partial<Record<keyof PreferenceDimensions, string>>;
26
+ /** Human-readable notes (e.g. constraint reasons, fallbacks). */
27
+ notes: string[];
28
+ }
29
+ /** Adapter for resolving and persisting preferences in the bundle runtime. */
30
+ export interface BundlePreferenceAdapter {
31
+ resolve(ctx: BundleContext): Promise<ResolvedPreferenceProfile>;
32
+ savePreferencePatch(args: {
33
+ actorId: string;
34
+ workspaceId?: string;
35
+ patch: Partial<PreferenceDimensions>;
36
+ scope: 'user' | 'workspace-user' | 'surface';
37
+ }): Promise<void>;
38
+ }
39
+ export interface BundleContext {
40
+ tenantId: string;
41
+ workspaceId?: string;
42
+ actorId?: string;
43
+ route: string;
44
+ params: Record<string, string>;
45
+ query: Record<string, string | string[]>;
46
+ device: 'desktop' | 'tablet' | 'mobile';
47
+ mode?: 'guided' | 'pro' | 'autopilot';
48
+ locale?: string;
49
+ timezone?: string;
50
+ entity?: {
51
+ type: string;
52
+ id: string;
53
+ };
54
+ conversation?: {
55
+ threadId?: string;
56
+ assistantId?: string;
57
+ activeIntent?: string;
58
+ };
59
+ /** Active saved view ID (viewKind key). When set, layout selection prefers view's defaultLayoutId. */
60
+ activeViewId?: string;
61
+ preferences: PreferenceDimensions;
62
+ capabilities: string[];
63
+ featureFlags?: string[];
64
+ }
65
+ /** Predicate for route/surface/layout selection. */
66
+ export type BundlePredicate<C extends BundleContext = BundleContext> = (ctx: C) => boolean;
67
+ /** Minimal params to build a BundleContext. Missing fields use defaults. */
68
+ export interface BuildContextParams {
69
+ route: string;
70
+ params?: Record<string, string>;
71
+ query?: Record<string, string | string[]>;
72
+ tenantId?: string;
73
+ workspaceId?: string;
74
+ actorId?: string;
75
+ device?: 'desktop' | 'tablet' | 'mobile';
76
+ preferences?: Partial<PreferenceDimensions>;
77
+ capabilities?: string[];
78
+ featureFlags?: string[];
79
+ mode?: 'guided' | 'pro' | 'autopilot';
80
+ locale?: string;
81
+ timezone?: string;
82
+ entity?: {
83
+ type: string;
84
+ id: string;
85
+ };
86
+ conversation?: {
87
+ threadId?: string;
88
+ assistantId?: string;
89
+ activeIntent?: string;
90
+ };
91
+ /** Active saved view ID (viewKind key). When set, layout selection prefers view's defaultLayoutId. */
92
+ activeViewId?: string;
93
+ }
94
+ export type BundleNodeKind = 'metric-strip' | 'data-view' | 'entity-card' | 'entity-header' | 'entity-summary' | 'entity-section' | 'entity-field' | 'entity-activity' | 'entity-relations' | 'entity-timeline' | 'entity-comments' | 'entity-attachments' | 'entity-view-switcher' | 'entity-automation-panel' | 'rich-doc' | 'chat-thread' | 'assistant-panel' | 'action-bar' | 'timeline' | 'board' | 'table' | 'calendar' | 'form' | 'chart' | 'relation-graph' | 'custom-widget';
95
+ export interface BundleMeta {
96
+ key: string;
97
+ version: string;
98
+ title: string;
99
+ description?: string;
100
+ owners?: string[];
101
+ tags?: string[];
102
+ stability?: 'experimental' | 'beta' | 'stable';
103
+ }
104
+ /** Supported field kinds for entity rendering. */
105
+ export type EntityFieldKind = 'text' | 'number' | 'date' | 'checkbox' | 'select' | 'options' | 'instance' | 'url' | 'relation' | 'rollup' | 'formula' | 'people';
106
+ /** Spec for how a field kind is rendered (viewer, editor, table cell, etc.). */
107
+ export interface FieldRendererSpec {
108
+ fieldKind: string;
109
+ viewer: string;
110
+ editor?: string;
111
+ summaryViewer?: string;
112
+ tableCell?: string;
113
+ filters?: string[];
114
+ validators?: string[];
115
+ }
116
+ /** Spec for how a section type is rendered. */
117
+ export interface SectionRendererSpec {
118
+ sectionKind: string;
119
+ renderer: string;
120
+ defaultCollapsed?: boolean;
121
+ densityBehavior?: 'minimal' | 'compact' | 'standard' | 'detailed';
122
+ }
123
+ /** Spec for how a saved view type is applied. */
124
+ export interface ViewRendererSpec {
125
+ viewKind: string;
126
+ renderer: string;
127
+ defaultLayoutId?: string;
128
+ promotedActions?: string[];
129
+ }
130
+ /** Per-entity-type surface configuration. */
131
+ export interface EntityTypeSurfaceSpec {
132
+ entityType: string;
133
+ defaultSurfaceId: string;
134
+ detailBlueprints: string[];
135
+ supportedViews: string[];
136
+ sectionsFromSchema?: boolean;
137
+ fieldsFromSchema?: boolean;
138
+ relationPanels?: string[];
139
+ }
140
+ /** Registry of entity types, field kinds, sections, and views. */
141
+ export interface EntitySurfaceRegistrySpec {
142
+ entityTypes: Record<string, EntityTypeSurfaceSpec>;
143
+ fieldKinds: Record<string, FieldRendererSpec>;
144
+ sectionKinds?: Record<string, SectionRendererSpec>;
145
+ viewKinds?: Record<string, ViewRendererSpec>;
146
+ }
147
+ /** Resolved field for entity rendering. */
148
+ export interface ResolvedField {
149
+ fieldId: string;
150
+ fieldKind: string;
151
+ title: string;
152
+ visible: boolean;
153
+ editable: boolean;
154
+ required: boolean;
155
+ sectionId?: string;
156
+ }
157
+ /** Resolved section for entity layout. */
158
+ export interface ResolvedSection {
159
+ sectionId: string;
160
+ sectionKind: string;
161
+ title: string;
162
+ collapsed?: boolean;
163
+ fieldIds: string[];
164
+ }
165
+ /** Resolved saved view preset. */
166
+ export interface ResolvedViewPreset {
167
+ viewId: string;
168
+ viewKind: string;
169
+ title: string;
170
+ filter?: unknown;
171
+ sort?: unknown;
172
+ group?: unknown;
173
+ displayType?: string;
174
+ visibleFieldIds?: string[];
175
+ layoutHints?: Record<string, unknown>;
176
+ }
177
+ /** Resolved entity schema for rendering. */
178
+ export interface ResolvedEntitySchema {
179
+ entityType: string;
180
+ sections: ResolvedSection[];
181
+ fields: ResolvedField[];
182
+ views: ResolvedViewPreset[];
183
+ }
184
+ /** Resolver for entity schemas. Stub in Phase 3; full impl deferred. */
185
+ export interface EntitySurfaceResolver {
186
+ resolveEntitySchema(args: {
187
+ entityType: string;
188
+ entityId: string;
189
+ workspaceId?: string;
190
+ }): Promise<ResolvedEntitySchema>;
191
+ }
192
+ export interface BundlePresetSpec {
193
+ presetId: string;
194
+ title: string;
195
+ description?: string;
196
+ preferencePatch: Partial<PreferenceDimensions>;
197
+ defaultLayoutIdBySurface?: Record<string, string>;
198
+ }
199
+ export interface BundleExtensionPointSpec {
200
+ extensionPointId: string;
201
+ title: string;
202
+ accepts: 'widget' | 'field-renderer' | 'action' | 'command' | 'surface-patch';
203
+ trust: 'core' | 'workspace' | 'signed-plugin' | 'ephemeral-ai';
204
+ }
205
+ export interface BundleTelemetrySpec {
206
+ namespace: string;
207
+ emitSurfaceResolved?: boolean;
208
+ emitPatchApplied?: boolean;
209
+ emitIntentMatched?: boolean;
210
+ emitPreferenceAdaptation?: boolean;
211
+ }
212
+ export interface BundleGovernanceSpec {
213
+ requireApprovalForWorkspacePatches?: boolean;
214
+ requireApprovalForAiPatches?: boolean;
215
+ retainAuditDays?: number;
216
+ }
217
+ export interface ModuleBundleSpec<C extends BundleContext = BundleContext> {
218
+ meta: BundleMeta;
219
+ /** Required features (e.g. ai-chat, metering) from contracts-spec defineFeature. */
220
+ requires?: {
221
+ key: string;
222
+ version: string;
223
+ }[];
224
+ routes: BundleRouteSpec<C>[];
225
+ surfaces: Record<string, SurfaceSpec<C>>;
226
+ entities?: EntitySurfaceRegistrySpec;
227
+ presets?: BundlePresetSpec[];
228
+ ai?: BundleAiSpec<C>;
229
+ extensions?: BundleExtensionPointSpec[];
230
+ telemetry?: BundleTelemetrySpec;
231
+ governance?: BundleGovernanceSpec;
232
+ }
233
+ export interface BundleRouteSpec<C extends BundleContext = BundleContext> {
234
+ routeId: string;
235
+ path: string;
236
+ defaultSurface: string;
237
+ candidateSurfaces?: string[];
238
+ when?: BundlePredicate<C>;
239
+ }
240
+ export interface ActionSpec {
241
+ actionId: string;
242
+ title: string;
243
+ operationKey?: string;
244
+ intent?: string;
245
+ placement?: 'header' | 'inline' | 'context' | 'assistant';
246
+ requiresCapabilities?: string[];
247
+ }
248
+ export interface CommandSpec {
249
+ commandId: string;
250
+ title: string;
251
+ intent: string;
252
+ shortcut?: string[];
253
+ }
254
+ export interface SurfaceSpec<C extends BundleContext = BundleContext> {
255
+ surfaceId: string;
256
+ kind: SurfaceKind;
257
+ title: string;
258
+ when?: BundlePredicate<C>;
259
+ priority?: number;
260
+ slots: SlotSpec[];
261
+ layouts: LayoutBlueprintSpec<C>[];
262
+ data: DataRecipeSpec<C>[];
263
+ actions?: ActionSpec[];
264
+ commands?: CommandSpec[];
265
+ ai?: SurfaceAiSpec<C>;
266
+ verification: SurfaceVerificationSpec;
267
+ }
268
+ export interface SlotSpec {
269
+ slotId: string;
270
+ role: 'header' | 'primary' | 'secondary' | 'assistant' | 'inspector' | 'footer' | 'floating' | 'command';
271
+ accepts: BundleNodeKind[];
272
+ cardinality: 'one' | 'many';
273
+ mutableByAi?: boolean;
274
+ mutableByUser?: boolean;
275
+ }
276
+ export interface LayoutBlueprintSpec<C extends BundleContext = BundleContext> {
277
+ layoutId: string;
278
+ title?: string;
279
+ when?: BundlePredicate<C>;
280
+ root: RegionNode;
281
+ }
282
+ export type RegionNode = PanelGroupRegion | StackRegion | TabsRegion | FloatingRegion | SlotRegion;
283
+ export interface PanelGroupRegion {
284
+ type: 'panel-group';
285
+ direction: 'horizontal' | 'vertical';
286
+ persistKey?: string;
287
+ children: RegionNode[];
288
+ }
289
+ export interface StackRegion {
290
+ type: 'stack';
291
+ direction: 'vertical' | 'horizontal';
292
+ gap?: 'none' | 'xs' | 'sm' | 'md' | 'lg';
293
+ children: RegionNode[];
294
+ }
295
+ export interface TabsRegion {
296
+ type: 'tabs';
297
+ tabs: {
298
+ key: string;
299
+ title: string;
300
+ child: RegionNode;
301
+ }[];
302
+ }
303
+ export interface FloatingRegion {
304
+ type: 'floating';
305
+ anchorSlotId: string;
306
+ child: RegionNode;
307
+ }
308
+ export interface SlotRegion {
309
+ type: 'slot';
310
+ slotId: string;
311
+ }
312
+ export interface DataRecipeSpec<C extends BundleContext = BundleContext> {
313
+ recipeId: string;
314
+ source: {
315
+ kind: 'operation';
316
+ key: string;
317
+ } | {
318
+ kind: 'data-view';
319
+ key: string;
320
+ } | {
321
+ kind: 'entity';
322
+ entityType: string;
323
+ };
324
+ when?: BundlePredicate<C>;
325
+ requestedDepth?: C['preferences']['dataDepth'];
326
+ hydrateInto?: string;
327
+ cacheTtlMs?: number;
328
+ }
329
+ export interface BundleAiSpec<C extends BundleContext = BundleContext> {
330
+ plannerId: string;
331
+ allowedPatchOps: SurfacePatchOp['op'][];
332
+ plannerPrompt: string;
333
+ maxPatchOpsPerTurn?: number;
334
+ canAskFollowUp?: boolean;
335
+ contextualTools?: string[];
336
+ when?: BundlePredicate<C>;
337
+ }
338
+ export interface SurfaceAiSpec<C extends BundleContext = BundleContext> {
339
+ assistantSlotId?: string;
340
+ allowLayoutPatches?: boolean;
341
+ allowSlotInsertion?: boolean;
342
+ allowedNodeKinds?: BundleNodeKind[];
343
+ allowedSlots?: string[];
344
+ plannerOverrides?: Partial<BundleAiSpec<C>>;
345
+ }
346
+ export interface SurfaceVerificationSpec {
347
+ dimensions: {
348
+ guidance: string;
349
+ density: string;
350
+ dataDepth: string;
351
+ control: string;
352
+ media: string;
353
+ pace: string;
354
+ narrative: string;
355
+ };
356
+ }
357
+ export interface SurfaceNode {
358
+ nodeId: string;
359
+ kind: BundleNodeKind;
360
+ title?: string;
361
+ props?: Record<string, unknown>;
362
+ children?: SurfaceNode[];
363
+ sourceBinding?: {
364
+ recipeId?: string;
365
+ entityType?: string;
366
+ fieldId?: string;
367
+ };
368
+ }
369
+ export type SurfacePatchOp = {
370
+ op: 'insert-node';
371
+ slotId: string;
372
+ node: SurfaceNode;
373
+ index?: number;
374
+ } | {
375
+ op: 'replace-node';
376
+ nodeId: string;
377
+ node: SurfaceNode;
378
+ } | {
379
+ op: 'remove-node';
380
+ nodeId: string;
381
+ } | {
382
+ op: 'move-node';
383
+ nodeId: string;
384
+ toSlotId: string;
385
+ index?: number;
386
+ } | {
387
+ op: 'resize-panel';
388
+ persistKey: string;
389
+ sizes: number[];
390
+ } | {
391
+ op: 'set-layout';
392
+ layoutId: string;
393
+ } | {
394
+ op: 'reveal-field';
395
+ fieldId: string;
396
+ } | {
397
+ op: 'hide-field';
398
+ fieldId: string;
399
+ } | {
400
+ op: 'promote-action';
401
+ actionId: string;
402
+ placement: 'header' | 'inline' | 'context' | 'assistant';
403
+ } | {
404
+ op: 'set-focus';
405
+ targetId: string;
406
+ };
407
+ /** Preference adaptation metadata applied during resolution. */
408
+ export interface ResolvedAdaptation {
409
+ appliedDimensions: PreferenceDimensions;
410
+ notes: string[];
411
+ }
412
+ /** Metadata for an overlay applied during resolution. */
413
+ export interface AppliedOverlayMeta {
414
+ overlayId: string;
415
+ scope: BundleScope;
416
+ appliedOps: number;
417
+ }
418
+ /** AI or workspace proposal for surface patches. */
419
+ export interface SurfacePatchProposal {
420
+ proposalId: string;
421
+ source: 'assistant' | 'workspace-rule' | 'session';
422
+ ops: SurfacePatchOp[];
423
+ approvalState: 'proposed' | 'approved' | 'rejected' | 'auto-approved';
424
+ }
425
+ /** Block draft for rich-doc insertion. Full BlockNote grammar deferred. */
426
+ export interface BlockDraft {
427
+ slotId: string;
428
+ blocks: unknown[];
429
+ }
430
+ /**
431
+ * Planner response contract. Maps to ContractSpecAgent/AgentSpec structured output.
432
+ * AI proposes SurfacePatchProposal objects; never emits JSX.
433
+ */
434
+ export interface PlannerResponse {
435
+ /** Short summary of the assistant's response. */
436
+ summary?: string;
437
+ /** Detected user intent (e.g. navigator, planner, explainer). */
438
+ intent?: string;
439
+ /** Optional follow-up question to clarify user needs. */
440
+ followUpQuestion?: string;
441
+ /** Tool names the assistant requested to call. */
442
+ toolRequests?: string[];
443
+ /** Proposed surface patches for user approval. */
444
+ patchProposals?: SurfacePatchProposal[];
445
+ /** Block drafts for rich-doc slots (BlockNote grammar). */
446
+ blockDrafts?: BlockDraft[];
447
+ }
448
+ /** Audit event names for patch lifecycle. */
449
+ export type PatchAuditEvent = 'patch.proposed' | 'patch.approved' | 'patch.rejected' | 'patch.auto-approved';
450
+ /** Payload for patch audit events. */
451
+ export interface PatchAuditPayload {
452
+ proposalId: string;
453
+ source: SurfacePatchProposal['source'];
454
+ opsCount: number;
455
+ reason?: string;
456
+ }
457
+ /** Callback for accept/reject UI. Emit audit event before applying. */
458
+ export type PatchApprovalHandler = (proposalId: string, decision: 'approved' | 'rejected', reason?: string) => void;
459
+ /** Policy effect from PDP. Aligns with spec 10_policy_audit_and_safety. */
460
+ export type PolicyEffect = 'allow' | 'deny' | 'redact' | 'disable-with-reason' | 'require-approval' | 'allow-session-only';
461
+ /** PDP decision for a target (node, field, action, surface). */
462
+ export interface UiPolicyDecision {
463
+ targetId: string;
464
+ effect: PolicyEffect;
465
+ reason?: string;
466
+ redactions?: string[];
467
+ }
468
+ /** Bundle audit event types. Every meaningful mutation emits one. */
469
+ export type BundleAuditEventType = 'surface.resolved' | 'patch.proposed' | 'patch.approved' | 'patch.rejected' | 'overlay.saved' | 'overlay.applied' | 'overlay.failed' | 'policy.denied' | 'policy.redacted';
470
+ /** Audit event shape. Integrate with lib.observability or custom logger. */
471
+ export interface BundleAuditEvent {
472
+ eventId: string;
473
+ at: string;
474
+ actorId?: string;
475
+ source: 'user' | 'assistant' | 'system' | 'policy';
476
+ bundleKey: string;
477
+ surfaceId?: string;
478
+ eventType: BundleAuditEventType;
479
+ payload: Record<string, unknown>;
480
+ }
481
+ /** Emitter for audit events. Plug into lib.observability or custom backend. */
482
+ export interface BundleAuditEmitter {
483
+ emit(event: BundleAuditEvent): void;
484
+ }
485
+ /** Approval metadata stored with overlays for rollback. */
486
+ export interface OverlayApprovalMeta {
487
+ approvalId: string;
488
+ actorId: string;
489
+ approvedAt: string;
490
+ scope: BundleScope;
491
+ forwardOps: SurfacePatchOp[];
492
+ inverseOps: SurfacePatchOp[];
493
+ reason?: string;
494
+ }
@@ -0,0 +1 @@
1
+ // @bun
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Bundle spec validators: undeclared slots in layouts, missing renderers for node kinds.
3
+ * Aligns with 12_typescript_api_and_package_skeleton.md lints.
4
+ */
5
+ import type { BundleContext, SurfaceSpec } from './types';
6
+ /**
7
+ * Validates that every slot referenced in layout roots is declared in surface.slots.
8
+ *
9
+ * @param surface - Surface spec to validate
10
+ * @throws Error if layout references undeclared slot
11
+ */
12
+ export declare function validateLayoutSlots<C extends BundleContext>(surface: SurfaceSpec<C>): void;
13
+ export interface ValidateNodeKindsResult {
14
+ warnings: string[];
15
+ }
16
+ /**
17
+ * Checks which node kinds in slot.accepts lack dedicated renderers.
18
+ * Returns warnings; does not throw. SlotRenderer uses generic fallback for unknown kinds.
19
+ *
20
+ * @param surface - Surface spec to check
21
+ * @returns Warnings for node kinds without dedicated renderers
22
+ */
23
+ export declare function validateBundleNodeKinds<C extends BundleContext>(surface: SurfaceSpec<C>): ValidateNodeKindsResult;
@@ -0,0 +1,66 @@
1
+ // @bun
2
+ // src/spec/validate-bundle.ts
3
+ var KNOWN_NODE_KIND_RENDERERS = new Set([
4
+ "entity-section",
5
+ "entity-field",
6
+ "action-bar",
7
+ "table",
8
+ "timeline",
9
+ "rich-doc",
10
+ "chat-thread",
11
+ "assistant-panel",
12
+ "entity-card",
13
+ "entity-header",
14
+ "entity-summary",
15
+ "entity-activity",
16
+ "entity-relations",
17
+ "relation-graph",
18
+ "custom-widget"
19
+ ]);
20
+ function collectSlotIdsFromRegion(node) {
21
+ const ids = [];
22
+ if (node.type === "slot") {
23
+ ids.push(node.slotId);
24
+ }
25
+ if (node.type === "panel-group" || node.type === "stack") {
26
+ for (const child of node.children) {
27
+ ids.push(...collectSlotIdsFromRegion(child));
28
+ }
29
+ }
30
+ if (node.type === "tabs") {
31
+ for (const tab of node.tabs) {
32
+ ids.push(...collectSlotIdsFromRegion(tab.child));
33
+ }
34
+ }
35
+ if (node.type === "floating") {
36
+ ids.push(node.anchorSlotId);
37
+ ids.push(...collectSlotIdsFromRegion(node.child));
38
+ }
39
+ return ids;
40
+ }
41
+ function validateLayoutSlots(surface) {
42
+ const declaredSlotIds = new Set(surface.slots.map((s) => s.slotId));
43
+ for (const layout of surface.layouts) {
44
+ const layoutSlotIds = collectSlotIdsFromRegion(layout.root);
45
+ for (const slotId of layoutSlotIds) {
46
+ if (!declaredSlotIds.has(slotId)) {
47
+ throw new Error(`Surface "${surface.surfaceId}" layout "${layout.layoutId}" references undeclared slot "${slotId}". Declared slots: ${[...declaredSlotIds].join(", ")}`);
48
+ }
49
+ }
50
+ }
51
+ }
52
+ function validateBundleNodeKinds(surface) {
53
+ const warnings = [];
54
+ for (const slot of surface.slots) {
55
+ for (const kind of slot.accepts) {
56
+ if (!KNOWN_NODE_KIND_RENDERERS.has(kind)) {
57
+ warnings.push(`Surface "${surface.surfaceId}" slot "${slot.slotId}" accepts "${kind}" which has no dedicated renderer (generic fallback used)`);
58
+ }
59
+ }
60
+ }
61
+ return { warnings };
62
+ }
63
+ export {
64
+ validateLayoutSlots,
65
+ validateBundleNodeKinds
66
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,39 @@
1
+ import type { SurfacePatchOp, BundleNodeKind } from './types';
2
+ /**
3
+ * Validates a single patch op schema. Throws on invalid shape.
4
+ * Reversibility: per spec Rule 4, each op has an inverse:
5
+ * - insert-node ↔ remove-node
6
+ * - replace-node ↔ replace-node (self-inverse)
7
+ * - remove-node ↔ insert-node
8
+ * - move-node ↔ move-node (reverse move)
9
+ * - resize-panel ↔ resize-panel (restore previous sizes)
10
+ * - set-layout ↔ set-layout (restore previous layout)
11
+ * - reveal-field ↔ hide-field
12
+ * - hide-field ↔ reveal-field
13
+ * - promote-action ↔ promote-action (restore previous placement)
14
+ * - set-focus ↔ set-focus (restore previous focus)
15
+ *
16
+ * @param op - The patch operation to validate
17
+ * @param index - Index in the ops array (for error messages)
18
+ */
19
+ export declare function validateSurfacePatchOp(op: SurfacePatchOp, index: number): void;
20
+ /**
21
+ * Validates an array of patch ops. Throws on first invalid op.
22
+ *
23
+ * @param ops - Patch operations to validate
24
+ */
25
+ export declare function validateSurfacePatch(ops: SurfacePatchOp[]): void;
26
+ /** Constraints for patch proposal validation (e.g. from BundleAiSpec, SurfaceAiSpec). */
27
+ export interface PatchProposalConstraints {
28
+ allowedOps: readonly SurfacePatchOp['op'][];
29
+ allowedSlots: readonly string[];
30
+ allowedNodeKinds: readonly BundleNodeKind[];
31
+ }
32
+ /**
33
+ * Validates a patch proposal against allowed ops, slots, and node kinds.
34
+ * Throws on first violation. Call before applying or accepting patches.
35
+ *
36
+ * @param ops - Patch operations to validate
37
+ * @param constraints - Allowed ops, slots, node kinds from bundle/surface spec
38
+ */
39
+ export declare function validatePatchProposal(ops: SurfacePatchOp[], constraints: PatchProposalConstraints): void;