@contractspec/lib.example-shared-ui 6.0.17 → 6.0.19

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 (84) hide show
  1. package/.turbo/turbo-build.log +81 -81
  2. package/CHANGELOG.md +28 -0
  3. package/dist/EvolutionDashboard.js +1 -803
  4. package/dist/EvolutionSidebar.js +1 -531
  5. package/dist/LocalDataIndicator.js +1 -68
  6. package/dist/MarkdownView.js +1 -213
  7. package/dist/OverlayContextProvider.js +1 -202
  8. package/dist/PersonalizationInsights.js +1 -455
  9. package/dist/SaveToStudioButton.js +1 -79
  10. package/dist/SpecDrivenTemplateShell.js +1 -203
  11. package/dist/SpecEditorPanel.js +17 -364
  12. package/dist/TemplateShell.js +1 -195
  13. package/dist/browser/EvolutionDashboard.js +1 -803
  14. package/dist/browser/EvolutionSidebar.js +1 -531
  15. package/dist/browser/LocalDataIndicator.js +1 -68
  16. package/dist/browser/MarkdownView.js +1 -213
  17. package/dist/browser/OverlayContextProvider.js +1 -202
  18. package/dist/browser/PersonalizationInsights.js +1 -455
  19. package/dist/browser/SaveToStudioButton.js +1 -79
  20. package/dist/browser/SpecDrivenTemplateShell.js +1 -203
  21. package/dist/browser/SpecEditorPanel.js +17 -364
  22. package/dist/browser/TemplateShell.js +1 -195
  23. package/dist/browser/bundles/ExampleTemplateBundle.js +1 -85
  24. package/dist/browser/bundles/index.js +1 -85
  25. package/dist/browser/hooks/index.js +40 -1151
  26. package/dist/browser/hooks/useBehaviorTracking.js +1 -157
  27. package/dist/browser/hooks/useEvolution.js +1 -260
  28. package/dist/browser/hooks/useRegistryTemplates.js +1 -31
  29. package/dist/browser/hooks/useSpecContent.js +17 -224
  30. package/dist/browser/hooks/useWorkflowComposer.js +24 -483
  31. package/dist/browser/index.js +40 -3122
  32. package/dist/browser/lib/component-registry.js +1 -48
  33. package/dist/browser/lib/runtime-context.js +1 -21
  34. package/dist/browser/markdown/formatPresentationName.js +1 -9
  35. package/dist/browser/markdown/useMarkdownPresentation.js +1 -65
  36. package/dist/browser/utils/fetchPresentationData.js +1 -15
  37. package/dist/browser/utils/generateSpecFromTemplate.js +16 -62
  38. package/dist/browser/utils/index.js +16 -76
  39. package/dist/bundles/ExampleTemplateBundle.js +1 -85
  40. package/dist/bundles/index.js +1 -85
  41. package/dist/hooks/index.js +40 -1151
  42. package/dist/hooks/useBehaviorTracking.js +1 -157
  43. package/dist/hooks/useEvolution.js +1 -260
  44. package/dist/hooks/useRegistryTemplates.js +1 -31
  45. package/dist/hooks/useSpecContent.js +17 -224
  46. package/dist/hooks/useWorkflowComposer.js +24 -483
  47. package/dist/index.js +40 -3122
  48. package/dist/lib/component-registry.js +1 -48
  49. package/dist/lib/runtime-context.js +1 -21
  50. package/dist/markdown/formatPresentationName.js +1 -9
  51. package/dist/markdown/useMarkdownPresentation.js +1 -65
  52. package/dist/node/EvolutionDashboard.js +1 -803
  53. package/dist/node/EvolutionSidebar.js +1 -531
  54. package/dist/node/LocalDataIndicator.js +1 -68
  55. package/dist/node/MarkdownView.js +1 -213
  56. package/dist/node/OverlayContextProvider.js +1 -202
  57. package/dist/node/PersonalizationInsights.js +1 -455
  58. package/dist/node/SaveToStudioButton.js +1 -79
  59. package/dist/node/SpecDrivenTemplateShell.js +1 -203
  60. package/dist/node/SpecEditorPanel.js +17 -364
  61. package/dist/node/TemplateShell.js +1 -195
  62. package/dist/node/bundles/ExampleTemplateBundle.js +1 -85
  63. package/dist/node/bundles/index.js +1 -85
  64. package/dist/node/hooks/index.js +40 -1151
  65. package/dist/node/hooks/useBehaviorTracking.js +1 -157
  66. package/dist/node/hooks/useEvolution.js +1 -260
  67. package/dist/node/hooks/useRegistryTemplates.js +1 -31
  68. package/dist/node/hooks/useSpecContent.js +17 -224
  69. package/dist/node/hooks/useWorkflowComposer.js +24 -483
  70. package/dist/node/index.js +40 -3122
  71. package/dist/node/lib/component-registry.js +1 -48
  72. package/dist/node/lib/runtime-context.js +1 -21
  73. package/dist/node/markdown/formatPresentationName.js +1 -9
  74. package/dist/node/markdown/useMarkdownPresentation.js +1 -65
  75. package/dist/node/utils/fetchPresentationData.js +1 -15
  76. package/dist/node/utils/generateSpecFromTemplate.js +16 -62
  77. package/dist/node/utils/index.js +16 -76
  78. package/dist/utils/fetchPresentationData.js +1 -15
  79. package/dist/utils/generateSpecFromTemplate.js +16 -62
  80. package/dist/utils/index.js +16 -76
  81. package/package.json +13 -13
  82. package/src/lib/component-registry.tsx +2 -1
  83. package/src/lib/runtime-context.tsx +1 -1
  84. package/src/lib/singletons.test.ts +19 -22
@@ -1,531 +1 @@
1
- // src/hooks/useEvolution.ts
2
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
- "use client";
4
- var EVOLUTION_STORAGE_KEY = "contractspec-evolution-data";
5
- function useEvolution(templateId) {
6
- const [usageStats, setUsageStats] = useState([]);
7
- const [anomalies, setAnomalies] = useState([]);
8
- const [suggestions, setSuggestions] = useState([]);
9
- const [hints, setHints] = useState([]);
10
- const [loading, setLoading] = useState(false);
11
- const metricsRef = useRef([]);
12
- const [operationCount, setOperationCount] = useState(0);
13
- useEffect(() => {
14
- try {
15
- const stored = localStorage.getItem(`${EVOLUTION_STORAGE_KEY}-${templateId}`);
16
- if (stored) {
17
- const data = JSON.parse(stored);
18
- setSuggestions(data.suggestions.map((s) => ({
19
- ...s,
20
- createdAt: new Date(s.createdAt)
21
- })));
22
- }
23
- } catch {}
24
- }, [templateId]);
25
- useEffect(() => {
26
- try {
27
- localStorage.setItem(`${EVOLUTION_STORAGE_KEY}-${templateId}`, JSON.stringify({ suggestions }));
28
- } catch {}
29
- }, [suggestions, templateId]);
30
- const trackOperation = useCallback((operationName, durationMs, success, errorCode) => {
31
- const sample = {
32
- operation: {
33
- name: operationName,
34
- version: "1.0.0",
35
- tenantId: "sandbox"
36
- },
37
- durationMs,
38
- success,
39
- timestamp: new Date,
40
- errorCode
41
- };
42
- metricsRef.current.push(sample);
43
- setOperationCount((prev) => prev + 1);
44
- }, []);
45
- const analyzeUsage = useCallback(() => {
46
- const samples = metricsRef.current;
47
- if (samples.length < 5)
48
- return;
49
- const groups = new Map;
50
- for (const sample of samples) {
51
- const key = `${sample.operation.name}.v${sample.operation.version}`;
52
- const arr = groups.get(key) ?? [];
53
- arr.push(sample);
54
- groups.set(key, arr);
55
- }
56
- const stats = [];
57
- const detectedAnomalies = [];
58
- groups.forEach((opSamples) => {
59
- if (opSamples.length < 3)
60
- return;
61
- const durations = opSamples.map((s) => s.durationMs).sort((a, b) => a - b);
62
- const errors = opSamples.filter((s) => !s.success);
63
- const totalCalls = opSamples.length;
64
- const errorRate = errors.length / totalCalls;
65
- const averageLatencyMs = durations.reduce((sum, value) => sum + value, 0) / totalCalls;
66
- const timestamps = opSamples.map((s) => s.timestamp.getTime());
67
- const firstSample = opSamples[0];
68
- if (!firstSample)
69
- return;
70
- const stat = {
71
- operation: firstSample.operation,
72
- totalCalls,
73
- successRate: 1 - errorRate,
74
- errorRate,
75
- averageLatencyMs,
76
- p95LatencyMs: percentile(durations, 0.95),
77
- p99LatencyMs: percentile(durations, 0.99),
78
- maxLatencyMs: Math.max(...durations),
79
- lastSeenAt: new Date(Math.max(...timestamps)),
80
- windowStart: new Date(Math.min(...timestamps)),
81
- windowEnd: new Date(Math.max(...timestamps)),
82
- topErrors: errors.reduce((acc, s) => {
83
- if (s.errorCode) {
84
- acc[s.errorCode] = (acc[s.errorCode] ?? 0) + 1;
85
- }
86
- return acc;
87
- }, {})
88
- };
89
- stats.push(stat);
90
- if (errorRate > 0.1) {
91
- detectedAnomalies.push({
92
- operation: stat.operation,
93
- severity: errorRate > 0.3 ? "high" : errorRate > 0.2 ? "medium" : "low",
94
- metric: "error-rate",
95
- description: `Error rate ${(errorRate * 100).toFixed(1)}% exceeds threshold`,
96
- detectedAt: new Date,
97
- threshold: 0.1,
98
- observedValue: errorRate
99
- });
100
- }
101
- if (stat.p99LatencyMs > 500) {
102
- detectedAnomalies.push({
103
- operation: stat.operation,
104
- severity: stat.p99LatencyMs > 1000 ? "high" : stat.p99LatencyMs > 750 ? "medium" : "low",
105
- metric: "latency",
106
- description: `P99 latency ${stat.p99LatencyMs.toFixed(0)}ms exceeds threshold`,
107
- detectedAt: new Date,
108
- threshold: 500,
109
- observedValue: stat.p99LatencyMs
110
- });
111
- }
112
- });
113
- setUsageStats(stats);
114
- setAnomalies(detectedAnomalies);
115
- const newHints = detectedAnomalies.map((anomaly) => ({
116
- operation: anomaly.operation,
117
- category: anomaly.metric === "latency" ? "performance" : "error-handling",
118
- summary: anomaly.metric === "latency" ? "Latency regression detected" : "Error spike detected",
119
- justification: anomaly.description,
120
- recommendedActions: anomaly.metric === "latency" ? [
121
- "Add caching layer",
122
- "Optimize database queries",
123
- "Consider pagination"
124
- ] : [
125
- "Add retry logic",
126
- "Improve error handling",
127
- "Add circuit breaker"
128
- ]
129
- }));
130
- setHints(newHints);
131
- }, []);
132
- const generateSuggestions = useCallback(async () => {
133
- if (anomalies.length === 0)
134
- return;
135
- setLoading(true);
136
- await new Promise((resolve) => setTimeout(resolve, 800));
137
- const newSuggestions = anomalies.map((anomaly) => ({
138
- id: `suggestion-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
139
- intent: {
140
- id: `intent-${anomaly.operation.name}`,
141
- type: anomaly.metric === "latency" ? "latency-regression" : anomaly.metric === "error-rate" ? "error-spike" : "throughput-drop",
142
- description: anomaly.description,
143
- operation: anomaly.operation,
144
- confidence: {
145
- score: anomaly.severity === "high" ? 0.9 : anomaly.severity === "medium" ? 0.7 : 0.5,
146
- sampleSize: usageStats.find((s) => s.operation.name === anomaly.operation.name)?.totalCalls ?? 0
147
- }
148
- },
149
- target: anomaly.operation,
150
- proposal: {
151
- summary: generateSuggestionSummary(anomaly),
152
- rationale: generateSuggestionRationale(anomaly),
153
- changeType: anomaly.metric === "error-rate" ? "policy-update" : "revision",
154
- recommendedActions: generateRecommendedActions(anomaly)
155
- },
156
- confidence: anomaly.severity === "high" ? 0.85 : anomaly.severity === "medium" ? 0.7 : 0.55,
157
- createdAt: new Date,
158
- createdBy: "ai-evolution-agent",
159
- status: "pending",
160
- priority: anomaly.severity
161
- }));
162
- setSuggestions((prev) => [...prev, ...newSuggestions]);
163
- setLoading(false);
164
- }, [anomalies, usageStats]);
165
- const approveSuggestion = useCallback((id, _notes) => {
166
- setSuggestions((prev) => prev.map((s) => s.id === id ? { ...s, status: "approved" } : s));
167
- }, []);
168
- const rejectSuggestion = useCallback((id, _notes) => {
169
- setSuggestions((prev) => prev.map((s) => s.id === id ? { ...s, status: "rejected" } : s));
170
- }, []);
171
- const clear = useCallback(() => {
172
- metricsRef.current = [];
173
- setOperationCount(0);
174
- setUsageStats([]);
175
- setAnomalies([]);
176
- setSuggestions([]);
177
- setHints([]);
178
- localStorage.removeItem(`${EVOLUTION_STORAGE_KEY}-${templateId}`);
179
- }, [templateId]);
180
- return useMemo(() => ({
181
- usageStats,
182
- anomalies,
183
- suggestions,
184
- hints,
185
- loading,
186
- trackOperation,
187
- analyzeUsage,
188
- generateSuggestions,
189
- approveSuggestion,
190
- rejectSuggestion,
191
- clear,
192
- operationCount
193
- }), [
194
- usageStats,
195
- anomalies,
196
- suggestions,
197
- hints,
198
- loading,
199
- trackOperation,
200
- analyzeUsage,
201
- generateSuggestions,
202
- approveSuggestion,
203
- rejectSuggestion,
204
- clear,
205
- operationCount
206
- ]);
207
- }
208
- function percentile(values, p) {
209
- if (!values.length)
210
- return 0;
211
- if (values.length === 1)
212
- return values[0] ?? 0;
213
- const idx = Math.min(values.length - 1, Math.floor(p * values.length));
214
- return values[idx] ?? 0;
215
- }
216
- function generateSuggestionSummary(anomaly) {
217
- if (anomaly.metric === "latency") {
218
- return `Add caching and pagination to ${anomaly.operation.name} to reduce latency`;
219
- }
220
- if (anomaly.metric === "error-rate") {
221
- return `Add retry policy and circuit breaker to ${anomaly.operation.name}`;
222
- }
223
- return `Optimize ${anomaly.operation.name} for improved throughput`;
224
- }
225
- function generateSuggestionRationale(anomaly) {
226
- if (anomaly.metric === "latency") {
227
- return `The operation ${anomaly.operation.name} is experiencing P99 latency of ${anomaly.observedValue?.toFixed(0)}ms, which is above the recommended threshold of ${anomaly.threshold}ms. This can impact user experience and downstream operations.`;
228
- }
229
- if (anomaly.metric === "error-rate") {
230
- return `The error rate for ${anomaly.operation.name} is ${((anomaly.observedValue ?? 0) * 100).toFixed(1)}%, indicating potential issues with input validation, external dependencies, or resource limits.`;
231
- }
232
- return `Throughput for ${anomaly.operation.name} has dropped significantly, suggesting potential bottlenecks or reduced demand that should be investigated.`;
233
- }
234
- function generateRecommendedActions(anomaly) {
235
- if (anomaly.metric === "latency") {
236
- return [
237
- "Add response caching for frequently accessed data",
238
- "Implement pagination for large result sets",
239
- "Optimize database queries with proper indexing",
240
- "Consider adding a GraphQL DataLoader for batching"
241
- ];
242
- }
243
- if (anomaly.metric === "error-rate") {
244
- return [
245
- "Add input validation at the contract level",
246
- "Implement retry policy with exponential backoff",
247
- "Add circuit breaker for external dependencies",
248
- "Enhance error logging for better debugging"
249
- ];
250
- }
251
- return [
252
- "Review resource allocation and scaling policies",
253
- "Check for upstream routing or load balancer issues",
254
- "Validate feature flag configurations",
255
- "Monitor dependency health metrics"
256
- ];
257
- }
258
-
259
- // src/EvolutionSidebar.tsx
260
- import { Button } from "@contractspec/lib.design-system";
261
- import { Badge } from "@contractspec/lib.ui-kit-web/ui/badge";
262
- import { Card } from "@contractspec/lib.ui-kit-web/ui/card";
263
- import { useCallback as useCallback2, useMemo as useMemo2 } from "react";
264
- import { jsxDEV } from "react/jsx-dev-runtime";
265
- "use client";
266
- function EvolutionSidebar({
267
- templateId,
268
- expanded = false,
269
- onToggle,
270
- onLog,
271
- onOpenEvolution
272
- }) {
273
- const {
274
- anomalies,
275
- suggestions,
276
- loading,
277
- approveSuggestion,
278
- rejectSuggestion,
279
- operationCount
280
- } = useEvolution(templateId);
281
- const pendingSuggestions = useMemo2(() => suggestions.filter((s) => s.status === "pending"), [suggestions]);
282
- const topAnomalies = useMemo2(() => anomalies.sort((a, b) => {
283
- const severityOrder = { high: 0, medium: 1, low: 2 };
284
- return severityOrder[a.severity] - severityOrder[b.severity];
285
- }).slice(0, 3), [anomalies]);
286
- const handleApprove = useCallback2((id) => {
287
- approveSuggestion(id);
288
- onLog?.(`Approved suggestion ${id.slice(0, 8)}`);
289
- }, [approveSuggestion, onLog]);
290
- const handleReject = useCallback2((id) => {
291
- rejectSuggestion(id);
292
- onLog?.(`Rejected suggestion ${id.slice(0, 8)}`);
293
- }, [rejectSuggestion, onLog]);
294
- if (!expanded) {
295
- return /* @__PURE__ */ jsxDEV("button", {
296
- onClick: onToggle,
297
- className: "flex items-center gap-2 rounded-lg border border-violet-500/30 bg-violet-500/10 px-3 py-2 text-sm transition hover:bg-violet-500/20",
298
- type: "button",
299
- children: [
300
- /* @__PURE__ */ jsxDEV("span", {
301
- children: "\uD83E\uDD16"
302
- }, undefined, false, undefined, this),
303
- /* @__PURE__ */ jsxDEV("span", {
304
- children: "Evolution"
305
- }, undefined, false, undefined, this),
306
- pendingSuggestions.length > 0 && /* @__PURE__ */ jsxDEV(Badge, {
307
- variant: "secondary",
308
- className: "border-amber-500/30 bg-amber-500/20 text-amber-400",
309
- children: pendingSuggestions.length
310
- }, undefined, false, undefined, this),
311
- anomalies.length > 0 && pendingSuggestions.length === 0 && /* @__PURE__ */ jsxDEV(Badge, {
312
- variant: "destructive",
313
- children: anomalies.length
314
- }, undefined, false, undefined, this)
315
- ]
316
- }, undefined, true, undefined, this);
317
- }
318
- return /* @__PURE__ */ jsxDEV(Card, {
319
- className: "w-80 overflow-hidden",
320
- children: [
321
- /* @__PURE__ */ jsxDEV("div", {
322
- className: "flex items-center justify-between border-violet-500/20 border-b bg-violet-500/5 px-3 py-2",
323
- children: [
324
- /* @__PURE__ */ jsxDEV("div", {
325
- className: "flex items-center gap-2",
326
- children: [
327
- /* @__PURE__ */ jsxDEV("span", {
328
- children: "\uD83E\uDD16"
329
- }, undefined, false, undefined, this),
330
- /* @__PURE__ */ jsxDEV("span", {
331
- className: "font-semibold text-sm",
332
- children: "Evolution"
333
- }, undefined, false, undefined, this)
334
- ]
335
- }, undefined, true, undefined, this),
336
- /* @__PURE__ */ jsxDEV("div", {
337
- className: "flex items-center gap-1",
338
- children: [
339
- onOpenEvolution && /* @__PURE__ */ jsxDEV(Button, {
340
- variant: "ghost",
341
- size: "sm",
342
- onPress: onOpenEvolution,
343
- children: "Expand"
344
- }, undefined, false, undefined, this),
345
- /* @__PURE__ */ jsxDEV("button", {
346
- onClick: onToggle,
347
- className: "p-1 text-muted-foreground hover:text-foreground",
348
- type: "button",
349
- title: "Collapse",
350
- children: "✕"
351
- }, undefined, false, undefined, this)
352
- ]
353
- }, undefined, true, undefined, this)
354
- ]
355
- }, undefined, true, undefined, this),
356
- /* @__PURE__ */ jsxDEV("div", {
357
- className: "max-h-96 overflow-y-auto p-3",
358
- children: [
359
- /* @__PURE__ */ jsxDEV("div", {
360
- className: "mb-3 flex items-center justify-between text-xs",
361
- children: [
362
- /* @__PURE__ */ jsxDEV("span", {
363
- className: "text-muted-foreground",
364
- children: [
365
- operationCount,
366
- " ops tracked"
367
- ]
368
- }, undefined, true, undefined, this),
369
- /* @__PURE__ */ jsxDEV("div", {
370
- className: "flex items-center gap-2",
371
- children: [
372
- anomalies.length > 0 && /* @__PURE__ */ jsxDEV(Badge, {
373
- variant: "destructive",
374
- children: [
375
- anomalies.length,
376
- " anomalies"
377
- ]
378
- }, undefined, true, undefined, this),
379
- pendingSuggestions.length > 0 && /* @__PURE__ */ jsxDEV(Badge, {
380
- variant: "secondary",
381
- className: "border-amber-500/30 bg-amber-500/20 text-amber-400",
382
- children: [
383
- pendingSuggestions.length,
384
- " pending"
385
- ]
386
- }, undefined, true, undefined, this)
387
- ]
388
- }, undefined, true, undefined, this)
389
- ]
390
- }, undefined, true, undefined, this),
391
- loading && /* @__PURE__ */ jsxDEV("div", {
392
- className: "py-4 text-center text-muted-foreground text-sm",
393
- children: "Generating suggestions..."
394
- }, undefined, false, undefined, this),
395
- topAnomalies.length > 0 && /* @__PURE__ */ jsxDEV("div", {
396
- className: "mb-4",
397
- children: [
398
- /* @__PURE__ */ jsxDEV("p", {
399
- className: "mb-2 font-semibold text-violet-400 text-xs uppercase",
400
- children: "Top Issues"
401
- }, undefined, false, undefined, this),
402
- /* @__PURE__ */ jsxDEV("div", {
403
- className: "space-y-2",
404
- children: topAnomalies.map((anomaly, index) => /* @__PURE__ */ jsxDEV("div", {
405
- className: "rounded border border-amber-500/20 bg-amber-500/5 p-2 text-xs",
406
- children: [
407
- /* @__PURE__ */ jsxDEV("div", {
408
- className: "flex items-center gap-2",
409
- children: [
410
- /* @__PURE__ */ jsxDEV("span", {
411
- children: anomaly.severity === "high" ? "\uD83D\uDD34" : anomaly.severity === "medium" ? "\uD83D\uDFE0" : "\uD83D\uDFE1"
412
- }, undefined, false, undefined, this),
413
- /* @__PURE__ */ jsxDEV("span", {
414
- className: "truncate font-medium",
415
- children: anomaly.operation.name
416
- }, undefined, false, undefined, this)
417
- ]
418
- }, undefined, true, undefined, this),
419
- /* @__PURE__ */ jsxDEV("p", {
420
- className: "mt-1 truncate text-muted-foreground",
421
- children: anomaly.description
422
- }, undefined, false, undefined, this)
423
- ]
424
- }, `${anomaly.operation.name}-${index}`, true, undefined, this))
425
- }, undefined, false, undefined, this)
426
- ]
427
- }, undefined, true, undefined, this),
428
- pendingSuggestions.length > 0 && /* @__PURE__ */ jsxDEV("div", {
429
- children: [
430
- /* @__PURE__ */ jsxDEV("p", {
431
- className: "mb-2 font-semibold text-violet-400 text-xs uppercase",
432
- children: "Pending Suggestions"
433
- }, undefined, false, undefined, this),
434
- /* @__PURE__ */ jsxDEV("div", {
435
- className: "space-y-2",
436
- children: [
437
- pendingSuggestions.slice(0, 3).map((suggestion) => /* @__PURE__ */ jsxDEV(CompactSuggestionCard, {
438
- suggestion,
439
- onApprove: handleApprove,
440
- onReject: handleReject
441
- }, suggestion.id, false, undefined, this)),
442
- pendingSuggestions.length > 3 && /* @__PURE__ */ jsxDEV("p", {
443
- className: "text-center text-muted-foreground text-xs",
444
- children: [
445
- "+",
446
- pendingSuggestions.length - 3,
447
- " more suggestions"
448
- ]
449
- }, undefined, true, undefined, this)
450
- ]
451
- }, undefined, true, undefined, this)
452
- ]
453
- }, undefined, true, undefined, this),
454
- anomalies.length === 0 && pendingSuggestions.length === 0 && !loading && /* @__PURE__ */ jsxDEV("div", {
455
- className: "py-4 text-center text-muted-foreground text-xs",
456
- children: "No issues detected. Keep coding!"
457
- }, undefined, false, undefined, this)
458
- ]
459
- }, undefined, true, undefined, this),
460
- onOpenEvolution && /* @__PURE__ */ jsxDEV("div", {
461
- className: "border-violet-500/20 border-t p-2",
462
- children: /* @__PURE__ */ jsxDEV(Button, {
463
- variant: "ghost",
464
- size: "sm",
465
- className: "w-full",
466
- onPress: onOpenEvolution,
467
- children: "Open Evolution Dashboard →"
468
- }, undefined, false, undefined, this)
469
- }, undefined, false, undefined, this)
470
- ]
471
- }, undefined, true, undefined, this);
472
- }
473
- function CompactSuggestionCard({
474
- suggestion,
475
- onApprove,
476
- onReject
477
- }) {
478
- return /* @__PURE__ */ jsxDEV("div", {
479
- className: "rounded border border-violet-500/20 bg-violet-500/5 p-2",
480
- children: [
481
- /* @__PURE__ */ jsxDEV("div", {
482
- className: "flex items-start justify-between gap-2",
483
- children: /* @__PURE__ */ jsxDEV("div", {
484
- className: "min-w-0 flex-1",
485
- children: [
486
- /* @__PURE__ */ jsxDEV("p", {
487
- className: "truncate font-medium text-xs",
488
- children: suggestion.proposal.summary
489
- }, undefined, false, undefined, this),
490
- /* @__PURE__ */ jsxDEV("div", {
491
- className: "mt-1 flex items-center gap-2 text-xs",
492
- children: [
493
- /* @__PURE__ */ jsxDEV(Badge, {
494
- variant: "secondary",
495
- children: suggestion.priority
496
- }, undefined, false, undefined, this),
497
- /* @__PURE__ */ jsxDEV("span", {
498
- className: "text-muted-foreground",
499
- children: [
500
- (suggestion.confidence * 100).toFixed(0),
501
- "%"
502
- ]
503
- }, undefined, true, undefined, this)
504
- ]
505
- }, undefined, true, undefined, this)
506
- ]
507
- }, undefined, true, undefined, this)
508
- }, undefined, false, undefined, this),
509
- /* @__PURE__ */ jsxDEV("div", {
510
- className: "mt-2 flex justify-end gap-1",
511
- children: [
512
- /* @__PURE__ */ jsxDEV("button", {
513
- onClick: () => onReject(suggestion.id),
514
- className: "rounded px-2 py-0.5 text-red-400 text-xs hover:bg-red-400/10",
515
- type: "button",
516
- children: "Reject"
517
- }, undefined, false, undefined, this),
518
- /* @__PURE__ */ jsxDEV("button", {
519
- onClick: () => onApprove(suggestion.id),
520
- className: "rounded bg-violet-500/20 px-2 py-0.5 text-violet-400 text-xs hover:bg-violet-500/30",
521
- type: "button",
522
- children: "Approve"
523
- }, undefined, false, undefined, this)
524
- ]
525
- }, undefined, true, undefined, this)
526
- ]
527
- }, undefined, true, undefined, this);
528
- }
529
- export {
530
- EvolutionSidebar
531
- };
1
+ import{useCallback as U,useEffect as p,useMemo as t,useRef as n,useState as T}from"react";var S="contractspec-evolution-data";function u(q){let[G,K]=T([]),[H,h]=T([]),[w,V]=T([]),[f,b]=T([]),[L,C]=T(!1),W=n([]),[k,E]=T(0);p(()=>{try{let Z=localStorage.getItem(`${S}-${q}`);if(Z){let D=JSON.parse(Z);V(D.suggestions.map(($)=>({...$,createdAt:new Date($.createdAt)})))}}catch{}},[q]),p(()=>{try{localStorage.setItem(`${S}-${q}`,JSON.stringify({suggestions:w}))}catch{}},[w,q]);let O=U((Z,D,$,X)=>{let v={operation:{name:Z,version:"1.0.0",tenantId:"sandbox"},durationMs:D,success:$,timestamp:new Date,errorCode:X};W.current.push(v),E((Q)=>Q+1)},[]),P=U(()=>{let Z=W.current;if(Z.length<5)return;let D=new Map;for(let Q of Z){let N=`${Q.operation.name}.v${Q.operation.version}`,I=D.get(N)??[];I.push(Q),D.set(N,I)}let $=[],X=[];D.forEach((Q)=>{if(Q.length<3)return;let N=Q.map((z)=>z.durationMs).sort((z,_)=>z-_),I=Q.filter((z)=>!z.success),x=Q.length,M=I.length/x,l=N.reduce((z,_)=>z+_,0)/x,j=Q.map((z)=>z.timestamp.getTime()),y=Q[0];if(!y)return;let Y={operation:y.operation,totalCalls:x,successRate:1-M,errorRate:M,averageLatencyMs:l,p95LatencyMs:r(N,0.95),p99LatencyMs:r(N,0.99),maxLatencyMs:Math.max(...N),lastSeenAt:new Date(Math.max(...j)),windowStart:new Date(Math.min(...j)),windowEnd:new Date(Math.max(...j)),topErrors:I.reduce((z,_)=>{if(_.errorCode)z[_.errorCode]=(z[_.errorCode]??0)+1;return z},{})};if($.push(Y),M>0.1)X.push({operation:Y.operation,severity:M>0.3?"high":M>0.2?"medium":"low",metric:"error-rate",description:`Error rate ${(M*100).toFixed(1)}% exceeds threshold`,detectedAt:new Date,threshold:0.1,observedValue:M});if(Y.p99LatencyMs>500)X.push({operation:Y.operation,severity:Y.p99LatencyMs>1000?"high":Y.p99LatencyMs>750?"medium":"low",metric:"latency",description:`P99 latency ${Y.p99LatencyMs.toFixed(0)}ms exceeds threshold`,detectedAt:new Date,threshold:500,observedValue:Y.p99LatencyMs})}),K($),h(X);let v=X.map((Q)=>({operation:Q.operation,category:Q.metric==="latency"?"performance":"error-handling",summary:Q.metric==="latency"?"Latency regression detected":"Error spike detected",justification:Q.description,recommendedActions:Q.metric==="latency"?["Add caching layer","Optimize database queries","Consider pagination"]:["Add retry logic","Improve error handling","Add circuit breaker"]}));b(v)},[]),B=U(async()=>{if(H.length===0)return;C(!0),await new Promise((D)=>setTimeout(D,800));let Z=H.map((D)=>({id:`suggestion-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,intent:{id:`intent-${D.operation.name}`,type:D.metric==="latency"?"latency-regression":D.metric==="error-rate"?"error-spike":"throughput-drop",description:D.description,operation:D.operation,confidence:{score:D.severity==="high"?0.9:D.severity==="medium"?0.7:0.5,sampleSize:G.find(($)=>$.operation.name===D.operation.name)?.totalCalls??0}},target:D.operation,proposal:{summary:o(D),rationale:s(D),changeType:D.metric==="error-rate"?"policy-update":"revision",recommendedActions:e(D)},confidence:D.severity==="high"?0.85:D.severity==="medium"?0.7:0.55,createdAt:new Date,createdBy:"ai-evolution-agent",status:"pending",priority:D.severity}));V((D)=>[...D,...Z]),C(!1)},[H,G]),A=U((Z,D)=>{V(($)=>$.map((X)=>X.id===Z?{...X,status:"approved"}:X))},[]),c=U((Z,D)=>{V(($)=>$.map((X)=>X.id===Z?{...X,status:"rejected"}:X))},[]),d=U(()=>{W.current=[],E(0),K([]),h([]),V([]),b([]),localStorage.removeItem(`${S}-${q}`)},[q]);return t(()=>({usageStats:G,anomalies:H,suggestions:w,hints:f,loading:L,trackOperation:O,analyzeUsage:P,generateSuggestions:B,approveSuggestion:A,rejectSuggestion:c,clear:d,operationCount:k}),[G,H,w,f,L,O,P,B,A,c,d,k])}function r(q,G){if(!q.length)return 0;if(q.length===1)return q[0]??0;let K=Math.min(q.length-1,Math.floor(G*q.length));return q[K]??0}function o(q){if(q.metric==="latency")return`Add caching and pagination to ${q.operation.name} to reduce latency`;if(q.metric==="error-rate")return`Add retry policy and circuit breaker to ${q.operation.name}`;return`Optimize ${q.operation.name} for improved throughput`}function s(q){if(q.metric==="latency")return`The operation ${q.operation.name} is experiencing P99 latency of ${q.observedValue?.toFixed(0)}ms, which is above the recommended threshold of ${q.threshold}ms. This can impact user experience and downstream operations.`;if(q.metric==="error-rate")return`The error rate for ${q.operation.name} is ${((q.observedValue??0)*100).toFixed(1)}%, indicating potential issues with input validation, external dependencies, or resource limits.`;return`Throughput for ${q.operation.name} has dropped significantly, suggesting potential bottlenecks or reduced demand that should be investigated.`}function e(q){if(q.metric==="latency")return["Add response caching for frequently accessed data","Implement pagination for large result sets","Optimize database queries with proper indexing","Consider adding a GraphQL DataLoader for batching"];if(q.metric==="error-rate")return["Add input validation at the contract level","Implement retry policy with exponential backoff","Add circuit breaker for external dependencies","Enhance error logging for better debugging"];return["Review resource allocation and scaling policies","Check for upstream routing or load balancer issues","Validate feature flag configurations","Monitor dependency health metrics"]}import{Button as i}from"@contractspec/lib.design-system";import{Badge as R}from"@contractspec/lib.ui-kit-web/ui/badge";import{Card as a}from"@contractspec/lib.ui-kit-web/ui/card";import{useCallback as g,useMemo as m}from"react";import{jsx as F,jsxs as J}from"react/jsx-runtime";function Zq({templateId:q,expanded:G=!1,onToggle:K,onLog:H,onOpenEvolution:h}){let{anomalies:w,suggestions:V,loading:f,approveSuggestion:b,rejectSuggestion:L,operationCount:C}=u(q),W=m(()=>V.filter((P)=>P.status==="pending"),[V]),k=m(()=>w.sort((P,B)=>{let A={high:0,medium:1,low:2};return A[P.severity]-A[B.severity]}).slice(0,3),[w]),E=g((P)=>{b(P),H?.(`Approved suggestion ${P.slice(0,8)}`)},[b,H]),O=g((P)=>{L(P),H?.(`Rejected suggestion ${P.slice(0,8)}`)},[L,H]);if(!G)return J("button",{onClick:K,className:"flex items-center gap-2 rounded-lg border border-violet-500/30 bg-violet-500/10 px-3 py-2 text-sm transition hover:bg-violet-500/20",type:"button",children:[F("span",{children:"\uD83E\uDD16"}),F("span",{children:"Evolution"}),W.length>0&&F(R,{variant:"secondary",className:"border-amber-500/30 bg-amber-500/20 text-amber-400",children:W.length}),w.length>0&&W.length===0&&F(R,{variant:"destructive",children:w.length})]});return J(a,{className:"w-80 overflow-hidden",children:[J("div",{className:"flex items-center justify-between border-violet-500/20 border-b bg-violet-500/5 px-3 py-2",children:[J("div",{className:"flex items-center gap-2",children:[F("span",{children:"\uD83E\uDD16"}),F("span",{className:"font-semibold text-sm",children:"Evolution"})]}),J("div",{className:"flex items-center gap-1",children:[h&&F(i,{variant:"ghost",size:"sm",onPress:h,children:"Expand"}),F("button",{onClick:K,className:"p-1 text-muted-foreground hover:text-foreground",type:"button",title:"Collapse",children:"✕"})]})]}),J("div",{className:"max-h-96 overflow-y-auto p-3",children:[J("div",{className:"mb-3 flex items-center justify-between text-xs",children:[J("span",{className:"text-muted-foreground",children:[C," ops tracked"]}),J("div",{className:"flex items-center gap-2",children:[w.length>0&&J(R,{variant:"destructive",children:[w.length," anomalies"]}),W.length>0&&J(R,{variant:"secondary",className:"border-amber-500/30 bg-amber-500/20 text-amber-400",children:[W.length," pending"]})]})]}),f&&F("div",{className:"py-4 text-center text-muted-foreground text-sm",children:"Generating suggestions..."}),k.length>0&&J("div",{className:"mb-4",children:[F("p",{className:"mb-2 font-semibold text-violet-400 text-xs uppercase",children:"Top Issues"}),F("div",{className:"space-y-2",children:k.map((P,B)=>J("div",{className:"rounded border border-amber-500/20 bg-amber-500/5 p-2 text-xs",children:[J("div",{className:"flex items-center gap-2",children:[F("span",{children:P.severity==="high"?"\uD83D\uDD34":P.severity==="medium"?"\uD83D\uDFE0":"\uD83D\uDFE1"}),F("span",{className:"truncate font-medium",children:P.operation.name})]}),F("p",{className:"mt-1 truncate text-muted-foreground",children:P.description})]},`${P.operation.name}-${B}`))})]}),W.length>0&&J("div",{children:[F("p",{className:"mb-2 font-semibold text-violet-400 text-xs uppercase",children:"Pending Suggestions"}),J("div",{className:"space-y-2",children:[W.slice(0,3).map((P)=>F(qq,{suggestion:P,onApprove:E,onReject:O},P.id)),W.length>3&&J("p",{className:"text-center text-muted-foreground text-xs",children:["+",W.length-3," more suggestions"]})]})]}),w.length===0&&W.length===0&&!f&&F("div",{className:"py-4 text-center text-muted-foreground text-xs",children:"No issues detected. Keep coding!"})]}),h&&F("div",{className:"border-violet-500/20 border-t p-2",children:F(i,{variant:"ghost",size:"sm",className:"w-full",onPress:h,children:"Open Evolution Dashboard →"})})]})}function qq({suggestion:q,onApprove:G,onReject:K}){return J("div",{className:"rounded border border-violet-500/20 bg-violet-500/5 p-2",children:[F("div",{className:"flex items-start justify-between gap-2",children:J("div",{className:"min-w-0 flex-1",children:[F("p",{className:"truncate font-medium text-xs",children:q.proposal.summary}),J("div",{className:"mt-1 flex items-center gap-2 text-xs",children:[F(R,{variant:"secondary",children:q.priority}),J("span",{className:"text-muted-foreground",children:[(q.confidence*100).toFixed(0),"%"]})]})]})}),J("div",{className:"mt-2 flex justify-end gap-1",children:[F("button",{onClick:()=>K(q.id),className:"rounded px-2 py-0.5 text-red-400 text-xs hover:bg-red-400/10",type:"button",children:"Reject"}),F("button",{onClick:()=>G(q.id),className:"rounded bg-violet-500/20 px-2 py-0.5 text-violet-400 text-xs hover:bg-violet-500/30",type:"button",children:"Approve"})]})]})}export{Zq as EvolutionSidebar};
@@ -1,68 +1 @@
1
- // src/lib/runtime-context.tsx
2
- import { createContext, useContext } from "react";
3
- "use client";
4
- var TEMPLATE_RUNTIME_CONTEXT_KEY = Symbol.for("@contractspec/lib.example-shared-ui/template-runtime-context");
5
- function getTemplateRuntimeContextSingleton() {
6
- const store = globalThis;
7
- store[TEMPLATE_RUNTIME_CONTEXT_KEY] ??= createContext(null);
8
- return store[TEMPLATE_RUNTIME_CONTEXT_KEY];
9
- }
10
- var TemplateRuntimeContext = getTemplateRuntimeContextSingleton();
11
- function useTemplateRuntime() {
12
- const context = useContext(TemplateRuntimeContext);
13
- if (!context) {
14
- throw new Error("useTemplateRuntime must be used within a TemplateRuntimeProvider");
15
- }
16
- return context;
17
- }
18
-
19
- // src/LocalDataIndicator.tsx
20
- import { RefreshCw, Shield } from "lucide-react";
21
- import { useState } from "react";
22
- import { jsxDEV } from "react/jsx-dev-runtime";
23
- "use client";
24
- function LocalDataIndicator() {
25
- const { projectId, templateId, template, installer } = useTemplateRuntime();
26
- const [isResetting, setIsResetting] = useState(false);
27
- const handleReset = async () => {
28
- setIsResetting(true);
29
- try {
30
- await installer.install(templateId, { projectId });
31
- } finally {
32
- setIsResetting(false);
33
- }
34
- };
35
- return /* @__PURE__ */ jsxDEV("div", {
36
- className: "inline-flex items-center gap-2 rounded-full border border-border bg-muted/40 px-3 py-1 text-muted-foreground text-xs",
37
- children: [
38
- /* @__PURE__ */ jsxDEV(Shield, {
39
- className: "h-3.5 w-3.5 text-violet-400"
40
- }, undefined, false, undefined, this),
41
- /* @__PURE__ */ jsxDEV("span", {
42
- children: [
43
- "Local runtime ·",
44
- " ",
45
- /* @__PURE__ */ jsxDEV("span", {
46
- className: "font-semibold text-foreground",
47
- children: template.name
48
- }, undefined, false, undefined, this)
49
- ]
50
- }, undefined, true, undefined, this),
51
- /* @__PURE__ */ jsxDEV("button", {
52
- type: "button",
53
- className: "inline-flex items-center gap-1 rounded-full border border-border px-2 py-0.5 font-semibold text-[11px] text-muted-foreground hover:text-foreground",
54
- onClick: handleReset,
55
- disabled: isResetting,
56
- children: [
57
- /* @__PURE__ */ jsxDEV(RefreshCw, {
58
- className: "h-3 w-3"
59
- }, undefined, false, undefined, this),
60
- isResetting ? "Resetting…" : "Reset data"
61
- ]
62
- }, undefined, true, undefined, this)
63
- ]
64
- }, undefined, true, undefined, this);
65
- }
66
- export {
67
- LocalDataIndicator
68
- };
1
+ import{createContext as u,useContext as f}from"react";var n=Symbol.for("@contractspec/lib.example-shared-ui/template-runtime-context");function p(){let e=globalThis;return e[n]??=u(null),e[n]}var c=p();function l(){let e=f(c);if(!e)throw Error("useTemplateRuntime must be used within a TemplateRuntimeProvider");return e}import{RefreshCw as b,Shield as g}from"lucide-react";import{useState as h}from"react";import{jsx as t,jsxs as r}from"react/jsx-runtime";function I(){let{projectId:e,templateId:d,template:s,installer:i}=l(),[a,o]=h(!1),m=async()=>{o(!0);try{await i.install(d,{projectId:e})}finally{o(!1)}};return r("div",{className:"inline-flex items-center gap-2 rounded-full border border-border bg-muted/40 px-3 py-1 text-muted-foreground text-xs",children:[t(g,{className:"h-3.5 w-3.5 text-violet-400"}),r("span",{children:["Local runtime ·"," ",t("span",{className:"font-semibold text-foreground",children:s.name})]}),r("button",{type:"button",className:"inline-flex items-center gap-1 rounded-full border border-border px-2 py-0.5 font-semibold text-[11px] text-muted-foreground hover:text-foreground",onClick:m,disabled:a,children:[t(b,{className:"h-3 w-3"}),a?"Resetting…":"Reset data"]})]})}export{I as LocalDataIndicator};