@contractspec/lib.example-shared-ui 1.11.0 → 1.12.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 (121) hide show
  1. package/.turbo/turbo-build.log +86 -11
  2. package/.turbo/turbo-prebuild.log +1 -0
  3. package/CHANGELOG.md +14 -0
  4. package/dist/EvolutionDashboard.d.ts +11 -0
  5. package/dist/EvolutionDashboard.d.ts.map +1 -0
  6. package/dist/EvolutionDashboard.js +804 -0
  7. package/dist/EvolutionSidebar.d.ts +19 -0
  8. package/dist/EvolutionSidebar.d.ts.map +1 -0
  9. package/dist/EvolutionSidebar.js +532 -0
  10. package/dist/LocalDataIndicator.d.ts +2 -0
  11. package/dist/LocalDataIndicator.d.ts.map +1 -0
  12. package/dist/LocalDataIndicator.js +63 -0
  13. package/dist/MarkdownView.d.ts +20 -0
  14. package/dist/MarkdownView.d.ts.map +1 -0
  15. package/dist/MarkdownView.js +304 -0
  16. package/dist/OverlayContextProvider.d.ts +79 -0
  17. package/dist/OverlayContextProvider.d.ts.map +1 -0
  18. package/dist/OverlayContextProvider.js +203 -0
  19. package/dist/PersonalizationInsights.d.ts +14 -0
  20. package/dist/PersonalizationInsights.d.ts.map +1 -0
  21. package/dist/PersonalizationInsights.js +456 -0
  22. package/dist/SaveToStudioButton.d.ts +8 -0
  23. package/dist/SaveToStudioButton.d.ts.map +1 -0
  24. package/dist/SaveToStudioButton.js +74 -0
  25. package/dist/SpecEditorPanel.d.ts +23 -0
  26. package/dist/SpecEditorPanel.d.ts.map +1 -0
  27. package/dist/SpecEditorPanel.js +720 -0
  28. package/dist/TemplateShell.d.ts +13 -0
  29. package/dist/TemplateShell.d.ts.map +1 -0
  30. package/dist/TemplateShell.js +190 -0
  31. package/dist/browser/EvolutionDashboard.js +803 -0
  32. package/dist/browser/EvolutionSidebar.js +531 -0
  33. package/dist/browser/LocalDataIndicator.js +62 -0
  34. package/dist/browser/MarkdownView.js +303 -0
  35. package/dist/browser/OverlayContextProvider.js +202 -0
  36. package/dist/browser/PersonalizationInsights.js +455 -0
  37. package/dist/browser/SaveToStudioButton.js +73 -0
  38. package/dist/browser/SpecEditorPanel.js +719 -0
  39. package/dist/browser/TemplateShell.js +189 -0
  40. package/dist/browser/hooks/index.js +1516 -0
  41. package/dist/browser/hooks/useBehaviorTracking.js +157 -0
  42. package/dist/browser/hooks/useEvolution.js +260 -0
  43. package/dist/browser/hooks/useRegistryTemplates.js +31 -0
  44. package/dist/browser/hooks/useSpecContent.js +579 -0
  45. package/dist/browser/hooks/useWorkflowComposer.js +493 -0
  46. package/dist/browser/index.js +3497 -0
  47. package/dist/browser/lib/component-registry.js +42 -0
  48. package/dist/browser/lib/runtime-context.js +15 -0
  49. package/dist/browser/lib/types.js +0 -0
  50. package/dist/browser/overlay-types.js +0 -0
  51. package/dist/browser/utils/fetchPresentationData.js +15 -0
  52. package/dist/browser/utils/generateSpecFromTemplate.js +423 -0
  53. package/dist/browser/utils/index.js +437 -0
  54. package/dist/hooks/index.d.ts +6 -0
  55. package/dist/hooks/index.d.ts.map +1 -0
  56. package/dist/hooks/index.js +1517 -0
  57. package/dist/hooks/useBehaviorTracking.d.ts +56 -0
  58. package/dist/hooks/useBehaviorTracking.d.ts.map +1 -0
  59. package/dist/hooks/useBehaviorTracking.js +158 -0
  60. package/dist/hooks/useEvolution.d.ts +111 -0
  61. package/dist/hooks/useEvolution.d.ts.map +1 -0
  62. package/dist/hooks/useEvolution.js +261 -0
  63. package/dist/hooks/useRegistryTemplates.d.ts +10 -0
  64. package/dist/hooks/useRegistryTemplates.d.ts.map +1 -0
  65. package/dist/hooks/useRegistryTemplates.js +32 -0
  66. package/dist/hooks/useSpecContent.d.ts +41 -0
  67. package/dist/hooks/useSpecContent.d.ts.map +1 -0
  68. package/dist/hooks/useSpecContent.js +580 -0
  69. package/dist/hooks/useWorkflowComposer.d.ts +94 -0
  70. package/dist/hooks/useWorkflowComposer.d.ts.map +1 -0
  71. package/dist/hooks/useWorkflowComposer.js +494 -0
  72. package/dist/index.d.ts +16 -0
  73. package/dist/index.d.ts.map +1 -0
  74. package/dist/index.js +3498 -0
  75. package/dist/lib/component-registry.d.ts +18 -0
  76. package/dist/lib/component-registry.d.ts.map +1 -0
  77. package/dist/lib/component-registry.js +43 -0
  78. package/dist/lib/runtime-context.d.ts +29 -0
  79. package/dist/lib/runtime-context.d.ts.map +1 -0
  80. package/dist/lib/runtime-context.js +16 -0
  81. package/dist/lib/types.d.ts +69 -0
  82. package/dist/lib/types.d.ts.map +1 -0
  83. package/dist/lib/types.js +1 -0
  84. package/dist/node/EvolutionDashboard.js +803 -0
  85. package/dist/node/EvolutionSidebar.js +531 -0
  86. package/dist/node/LocalDataIndicator.js +62 -0
  87. package/dist/node/MarkdownView.js +303 -0
  88. package/dist/node/OverlayContextProvider.js +202 -0
  89. package/dist/node/PersonalizationInsights.js +455 -0
  90. package/dist/node/SaveToStudioButton.js +73 -0
  91. package/dist/node/SpecEditorPanel.js +719 -0
  92. package/dist/node/TemplateShell.js +189 -0
  93. package/dist/node/hooks/index.js +1516 -0
  94. package/dist/node/hooks/useBehaviorTracking.js +157 -0
  95. package/dist/node/hooks/useEvolution.js +260 -0
  96. package/dist/node/hooks/useRegistryTemplates.js +31 -0
  97. package/dist/node/hooks/useSpecContent.js +579 -0
  98. package/dist/node/hooks/useWorkflowComposer.js +493 -0
  99. package/dist/node/index.js +3497 -0
  100. package/dist/node/lib/component-registry.js +42 -0
  101. package/dist/node/lib/runtime-context.js +15 -0
  102. package/dist/node/lib/types.js +0 -0
  103. package/dist/node/overlay-types.js +0 -0
  104. package/dist/node/utils/fetchPresentationData.js +15 -0
  105. package/dist/node/utils/generateSpecFromTemplate.js +423 -0
  106. package/dist/node/utils/index.js +437 -0
  107. package/dist/overlay-types.d.ts +41 -0
  108. package/dist/overlay-types.d.ts.map +1 -0
  109. package/dist/overlay-types.js +1 -0
  110. package/dist/utils/fetchPresentationData.d.ts +34 -0
  111. package/dist/utils/fetchPresentationData.d.ts.map +1 -0
  112. package/dist/utils/fetchPresentationData.js +16 -0
  113. package/dist/utils/generateSpecFromTemplate.d.ts +7 -0
  114. package/dist/utils/generateSpecFromTemplate.d.ts.map +1 -0
  115. package/dist/utils/generateSpecFromTemplate.js +424 -0
  116. package/dist/utils/index.d.ts +3 -0
  117. package/dist/utils/index.d.ts.map +1 -0
  118. package/dist/utils/index.js +438 -0
  119. package/package.json +219 -14
  120. package/.turbo/turbo-build$colon$bundle.log +0 -9
  121. package/dist/index.mjs +0 -3121
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSpecContent.d.ts","sourceRoot":"","sources":["../../src/hooks/useSpecContent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAS/C;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;KAC/B,EAAE,CAAC;CACL;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,2CAA2C;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,6BAA6B;IAC7B,UAAU,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACxC,0BAA0B;IAC1B,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,mCAAmC;IACnC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,oBAAoB,CAAC;IACrC,gCAAgC;IAChC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,2BAA2B;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,UAAU,GAAG,oBAAoB,CA8L3E"}
@@ -0,0 +1,580 @@
1
+ // @bun
2
+ // src/lib/runtime-context.tsx
3
+ import { createContext, useContext } from "react";
4
+ "use client";
5
+ var TemplateRuntimeContext = createContext(null);
6
+ function useTemplateRuntime() {
7
+ const context = useContext(TemplateRuntimeContext);
8
+ if (!context) {
9
+ throw new Error("useTemplateRuntime must be used within a TemplateRuntimeProvider");
10
+ }
11
+ return context;
12
+ }
13
+
14
+ // src/utils/generateSpecFromTemplate.ts
15
+ function generateSpecFromTemplate(template) {
16
+ const templateId = template?.id ?? "unknown";
17
+ if (!template) {
18
+ return generateDefaultSpec(templateId);
19
+ }
20
+ switch (templateId) {
21
+ case "crm-pipeline":
22
+ return generateCrmPipelineSpec(template.schema.contracts);
23
+ case "saas-boilerplate":
24
+ return generateSaasBoilerplateSpec(template.schema.contracts);
25
+ case "agent-console":
26
+ return generateAgentConsoleSpec(template.schema.contracts);
27
+ case "todos-app":
28
+ return generateTodosSpec(template.schema.contracts);
29
+ case "messaging-app":
30
+ return generateMessagingSpec(template.schema.contracts);
31
+ case "recipe-app-i18n":
32
+ return generateRecipeSpec(template.schema.contracts);
33
+ default:
34
+ return generateDefaultSpec(templateId);
35
+ }
36
+ }
37
+ function generateCrmPipelineSpec(contracts) {
38
+ return `// CRM Pipeline Specs
39
+ // Contracts: ${contracts.join(", ")}
40
+
41
+ contractSpec("crm.deal.updateStage.v1", {
42
+ goal: "Move a deal to a different pipeline stage",
43
+ transport: { gql: { mutation: "updateDealStage" } },
44
+ io: {
45
+ input: {
46
+ dealId: "string",
47
+ stageId: "string",
48
+ notes: "string?"
49
+ },
50
+ output: {
51
+ deal: {
52
+ id: "string",
53
+ stage: "string",
54
+ probability: "number",
55
+ value: "number"
56
+ }
57
+ }
58
+ },
59
+ events: ["deal.stage.changed"],
60
+ policy: { auth: "user", rbac: "org:sales" }
61
+ });
62
+
63
+ contractSpec("crm.deal.create.v1", {
64
+ goal: "Create a new deal in the pipeline",
65
+ transport: { gql: { mutation: "createDeal" } },
66
+ io: {
67
+ input: {
68
+ title: "string",
69
+ value: "number",
70
+ contactId: "string",
71
+ stageId: "string",
72
+ ownerId: "string?"
73
+ },
74
+ output: {
75
+ deal: {
76
+ id: "string",
77
+ title: "string",
78
+ value: "number",
79
+ stage: "string",
80
+ createdAt: "ISO8601"
81
+ }
82
+ }
83
+ },
84
+ events: ["deal.created"]
85
+ });
86
+
87
+ contractSpec("crm.contact.list.v1", {
88
+ goal: "List contacts with filtering and pagination",
89
+ transport: { gql: { query: "listContacts" } },
90
+ io: {
91
+ input: {
92
+ filter: {
93
+ search: "string?",
94
+ companyId: "string?",
95
+ tags: "string[]?"
96
+ },
97
+ pagination: {
98
+ page: "number",
99
+ limit: "number"
100
+ }
101
+ },
102
+ output: {
103
+ contacts: "array<Contact>",
104
+ total: "number",
105
+ hasMore: "boolean"
106
+ }
107
+ }
108
+ });`;
109
+ }
110
+ function generateSaasBoilerplateSpec(contracts) {
111
+ return `// SaaS Boilerplate Specs
112
+ // Contracts: ${contracts.join(", ")}
113
+
114
+ contractSpec("saas.project.create.v1", {
115
+ goal: "Create a new project in an organization",
116
+ transport: { gql: { mutation: "createProject" } },
117
+ io: {
118
+ input: {
119
+ orgId: "string",
120
+ name: "string",
121
+ description: "string?"
122
+ },
123
+ output: {
124
+ project: {
125
+ id: "string",
126
+ name: "string",
127
+ description: "string?",
128
+ createdAt: "ISO8601"
129
+ }
130
+ }
131
+ },
132
+ policy: { auth: "user", rbac: "org:member" }
133
+ });
134
+
135
+ contractSpec("saas.billing.recordUsage.v1", {
136
+ goal: "Record usage for billing purposes",
137
+ transport: { gql: { mutation: "recordUsage" } },
138
+ io: {
139
+ input: {
140
+ orgId: "string",
141
+ metric: "enum<'api_calls'|'storage_gb'|'seats'>",
142
+ quantity: "number",
143
+ timestamp: "ISO8601?"
144
+ },
145
+ output: {
146
+ usage: {
147
+ id: "string",
148
+ metric: "string",
149
+ quantity: "number",
150
+ recordedAt: "ISO8601"
151
+ }
152
+ }
153
+ },
154
+ events: ["billing.usage.recorded"]
155
+ });
156
+
157
+ contractSpec("saas.settings.update.v1", {
158
+ goal: "Update organization or user settings",
159
+ transport: { gql: { mutation: "updateSettings" } },
160
+ io: {
161
+ input: {
162
+ scope: "enum<'org'|'user'>",
163
+ targetId: "string",
164
+ settings: "Record<string, unknown>"
165
+ },
166
+ output: {
167
+ settings: {
168
+ scope: "string",
169
+ values: "Record<string, unknown>",
170
+ updatedAt: "ISO8601"
171
+ }
172
+ }
173
+ },
174
+ events: ["settings.updated"]
175
+ });`;
176
+ }
177
+ function generateAgentConsoleSpec(contracts) {
178
+ return `// Agent Console Specs
179
+ // Contracts: ${contracts.join(", ")}
180
+
181
+ contractSpec("agent.run.execute.v1", {
182
+ goal: "Execute an agent run with specified tools",
183
+ transport: { gql: { mutation: "executeAgentRun" } },
184
+ io: {
185
+ input: {
186
+ agentId: "string",
187
+ input: "string",
188
+ tools: "string[]?",
189
+ maxSteps: "number?"
190
+ },
191
+ output: {
192
+ runId: "string",
193
+ status: "enum<'running'|'completed'|'failed'>",
194
+ steps: "number"
195
+ }
196
+ },
197
+ events: ["run.started", "run.completed", "run.failed"]
198
+ });
199
+
200
+ contractSpec("agent.tool.create.v1", {
201
+ goal: "Register a new tool in the tool registry",
202
+ transport: { gql: { mutation: "createTool" } },
203
+ io: {
204
+ input: {
205
+ name: "string",
206
+ description: "string",
207
+ category: "enum<'code'|'data'|'api'|'file'|'custom'>",
208
+ schema: "JSONSchema",
209
+ handler: "string"
210
+ },
211
+ output: {
212
+ tool: {
213
+ id: "string",
214
+ name: "string",
215
+ category: "string",
216
+ createdAt: "ISO8601"
217
+ }
218
+ }
219
+ },
220
+ events: ["tool.created"]
221
+ });
222
+
223
+ contractSpec("agent.agent.create.v1", {
224
+ goal: "Create a new AI agent configuration",
225
+ transport: { gql: { mutation: "createAgent" } },
226
+ io: {
227
+ input: {
228
+ name: "string",
229
+ description: "string",
230
+ model: "string",
231
+ systemPrompt: "string?",
232
+ tools: "string[]?"
233
+ },
234
+ output: {
235
+ agent: {
236
+ id: "string",
237
+ name: "string",
238
+ model: "string",
239
+ toolCount: "number",
240
+ createdAt: "ISO8601"
241
+ }
242
+ }
243
+ },
244
+ events: ["agent.created"]
245
+ });`;
246
+ }
247
+ function generateTodosSpec(contracts) {
248
+ return `// To-dos App Specs
249
+ // Contracts: ${contracts.join(", ")}
250
+
251
+ contractSpec("tasks.board.v1", {
252
+ goal: "Assign and approve craft work",
253
+ transport: { gql: { field: "tasksBoard" } },
254
+ io: {
255
+ input: {
256
+ tenantId: "string",
257
+ assignee: "string?",
258
+ status: "enum<'pending'|'in_progress'|'completed'>?"
259
+ },
260
+ output: {
261
+ tasks: "array<Task>",
262
+ summary: {
263
+ total: "number",
264
+ completed: "number",
265
+ overdue: "number"
266
+ }
267
+ }
268
+ }
269
+ });
270
+
271
+ contractSpec("tasks.create.v1", {
272
+ goal: "Create a new task",
273
+ transport: { gql: { mutation: "createTask" } },
274
+ io: {
275
+ input: {
276
+ title: "string",
277
+ description: "string?",
278
+ assignee: "string?",
279
+ priority: "enum<'low'|'medium'|'high'>",
280
+ dueDate: "ISO8601?"
281
+ },
282
+ output: {
283
+ task: {
284
+ id: "string",
285
+ title: "string",
286
+ status: "string",
287
+ createdAt: "ISO8601"
288
+ }
289
+ }
290
+ },
291
+ events: ["task.created"]
292
+ });
293
+
294
+ contractSpec("tasks.complete.v1", {
295
+ goal: "Mark a task as completed",
296
+ transport: { gql: { mutation: "completeTask" } },
297
+ io: {
298
+ input: { taskId: "string" },
299
+ output: {
300
+ task: {
301
+ id: "string",
302
+ status: "string",
303
+ completedAt: "ISO8601"
304
+ }
305
+ }
306
+ },
307
+ events: ["task.completed"]
308
+ });`;
309
+ }
310
+ function generateMessagingSpec(contracts) {
311
+ return `// Messaging App Specs
312
+ // Contracts: ${contracts.join(", ")}
313
+
314
+ contractSpec("messaging.send.v1", {
315
+ goal: "Deliver intent-rich updates",
316
+ io: {
317
+ input: {
318
+ conversationId: "string",
319
+ body: "richtext",
320
+ attachments: "array<Attachment>?"
321
+ },
322
+ output: {
323
+ messageId: "string",
324
+ deliveredAt: "ISO8601"
325
+ }
326
+ },
327
+ events: ["message.sent", "message.delivered"]
328
+ });
329
+
330
+ contractSpec("messaging.conversation.create.v1", {
331
+ goal: "Start a new conversation",
332
+ transport: { gql: { mutation: "createConversation" } },
333
+ io: {
334
+ input: {
335
+ participants: "string[]",
336
+ title: "string?",
337
+ type: "enum<'direct'|'group'>"
338
+ },
339
+ output: {
340
+ conversation: {
341
+ id: "string",
342
+ title: "string?",
343
+ participantCount: "number",
344
+ createdAt: "ISO8601"
345
+ }
346
+ }
347
+ },
348
+ events: ["conversation.created"]
349
+ });
350
+
351
+ contractSpec("messaging.read.v1", {
352
+ goal: "Mark messages as read",
353
+ transport: { gql: { mutation: "markRead" } },
354
+ io: {
355
+ input: {
356
+ conversationId: "string",
357
+ messageIds: "string[]"
358
+ },
359
+ output: {
360
+ readCount: "number",
361
+ readAt: "ISO8601"
362
+ }
363
+ },
364
+ events: ["message.read"]
365
+ });`;
366
+ }
367
+ function generateRecipeSpec(contracts) {
368
+ return `// Recipe App (i18n) Specs
369
+ // Contracts: ${contracts.join(", ")}
370
+
371
+ contractSpec("recipes.lookup.v1", {
372
+ goal: "Serve bilingual rituals",
373
+ io: {
374
+ input: {
375
+ locale: "enum<'EN'|'FR'>",
376
+ slug: "string"
377
+ },
378
+ output: {
379
+ title: "string",
380
+ content: "markdown",
381
+ ingredients: "array<Ingredient>",
382
+ instructions: "array<Instruction>"
383
+ }
384
+ }
385
+ });
386
+
387
+ contractSpec("recipes.list.v1", {
388
+ goal: "Browse recipes with filtering",
389
+ transport: { gql: { query: "listRecipes" } },
390
+ io: {
391
+ input: {
392
+ locale: "enum<'EN'|'FR'>",
393
+ category: "string?",
394
+ search: "string?",
395
+ favorites: "boolean?"
396
+ },
397
+ output: {
398
+ recipes: "array<RecipeSummary>",
399
+ categories: "array<Category>",
400
+ total: "number"
401
+ }
402
+ }
403
+ });
404
+
405
+ contractSpec("recipes.favorite.toggle.v1", {
406
+ goal: "Toggle recipe favorite status",
407
+ transport: { gql: { mutation: "toggleFavorite" } },
408
+ io: {
409
+ input: { recipeId: "string" },
410
+ output: {
411
+ isFavorite: "boolean",
412
+ totalFavorites: "number"
413
+ }
414
+ },
415
+ events: ["recipe.favorited", "recipe.unfavorited"]
416
+ });`;
417
+ }
418
+ function generateDefaultSpec(templateId) {
419
+ return `// ${templateId} Specs
420
+
421
+ contractSpec("${templateId}.main.v1", {
422
+ goal: "Main operation for ${templateId}",
423
+ transport: { gql: { query: "main" } },
424
+ io: {
425
+ input: {
426
+ id: "string"
427
+ },
428
+ output: {
429
+ result: "unknown"
430
+ }
431
+ }
432
+ });`;
433
+ }
434
+
435
+ // src/hooks/useSpecContent.ts
436
+ import { useCallback, useEffect, useState } from "react";
437
+ "use client";
438
+ var SPEC_STORAGE_KEY = "contractspec-spec-content";
439
+ function useSpecContent(templateId) {
440
+ const { template } = useTemplateRuntime();
441
+ const [content, setContentState] = useState("");
442
+ const [savedContent, setSavedContent] = useState("");
443
+ const [loading, setLoading] = useState(true);
444
+ const [validation, setValidation] = useState(null);
445
+ const [lastSaved, setLastSaved] = useState(null);
446
+ useEffect(() => {
447
+ setLoading(true);
448
+ try {
449
+ const stored = localStorage.getItem(`${SPEC_STORAGE_KEY}-${templateId}`);
450
+ if (stored) {
451
+ const parsed = JSON.parse(stored);
452
+ if (parsed.content) {
453
+ setContentState(parsed.content);
454
+ setSavedContent(parsed.content);
455
+ setLastSaved(parsed.savedAt);
456
+ } else {
457
+ const generated = generateSpecFromTemplate(template);
458
+ setContentState(generated);
459
+ setSavedContent(generated);
460
+ }
461
+ } else {
462
+ const generated = generateSpecFromTemplate(template);
463
+ setContentState(generated);
464
+ setSavedContent(generated);
465
+ }
466
+ } catch {
467
+ const generated = generateSpecFromTemplate(template);
468
+ setContentState(generated);
469
+ setSavedContent(generated);
470
+ }
471
+ setLoading(false);
472
+ }, [templateId]);
473
+ const setContent = useCallback((newContent) => {
474
+ setContentState(newContent);
475
+ setValidation(null);
476
+ }, []);
477
+ const save = useCallback(() => {
478
+ try {
479
+ const savedAt = new Date().toISOString();
480
+ localStorage.setItem(`${SPEC_STORAGE_KEY}-${templateId}`, JSON.stringify({
481
+ content,
482
+ savedAt
483
+ }));
484
+ setSavedContent(content);
485
+ setLastSaved(savedAt);
486
+ } catch {}
487
+ }, [content, templateId]);
488
+ const validate = useCallback(() => {
489
+ const errors = [];
490
+ const lines = content.split(`
491
+ `);
492
+ if (!content.includes("contractSpec(")) {
493
+ errors.push({
494
+ line: 1,
495
+ message: "Spec must contain a contractSpec() definition",
496
+ severity: "error"
497
+ });
498
+ }
499
+ if (!content.includes("goal:")) {
500
+ errors.push({
501
+ line: 1,
502
+ message: "Spec should have a goal field",
503
+ severity: "warning"
504
+ });
505
+ }
506
+ if (!content.includes("io:")) {
507
+ errors.push({
508
+ line: 1,
509
+ message: "Spec should define io (input/output)",
510
+ severity: "warning"
511
+ });
512
+ }
513
+ const openBraces = (content.match(/{/g) ?? []).length;
514
+ const closeBraces = (content.match(/}/g) ?? []).length;
515
+ if (openBraces !== closeBraces) {
516
+ errors.push({
517
+ line: lines.length,
518
+ message: `Unbalanced braces: ${openBraces} opening, ${closeBraces} closing`,
519
+ severity: "error"
520
+ });
521
+ }
522
+ const openParens = (content.match(/\(/g) ?? []).length;
523
+ const closeParens = (content.match(/\)/g) ?? []).length;
524
+ if (openParens !== closeParens) {
525
+ errors.push({
526
+ line: lines.length,
527
+ message: `Unbalanced parentheses: ${openParens} opening, ${closeParens} closing`,
528
+ severity: "error"
529
+ });
530
+ }
531
+ lines.forEach((line, index) => {
532
+ const singleQuotes = (line.match(/'/g) ?? []).length;
533
+ const doubleQuotes = (line.match(/"/g) ?? []).length;
534
+ if (singleQuotes % 2 !== 0) {
535
+ errors.push({
536
+ line: index + 1,
537
+ message: "Unclosed single quote",
538
+ severity: "error"
539
+ });
540
+ }
541
+ if (doubleQuotes % 2 !== 0) {
542
+ errors.push({
543
+ line: index + 1,
544
+ message: "Unclosed double quote",
545
+ severity: "error"
546
+ });
547
+ }
548
+ });
549
+ const result = {
550
+ valid: errors.filter((e) => e.severity === "error").length === 0,
551
+ errors
552
+ };
553
+ setValidation(result);
554
+ return result;
555
+ }, [content]);
556
+ const reset = useCallback(() => {
557
+ const generated = generateSpecFromTemplate(template);
558
+ setContentState(generated);
559
+ setSavedContent(generated);
560
+ setValidation(null);
561
+ setLastSaved(null);
562
+ try {
563
+ localStorage.removeItem(`${SPEC_STORAGE_KEY}-${templateId}`);
564
+ } catch {}
565
+ }, [templateId]);
566
+ return {
567
+ content,
568
+ loading,
569
+ isDirty: content !== savedContent,
570
+ validation,
571
+ setContent,
572
+ save,
573
+ validate,
574
+ reset,
575
+ lastSaved
576
+ };
577
+ }
578
+ export {
579
+ useSpecContent
580
+ };
@@ -0,0 +1,94 @@
1
+ import type { TemplateId } from '../lib/types';
2
+ /**
3
+ * Workflow step types
4
+ */
5
+ export type StepType = 'action' | 'decision' | 'wait' | 'parallel' | 'end';
6
+ /**
7
+ * Workflow step definition
8
+ */
9
+ export interface ComposerWorkflowStep {
10
+ id: string;
11
+ name: string;
12
+ type: StepType;
13
+ description?: string;
14
+ next?: string | string[];
15
+ condition?: string;
16
+ timeout?: number;
17
+ retries?: number;
18
+ onError?: string;
19
+ }
20
+ /**
21
+ * Workflow spec definition
22
+ */
23
+ export interface WorkflowSpec {
24
+ meta: {
25
+ key: string;
26
+ version: string;
27
+ description?: string;
28
+ };
29
+ steps: ComposerWorkflowStep[];
30
+ start: string;
31
+ context?: Record<string, unknown>;
32
+ }
33
+ /**
34
+ * Workflow extension scope
35
+ */
36
+ export interface WorkflowExtensionScope {
37
+ tenantId?: string;
38
+ role?: string;
39
+ device?: string;
40
+ }
41
+ /**
42
+ * Step injection definition
43
+ */
44
+ export interface StepInjection {
45
+ id?: string;
46
+ after?: string;
47
+ before?: string;
48
+ inject: ComposerWorkflowStep;
49
+ when?: string;
50
+ transitionTo?: string;
51
+ transitionFrom?: string;
52
+ }
53
+ /**
54
+ * Workflow extension definition
55
+ */
56
+ export interface WorkflowExtension extends WorkflowExtensionScope {
57
+ workflow: string;
58
+ baseVersion?: number;
59
+ priority?: number;
60
+ customSteps?: StepInjection[];
61
+ hiddenSteps?: string[];
62
+ metadata?: Record<string, unknown>;
63
+ }
64
+ /**
65
+ * Hook return type
66
+ */
67
+ export interface UseWorkflowComposerReturn {
68
+ /** Current composed workflow */
69
+ workflow: WorkflowSpec | null;
70
+ /** Available base workflows */
71
+ baseWorkflows: WorkflowSpec[];
72
+ /** Current extensions */
73
+ extensions: WorkflowExtension[];
74
+ /** Select a base workflow */
75
+ selectWorkflow: (workflowName: string) => void;
76
+ /** Add an extension */
77
+ addExtension: (extension: WorkflowExtension) => void;
78
+ /** Remove an extension */
79
+ removeExtension: (workflowName: string, index: number) => void;
80
+ /** Compose workflow with current extensions */
81
+ compose: (scope?: WorkflowExtensionScope) => WorkflowSpec | null;
82
+ /** Generate TypeScript code for the spec editor */
83
+ generateSpecCode: () => string;
84
+ /** Loading state */
85
+ loading: boolean;
86
+ /** Error state */
87
+ error: string | null;
88
+ }
89
+ /**
90
+ * Hook for composing workflows in the sandbox.
91
+ * Provides workflow selection, extension management, and code generation.
92
+ */
93
+ export declare function useWorkflowComposer(templateId: TemplateId): UseWorkflowComposerReturn;
94
+ //# sourceMappingURL=useWorkflowComposer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWorkflowComposer.d.ts","sourceRoot":"","sources":["../../src/hooks/useWorkflowComposer.ts"],"names":[],"mappings":"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"}