@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,793 @@
1
+ // @bun
2
+ // src/adapters/blocknote-stub.tsx
3
+ import { jsxDEV } from "react/jsx-dev-runtime";
4
+ var blocknoteAdapterStub = {
5
+ supportsNode(_kind) {
6
+ return false;
7
+ },
8
+ createSchema(_registry) {
9
+ return {};
10
+ },
11
+ renderNode(node, _ctx) {
12
+ return /* @__PURE__ */ jsxDEV("div", {
13
+ "data-blocknote-stub": true,
14
+ "data-node-id": node.nodeId,
15
+ children: node.title ?? node.kind
16
+ }, undefined, false, undefined, this);
17
+ },
18
+ async serialize(node) {
19
+ return { nodeId: node.nodeId, kind: node.kind };
20
+ },
21
+ async deserialize(input) {
22
+ const o = input;
23
+ return {
24
+ nodeId: o?.nodeId ?? "stub",
25
+ kind: o?.kind ?? "custom-widget"
26
+ };
27
+ }
28
+ };
29
+
30
+ // src/adapters/motion-stub.ts
31
+ var PACE_TOKENS = {
32
+ deliberate: {
33
+ durationMs: 300,
34
+ enableEntrance: true,
35
+ layout: true
36
+ },
37
+ balanced: {
38
+ durationMs: 150,
39
+ enableEntrance: true,
40
+ layout: true
41
+ },
42
+ rapid: {
43
+ durationMs: 50,
44
+ enableEntrance: false,
45
+ layout: false
46
+ }
47
+ };
48
+ var motionAdapterStub = {
49
+ getTokens(pace) {
50
+ return PACE_TOKENS[pace] ?? PACE_TOKENS.balanced;
51
+ }
52
+ };
53
+
54
+ // src/adapters/resizable-panels-stub.tsx
55
+ import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
56
+ var LAYOUT_STORAGE_KEY = "surface-runtime:panel-layout:";
57
+ var resizablePanelsAdapterStub = {
58
+ renderPanelGroup(region, ctx, renderChild) {
59
+ const direction = region.direction === "horizontal" ? "row" : "column";
60
+ return /* @__PURE__ */ jsxDEV2("div", {
61
+ "data-panel-group": true,
62
+ "data-persist-key": region.persistKey,
63
+ style: {
64
+ display: "flex",
65
+ flexDirection: direction,
66
+ flex: 1,
67
+ minHeight: 0
68
+ },
69
+ children: region.children.map((child, i) => /* @__PURE__ */ jsxDEV2("div", {
70
+ style: { flex: 1, minWidth: 0, minHeight: 0 },
71
+ children: renderChild(child, ctx)
72
+ }, i, false, undefined, this))
73
+ }, undefined, false, undefined, this);
74
+ },
75
+ async restoreLayout(persistKey) {
76
+ if (typeof localStorage === "undefined")
77
+ return null;
78
+ try {
79
+ const raw = localStorage.getItem(LAYOUT_STORAGE_KEY + persistKey);
80
+ if (!raw)
81
+ return null;
82
+ const parsed = JSON.parse(raw);
83
+ return Array.isArray(parsed) ? parsed : null;
84
+ } catch {
85
+ return null;
86
+ }
87
+ },
88
+ async saveLayout(persistKey, sizes) {
89
+ if (typeof localStorage === "undefined")
90
+ return;
91
+ try {
92
+ localStorage.setItem(LAYOUT_STORAGE_KEY + persistKey, JSON.stringify(sizes));
93
+ } catch {}
94
+ }
95
+ };
96
+
97
+ // src/telemetry/surface-metrics.ts
98
+ import {
99
+ createCounter,
100
+ createHistogram
101
+ } from "@contractspec/lib.observability/metrics";
102
+ var METER_NAME = "@contractspec/lib.surface-runtime";
103
+ var resolutionDurationMs = createHistogram("bundle_surface_resolution_duration_ms", "Time to resolve bundle spec to surface plan in milliseconds", METER_NAME);
104
+ var patchAcceptanceCounter = createCounter("bundle_surface_patch_acceptance_total", "Total AI patch proposals accepted by user", METER_NAME);
105
+ var patchRejectionCounter = createCounter("bundle_surface_patch_rejection_total", "Total AI patch proposals rejected by user", METER_NAME);
106
+ var policyDenialCounter = createCounter("bundle_surface_policy_denial_total", "Total policy denials (actions denied by policy)", METER_NAME);
107
+ var surfaceFallbackCounter = createCounter("bundle_surface_fallback_total", "Total surface or layout fallbacks during resolution", METER_NAME);
108
+ var missingRendererCounter = createCounter("bundle_surface_renderer_missing_total", "Total slots with no renderer for requested node kind", METER_NAME);
109
+
110
+ // src/i18n/catalogs/en.ts
111
+ import { defineTranslation } from "@contractspec/lib.contracts-spec/translations";
112
+ var enMessages = defineTranslation({
113
+ meta: {
114
+ key: "surface-runtime.messages",
115
+ version: "1.0.0",
116
+ domain: "surface-runtime",
117
+ description: "User-facing strings for surface-runtime UI components",
118
+ owners: ["platform"],
119
+ stability: "experimental"
120
+ },
121
+ locale: "en",
122
+ fallback: "en",
123
+ messages: {
124
+ "overlay.conflicts.title": {
125
+ value: "Overlay conflicts",
126
+ description: "Title for overlay conflict resolution banner"
127
+ },
128
+ "overlay.conflicts.keepScope": {
129
+ value: "Keep {scope}",
130
+ description: "Button to keep overlay from scope A or B"
131
+ },
132
+ "patch.accept": {
133
+ value: "Accept",
134
+ description: "Accept patch proposal button"
135
+ },
136
+ "patch.reject": {
137
+ value: "Reject",
138
+ description: "Reject patch proposal button"
139
+ },
140
+ "patch.addWidget": {
141
+ value: "Add {title} to {slot}",
142
+ description: "Insert node proposal summary"
143
+ },
144
+ "patch.removeItem": {
145
+ value: "Remove item",
146
+ description: "Remove node proposal summary"
147
+ },
148
+ "patch.switchLayout": {
149
+ value: "Switch to {layoutId} layout",
150
+ description: "Set layout proposal summary"
151
+ },
152
+ "patch.showField": {
153
+ value: "Show field {fieldId}",
154
+ description: "Reveal field proposal summary"
155
+ },
156
+ "patch.hideField": {
157
+ value: "Hide field {fieldId}",
158
+ description: "Hide field proposal summary"
159
+ },
160
+ "patch.moveTo": {
161
+ value: "Move to {slot}",
162
+ description: "Move node proposal summary"
163
+ },
164
+ "patch.replaceItem": {
165
+ value: "Replace item",
166
+ description: "Replace node proposal summary"
167
+ },
168
+ "patch.promote": {
169
+ value: "Promote {actionId}",
170
+ description: "Promote action proposal summary"
171
+ },
172
+ "patch.changes": {
173
+ value: "{count} changes",
174
+ description: "Multiple patch ops summary"
175
+ }
176
+ }
177
+ });
178
+
179
+ // src/i18n/catalogs/es.ts
180
+ import { defineTranslation as defineTranslation2 } from "@contractspec/lib.contracts-spec/translations";
181
+ var esMessages = defineTranslation2({
182
+ meta: {
183
+ key: "surface-runtime.messages",
184
+ version: "1.0.0",
185
+ domain: "surface-runtime",
186
+ description: "User-facing strings for surface-runtime UI components",
187
+ owners: ["platform"],
188
+ stability: "experimental"
189
+ },
190
+ locale: "es",
191
+ fallback: "en",
192
+ messages: {
193
+ "overlay.conflicts.title": { value: "Conflictos de superposici\xF3n" },
194
+ "overlay.conflicts.keepScope": { value: "Mantener {scope}" },
195
+ "patch.accept": { value: "Aceptar" },
196
+ "patch.reject": { value: "Rechazar" },
197
+ "patch.addWidget": { value: "A\xF1adir {title} a {slot}" },
198
+ "patch.removeItem": { value: "Eliminar elemento" },
199
+ "patch.switchLayout": { value: "Cambiar a disposici\xF3n {layoutId}" },
200
+ "patch.showField": { value: "Mostrar campo {fieldId}" },
201
+ "patch.hideField": { value: "Ocultar campo {fieldId}" },
202
+ "patch.moveTo": { value: "Mover a {slot}" },
203
+ "patch.replaceItem": { value: "Reemplazar elemento" },
204
+ "patch.promote": { value: "Promover {actionId}" },
205
+ "patch.changes": { value: "{count} cambios" }
206
+ }
207
+ });
208
+
209
+ // src/i18n/catalogs/fr.ts
210
+ import { defineTranslation as defineTranslation3 } from "@contractspec/lib.contracts-spec/translations";
211
+ var frMessages = defineTranslation3({
212
+ meta: {
213
+ key: "surface-runtime.messages",
214
+ version: "1.0.0",
215
+ domain: "surface-runtime",
216
+ description: "User-facing strings for surface-runtime UI components",
217
+ owners: ["platform"],
218
+ stability: "experimental"
219
+ },
220
+ locale: "fr",
221
+ fallback: "en",
222
+ messages: {
223
+ "overlay.conflicts.title": { value: "Conflits de superposition" },
224
+ "overlay.conflicts.keepScope": { value: "Conserver {scope}" },
225
+ "patch.accept": { value: "Accepter" },
226
+ "patch.reject": { value: "Rejeter" },
227
+ "patch.addWidget": { value: "Ajouter {title} \xE0 {slot}" },
228
+ "patch.removeItem": { value: "Supprimer l'\xE9l\xE9ment" },
229
+ "patch.switchLayout": { value: "Passer \xE0 la disposition {layoutId}" },
230
+ "patch.showField": { value: "Afficher le champ {fieldId}" },
231
+ "patch.hideField": { value: "Masquer le champ {fieldId}" },
232
+ "patch.moveTo": { value: "D\xE9placer vers {slot}" },
233
+ "patch.replaceItem": { value: "Remplacer l'\xE9l\xE9ment" },
234
+ "patch.promote": { value: "Promouvoir {actionId}" },
235
+ "patch.changes": { value: "{count} modifications" }
236
+ }
237
+ });
238
+
239
+ // src/i18n/messages.ts
240
+ import {
241
+ createI18nFactory
242
+ } from "@contractspec/lib.contracts-spec/translations";
243
+ var factory = createI18nFactory({
244
+ specKey: "surface-runtime.messages",
245
+ catalogs: [enMessages, frMessages, esMessages]
246
+ });
247
+ var createSurfaceI18n = factory.create;
248
+ var getDefaultSurfaceI18n = factory.getDefault;
249
+
250
+ // src/i18n/keys.ts
251
+ var SURFACE_KEYS = {
252
+ "overlay.conflicts.title": "overlay.conflicts.title",
253
+ "overlay.conflicts.keepScope": "overlay.conflicts.keepScope",
254
+ "patch.accept": "patch.accept",
255
+ "patch.reject": "patch.reject",
256
+ "patch.addWidget": "patch.addWidget",
257
+ "patch.removeItem": "patch.removeItem",
258
+ "patch.switchLayout": "patch.switchLayout",
259
+ "patch.showField": "patch.showField",
260
+ "patch.hideField": "patch.hideField",
261
+ "patch.moveTo": "patch.moveTo",
262
+ "patch.replaceItem": "patch.replaceItem",
263
+ "patch.promote": "patch.promote",
264
+ "patch.changes": "patch.changes"
265
+ };
266
+
267
+ // src/i18n/index.ts
268
+ import {
269
+ resolveLocale,
270
+ isSupportedLocale,
271
+ DEFAULT_LOCALE,
272
+ SUPPORTED_LOCALES
273
+ } from "@contractspec/lib.contracts-spec/translations";
274
+
275
+ // src/react/BundleProvider.tsx
276
+ import { createContext, useContext } from "react";
277
+ import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
278
+ "use client";
279
+ var BundlePlanContext = createContext(null);
280
+ var PreferencesContext = createContext(null);
281
+ var EditingContext = createContext(false);
282
+ function BundleProvider({
283
+ plan,
284
+ children,
285
+ isEditing = false
286
+ }) {
287
+ const preferences = plan.adaptation.appliedDimensions;
288
+ return /* @__PURE__ */ jsxDEV3(BundlePlanContext.Provider, {
289
+ value: plan,
290
+ children: /* @__PURE__ */ jsxDEV3(PreferencesContext.Provider, {
291
+ value: preferences,
292
+ children: /* @__PURE__ */ jsxDEV3(EditingContext.Provider, {
293
+ value: isEditing,
294
+ children
295
+ }, undefined, false, undefined, this)
296
+ }, undefined, false, undefined, this)
297
+ }, undefined, false, undefined, this);
298
+ }
299
+ function useIsEditing() {
300
+ return useContext(EditingContext);
301
+ }
302
+ function useBundlePlan() {
303
+ const value = useContext(BundlePlanContext);
304
+ if (!value) {
305
+ throw new Error("useBundlePlan must be used inside BundleProvider.");
306
+ }
307
+ return value;
308
+ }
309
+ function useBundlePreferences() {
310
+ const value = useContext(PreferencesContext);
311
+ if (!value) {
312
+ throw new Error("useBundlePreferences must be used inside BundleProvider.");
313
+ }
314
+ return value;
315
+ }
316
+
317
+ // src/react/RegionRenderer.tsx
318
+ import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
319
+ function RegionRenderer({
320
+ region,
321
+ ctx,
322
+ renderSlot
323
+ }) {
324
+ const renderChild = (child, childCtx) => /* @__PURE__ */ jsxDEV4(RegionRenderer, {
325
+ region: child,
326
+ ctx: childCtx,
327
+ renderSlot
328
+ }, undefined, false, undefined, this);
329
+ switch (region.type) {
330
+ case "panel-group":
331
+ return resizablePanelsAdapterStub.renderPanelGroup(region, ctx, renderChild);
332
+ case "stack": {
333
+ const direction = region.direction === "horizontal" ? "row" : "column";
334
+ const gapMap = {
335
+ none: 0,
336
+ xs: 4,
337
+ sm: 8,
338
+ md: 16,
339
+ lg: 24
340
+ };
341
+ const gap = gapMap[region.gap ?? "md"];
342
+ return /* @__PURE__ */ jsxDEV4("div", {
343
+ "data-region": "stack",
344
+ style: {
345
+ display: "flex",
346
+ flexDirection: direction,
347
+ gap,
348
+ flex: 1,
349
+ minHeight: 0
350
+ },
351
+ children: region.children.map((child, i) => /* @__PURE__ */ jsxDEV4("div", {
352
+ style: { flex: 1, minWidth: 0, minHeight: 0 },
353
+ children: /* @__PURE__ */ jsxDEV4(RegionRenderer, {
354
+ region: child,
355
+ ctx,
356
+ renderSlot
357
+ }, undefined, false, undefined, this)
358
+ }, i, false, undefined, this))
359
+ }, undefined, false, undefined, this);
360
+ }
361
+ case "tabs":
362
+ return /* @__PURE__ */ jsxDEV4("div", {
363
+ "data-region": "tabs",
364
+ children: [
365
+ /* @__PURE__ */ jsxDEV4("div", {
366
+ role: "tablist",
367
+ children: region.tabs.map((t) => /* @__PURE__ */ jsxDEV4("button", {
368
+ type: "button",
369
+ role: "tab",
370
+ children: t.title
371
+ }, t.key, false, undefined, this))
372
+ }, undefined, false, undefined, this),
373
+ region.tabs[0] && /* @__PURE__ */ jsxDEV4(RegionRenderer, {
374
+ region: region.tabs[0].child,
375
+ ctx,
376
+ renderSlot
377
+ }, undefined, false, undefined, this)
378
+ ]
379
+ }, undefined, true, undefined, this);
380
+ case "slot":
381
+ return /* @__PURE__ */ jsxDEV4("div", {
382
+ "data-slot": region.slotId,
383
+ children: renderSlot(region.slotId, ctx)
384
+ }, undefined, false, undefined, this);
385
+ case "floating":
386
+ return /* @__PURE__ */ jsxDEV4("div", {
387
+ "data-floating": true,
388
+ "data-anchor": region.anchorSlotId,
389
+ children: /* @__PURE__ */ jsxDEV4(RegionRenderer, {
390
+ region: region.child,
391
+ ctx,
392
+ renderSlot
393
+ }, undefined, false, undefined, this)
394
+ }, undefined, false, undefined, this);
395
+ default:
396
+ return null;
397
+ }
398
+ }
399
+
400
+ // src/react/SlotRenderer.tsx
401
+ import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
402
+ function SlotRenderer({ slotId, ctx, nodes }) {
403
+ if (nodes.length === 0) {
404
+ return /* @__PURE__ */ jsxDEV5("div", {
405
+ "data-slot-placeholder": true,
406
+ "data-slot-id": slotId
407
+ }, undefined, false, undefined, this);
408
+ }
409
+ return /* @__PURE__ */ jsxDEV5("div", {
410
+ "data-slot": slotId,
411
+ children: nodes.map((node) => /* @__PURE__ */ jsxDEV5(SlotNodeRenderer, {
412
+ node,
413
+ ctx,
414
+ slotId
415
+ }, node.nodeId, false, undefined, this))
416
+ }, undefined, false, undefined, this);
417
+ }
418
+ function SlotNodeRenderer({
419
+ node,
420
+ ctx,
421
+ slotId
422
+ }) {
423
+ if (blocknoteAdapterStub.supportsNode(node.kind)) {
424
+ return blocknoteAdapterStub.renderNode(node, ctx);
425
+ }
426
+ if (node.kind === "entity-section") {
427
+ return /* @__PURE__ */ jsxDEV5("section", {
428
+ "data-node-id": node.nodeId,
429
+ "data-kind": "entity-section",
430
+ children: [
431
+ /* @__PURE__ */ jsxDEV5("header", {
432
+ "data-entity-section-header": true,
433
+ children: node.title ?? "Section"
434
+ }, undefined, false, undefined, this),
435
+ /* @__PURE__ */ jsxDEV5("div", {
436
+ "data-entity-section-content": true,
437
+ children: node.children?.map((child) => child ? /* @__PURE__ */ jsxDEV5(SlotNodeRenderer, {
438
+ node: child,
439
+ ctx,
440
+ slotId
441
+ }, child.nodeId, false, undefined, this) : null)
442
+ }, undefined, false, undefined, this)
443
+ ]
444
+ }, undefined, true, undefined, this);
445
+ }
446
+ if (node.kind === "entity-field") {
447
+ const fieldId = node.sourceBinding?.fieldId;
448
+ return /* @__PURE__ */ jsxDEV5("div", {
449
+ "data-node-id": node.nodeId,
450
+ "data-kind": "entity-field",
451
+ "data-field-id": fieldId,
452
+ children: [
453
+ /* @__PURE__ */ jsxDEV5("span", {
454
+ "data-entity-field-label": true,
455
+ children: node.title ?? fieldId ?? "Field"
456
+ }, undefined, false, undefined, this),
457
+ /* @__PURE__ */ jsxDEV5("span", {
458
+ "data-entity-field-value": true
459
+ }, undefined, false, undefined, this)
460
+ ]
461
+ }, undefined, true, undefined, this);
462
+ }
463
+ missingRendererCounter.add(1, {
464
+ nodeKind: node.kind,
465
+ slotId
466
+ });
467
+ return /* @__PURE__ */ jsxDEV5("div", {
468
+ "data-node-id": node.nodeId,
469
+ "data-kind": node.kind,
470
+ "data-renderer-missing": true,
471
+ children: node.title ?? node.kind
472
+ }, undefined, false, undefined, this);
473
+ }
474
+
475
+ // src/react/PatchProposalCard.tsx
476
+ import { useMemo } from "react";
477
+ import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
478
+ "use client";
479
+ function PatchProposalCard({
480
+ proposal,
481
+ onAccept,
482
+ onReject,
483
+ locale
484
+ }) {
485
+ const i18n = useMemo(() => createSurfaceI18n(locale), [locale]);
486
+ const firstOp = proposal.ops[0];
487
+ const summary = proposal.ops.length === 1 && firstOp ? describeOp(firstOp, i18n) : i18n.t("patch.changes", { count: proposal.ops.length });
488
+ return /* @__PURE__ */ jsxDEV6("div", {
489
+ "data-proposal-id": proposal.proposalId,
490
+ style: {
491
+ padding: "12px",
492
+ border: "1px solid var(--border, #e5e7eb)",
493
+ borderRadius: "8px",
494
+ marginBottom: "8px",
495
+ backgroundColor: "var(--muted, #f9fafb)"
496
+ },
497
+ children: [
498
+ /* @__PURE__ */ jsxDEV6("div", {
499
+ style: { marginBottom: "8px", fontSize: "14px" },
500
+ children: summary
501
+ }, undefined, false, undefined, this),
502
+ /* @__PURE__ */ jsxDEV6("div", {
503
+ style: { display: "flex", gap: "8px" },
504
+ children: [
505
+ /* @__PURE__ */ jsxDEV6("button", {
506
+ type: "button",
507
+ onClick: () => onAccept(proposal.proposalId),
508
+ style: {
509
+ padding: "4px 12px",
510
+ fontSize: "13px",
511
+ borderRadius: "4px",
512
+ border: "none",
513
+ backgroundColor: "var(--primary, #3b82f6)",
514
+ color: "white",
515
+ cursor: "pointer"
516
+ },
517
+ children: i18n.t("patch.accept")
518
+ }, undefined, false, undefined, this),
519
+ /* @__PURE__ */ jsxDEV6("button", {
520
+ type: "button",
521
+ onClick: () => onReject(proposal.proposalId),
522
+ style: {
523
+ padding: "4px 12px",
524
+ fontSize: "13px",
525
+ borderRadius: "4px",
526
+ border: "1px solid var(--border, #e5e7eb)",
527
+ backgroundColor: "transparent",
528
+ cursor: "pointer"
529
+ },
530
+ children: i18n.t("patch.reject")
531
+ }, undefined, false, undefined, this)
532
+ ]
533
+ }, undefined, true, undefined, this)
534
+ ]
535
+ }, undefined, true, undefined, this);
536
+ }
537
+ function describeOp(op, i18n) {
538
+ switch (op.op) {
539
+ case "insert-node":
540
+ return i18n.t("patch.addWidget", {
541
+ title: op.node?.title ?? op.node?.kind ?? "widget",
542
+ slot: op.slotId ?? "slot"
543
+ });
544
+ case "remove-node":
545
+ return i18n.t("patch.removeItem");
546
+ case "set-layout":
547
+ return i18n.t("patch.switchLayout", { layoutId: op.layoutId });
548
+ case "reveal-field":
549
+ return i18n.t("patch.showField", { fieldId: op.fieldId });
550
+ case "hide-field":
551
+ return i18n.t("patch.hideField", { fieldId: op.fieldId });
552
+ case "move-node":
553
+ return i18n.t("patch.moveTo", { slot: op.toSlotId ?? "slot" });
554
+ case "replace-node":
555
+ return i18n.t("patch.replaceItem");
556
+ case "promote-action":
557
+ return i18n.t("patch.promote", { actionId: op.actionId });
558
+ default:
559
+ return `${op.op}`;
560
+ }
561
+ }
562
+
563
+ // src/react/OverlayConflictResolver.tsx
564
+ import { useMemo as useMemo2 } from "react";
565
+ import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
566
+ "use client";
567
+ function OverlayConflictResolver({
568
+ conflicts,
569
+ onResolve,
570
+ locale
571
+ }) {
572
+ const i18n = useMemo2(() => createSurfaceI18n(locale), [locale]);
573
+ return /* @__PURE__ */ jsxDEV7("div", {
574
+ "data-overlay-conflicts": true,
575
+ style: {
576
+ padding: "12px",
577
+ marginBottom: "12px",
578
+ border: "1px solid var(--destructive, #ef4444)",
579
+ borderRadius: "8px",
580
+ backgroundColor: "var(--destructive/10, #fef2f2)"
581
+ },
582
+ children: [
583
+ /* @__PURE__ */ jsxDEV7("div", {
584
+ style: {
585
+ fontSize: "14px",
586
+ fontWeight: 600,
587
+ marginBottom: "8px",
588
+ color: "var(--destructive, #ef4444)"
589
+ },
590
+ children: i18n.t("overlay.conflicts.title")
591
+ }, undefined, false, undefined, this),
592
+ conflicts.map((c) => /* @__PURE__ */ jsxDEV7("div", {
593
+ style: {
594
+ padding: "8px",
595
+ marginBottom: "8px",
596
+ backgroundColor: "white",
597
+ borderRadius: "4px",
598
+ fontSize: "13px"
599
+ },
600
+ children: [
601
+ /* @__PURE__ */ jsxDEV7("span", {
602
+ children: c.targetKey
603
+ }, undefined, false, undefined, this),
604
+ /* @__PURE__ */ jsxDEV7("span", {
605
+ style: { margin: "0 8px", color: "#9ca3af" },
606
+ children: [
607
+ "(",
608
+ c.scopeA,
609
+ " vs ",
610
+ c.scopeB,
611
+ ")"
612
+ ]
613
+ }, undefined, true, undefined, this),
614
+ /* @__PURE__ */ jsxDEV7("div", {
615
+ style: { marginTop: "8px", display: "flex", gap: "8px" },
616
+ children: [
617
+ /* @__PURE__ */ jsxDEV7("button", {
618
+ type: "button",
619
+ onClick: () => onResolve({ targetKey: c.targetKey, chosenScope: "A" }),
620
+ style: {
621
+ padding: "4px 12px",
622
+ fontSize: "12px",
623
+ borderRadius: "4px",
624
+ border: "1px solid #e5e7eb",
625
+ backgroundColor: "white",
626
+ cursor: "pointer"
627
+ },
628
+ children: i18n.t("overlay.conflicts.keepScope", { scope: c.scopeA })
629
+ }, undefined, false, undefined, this),
630
+ /* @__PURE__ */ jsxDEV7("button", {
631
+ type: "button",
632
+ onClick: () => onResolve({ targetKey: c.targetKey, chosenScope: "B" }),
633
+ style: {
634
+ padding: "4px 12px",
635
+ fontSize: "12px",
636
+ borderRadius: "4px",
637
+ border: "1px solid #e5e7eb",
638
+ backgroundColor: "white",
639
+ cursor: "pointer"
640
+ },
641
+ children: i18n.t("overlay.conflicts.keepScope", { scope: c.scopeB })
642
+ }, undefined, false, undefined, this)
643
+ ]
644
+ }, undefined, true, undefined, this)
645
+ ]
646
+ }, `${c.targetKey}-${c.overlayIdA}-${c.overlayIdB}`, true, undefined, this))
647
+ ]
648
+ }, undefined, true, undefined, this);
649
+ }
650
+
651
+ // src/react/BundleRenderer.tsx
652
+ import { jsxDEV as jsxDEV8, Fragment } from "react/jsx-dev-runtime";
653
+ "use client";
654
+ function BundleRenderer({
655
+ assistantSlotId,
656
+ assistantSlotContent,
657
+ onPatchAccept,
658
+ onPatchReject,
659
+ onOverlayConflictResolve
660
+ } = {}) {
661
+ const plan = useBundlePlan();
662
+ const motionTokens = motionAdapterStub.getTokens(plan.adaptation.appliedDimensions.pace);
663
+ const ctx = {
664
+ plan,
665
+ bindings: plan.bindings,
666
+ preferences: plan.adaptation.appliedDimensions
667
+ };
668
+ const proposals = plan.ai?.proposals?.filter((p) => p.approvalState === "proposed");
669
+ const locale = plan.locale;
670
+ const renderSlot = (slotId, slotCtx) => {
671
+ if (assistantSlotId && slotId === assistantSlotId) {
672
+ return /* @__PURE__ */ jsxDEV8(Fragment, {
673
+ children: [
674
+ proposals && proposals.length > 0 && onPatchAccept && onPatchReject && /* @__PURE__ */ jsxDEV8("div", {
675
+ style: { marginBottom: "12px" },
676
+ children: proposals.map((p) => /* @__PURE__ */ jsxDEV8(PatchProposalCard, {
677
+ proposal: p,
678
+ onAccept: onPatchAccept,
679
+ onReject: onPatchReject,
680
+ locale
681
+ }, p.proposalId, false, undefined, this))
682
+ }, undefined, false, undefined, this),
683
+ assistantSlotContent
684
+ ]
685
+ }, undefined, true, undefined, this);
686
+ }
687
+ const nodes = getNodesForSlot(plan.nodes, slotId);
688
+ return /* @__PURE__ */ jsxDEV8(SlotRenderer, {
689
+ slotId,
690
+ ctx: slotCtx,
691
+ nodes
692
+ }, undefined, false, undefined, this);
693
+ };
694
+ const conflicts = plan.overlayConflicts ?? [];
695
+ return /* @__PURE__ */ jsxDEV8("div", {
696
+ "data-bundle-key": plan.bundleKey,
697
+ "data-surface-id": plan.surfaceId,
698
+ "data-layout-id": plan.layoutId,
699
+ style: {
700
+ display: "flex",
701
+ flexDirection: "column",
702
+ height: "100%",
703
+ minHeight: 0,
704
+ transition: motionTokens.layout ? `all ${motionTokens.durationMs}ms ease` : undefined
705
+ },
706
+ children: [
707
+ conflicts.length > 0 && onOverlayConflictResolve && /* @__PURE__ */ jsxDEV8(OverlayConflictResolver, {
708
+ conflicts,
709
+ onResolve: onOverlayConflictResolve,
710
+ locale
711
+ }, undefined, false, undefined, this),
712
+ /* @__PURE__ */ jsxDEV8(RegionRenderer, {
713
+ region: plan.layoutRoot,
714
+ ctx,
715
+ renderSlot
716
+ }, undefined, false, undefined, this)
717
+ ]
718
+ }, undefined, true, undefined, this);
719
+ }
720
+ function getNodesForSlot(nodes, slotId) {
721
+ if (slotId === "primary")
722
+ return nodes;
723
+ return [];
724
+ }
725
+
726
+ // src/react/WidgetPalette.tsx
727
+ import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
728
+ "use client";
729
+ function WidgetPalette({
730
+ registry,
731
+ allowedNodeKinds,
732
+ onInsert
733
+ }) {
734
+ const widgets = registry.listByTrust("core");
735
+ const filtered = !allowedNodeKinds || allowedNodeKinds.includes("custom-widget") ? widgets : [];
736
+ return /* @__PURE__ */ jsxDEV9("div", {
737
+ "data-widget-palette": true,
738
+ style: {
739
+ padding: "12px",
740
+ minWidth: "180px",
741
+ borderRight: "1px solid var(--border, #e5e7eb)",
742
+ backgroundColor: "var(--muted, #f9fafb)"
743
+ },
744
+ children: [
745
+ /* @__PURE__ */ jsxDEV9("div", {
746
+ style: {
747
+ fontSize: "12px",
748
+ fontWeight: 600,
749
+ marginBottom: "8px",
750
+ textTransform: "uppercase",
751
+ color: "var(--muted-foreground, #6b7280)"
752
+ },
753
+ children: "Widgets"
754
+ }, undefined, false, undefined, this),
755
+ /* @__PURE__ */ jsxDEV9("ul", {
756
+ style: { listStyle: "none", margin: 0, padding: 0 },
757
+ children: filtered.map((w) => /* @__PURE__ */ jsxDEV9("li", {
758
+ "data-widget-key": w.widgetKey,
759
+ role: onInsert ? "button" : undefined,
760
+ tabIndex: onInsert ? 0 : undefined,
761
+ style: {
762
+ padding: "8px 12px",
763
+ marginBottom: "4px",
764
+ borderRadius: "6px",
765
+ cursor: onInsert ? "grab" : "default",
766
+ backgroundColor: "white",
767
+ border: "1px solid var(--border, #e5e7eb)"
768
+ },
769
+ onClick: onInsert ? () => onInsert(w.widgetKey, "primary") : undefined,
770
+ onKeyDown: onInsert ? (e) => {
771
+ if (e.key === "Enter" || e.key === " ") {
772
+ e.preventDefault();
773
+ onInsert(w.widgetKey, "primary");
774
+ }
775
+ } : undefined,
776
+ children: w.title
777
+ }, w.widgetKey, false, undefined, this))
778
+ }, undefined, false, undefined, this)
779
+ ]
780
+ }, undefined, true, undefined, this);
781
+ }
782
+ export {
783
+ useIsEditing,
784
+ useBundlePreferences,
785
+ useBundlePlan,
786
+ WidgetPalette,
787
+ SlotRenderer,
788
+ RegionRenderer,
789
+ PatchProposalCard,
790
+ OverlayConflictResolver,
791
+ BundleRenderer,
792
+ BundleProvider
793
+ };