@contractspec/lib.example-shared-ui 6.0.16 → 6.0.18
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.
- package/.turbo/turbo-build.log +81 -81
- package/CHANGELOG.md +32 -0
- package/dist/EvolutionDashboard.js +1 -803
- package/dist/EvolutionSidebar.js +1 -531
- package/dist/LocalDataIndicator.js +1 -62
- package/dist/MarkdownView.js +1 -207
- package/dist/OverlayContextProvider.js +1 -202
- package/dist/PersonalizationInsights.js +1 -455
- package/dist/SaveToStudioButton.js +1 -73
- package/dist/SpecDrivenTemplateShell.js +1 -197
- package/dist/SpecEditorPanel.js +17 -358
- package/dist/TemplateShell.js +1 -189
- package/dist/browser/EvolutionDashboard.js +1 -803
- package/dist/browser/EvolutionSidebar.js +1 -531
- package/dist/browser/LocalDataIndicator.js +1 -62
- package/dist/browser/MarkdownView.js +1 -207
- package/dist/browser/OverlayContextProvider.js +1 -202
- package/dist/browser/PersonalizationInsights.js +1 -455
- package/dist/browser/SaveToStudioButton.js +1 -73
- package/dist/browser/SpecDrivenTemplateShell.js +1 -197
- package/dist/browser/SpecEditorPanel.js +17 -358
- package/dist/browser/TemplateShell.js +1 -189
- package/dist/browser/bundles/ExampleTemplateBundle.js +1 -85
- package/dist/browser/bundles/index.js +1 -85
- package/dist/browser/hooks/index.js +40 -1145
- package/dist/browser/hooks/useBehaviorTracking.js +1 -157
- package/dist/browser/hooks/useEvolution.js +1 -260
- package/dist/browser/hooks/useRegistryTemplates.js +1 -31
- package/dist/browser/hooks/useSpecContent.js +17 -218
- package/dist/browser/hooks/useWorkflowComposer.js +24 -483
- package/dist/browser/index.js +40 -3110
- package/dist/browser/lib/component-registry.js +1 -42
- package/dist/browser/lib/runtime-context.js +1 -15
- package/dist/browser/markdown/formatPresentationName.js +1 -9
- package/dist/browser/markdown/useMarkdownPresentation.js +1 -65
- package/dist/browser/utils/fetchPresentationData.js +1 -15
- package/dist/browser/utils/generateSpecFromTemplate.js +16 -62
- package/dist/browser/utils/index.js +16 -76
- package/dist/bundles/ExampleTemplateBundle.js +1 -85
- package/dist/bundles/index.js +1 -85
- package/dist/hooks/index.js +40 -1145
- package/dist/hooks/useBehaviorTracking.js +1 -157
- package/dist/hooks/useEvolution.js +1 -260
- package/dist/hooks/useRegistryTemplates.js +1 -31
- package/dist/hooks/useSpecContent.js +17 -218
- package/dist/hooks/useWorkflowComposer.js +24 -483
- package/dist/index.js +40 -3110
- package/dist/lib/component-registry.js +1 -42
- package/dist/lib/runtime-context.d.ts +2 -1
- package/dist/lib/runtime-context.js +1 -15
- package/dist/lib/singletons.test.d.ts +1 -0
- package/dist/markdown/formatPresentationName.js +1 -9
- package/dist/markdown/useMarkdownPresentation.js +1 -65
- package/dist/node/EvolutionDashboard.js +1 -803
- package/dist/node/EvolutionSidebar.js +1 -531
- package/dist/node/LocalDataIndicator.js +1 -62
- package/dist/node/MarkdownView.js +1 -207
- package/dist/node/OverlayContextProvider.js +1 -202
- package/dist/node/PersonalizationInsights.js +1 -455
- package/dist/node/SaveToStudioButton.js +1 -73
- package/dist/node/SpecDrivenTemplateShell.js +1 -197
- package/dist/node/SpecEditorPanel.js +17 -358
- package/dist/node/TemplateShell.js +1 -189
- package/dist/node/bundles/ExampleTemplateBundle.js +1 -85
- package/dist/node/bundles/index.js +1 -85
- package/dist/node/hooks/index.js +40 -1145
- package/dist/node/hooks/useBehaviorTracking.js +1 -157
- package/dist/node/hooks/useEvolution.js +1 -260
- package/dist/node/hooks/useRegistryTemplates.js +1 -31
- package/dist/node/hooks/useSpecContent.js +17 -218
- package/dist/node/hooks/useWorkflowComposer.js +24 -483
- package/dist/node/index.js +40 -3110
- package/dist/node/lib/component-registry.js +1 -42
- package/dist/node/lib/runtime-context.js +1 -15
- package/dist/node/markdown/formatPresentationName.js +1 -9
- package/dist/node/markdown/useMarkdownPresentation.js +1 -65
- package/dist/node/utils/fetchPresentationData.js +1 -15
- package/dist/node/utils/generateSpecFromTemplate.js +16 -62
- package/dist/node/utils/index.js +16 -76
- package/dist/utils/fetchPresentationData.js +1 -15
- package/dist/utils/generateSpecFromTemplate.js +16 -62
- package/dist/utils/index.js +16 -76
- package/package.json +14 -14
- package/src/lib/component-registry.tsx +16 -1
- package/src/lib/runtime-context.tsx +17 -3
- package/src/lib/singletons.test.ts +51 -0
|
@@ -1,198 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
|
|
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/LocalDataIndicator.tsx
|
|
15
|
-
import { RefreshCw, Shield } from "lucide-react";
|
|
16
|
-
import { useState } from "react";
|
|
17
|
-
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
18
|
-
"use client";
|
|
19
|
-
function LocalDataIndicator() {
|
|
20
|
-
const { projectId, templateId, template, installer } = useTemplateRuntime();
|
|
21
|
-
const [isResetting, setIsResetting] = useState(false);
|
|
22
|
-
const handleReset = async () => {
|
|
23
|
-
setIsResetting(true);
|
|
24
|
-
try {
|
|
25
|
-
await installer.install(templateId, { projectId });
|
|
26
|
-
} finally {
|
|
27
|
-
setIsResetting(false);
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
return /* @__PURE__ */ jsxDEV("div", {
|
|
31
|
-
className: "inline-flex items-center gap-2 rounded-full border border-border bg-muted/40 px-3 py-1 text-muted-foreground text-xs",
|
|
32
|
-
children: [
|
|
33
|
-
/* @__PURE__ */ jsxDEV(Shield, {
|
|
34
|
-
className: "h-3.5 w-3.5 text-violet-400"
|
|
35
|
-
}, undefined, false, undefined, this),
|
|
36
|
-
/* @__PURE__ */ jsxDEV("span", {
|
|
37
|
-
children: [
|
|
38
|
-
"Local runtime \xB7",
|
|
39
|
-
" ",
|
|
40
|
-
/* @__PURE__ */ jsxDEV("span", {
|
|
41
|
-
className: "font-semibold text-foreground",
|
|
42
|
-
children: template.name
|
|
43
|
-
}, undefined, false, undefined, this)
|
|
44
|
-
]
|
|
45
|
-
}, undefined, true, undefined, this),
|
|
46
|
-
/* @__PURE__ */ jsxDEV("button", {
|
|
47
|
-
type: "button",
|
|
48
|
-
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",
|
|
49
|
-
onClick: handleReset,
|
|
50
|
-
disabled: isResetting,
|
|
51
|
-
children: [
|
|
52
|
-
/* @__PURE__ */ jsxDEV(RefreshCw, {
|
|
53
|
-
className: "h-3 w-3"
|
|
54
|
-
}, undefined, false, undefined, this),
|
|
55
|
-
isResetting ? "Resetting\u2026" : "Reset data"
|
|
56
|
-
]
|
|
57
|
-
}, undefined, true, undefined, this)
|
|
58
|
-
]
|
|
59
|
-
}, undefined, true, undefined, this);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// src/SaveToStudioButton.tsx
|
|
63
|
-
import { Sparkles } from "lucide-react";
|
|
64
|
-
import { useState as useState2 } from "react";
|
|
65
|
-
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
66
|
-
"use client";
|
|
67
|
-
function SaveToStudioButton({
|
|
68
|
-
organizationId = "demo-org",
|
|
69
|
-
projectName,
|
|
70
|
-
endpoint,
|
|
71
|
-
token
|
|
72
|
-
}) {
|
|
73
|
-
const { installer, templateId, template } = useTemplateRuntime();
|
|
74
|
-
const [status, setStatus] = useState2("idle");
|
|
75
|
-
const [error, setError] = useState2(null);
|
|
76
|
-
const handleSave = async () => {
|
|
77
|
-
setStatus("saving");
|
|
78
|
-
setError(null);
|
|
79
|
-
try {
|
|
80
|
-
await installer.saveToStudio({
|
|
81
|
-
templateId,
|
|
82
|
-
projectName: projectName ?? `${template.name} demo`,
|
|
83
|
-
organizationId,
|
|
84
|
-
endpoint,
|
|
85
|
-
token
|
|
86
|
-
});
|
|
87
|
-
setStatus("saved");
|
|
88
|
-
setTimeout(() => setStatus("idle"), 3000);
|
|
89
|
-
} catch (err) {
|
|
90
|
-
setStatus("error");
|
|
91
|
-
setError(err instanceof Error ? err.message : "Unknown error");
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
return /* @__PURE__ */ jsxDEV2("div", {
|
|
95
|
-
className: "flex flex-col items-end gap-1",
|
|
96
|
-
children: [
|
|
97
|
-
/* @__PURE__ */ jsxDEV2("button", {
|
|
98
|
-
type: "button",
|
|
99
|
-
className: "btn-primary inline-flex items-center gap-2 text-sm",
|
|
100
|
-
onClick: handleSave,
|
|
101
|
-
disabled: status === "saving",
|
|
102
|
-
children: [
|
|
103
|
-
/* @__PURE__ */ jsxDEV2(Sparkles, {
|
|
104
|
-
className: "h-4 w-4"
|
|
105
|
-
}, undefined, false, undefined, this),
|
|
106
|
-
status === "saving" ? "Publishing\u2026" : "Save to Studio"
|
|
107
|
-
]
|
|
108
|
-
}, undefined, true, undefined, this),
|
|
109
|
-
status === "error" && error ? /* @__PURE__ */ jsxDEV2("p", {
|
|
110
|
-
className: "text-destructive text-xs",
|
|
111
|
-
children: error
|
|
112
|
-
}, undefined, false, undefined, this) : null,
|
|
113
|
-
status === "saved" ? /* @__PURE__ */ jsxDEV2("p", {
|
|
114
|
-
className: "text-emerald-400 text-xs",
|
|
115
|
-
children: "Template sent to Studio."
|
|
116
|
-
}, undefined, false, undefined, this) : null
|
|
117
|
-
]
|
|
118
|
-
}, undefined, true, undefined, this);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// src/SpecDrivenTemplateShell.tsx
|
|
122
|
-
import {
|
|
123
|
-
BundleProvider,
|
|
124
|
-
BundleRenderer
|
|
125
|
-
} from "@contractspec/lib.surface-runtime/react";
|
|
126
|
-
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
127
|
-
function SpecDrivenTemplateShell({
|
|
128
|
-
plan,
|
|
129
|
-
title,
|
|
130
|
-
description,
|
|
131
|
-
sidebar,
|
|
132
|
-
actions,
|
|
133
|
-
showSaveAction = true,
|
|
134
|
-
saveProps,
|
|
135
|
-
children
|
|
136
|
-
}) {
|
|
137
|
-
const headerContent = /* @__PURE__ */ jsxDEV3("header", {
|
|
138
|
-
className: "rounded-2xl border border-border bg-card p-6 shadow-sm",
|
|
139
|
-
children: [
|
|
140
|
-
/* @__PURE__ */ jsxDEV3("div", {
|
|
141
|
-
className: "flex flex-wrap items-center justify-between gap-4",
|
|
142
|
-
children: [
|
|
143
|
-
/* @__PURE__ */ jsxDEV3("div", {
|
|
144
|
-
children: [
|
|
145
|
-
/* @__PURE__ */ jsxDEV3("p", {
|
|
146
|
-
className: "font-semibold text-muted-foreground text-sm uppercase tracking-wide",
|
|
147
|
-
children: "ContractSpec Templates"
|
|
148
|
-
}, undefined, false, undefined, this),
|
|
149
|
-
/* @__PURE__ */ jsxDEV3("h1", {
|
|
150
|
-
className: "font-bold text-3xl",
|
|
151
|
-
children: title
|
|
152
|
-
}, undefined, false, undefined, this),
|
|
153
|
-
description ? /* @__PURE__ */ jsxDEV3("p", {
|
|
154
|
-
className: "mt-2 max-w-2xl text-muted-foreground text-sm",
|
|
155
|
-
children: description
|
|
156
|
-
}, undefined, false, undefined, this) : null
|
|
157
|
-
]
|
|
158
|
-
}, undefined, true, undefined, this),
|
|
159
|
-
/* @__PURE__ */ jsxDEV3("div", {
|
|
160
|
-
className: "flex flex-col items-end gap-2",
|
|
161
|
-
children: [
|
|
162
|
-
/* @__PURE__ */ jsxDEV3(LocalDataIndicator, {}, undefined, false, undefined, this),
|
|
163
|
-
showSaveAction ? /* @__PURE__ */ jsxDEV3(SaveToStudioButton, {
|
|
164
|
-
...saveProps
|
|
165
|
-
}, undefined, false, undefined, this) : null
|
|
166
|
-
]
|
|
167
|
-
}, undefined, true, undefined, this)
|
|
168
|
-
]
|
|
169
|
-
}, undefined, true, undefined, this),
|
|
170
|
-
actions ? /* @__PURE__ */ jsxDEV3("div", {
|
|
171
|
-
className: "mt-4",
|
|
172
|
-
children: actions
|
|
173
|
-
}, undefined, false, undefined, this) : null
|
|
174
|
-
]
|
|
175
|
-
}, undefined, true, undefined, this);
|
|
176
|
-
const slotContent = {
|
|
177
|
-
header: headerContent,
|
|
178
|
-
primary: /* @__PURE__ */ jsxDEV3("main", {
|
|
179
|
-
className: "space-y-4 p-2",
|
|
180
|
-
children
|
|
181
|
-
}, undefined, false, undefined, this)
|
|
182
|
-
};
|
|
183
|
-
if (sidebar != null) {
|
|
184
|
-
slotContent.sidebar = /* @__PURE__ */ jsxDEV3("aside", {
|
|
185
|
-
className: "rounded-2xl border border-border bg-card p-4",
|
|
186
|
-
children: sidebar
|
|
187
|
-
}, undefined, false, undefined, this);
|
|
188
|
-
}
|
|
189
|
-
return /* @__PURE__ */ jsxDEV3(BundleProvider, {
|
|
190
|
-
plan,
|
|
191
|
-
children: /* @__PURE__ */ jsxDEV3(BundleRenderer, {
|
|
192
|
-
slotContent
|
|
193
|
-
}, undefined, false, undefined, this)
|
|
194
|
-
}, undefined, false, undefined, this);
|
|
195
|
-
}
|
|
196
|
-
export {
|
|
197
|
-
SpecDrivenTemplateShell
|
|
198
|
-
};
|
|
2
|
+
import{createContext as w,useContext as R}from"react";var y=Symbol.for("@contractspec/lib.example-shared-ui/template-runtime-context");function I(){let e=globalThis;return e[y]??=w(null),e[y]}var z=I();function p(){let e=R(z);if(!e)throw Error("useTemplateRuntime must be used within a TemplateRuntimeProvider");return e}import{RefreshCw as $,Shield as q}from"lucide-react";import{useState as F}from"react";import{jsx as f,jsxs as g}from"react/jsx-runtime";function S(){let{projectId:e,templateId:m,template:a,installer:o}=p(),[r,n]=F(!1),i=async()=>{n(!0);try{await o.install(m,{projectId:e})}finally{n(!1)}};return g("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:[f(q,{className:"h-3.5 w-3.5 text-violet-400"}),g("span",{children:["Local runtime \xB7"," ",f("span",{className:"font-semibold text-foreground",children:a.name})]}),g("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:i,disabled:r,children:[f($,{className:"h-3 w-3"}),r?"Resetting\u2026":"Reset data"]})]})}import{Sparkles as G}from"lucide-react";import{useState as N}from"react";import{jsx as b,jsxs as h}from"react/jsx-runtime";function k({organizationId:e="demo-org",projectName:m,endpoint:a,token:o}){let{installer:r,templateId:n,template:i}=p(),[l,d]=N("idle"),[u,c]=N(null);return h("div",{className:"flex flex-col items-end gap-1",children:[h("button",{type:"button",className:"btn-primary inline-flex items-center gap-2 text-sm",onClick:async()=>{d("saving"),c(null);try{await r.saveToStudio({templateId:n,projectName:m??`${i.name} demo`,organizationId:e,endpoint:a,token:o}),d("saved"),setTimeout(()=>d("idle"),3000)}catch(v){d("error"),c(v instanceof Error?v.message:"Unknown error")}},disabled:l==="saving",children:[b(G,{className:"h-4 w-4"}),l==="saving"?"Publishing\u2026":"Save to Studio"]}),l==="error"&&u?b("p",{className:"text-destructive text-xs",children:u}):null,l==="saved"?b("p",{className:"text-emerald-400 text-xs",children:"Template sent to Studio."}):null]})}import{BundleProvider as H,BundleRenderer as J}from"@contractspec/lib.surface-runtime/react";import{jsx as t,jsxs as s}from"react/jsx-runtime";function x({plan:e,title:m,description:a,sidebar:o,actions:r,showSaveAction:n=!0,saveProps:i,children:l}){let u={header:s("header",{className:"rounded-2xl border border-border bg-card p-6 shadow-sm",children:[s("div",{className:"flex flex-wrap items-center justify-between gap-4",children:[s("div",{children:[t("p",{className:"font-semibold text-muted-foreground text-sm uppercase tracking-wide",children:"ContractSpec Templates"}),t("h1",{className:"font-bold text-3xl",children:m}),a?t("p",{className:"mt-2 max-w-2xl text-muted-foreground text-sm",children:a}):null]}),s("div",{className:"flex flex-col items-end gap-2",children:[t(S,{}),n?t(k,{...i}):null]})]}),r?t("div",{className:"mt-4",children:r}):null]}),primary:t("main",{className:"space-y-4 p-2",children:l})};if(o!=null)u.sidebar=t("aside",{className:"rounded-2xl border border-border bg-card p-4",children:o});return t(H,{plan:e,children:t(J,{slotContent:u})})}export{x as SpecDrivenTemplateShell};
|
package/dist/SpecEditorPanel.js
CHANGED
|
@@ -1,42 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
|
|
3
|
-
|
|
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(", ")}
|
|
2
|
+
import{createContext as g,useContext as i}from"react";var L=Symbol.for("@contractspec/lib.example-shared-ui/template-runtime-context");function m(){let q=globalThis;return q[L]??=g(null),q[L]}var c=m();function x(){let q=i(c);if(!q)throw Error("useTemplateRuntime must be used within a TemplateRuntimeProvider");return q}function F(q){let Z=q?.id??"unknown";if(!q)return I(Z);switch(Z){case"crm-pipeline":return p(q.schema.contracts);case"saas-boilerplate":return d(q.schema.contracts);case"agent-console":return l(q.schema.contracts);case"todos-app":return r(q.schema.contracts);case"messaging-app":return s(q.schema.contracts);case"recipe-app-i18n":return o(q.schema.contracts);default:return I(Z)}}function p(q){return`// CRM Pipeline Specs
|
|
3
|
+
// Contracts: ${q.join(", ")}
|
|
40
4
|
|
|
41
5
|
contractSpec("crm.deal.updateStage.v1", {
|
|
42
6
|
goal: "Move a deal to a different pipeline stage",
|
|
@@ -105,11 +69,8 @@ contractSpec("crm.contact.list.v1", {
|
|
|
105
69
|
hasMore: "boolean"
|
|
106
70
|
}
|
|
107
71
|
}
|
|
108
|
-
})
|
|
109
|
-
}
|
|
110
|
-
function generateSaasBoilerplateSpec(contracts) {
|
|
111
|
-
return `// SaaS Boilerplate Specs
|
|
112
|
-
// Contracts: ${contracts.join(", ")}
|
|
72
|
+
});`}function d(q){return`// SaaS Boilerplate Specs
|
|
73
|
+
// Contracts: ${q.join(", ")}
|
|
113
74
|
|
|
114
75
|
contractSpec("saas.project.create.v1", {
|
|
115
76
|
goal: "Create a new project in an organization",
|
|
@@ -172,11 +133,8 @@ contractSpec("saas.settings.update.v1", {
|
|
|
172
133
|
}
|
|
173
134
|
},
|
|
174
135
|
events: ["settings.updated"]
|
|
175
|
-
})
|
|
176
|
-
}
|
|
177
|
-
function generateAgentConsoleSpec(contracts) {
|
|
178
|
-
return `// Agent Console Specs
|
|
179
|
-
// Contracts: ${contracts.join(", ")}
|
|
136
|
+
});`}function l(q){return`// Agent Console Specs
|
|
137
|
+
// Contracts: ${q.join(", ")}
|
|
180
138
|
|
|
181
139
|
contractSpec("agent.run.execute.v1", {
|
|
182
140
|
goal: "Execute an agent run with specified tools",
|
|
@@ -242,11 +200,8 @@ contractSpec("agent.agent.create.v1", {
|
|
|
242
200
|
}
|
|
243
201
|
},
|
|
244
202
|
events: ["agent.created"]
|
|
245
|
-
})
|
|
246
|
-
}
|
|
247
|
-
function generateTodosSpec(contracts) {
|
|
248
|
-
return `// To-dos App Specs
|
|
249
|
-
// Contracts: ${contracts.join(", ")}
|
|
203
|
+
});`}function r(q){return`// To-dos App Specs
|
|
204
|
+
// Contracts: ${q.join(", ")}
|
|
250
205
|
|
|
251
206
|
contractSpec("tasks.board.v1", {
|
|
252
207
|
goal: "Assign and approve craft work",
|
|
@@ -305,11 +260,8 @@ contractSpec("tasks.complete.v1", {
|
|
|
305
260
|
}
|
|
306
261
|
},
|
|
307
262
|
events: ["task.completed"]
|
|
308
|
-
})
|
|
309
|
-
}
|
|
310
|
-
function generateMessagingSpec(contracts) {
|
|
311
|
-
return `// Messaging App Specs
|
|
312
|
-
// Contracts: ${contracts.join(", ")}
|
|
263
|
+
});`}function s(q){return`// Messaging App Specs
|
|
264
|
+
// Contracts: ${q.join(", ")}
|
|
313
265
|
|
|
314
266
|
contractSpec("messaging.send.v1", {
|
|
315
267
|
goal: "Deliver intent-rich updates",
|
|
@@ -362,11 +314,8 @@ contractSpec("messaging.read.v1", {
|
|
|
362
314
|
}
|
|
363
315
|
},
|
|
364
316
|
events: ["message.read"]
|
|
365
|
-
})
|
|
366
|
-
}
|
|
367
|
-
function generateRecipeSpec(contracts) {
|
|
368
|
-
return `// Recipe App (i18n) Specs
|
|
369
|
-
// Contracts: ${contracts.join(", ")}
|
|
317
|
+
});`}function o(q){return`// Recipe App (i18n) Specs
|
|
318
|
+
// Contracts: ${q.join(", ")}
|
|
370
319
|
|
|
371
320
|
contractSpec("recipes.lookup.v1", {
|
|
372
321
|
goal: "Serve bilingual rituals",
|
|
@@ -413,13 +362,10 @@ contractSpec("recipes.favorite.toggle.v1", {
|
|
|
413
362
|
}
|
|
414
363
|
},
|
|
415
364
|
events: ["recipe.favorited", "recipe.unfavorited"]
|
|
416
|
-
})
|
|
417
|
-
}
|
|
418
|
-
function generateDefaultSpec(templateId) {
|
|
419
|
-
return `// ${templateId} Specs
|
|
365
|
+
});`}function I(q){return`// ${q} Specs
|
|
420
366
|
|
|
421
|
-
contractSpec("${
|
|
422
|
-
goal: "Main operation for ${
|
|
367
|
+
contractSpec("${q}.main.v1", {
|
|
368
|
+
goal: "Main operation for ${q}",
|
|
423
369
|
transport: { gql: { query: "main" } },
|
|
424
370
|
io: {
|
|
425
371
|
input: {
|
|
@@ -429,292 +375,5 @@ contractSpec("${templateId}.main.v1", {
|
|
|
429
375
|
result: "unknown"
|
|
430
376
|
}
|
|
431
377
|
}
|
|
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
|
-
|
|
579
|
-
// src/SpecEditorPanel.tsx
|
|
580
|
-
import { Button, LoaderBlock } from "@contractspec/lib.design-system";
|
|
581
|
-
import { Badge } from "@contractspec/lib.ui-kit-web/ui/badge";
|
|
582
|
-
import { useCallback as useCallback2, useEffect as useEffect2 } from "react";
|
|
583
|
-
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
584
|
-
"use client";
|
|
585
|
-
function SpecEditorPanel({
|
|
586
|
-
templateId,
|
|
587
|
-
SpecEditor,
|
|
588
|
-
onLog
|
|
589
|
-
}) {
|
|
590
|
-
const {
|
|
591
|
-
content,
|
|
592
|
-
loading,
|
|
593
|
-
isDirty,
|
|
594
|
-
validation,
|
|
595
|
-
setContent,
|
|
596
|
-
save,
|
|
597
|
-
validate,
|
|
598
|
-
reset,
|
|
599
|
-
lastSaved
|
|
600
|
-
} = useSpecContent(templateId);
|
|
601
|
-
useEffect2(() => {
|
|
602
|
-
if (!loading && content) {
|
|
603
|
-
onLog?.(`Spec loaded for ${templateId}`);
|
|
604
|
-
}
|
|
605
|
-
}, [loading, content, templateId, onLog]);
|
|
606
|
-
const handleSave = useCallback2(() => {
|
|
607
|
-
save();
|
|
608
|
-
onLog?.("Spec saved locally");
|
|
609
|
-
}, [save, onLog]);
|
|
610
|
-
const handleValidate = useCallback2(() => {
|
|
611
|
-
const result = validate();
|
|
612
|
-
if (result.valid) {
|
|
613
|
-
onLog?.("Spec validation passed");
|
|
614
|
-
} else {
|
|
615
|
-
const errorCount = result.errors.filter((e) => e.severity === "error").length;
|
|
616
|
-
const warnCount = result.errors.filter((e) => e.severity === "warning").length;
|
|
617
|
-
onLog?.(`Spec validation: ${errorCount} errors, ${warnCount} warnings`);
|
|
618
|
-
}
|
|
619
|
-
}, [validate, onLog]);
|
|
620
|
-
const handleReset = useCallback2(() => {
|
|
621
|
-
reset();
|
|
622
|
-
onLog?.("Spec reset to template defaults");
|
|
623
|
-
}, [reset, onLog]);
|
|
624
|
-
if (loading) {
|
|
625
|
-
return /* @__PURE__ */ jsxDEV(LoaderBlock, {
|
|
626
|
-
label: "Loading spec..."
|
|
627
|
-
}, undefined, false, undefined, this);
|
|
628
|
-
}
|
|
629
|
-
return /* @__PURE__ */ jsxDEV("div", {
|
|
630
|
-
className: "space-y-4",
|
|
631
|
-
children: [
|
|
632
|
-
/* @__PURE__ */ jsxDEV("div", {
|
|
633
|
-
className: "flex items-center justify-between",
|
|
634
|
-
children: [
|
|
635
|
-
/* @__PURE__ */ jsxDEV("div", {
|
|
636
|
-
className: "flex items-center gap-2",
|
|
637
|
-
children: [
|
|
638
|
-
/* @__PURE__ */ jsxDEV(Button, {
|
|
639
|
-
variant: "default",
|
|
640
|
-
size: "sm",
|
|
641
|
-
onClick: handleSave,
|
|
642
|
-
children: "Save"
|
|
643
|
-
}, undefined, false, undefined, this),
|
|
644
|
-
/* @__PURE__ */ jsxDEV(Button, {
|
|
645
|
-
variant: "outline",
|
|
646
|
-
size: "sm",
|
|
647
|
-
onClick: handleValidate,
|
|
648
|
-
children: "Validate"
|
|
649
|
-
}, undefined, false, undefined, this),
|
|
650
|
-
isDirty && /* @__PURE__ */ jsxDEV(Badge, {
|
|
651
|
-
variant: "secondary",
|
|
652
|
-
className: "border-amber-500/30 bg-amber-500/20 text-amber-400",
|
|
653
|
-
children: "Unsaved changes"
|
|
654
|
-
}, undefined, false, undefined, this),
|
|
655
|
-
validation && /* @__PURE__ */ jsxDEV(Badge, {
|
|
656
|
-
variant: validation.valid ? "default" : "destructive",
|
|
657
|
-
className: validation.valid ? "border-green-500/30 bg-green-500/20 text-green-400" : "",
|
|
658
|
-
children: validation.valid ? "Valid" : `${validation.errors.filter((e) => e.severity === "error").length} errors`
|
|
659
|
-
}, undefined, false, undefined, this)
|
|
660
|
-
]
|
|
661
|
-
}, undefined, true, undefined, this),
|
|
662
|
-
/* @__PURE__ */ jsxDEV("div", {
|
|
663
|
-
className: "flex items-center gap-2",
|
|
664
|
-
children: [
|
|
665
|
-
lastSaved && /* @__PURE__ */ jsxDEV("span", {
|
|
666
|
-
className: "text-muted-foreground text-xs",
|
|
667
|
-
children: [
|
|
668
|
-
"Last saved: ",
|
|
669
|
-
new Date(lastSaved).toLocaleTimeString()
|
|
670
|
-
]
|
|
671
|
-
}, undefined, true, undefined, this),
|
|
672
|
-
/* @__PURE__ */ jsxDEV(Button, {
|
|
673
|
-
variant: "ghost",
|
|
674
|
-
size: "sm",
|
|
675
|
-
onPress: handleReset,
|
|
676
|
-
children: "Reset"
|
|
677
|
-
}, undefined, false, undefined, this)
|
|
678
|
-
]
|
|
679
|
-
}, undefined, true, undefined, this)
|
|
680
|
-
]
|
|
681
|
-
}, undefined, true, undefined, this),
|
|
682
|
-
validation && validation.errors.length > 0 && /* @__PURE__ */ jsxDEV("div", {
|
|
683
|
-
className: "rounded-lg border border-amber-500/50 bg-amber-500/10 p-3",
|
|
684
|
-
children: [
|
|
685
|
-
/* @__PURE__ */ jsxDEV("p", {
|
|
686
|
-
className: "mb-2 font-semibold text-amber-400 text-xs uppercase",
|
|
687
|
-
children: "Validation Issues"
|
|
688
|
-
}, undefined, false, undefined, this),
|
|
689
|
-
/* @__PURE__ */ jsxDEV("ul", {
|
|
690
|
-
className: "space-y-1",
|
|
691
|
-
children: validation.errors.map((error, index) => /* @__PURE__ */ jsxDEV("li", {
|
|
692
|
-
className: `text-xs ${error.severity === "error" ? "text-red-400" : "text-amber-400"}`,
|
|
693
|
-
children: [
|
|
694
|
-
"Line ",
|
|
695
|
-
error.line,
|
|
696
|
-
": ",
|
|
697
|
-
error.message
|
|
698
|
-
]
|
|
699
|
-
}, `${error.line}-${error.message}-${index}`, true, undefined, this))
|
|
700
|
-
}, undefined, false, undefined, this)
|
|
701
|
-
]
|
|
702
|
-
}, undefined, true, undefined, this),
|
|
703
|
-
/* @__PURE__ */ jsxDEV("div", {
|
|
704
|
-
className: "rounded-2xl border border-border bg-card p-4",
|
|
705
|
-
children: /* @__PURE__ */ jsxDEV(SpecEditor, {
|
|
706
|
-
projectId: "sandbox",
|
|
707
|
-
type: "CAPABILITY",
|
|
708
|
-
content,
|
|
709
|
-
onChange: setContent,
|
|
710
|
-
metadata: { template: templateId },
|
|
711
|
-
onSave: handleSave,
|
|
712
|
-
onValidate: handleValidate
|
|
713
|
-
}, undefined, false, undefined, this)
|
|
714
|
-
}, undefined, false, undefined, this)
|
|
715
|
-
]
|
|
716
|
-
}, undefined, true, undefined, this);
|
|
717
|
-
}
|
|
718
|
-
export {
|
|
719
|
-
SpecEditorPanel
|
|
720
|
-
};
|
|
378
|
+
});`}import{useCallback as A,useEffect as n,useState as K}from"react";var R="contractspec-spec-content";function v(q){let{template:Z}=x(),[H,$]=K(""),[w,X]=K(""),[y,M]=K(!0),[O,D]=K(null),[V,N]=K(null);n(()=>{M(!0);try{let z=localStorage.getItem(`${R}-${q}`);if(z){let W=JSON.parse(z);if(W.content)$(W.content),X(W.content),N(W.savedAt);else{let U=F(Z);$(U),X(U)}}else{let W=F(Z);$(W),X(W)}}catch{let z=F(Z);$(z),X(z)}M(!1)},[q]);let Y=A((z)=>{$(z),D(null)},[]),h=A(()=>{try{let z=new Date().toISOString();localStorage.setItem(`${R}-${q}`,JSON.stringify({content:H,savedAt:z})),X(H),N(z)}catch{}},[H,q]),P=A(()=>{let z=[],W=H.split(`
|
|
379
|
+
`);if(!H.includes("contractSpec("))z.push({line:1,message:"Spec must contain a contractSpec() definition",severity:"error"});if(!H.includes("goal:"))z.push({line:1,message:"Spec should have a goal field",severity:"warning"});if(!H.includes("io:"))z.push({line:1,message:"Spec should define io (input/output)",severity:"warning"});let U=(H.match(/{/g)??[]).length,B=(H.match(/}/g)??[]).length;if(U!==B)z.push({line:W.length,message:`Unbalanced braces: ${U} opening, ${B} closing`,severity:"error"});let _=(H.match(/\(/g)??[]).length,j=(H.match(/\)/g)??[]).length;if(_!==j)z.push({line:W.length,message:`Unbalanced parentheses: ${_} opening, ${j} closing`,severity:"error"});W.forEach((f,E)=>{let u=(f.match(/'/g)??[]).length,S=(f.match(/"/g)??[]).length;if(u%2!==0)z.push({line:E+1,message:"Unclosed single quote",severity:"error"});if(S%2!==0)z.push({line:E+1,message:"Unclosed double quote",severity:"error"})});let T={valid:z.filter((f)=>f.severity==="error").length===0,errors:z};return D(T),T},[H]),J=A(()=>{let z=F(Z);$(z),X(z),D(null),N(null);try{localStorage.removeItem(`${R}-${q}`)}catch{}},[q]);return{content:H,loading:y,isDirty:H!==w,validation:O,setContent:Y,save:h,validate:P,reset:J,lastSaved:V}}import{Button as b,LoaderBlock as a}from"@contractspec/lib.design-system";import{Badge as C}from"@contractspec/lib.ui-kit-web/ui/badge";import{useCallback as k,useEffect as t}from"react";import{jsx as Q,jsxs as G}from"react/jsx-runtime";function Xq({templateId:q,SpecEditor:Z,onLog:H}){let{content:$,loading:w,isDirty:X,validation:y,setContent:M,save:O,validate:D,reset:V,lastSaved:N}=v(q);t(()=>{if(!w&&$)H?.(`Spec loaded for ${q}`)},[w,$,q,H]);let Y=k(()=>{O(),H?.("Spec saved locally")},[O,H]),h=k(()=>{let J=D();if(J.valid)H?.("Spec validation passed");else{let z=J.errors.filter((U)=>U.severity==="error").length,W=J.errors.filter((U)=>U.severity==="warning").length;H?.(`Spec validation: ${z} errors, ${W} warnings`)}},[D,H]),P=k(()=>{V(),H?.("Spec reset to template defaults")},[V,H]);if(w)return Q(a,{label:"Loading spec..."});return G("div",{className:"space-y-4",children:[G("div",{className:"flex items-center justify-between",children:[G("div",{className:"flex items-center gap-2",children:[Q(b,{variant:"default",size:"sm",onClick:Y,children:"Save"}),Q(b,{variant:"outline",size:"sm",onClick:h,children:"Validate"}),X&&Q(C,{variant:"secondary",className:"border-amber-500/30 bg-amber-500/20 text-amber-400",children:"Unsaved changes"}),y&&Q(C,{variant:y.valid?"default":"destructive",className:y.valid?"border-green-500/30 bg-green-500/20 text-green-400":"",children:y.valid?"Valid":`${y.errors.filter((J)=>J.severity==="error").length} errors`})]}),G("div",{className:"flex items-center gap-2",children:[N&&G("span",{className:"text-muted-foreground text-xs",children:["Last saved: ",new Date(N).toLocaleTimeString()]}),Q(b,{variant:"ghost",size:"sm",onPress:P,children:"Reset"})]})]}),y&&y.errors.length>0&&G("div",{className:"rounded-lg border border-amber-500/50 bg-amber-500/10 p-3",children:[Q("p",{className:"mb-2 font-semibold text-amber-400 text-xs uppercase",children:"Validation Issues"}),Q("ul",{className:"space-y-1",children:y.errors.map((J,z)=>G("li",{className:`text-xs ${J.severity==="error"?"text-red-400":"text-amber-400"}`,children:["Line ",J.line,": ",J.message]},`${J.line}-${J.message}-${z}`))})]}),Q("div",{className:"rounded-2xl border border-border bg-card p-4",children:Q(Z,{projectId:"sandbox",type:"CAPABILITY",content:$,onChange:M,metadata:{template:q},onSave:Y,onValidate:h})})]})}export{Xq as SpecEditorPanel};
|