@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 @@
1
+ export {};
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Example PM workbench bundle. Demonstrates defineModuleBundle usage.
3
+ * Typechecks against @contractspec/lib.surface-runtime public API.
4
+ */
5
+ export declare const PmWorkbenchBundle: {
6
+ readonly meta: {
7
+ readonly key: "pm.workbench";
8
+ readonly version: "0.1.0";
9
+ readonly title: "PM Workbench";
10
+ readonly description: "AI-native PM workbench for relation-rich issues and saved views";
11
+ readonly owners: ["team-pm-platform"];
12
+ readonly tags: ["pm", "issues", "workbench", "ai-native"];
13
+ readonly stability: "experimental";
14
+ };
15
+ readonly routes: [{
16
+ readonly routeId: "pm-issue";
17
+ readonly path: "/operate/pm/issues/:issueId";
18
+ readonly defaultSurface: "issue-workbench";
19
+ }];
20
+ readonly entities: {
21
+ readonly entityTypes: {
22
+ readonly 'pm.issue': {
23
+ readonly entityType: "pm.issue";
24
+ readonly defaultSurfaceId: "issue-workbench";
25
+ readonly detailBlueprints: ["balanced-three-pane", "dense-ops-mode"];
26
+ readonly supportedViews: ["minimal-summary", "balanced-detail", "dense-workbench"];
27
+ readonly sectionsFromSchema: true;
28
+ readonly fieldsFromSchema: true;
29
+ readonly relationPanels: ["relations", "meeting-evidence", "decision-trail"];
30
+ };
31
+ };
32
+ readonly fieldKinds: {
33
+ readonly text: {
34
+ readonly fieldKind: "text";
35
+ readonly viewer: "text-viewer";
36
+ readonly editor: "text-editor";
37
+ };
38
+ readonly number: {
39
+ readonly fieldKind: "number";
40
+ readonly viewer: "number-viewer";
41
+ readonly editor: "number-editor";
42
+ };
43
+ readonly date: {
44
+ readonly fieldKind: "date";
45
+ readonly viewer: "date-viewer";
46
+ readonly editor: "date-editor";
47
+ };
48
+ readonly select: {
49
+ readonly fieldKind: "select";
50
+ readonly viewer: "select-viewer";
51
+ readonly editor: "select-editor";
52
+ };
53
+ };
54
+ readonly sectionKinds: {
55
+ readonly overview: {
56
+ readonly sectionKind: "overview";
57
+ readonly renderer: "section-overview";
58
+ };
59
+ readonly details: {
60
+ readonly sectionKind: "details";
61
+ readonly renderer: "section-details";
62
+ };
63
+ readonly relations: {
64
+ readonly sectionKind: "relations";
65
+ readonly renderer: "section-relations";
66
+ };
67
+ readonly activity: {
68
+ readonly sectionKind: "activity";
69
+ readonly renderer: "section-activity";
70
+ };
71
+ };
72
+ readonly viewKinds: {
73
+ readonly 'minimal-summary': {
74
+ readonly viewKind: "minimal-summary";
75
+ readonly renderer: "view-minimal";
76
+ };
77
+ readonly 'balanced-detail': {
78
+ readonly viewKind: "balanced-detail";
79
+ readonly renderer: "view-balanced";
80
+ readonly defaultLayoutId: "balanced-three-pane";
81
+ };
82
+ readonly 'dense-workbench': {
83
+ readonly viewKind: "dense-workbench";
84
+ readonly renderer: "view-dense";
85
+ readonly defaultLayoutId: "dense-ops-mode";
86
+ };
87
+ };
88
+ };
89
+ readonly surfaces: {
90
+ readonly 'issue-workbench': {
91
+ readonly surfaceId: "issue-workbench";
92
+ readonly kind: "workbench";
93
+ readonly title: "Issue Workbench";
94
+ readonly slots: [{
95
+ readonly slotId: "header";
96
+ readonly role: "header";
97
+ readonly accepts: ["action-bar"];
98
+ readonly cardinality: "many";
99
+ }, {
100
+ readonly slotId: "primary";
101
+ readonly role: "primary";
102
+ readonly accepts: ["entity-section", "table", "rich-doc"];
103
+ readonly cardinality: "many";
104
+ readonly mutableByAi: true;
105
+ readonly mutableByUser: true;
106
+ }, {
107
+ readonly slotId: "secondary";
108
+ readonly role: "secondary";
109
+ readonly accepts: ["entity-section", "table", "timeline"];
110
+ readonly cardinality: "many";
111
+ readonly mutableByAi: true;
112
+ readonly mutableByUser: true;
113
+ }, {
114
+ readonly slotId: "assistant";
115
+ readonly role: "assistant";
116
+ readonly accepts: ["assistant-panel", "chat-thread"];
117
+ readonly cardinality: "many";
118
+ readonly mutableByAi: true;
119
+ readonly mutableByUser: true;
120
+ }, {
121
+ readonly slotId: "inspector";
122
+ readonly role: "inspector";
123
+ readonly accepts: ["entity-field", "relation-graph", "custom-widget"];
124
+ readonly cardinality: "many";
125
+ readonly mutableByAi: true;
126
+ readonly mutableByUser: true;
127
+ }];
128
+ readonly layouts: [{
129
+ readonly layoutId: "balanced-three-pane";
130
+ readonly title: "Balanced 3-pane";
131
+ readonly root: {
132
+ readonly type: "panel-group";
133
+ readonly direction: "horizontal";
134
+ readonly persistKey: "pm.issue.balanced-three-pane";
135
+ readonly children: [{
136
+ readonly type: "slot";
137
+ readonly slotId: "primary";
138
+ }, {
139
+ readonly type: "panel-group";
140
+ readonly direction: "vertical";
141
+ readonly persistKey: "pm.issue.right-stack";
142
+ readonly children: [{
143
+ readonly type: "slot";
144
+ readonly slotId: "secondary";
145
+ }, {
146
+ readonly type: "slot";
147
+ readonly slotId: "assistant";
148
+ }];
149
+ }, {
150
+ readonly type: "slot";
151
+ readonly slotId: "inspector";
152
+ }];
153
+ };
154
+ }];
155
+ readonly data: [{
156
+ readonly recipeId: "issue-core";
157
+ readonly source: {
158
+ readonly kind: "entity";
159
+ readonly entityType: "pm.issue";
160
+ };
161
+ readonly requestedDepth: "detailed";
162
+ readonly hydrateInto: "issue";
163
+ }];
164
+ readonly verification: {
165
+ readonly dimensions: {
166
+ readonly guidance: "Can reveal walkthrough notes, field help, and AI explanations.";
167
+ readonly density: "Can select compact, balanced, or dense multi-pane layouts.";
168
+ readonly dataDepth: "Controls issue relation hydration, activity size, and inspector depth.";
169
+ readonly control: "Shows advanced commands and raw config tabs only when allowed.";
170
+ readonly media: "Supports text-first detail, visual graph, and hybrid assistant modes.";
171
+ readonly pace: "Maps to motion tokens and confirmation behavior.";
172
+ readonly narrative: "Can order issue summary before or after evidence/activity sections.";
173
+ };
174
+ };
175
+ };
176
+ };
177
+ };
@@ -0,0 +1,477 @@
1
+ // @bun
2
+ // src/spec/validate-surface-patch.ts
3
+ var VALID_OPS = [
4
+ "insert-node",
5
+ "replace-node",
6
+ "remove-node",
7
+ "move-node",
8
+ "resize-panel",
9
+ "set-layout",
10
+ "reveal-field",
11
+ "hide-field",
12
+ "promote-action",
13
+ "set-focus"
14
+ ];
15
+ var VALID_NODE_KINDS = [
16
+ "metric-strip",
17
+ "data-view",
18
+ "entity-card",
19
+ "entity-header",
20
+ "entity-summary",
21
+ "entity-section",
22
+ "entity-field",
23
+ "entity-activity",
24
+ "entity-relations",
25
+ "entity-timeline",
26
+ "entity-comments",
27
+ "entity-attachments",
28
+ "entity-view-switcher",
29
+ "entity-automation-panel",
30
+ "rich-doc",
31
+ "chat-thread",
32
+ "assistant-panel",
33
+ "action-bar",
34
+ "timeline",
35
+ "board",
36
+ "table",
37
+ "calendar",
38
+ "form",
39
+ "chart",
40
+ "relation-graph",
41
+ "custom-widget"
42
+ ];
43
+ function validateSurfaceNode(node, path) {
44
+ if (!node.nodeId || typeof node.nodeId !== "string") {
45
+ throw new Error(`${path}: nodeId must be a non-empty string`);
46
+ }
47
+ if (!node.kind || !VALID_NODE_KINDS.includes(node.kind)) {
48
+ throw new Error(`${path}: kind must be one of ${VALID_NODE_KINDS.join(", ")}`);
49
+ }
50
+ if (node.children) {
51
+ for (let i = 0;i < node.children.length; i++) {
52
+ const child = node.children[i];
53
+ if (child)
54
+ validateSurfaceNode(child, `${path}.children[${i}]`);
55
+ }
56
+ }
57
+ }
58
+ function validateSurfacePatchOp(op, index) {
59
+ const path = `ops[${index}]`;
60
+ if (!op || typeof op !== "object" || !("op" in op)) {
61
+ throw new Error(`${path}: must be an object with op field`);
62
+ }
63
+ const opType = op.op;
64
+ if (!VALID_OPS.includes(opType)) {
65
+ throw new Error(`${path}: op must be one of ${VALID_OPS.join(", ")}`);
66
+ }
67
+ switch (op.op) {
68
+ case "insert-node":
69
+ if (!op.slotId || typeof op.slotId !== "string") {
70
+ throw new Error(`${path}: insert-node requires slotId string`);
71
+ }
72
+ if (!op.node) {
73
+ throw new Error(`${path}: insert-node requires node`);
74
+ }
75
+ validateSurfaceNode(op.node, `${path}.node`);
76
+ if (op.index !== undefined && typeof op.index !== "number") {
77
+ throw new Error(`${path}: insert-node index must be number if present`);
78
+ }
79
+ break;
80
+ case "replace-node":
81
+ if (!op.nodeId || typeof op.nodeId !== "string") {
82
+ throw new Error(`${path}: replace-node requires nodeId string`);
83
+ }
84
+ if (!op.node) {
85
+ throw new Error(`${path}: replace-node requires node`);
86
+ }
87
+ validateSurfaceNode(op.node, `${path}.node`);
88
+ break;
89
+ case "remove-node":
90
+ if (!op.nodeId || typeof op.nodeId !== "string") {
91
+ throw new Error(`${path}: remove-node requires nodeId string`);
92
+ }
93
+ break;
94
+ case "move-node":
95
+ if (!op.nodeId || typeof op.nodeId !== "string") {
96
+ throw new Error(`${path}: move-node requires nodeId string`);
97
+ }
98
+ if (!op.toSlotId || typeof op.toSlotId !== "string") {
99
+ throw new Error(`${path}: move-node requires toSlotId string`);
100
+ }
101
+ if (op.index !== undefined && typeof op.index !== "number") {
102
+ throw new Error(`${path}: move-node index must be number if present`);
103
+ }
104
+ break;
105
+ case "resize-panel":
106
+ if (!op.persistKey || typeof op.persistKey !== "string") {
107
+ throw new Error(`${path}: resize-panel requires persistKey string`);
108
+ }
109
+ if (!Array.isArray(op.sizes) || op.sizes.some((s) => typeof s !== "number")) {
110
+ throw new Error(`${path}: resize-panel requires sizes number[]`);
111
+ }
112
+ break;
113
+ case "set-layout":
114
+ if (!op.layoutId || typeof op.layoutId !== "string") {
115
+ throw new Error(`${path}: set-layout requires layoutId string`);
116
+ }
117
+ break;
118
+ case "reveal-field":
119
+ case "hide-field":
120
+ if (!op.fieldId || typeof op.fieldId !== "string") {
121
+ throw new Error(`${path}: ${op.op} requires fieldId string`);
122
+ }
123
+ break;
124
+ case "promote-action": {
125
+ if (!op.actionId || typeof op.actionId !== "string") {
126
+ throw new Error(`${path}: promote-action requires actionId string`);
127
+ }
128
+ const validPlacements = ["header", "inline", "context", "assistant"];
129
+ if (!op.placement || !validPlacements.includes(op.placement)) {
130
+ throw new Error(`${path}: promote-action placement must be one of ${validPlacements.join(", ")}`);
131
+ }
132
+ break;
133
+ }
134
+ case "set-focus":
135
+ if (!op.targetId || typeof op.targetId !== "string") {
136
+ throw new Error(`${path}: set-focus requires targetId string`);
137
+ }
138
+ break;
139
+ default:
140
+ throw new Error(`${path}: unknown op "${opType}"`);
141
+ }
142
+ }
143
+ function validateSurfacePatch(ops) {
144
+ if (!Array.isArray(ops)) {
145
+ throw new Error("Patch ops must be an array");
146
+ }
147
+ for (let i = 0;i < ops.length; i++) {
148
+ const op = ops[i];
149
+ if (op)
150
+ validateSurfacePatchOp(op, i);
151
+ }
152
+ }
153
+ function validateSurfaceNodeAgainstKinds(node, allowedKinds, path) {
154
+ if (!allowedKinds.includes(node.kind)) {
155
+ throw new Error(`${path}: kind "${node.kind}" not in allowed list [${allowedKinds.join(", ")}]`);
156
+ }
157
+ if (node.children) {
158
+ for (let i = 0;i < node.children.length; i++) {
159
+ const child = node.children[i];
160
+ if (child)
161
+ validateSurfaceNodeAgainstKinds(child, allowedKinds, `${path}.children[${i}]`);
162
+ }
163
+ }
164
+ }
165
+ function validatePatchProposal(ops, constraints) {
166
+ if (!Array.isArray(ops)) {
167
+ throw new Error("Patch ops must be an array");
168
+ }
169
+ const { allowedOps, allowedSlots, allowedNodeKinds } = constraints;
170
+ for (let i = 0;i < ops.length; i++) {
171
+ const op = ops[i];
172
+ if (!op)
173
+ continue;
174
+ const path = `ops[${i}]`;
175
+ if (!allowedOps.includes(op.op)) {
176
+ throw new Error(`${path}: op "${op.op}" not in allowed list [${allowedOps.join(", ")}]`);
177
+ }
178
+ switch (op.op) {
179
+ case "insert-node":
180
+ if (!allowedSlots.includes(op.slotId)) {
181
+ throw new Error(`${path}: slotId "${op.slotId}" not in allowed slots [${allowedSlots.join(", ")}]`);
182
+ }
183
+ if (op.node) {
184
+ validateSurfaceNodeAgainstKinds(op.node, allowedNodeKinds, `${path}.node`);
185
+ }
186
+ break;
187
+ case "move-node":
188
+ if (!allowedSlots.includes(op.toSlotId)) {
189
+ throw new Error(`${path}: toSlotId "${op.toSlotId}" not in allowed slots [${allowedSlots.join(", ")}]`);
190
+ }
191
+ break;
192
+ case "replace-node":
193
+ if (op.node) {
194
+ validateSurfaceNodeAgainstKinds(op.node, allowedNodeKinds, `${path}.node`);
195
+ }
196
+ break;
197
+ default:
198
+ break;
199
+ }
200
+ }
201
+ validateSurfacePatch(ops);
202
+ }
203
+ // src/spec/validate-bundle.ts
204
+ var KNOWN_NODE_KIND_RENDERERS = new Set([
205
+ "entity-section",
206
+ "entity-field",
207
+ "action-bar",
208
+ "table",
209
+ "timeline",
210
+ "rich-doc",
211
+ "chat-thread",
212
+ "assistant-panel",
213
+ "entity-card",
214
+ "entity-header",
215
+ "entity-summary",
216
+ "entity-activity",
217
+ "entity-relations",
218
+ "relation-graph",
219
+ "custom-widget"
220
+ ]);
221
+ function collectSlotIdsFromRegion(node) {
222
+ const ids = [];
223
+ if (node.type === "slot") {
224
+ ids.push(node.slotId);
225
+ }
226
+ if (node.type === "panel-group" || node.type === "stack") {
227
+ for (const child of node.children) {
228
+ ids.push(...collectSlotIdsFromRegion(child));
229
+ }
230
+ }
231
+ if (node.type === "tabs") {
232
+ for (const tab of node.tabs) {
233
+ ids.push(...collectSlotIdsFromRegion(tab.child));
234
+ }
235
+ }
236
+ if (node.type === "floating") {
237
+ ids.push(node.anchorSlotId);
238
+ ids.push(...collectSlotIdsFromRegion(node.child));
239
+ }
240
+ return ids;
241
+ }
242
+ function validateLayoutSlots(surface) {
243
+ const declaredSlotIds = new Set(surface.slots.map((s) => s.slotId));
244
+ for (const layout of surface.layouts) {
245
+ const layoutSlotIds = collectSlotIdsFromRegion(layout.root);
246
+ for (const slotId of layoutSlotIds) {
247
+ if (!declaredSlotIds.has(slotId)) {
248
+ throw new Error(`Surface "${surface.surfaceId}" layout "${layout.layoutId}" references undeclared slot "${slotId}". Declared slots: ${[...declaredSlotIds].join(", ")}`);
249
+ }
250
+ }
251
+ }
252
+ }
253
+ function validateBundleNodeKinds(surface) {
254
+ const warnings = [];
255
+ for (const slot of surface.slots) {
256
+ for (const kind of slot.accepts) {
257
+ if (!KNOWN_NODE_KIND_RENDERERS.has(kind)) {
258
+ warnings.push(`Surface "${surface.surfaceId}" slot "${slot.slotId}" accepts "${kind}" which has no dedicated renderer (generic fallback used)`);
259
+ }
260
+ }
261
+ }
262
+ return { warnings };
263
+ }
264
+
265
+ // src/spec/define-module-bundle.ts
266
+ function defineModuleBundle(spec) {
267
+ if (!spec.meta?.key || !spec.meta?.version || !spec.meta?.title) {
268
+ throw new Error("ModuleBundleSpec must have meta.key, meta.version, and meta.title");
269
+ }
270
+ if (!spec.routes?.length) {
271
+ throw new Error("ModuleBundleSpec must have at least one route");
272
+ }
273
+ if (!spec.surfaces || Object.keys(spec.surfaces).length === 0) {
274
+ throw new Error("ModuleBundleSpec must have at least one surface");
275
+ }
276
+ if (spec.entities) {
277
+ if (!spec.entities.entityTypes || typeof spec.entities.entityTypes !== "object") {
278
+ throw new Error("ModuleBundleSpec.entities must have entityTypes object when present");
279
+ }
280
+ if (!spec.entities.fieldKinds || typeof spec.entities.fieldKinds !== "object") {
281
+ throw new Error("ModuleBundleSpec.entities must have fieldKinds object when present");
282
+ }
283
+ }
284
+ const REQUIRED_DIMENSIONS = [
285
+ "guidance",
286
+ "density",
287
+ "dataDepth",
288
+ "control",
289
+ "media",
290
+ "pace",
291
+ "narrative"
292
+ ];
293
+ const MIN_DESCRIPTION_LENGTH = 10;
294
+ for (const surface of Object.values(spec.surfaces)) {
295
+ if (!surface.verification?.dimensions) {
296
+ throw new Error(`Surface "${surface.surfaceId}" must have verification.dimensions for all 7 preference dimensions`);
297
+ }
298
+ const dims = surface.verification.dimensions;
299
+ for (const d of REQUIRED_DIMENSIONS) {
300
+ const val = dims[d];
301
+ if (!val || typeof val !== "string") {
302
+ throw new Error(`Surface "${surface.surfaceId}" verification.dimensions.${d} must be a non-empty string`);
303
+ }
304
+ const trimmed = val.trim();
305
+ if (trimmed.length < MIN_DESCRIPTION_LENGTH) {
306
+ throw new Error(`Surface "${surface.surfaceId}" verification.dimensions.${d} must be at least ${MIN_DESCRIPTION_LENGTH} characters (got ${trimmed.length})`);
307
+ }
308
+ }
309
+ validateLayoutSlots(surface);
310
+ }
311
+ return spec;
312
+ }
313
+ // src/examples/pm-workbench.bundle.ts
314
+ var PmWorkbenchBundle = defineModuleBundle({
315
+ meta: {
316
+ key: "pm.workbench",
317
+ version: "0.1.0",
318
+ title: "PM Workbench",
319
+ description: "AI-native PM workbench for relation-rich issues and saved views",
320
+ owners: ["team-pm-platform"],
321
+ tags: ["pm", "issues", "workbench", "ai-native"],
322
+ stability: "experimental"
323
+ },
324
+ routes: [
325
+ {
326
+ routeId: "pm-issue",
327
+ path: "/operate/pm/issues/:issueId",
328
+ defaultSurface: "issue-workbench"
329
+ }
330
+ ],
331
+ entities: {
332
+ entityTypes: {
333
+ "pm.issue": {
334
+ entityType: "pm.issue",
335
+ defaultSurfaceId: "issue-workbench",
336
+ detailBlueprints: ["balanced-three-pane", "dense-ops-mode"],
337
+ supportedViews: [
338
+ "minimal-summary",
339
+ "balanced-detail",
340
+ "dense-workbench"
341
+ ],
342
+ sectionsFromSchema: true,
343
+ fieldsFromSchema: true,
344
+ relationPanels: ["relations", "meeting-evidence", "decision-trail"]
345
+ }
346
+ },
347
+ fieldKinds: {
348
+ text: { fieldKind: "text", viewer: "text-viewer", editor: "text-editor" },
349
+ number: {
350
+ fieldKind: "number",
351
+ viewer: "number-viewer",
352
+ editor: "number-editor"
353
+ },
354
+ date: { fieldKind: "date", viewer: "date-viewer", editor: "date-editor" },
355
+ select: {
356
+ fieldKind: "select",
357
+ viewer: "select-viewer",
358
+ editor: "select-editor"
359
+ }
360
+ },
361
+ sectionKinds: {
362
+ overview: { sectionKind: "overview", renderer: "section-overview" },
363
+ details: { sectionKind: "details", renderer: "section-details" },
364
+ relations: { sectionKind: "relations", renderer: "section-relations" },
365
+ activity: { sectionKind: "activity", renderer: "section-activity" }
366
+ },
367
+ viewKinds: {
368
+ "minimal-summary": {
369
+ viewKind: "minimal-summary",
370
+ renderer: "view-minimal"
371
+ },
372
+ "balanced-detail": {
373
+ viewKind: "balanced-detail",
374
+ renderer: "view-balanced",
375
+ defaultLayoutId: "balanced-three-pane"
376
+ },
377
+ "dense-workbench": {
378
+ viewKind: "dense-workbench",
379
+ renderer: "view-dense",
380
+ defaultLayoutId: "dense-ops-mode"
381
+ }
382
+ }
383
+ },
384
+ surfaces: {
385
+ "issue-workbench": {
386
+ surfaceId: "issue-workbench",
387
+ kind: "workbench",
388
+ title: "Issue Workbench",
389
+ slots: [
390
+ {
391
+ slotId: "header",
392
+ role: "header",
393
+ accepts: ["action-bar"],
394
+ cardinality: "many"
395
+ },
396
+ {
397
+ slotId: "primary",
398
+ role: "primary",
399
+ accepts: ["entity-section", "table", "rich-doc"],
400
+ cardinality: "many",
401
+ mutableByAi: true,
402
+ mutableByUser: true
403
+ },
404
+ {
405
+ slotId: "secondary",
406
+ role: "secondary",
407
+ accepts: ["entity-section", "table", "timeline"],
408
+ cardinality: "many",
409
+ mutableByAi: true,
410
+ mutableByUser: true
411
+ },
412
+ {
413
+ slotId: "assistant",
414
+ role: "assistant",
415
+ accepts: ["assistant-panel", "chat-thread"],
416
+ cardinality: "many",
417
+ mutableByAi: true,
418
+ mutableByUser: true
419
+ },
420
+ {
421
+ slotId: "inspector",
422
+ role: "inspector",
423
+ accepts: ["entity-field", "relation-graph", "custom-widget"],
424
+ cardinality: "many",
425
+ mutableByAi: true,
426
+ mutableByUser: true
427
+ }
428
+ ],
429
+ layouts: [
430
+ {
431
+ layoutId: "balanced-three-pane",
432
+ title: "Balanced 3-pane",
433
+ root: {
434
+ type: "panel-group",
435
+ direction: "horizontal",
436
+ persistKey: "pm.issue.balanced-three-pane",
437
+ children: [
438
+ { type: "slot", slotId: "primary" },
439
+ {
440
+ type: "panel-group",
441
+ direction: "vertical",
442
+ persistKey: "pm.issue.right-stack",
443
+ children: [
444
+ { type: "slot", slotId: "secondary" },
445
+ { type: "slot", slotId: "assistant" }
446
+ ]
447
+ },
448
+ { type: "slot", slotId: "inspector" }
449
+ ]
450
+ }
451
+ }
452
+ ],
453
+ data: [
454
+ {
455
+ recipeId: "issue-core",
456
+ source: { kind: "entity", entityType: "pm.issue" },
457
+ requestedDepth: "detailed",
458
+ hydrateInto: "issue"
459
+ }
460
+ ],
461
+ verification: {
462
+ dimensions: {
463
+ guidance: "Can reveal walkthrough notes, field help, and AI explanations.",
464
+ density: "Can select compact, balanced, or dense multi-pane layouts.",
465
+ dataDepth: "Controls issue relation hydration, activity size, and inspector depth.",
466
+ control: "Shows advanced commands and raw config tabs only when allowed.",
467
+ media: "Supports text-first detail, visual graph, and hybrid assistant modes.",
468
+ pace: "Maps to motion tokens and confirmation behavior.",
469
+ narrative: "Can order issue summary before or after evidence/activity sections."
470
+ }
471
+ }
472
+ }
473
+ }
474
+ });
475
+ export {
476
+ PmWorkbenchBundle
477
+ };
@@ -0,0 +1 @@
1
+ export declare const enMessages: import("@contractspec/lib.contracts-spec/translations").TranslationSpec;