total-recall-brain 3.35.0 → 3.36.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.
- package/bin/total-recall.mjs +17 -4
- package/frontend/dist/assets/{index-BPrkIYkZ.js → index-DZ4ypNEl.js} +135 -135
- package/frontend/dist/brand/plugins/phone.svg +20 -0
- package/frontend/dist/index.html +1 -1
- package/frontend/src/App.tsx +3 -30
- package/frontend/src/api/plugins.ts +18 -0
- package/frontend/src/components/plugins/previews/CodeQualityPreview.tsx +78 -86
- package/frontend/src/components/plugins/previews/ComposableCliPreview.tsx +74 -84
- package/frontend/src/components/plugins/previews/DecisionPreview.tsx +158 -106
- package/frontend/src/components/plugins/previews/DesignPreview.tsx +109 -75
- package/frontend/src/components/plugins/previews/DomainsPreview.tsx +69 -88
- package/frontend/src/components/plugins/previews/ImageGeneratorPreview.tsx +286 -0
- package/frontend/src/components/plugins/previews/PhonePreview.tsx +490 -76
- package/frontend/src/components/plugins/previews/SigningPreview.tsx +164 -50
- package/frontend/src/components/plugins/previews/TextPreview.tsx +85 -86
- package/frontend/src/components/plugins/previews/UserAutomationsPreview.tsx +30 -0
- package/frontend/src/components/plugins/previews/index.tsx +6 -1
- package/frontend/src/pages/PluginsPage.tsx +603 -136
- package/package.json +2 -5
- package/scaffold/.agent/skills/plugins/SKILL.md +200 -6
- package/src/cli/plugin/create.mjs +156 -11
- package/src/cli/plugin/index.mjs +5 -0
- package/src/core/embeddings.mjs +2 -0
- package/src/core/plugin-loader.mjs +18 -3
- package/src/core/plugin-store.mjs +122 -11
- package/src/core/surface.mjs +29 -1
- package/src/core/vault.mjs +6 -2
- package/src/server/route-manifest.json +22 -2
- package/src/server/routes/plugins-mesh.mjs +9 -1
- package/src/server/routes/plugins.mjs +65 -1
- package/frontend/src/pages/AutomationsPage.spec.tsx +0 -61
- package/frontend/src/pages/AutomationsPage.tsx +0 -354
- package/plugins/creative-search/README.md +0 -33
- package/plugins/creative-search/cli.mjs +0 -415
- package/plugins/creative-search/config.mjs +0 -129
- package/plugins/creative-search/generator.mjs +0 -13
- package/plugins/creative-search/plugin.json +0 -61
- package/plugins/creative-search/ui/DESIGN.md +0 -50
- package/plugins/creative-search/ui/csearch-main.js +0 -314
- package/plugins/creative-search/ui/csearch-settings.js +0 -392
- package/plugins/creative-search/ui/index.js +0 -2
- package/plugins/creative-search/ui/tokens.css +0 -34
- package/plugins/dsh/README.md +0 -20
- package/plugins/dsh/cli.mjs +0 -232
- package/plugins/dsh/generator.mjs +0 -65
- package/plugins/dsh/plugin.json +0 -57
- package/plugins/dsh/ui/DESIGN.md +0 -48
- package/plugins/dsh/ui/dsh-main.js +0 -226
- package/plugins/dsh/ui/dsh-status.js +0 -265
- package/plugins/dsh/ui/index.js +0 -2
- package/plugins/dsh/ui/tokens.css +0 -32
- package/plugins/git-sentinel/README.md +0 -29
- package/plugins/git-sentinel/cli.mjs +0 -89
- package/plugins/git-sentinel/plugin.json +0 -18
- package/plugins/operator-alerts/README.md +0 -32
- package/plugins/operator-alerts/cli.mjs +0 -57
- package/plugins/operator-alerts/notify-core.mjs +0 -216
- package/plugins/operator-alerts/plugin.json +0 -20
- package/plugins/skill-manager/README.md +0 -57
- package/plugins/skill-manager/cli.mjs +0 -123
- package/plugins/skill-manager/plugin.json +0 -25
- package/plugins/skill-manager/route.mjs +0 -106
- package/plugins/system-monitor/README.md +0 -28
- package/plugins/system-monitor/cli.mjs +0 -80
- package/plugins/system-monitor/generator.mjs +0 -19
- package/plugins/system-monitor/plugin.json +0 -29
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type CSSProperties } from "react"
|
|
1
|
+
import { useState, useRef, useEffect, type CSSProperties } from "react"
|
|
2
|
+
import { runPluginCommand } from "../../../api"
|
|
2
3
|
|
|
3
4
|
const styles: Record<string, CSSProperties> = {
|
|
4
5
|
container: {
|
|
@@ -12,7 +13,8 @@ const styles: Record<string, CSSProperties> = {
|
|
|
12
13
|
header: {
|
|
13
14
|
display: "flex",
|
|
14
15
|
justifyContent: "space-between",
|
|
15
|
-
|
|
16
|
+
alignItems: "center",
|
|
17
|
+
marginBottom: "16px",
|
|
16
18
|
},
|
|
17
19
|
label: {
|
|
18
20
|
color: "#888",
|
|
@@ -26,84 +28,196 @@ const styles: Record<string, CSSProperties> = {
|
|
|
26
28
|
padding: "4px 10px",
|
|
27
29
|
borderRadius: "20px",
|
|
28
30
|
fontSize: "11px",
|
|
31
|
+
fontWeight: 600,
|
|
29
32
|
},
|
|
30
33
|
docFrame: {
|
|
31
34
|
background: "#0d1117",
|
|
32
35
|
border: "1px solid #2a2a4a",
|
|
33
36
|
borderRadius: "8px",
|
|
34
37
|
padding: "16px",
|
|
35
|
-
marginBottom: "
|
|
38
|
+
marginBottom: "16px",
|
|
36
39
|
},
|
|
37
40
|
docTitle: {
|
|
38
|
-
fontSize: "
|
|
41
|
+
fontSize: "14px",
|
|
39
42
|
fontWeight: 600,
|
|
40
|
-
marginBottom: "
|
|
43
|
+
marginBottom: "6px",
|
|
41
44
|
color: "#c0c0ff",
|
|
42
45
|
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
padding: "
|
|
48
|
-
|
|
46
|
+
canvasBox: {
|
|
47
|
+
background: "#141428",
|
|
48
|
+
border: "1px dashed #4a4a7a",
|
|
49
|
+
borderRadius: "8px",
|
|
50
|
+
padding: "8px",
|
|
51
|
+
marginBottom: "12px",
|
|
52
|
+
textAlign: "center" as const,
|
|
49
53
|
},
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
canvas: {
|
|
55
|
+
background: "#0d1117",
|
|
56
|
+
borderRadius: "4px",
|
|
57
|
+
cursor: "crosshair",
|
|
58
|
+
display: "block",
|
|
59
|
+
margin: "0 auto",
|
|
53
60
|
},
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
actions: {
|
|
62
|
+
display: "flex",
|
|
63
|
+
gap: "8px",
|
|
64
|
+
marginBottom: "16px",
|
|
57
65
|
},
|
|
58
|
-
|
|
59
|
-
background: "#
|
|
60
|
-
border: "
|
|
66
|
+
signBtn: {
|
|
67
|
+
background: "linear-gradient(135deg, #2e7d32, #1b5e20)",
|
|
68
|
+
border: "none",
|
|
61
69
|
borderRadius: "6px",
|
|
62
|
-
padding: "20px",
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
padding: "10px 20px",
|
|
71
|
+
color: "#fff",
|
|
72
|
+
fontSize: "13px",
|
|
73
|
+
fontWeight: 600,
|
|
74
|
+
cursor: "pointer",
|
|
75
|
+
flex: 1,
|
|
66
76
|
},
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
77
|
+
clearBtn: {
|
|
78
|
+
background: "#2a2a4a",
|
|
79
|
+
border: "none",
|
|
80
|
+
borderRadius: "6px",
|
|
81
|
+
padding: "10px 16px",
|
|
82
|
+
color: "#aaa",
|
|
83
|
+
fontSize: "13px",
|
|
84
|
+
cursor: "pointer",
|
|
71
85
|
},
|
|
72
|
-
|
|
86
|
+
receipt: {
|
|
87
|
+
background: "#090d13",
|
|
88
|
+
border: "1px solid #1a3a1a",
|
|
89
|
+
borderRadius: "8px",
|
|
90
|
+
padding: "12px",
|
|
73
91
|
fontSize: "11px",
|
|
74
|
-
|
|
75
|
-
|
|
92
|
+
fontFamily: "var(--font-mono, monospace)",
|
|
93
|
+
color: "#81c784",
|
|
94
|
+
wordBreak: "break-all" as const,
|
|
76
95
|
},
|
|
77
96
|
}
|
|
78
97
|
|
|
79
98
|
export function SigningPreview() {
|
|
99
|
+
const canvasRef = useRef<HTMLCanvasElement | null>(null)
|
|
100
|
+
const [isDrawing, setIsDrawing] = useState(false)
|
|
101
|
+
const [hasSignature, setHasSignature] = useState(false)
|
|
102
|
+
const [status, setStatus] = useState<string | null>(null)
|
|
103
|
+
const [signatureHash, setSignatureHash] = useState<string | null>(null)
|
|
104
|
+
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
const canvas = canvasRef.current
|
|
107
|
+
if (!canvas) return
|
|
108
|
+
const ctx = canvas.getContext("2d")
|
|
109
|
+
if (!ctx) return
|
|
110
|
+
ctx.strokeStyle = "#80d8ff"
|
|
111
|
+
ctx.lineWidth = 2
|
|
112
|
+
ctx.lineCap = "round"
|
|
113
|
+
}, [])
|
|
114
|
+
|
|
115
|
+
const startDrawing = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
|
116
|
+
const canvas = canvasRef.current
|
|
117
|
+
if (!canvas) return
|
|
118
|
+
const ctx = canvas.getContext("2d")
|
|
119
|
+
if (!ctx) return
|
|
120
|
+
const rect = canvas.getBoundingClientRect()
|
|
121
|
+
ctx.beginPath()
|
|
122
|
+
ctx.moveTo(e.clientX - rect.left, e.clientY - rect.top)
|
|
123
|
+
setIsDrawing(true)
|
|
124
|
+
setHasSignature(true)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const draw = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
|
128
|
+
if (!isDrawing) return
|
|
129
|
+
const canvas = canvasRef.current
|
|
130
|
+
if (!canvas) return
|
|
131
|
+
const ctx = canvas.getContext("2d")
|
|
132
|
+
if (!ctx) return
|
|
133
|
+
const rect = canvas.getBoundingClientRect()
|
|
134
|
+
ctx.lineTo(e.clientX - rect.left, e.clientY - rect.top)
|
|
135
|
+
ctx.stroke()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const stopDrawing = () => {
|
|
139
|
+
setIsDrawing(false)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const clearCanvas = () => {
|
|
143
|
+
const canvas = canvasRef.current
|
|
144
|
+
if (!canvas) return
|
|
145
|
+
const ctx = canvas.getContext("2d")
|
|
146
|
+
if (!ctx) return
|
|
147
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
|
148
|
+
setHasSignature(false)
|
|
149
|
+
setStatus(null)
|
|
150
|
+
setSignatureHash(null)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const handleSign = async () => {
|
|
154
|
+
if (!hasSignature) return
|
|
155
|
+
setStatus("Generating cryptographic digest...")
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
const canvas = canvasRef.current
|
|
159
|
+
const dataUrl = canvas?.toDataURL() || "empty"
|
|
160
|
+
const encoder = new TextEncoder()
|
|
161
|
+
const data = encoder.encode(dataUrl + Date.now().toString())
|
|
162
|
+
const hashBuffer = await window.crypto.subtle.digest("SHA-256", data)
|
|
163
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer))
|
|
164
|
+
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("")
|
|
165
|
+
setSignatureHash(hashHex)
|
|
166
|
+
|
|
167
|
+
const res = await runPluginCommand("signing", "verify", [hashHex])
|
|
168
|
+
setStatus(res.output || `Cryptographically verified signature digest: ${hashHex.slice(0, 16)}…`)
|
|
169
|
+
} catch (err: any) {
|
|
170
|
+
setStatus(`Signing error: ${err?.message || "Cryptographic operation failed"}`)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
80
174
|
return (
|
|
81
175
|
<div style={styles.container}>
|
|
82
176
|
<div style={styles.header}>
|
|
83
|
-
<span style={styles.label}>
|
|
84
|
-
<span style={styles.badge}>
|
|
177
|
+
<span style={styles.label}>Cryptographic Document Signing</span>
|
|
178
|
+
<span style={styles.badge}>Live Canvas</span>
|
|
85
179
|
</div>
|
|
180
|
+
|
|
86
181
|
<div style={styles.docFrame}>
|
|
87
|
-
<div style={styles.docTitle}>
|
|
88
|
-
<div style={
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
182
|
+
<div style={styles.docTitle}>Verification Certificate — Total Recall Node</div>
|
|
183
|
+
<div style={{ fontSize: "12px", color: "#888" }}>Documenso & SSSS Cryptographic Carrier</div>
|
|
184
|
+
</div>
|
|
185
|
+
|
|
186
|
+
<div style={styles.canvasBox}>
|
|
187
|
+
<canvas
|
|
188
|
+
ref={canvasRef}
|
|
189
|
+
width={440}
|
|
190
|
+
height={120}
|
|
191
|
+
style={styles.canvas}
|
|
192
|
+
onMouseDown={startDrawing}
|
|
193
|
+
onMouseMove={draw}
|
|
194
|
+
onMouseUp={stopDrawing}
|
|
195
|
+
onMouseLeave={stopDrawing}
|
|
196
|
+
/>
|
|
197
|
+
<div style={{ fontSize: "11px", color: "#666", marginTop: "6px" }}>
|
|
198
|
+
Draw signature above to authorize cryptographic verification
|
|
99
199
|
</div>
|
|
100
200
|
</div>
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
|
|
201
|
+
|
|
202
|
+
<div style={styles.actions}>
|
|
203
|
+
<button style={styles.clearBtn} onClick={clearCanvas}>
|
|
204
|
+
Clear
|
|
205
|
+
</button>
|
|
206
|
+
<button
|
|
207
|
+
style={styles.signBtn}
|
|
208
|
+
onClick={handleSign}
|
|
209
|
+
disabled={!hasSignature}
|
|
210
|
+
>
|
|
211
|
+
Sign & Verify Hash
|
|
212
|
+
</button>
|
|
106
213
|
</div>
|
|
214
|
+
|
|
215
|
+
{signatureHash && (
|
|
216
|
+
<div style={styles.receipt}>
|
|
217
|
+
<div><strong>SHA-256 Receipt:</strong> {signatureHash}</div>
|
|
218
|
+
<div style={{ marginTop: "4px", color: "#a5d6a7" }}>{status}</div>
|
|
219
|
+
</div>
|
|
220
|
+
)}
|
|
107
221
|
</div>
|
|
108
222
|
)
|
|
109
223
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type CSSProperties } from "react"
|
|
1
|
+
import { useState, type CSSProperties } from "react"
|
|
2
|
+
import { runPluginCommand } from "../../../api"
|
|
2
3
|
|
|
3
4
|
const styles: Record<string, CSSProperties> = {
|
|
4
5
|
container: {
|
|
@@ -7,11 +8,12 @@ const styles: Record<string, CSSProperties> = {
|
|
|
7
8
|
padding: "24px",
|
|
8
9
|
fontFamily: "var(--font-sans, system-ui, sans-serif)",
|
|
9
10
|
color: "#e0e0e0",
|
|
10
|
-
maxWidth: "
|
|
11
|
+
maxWidth: "500px",
|
|
11
12
|
},
|
|
12
13
|
header: {
|
|
13
14
|
display: "flex",
|
|
14
15
|
justifyContent: "space-between",
|
|
16
|
+
alignItems: "center",
|
|
15
17
|
marginBottom: "16px",
|
|
16
18
|
},
|
|
17
19
|
label: {
|
|
@@ -21,124 +23,121 @@ const styles: Record<string, CSSProperties> = {
|
|
|
21
23
|
letterSpacing: "1px",
|
|
22
24
|
},
|
|
23
25
|
badge: {
|
|
24
|
-
background: "#
|
|
25
|
-
color: "#
|
|
26
|
+
background: "#1a3a2a",
|
|
27
|
+
color: "#00e676",
|
|
26
28
|
padding: "4px 10px",
|
|
27
29
|
borderRadius: "20px",
|
|
28
30
|
fontSize: "11px",
|
|
29
|
-
},
|
|
30
|
-
contactBar: {
|
|
31
|
-
display: "flex",
|
|
32
|
-
alignItems: "center",
|
|
33
|
-
gap: "10px",
|
|
34
|
-
padding: "10px 0",
|
|
35
|
-
marginBottom: "12px",
|
|
36
|
-
borderBottom: "1px solid #2a2a4a",
|
|
37
|
-
},
|
|
38
|
-
avatar: {
|
|
39
|
-
width: "32px",
|
|
40
|
-
height: "32px",
|
|
41
|
-
borderRadius: "50%",
|
|
42
|
-
background: "#2a2a5a",
|
|
43
|
-
display: "flex",
|
|
44
|
-
alignItems: "center",
|
|
45
|
-
justifyContent: "center",
|
|
46
|
-
fontSize: "14px",
|
|
47
|
-
fontWeight: 700,
|
|
48
|
-
color: "#c0c0ff",
|
|
49
|
-
},
|
|
50
|
-
contactName: {
|
|
51
|
-
fontSize: "14px",
|
|
52
31
|
fontWeight: 600,
|
|
53
32
|
},
|
|
54
|
-
|
|
33
|
+
threadBox: {
|
|
34
|
+
background: "#0d1117",
|
|
35
|
+
border: "1px solid #2a2a4a",
|
|
36
|
+
borderRadius: "8px",
|
|
37
|
+
padding: "12px",
|
|
38
|
+
maxHeight: "180px",
|
|
39
|
+
overflowY: "auto" as const,
|
|
40
|
+
marginBottom: "14px",
|
|
55
41
|
display: "flex",
|
|
56
|
-
flexDirection: "column"
|
|
42
|
+
flexDirection: "column",
|
|
57
43
|
gap: "8px",
|
|
58
|
-
marginBottom: "12px",
|
|
59
44
|
},
|
|
60
|
-
|
|
61
|
-
background: "#
|
|
62
|
-
|
|
63
|
-
borderRadius: "
|
|
64
|
-
padding: "10px 14px",
|
|
65
|
-
fontSize: "13px",
|
|
66
|
-
color: "#ccc",
|
|
67
|
-
maxWidth: "80%",
|
|
68
|
-
alignSelf: "flex-start" as const,
|
|
69
|
-
},
|
|
70
|
-
bubbleOut: {
|
|
71
|
-
background: "#2a2a5a",
|
|
72
|
-
border: "1px solid #3a3a7a",
|
|
73
|
-
borderRadius: "12px 12px 4px 12px",
|
|
74
|
-
padding: "10px 14px",
|
|
45
|
+
msgBubble: {
|
|
46
|
+
background: "#1e1e38",
|
|
47
|
+
padding: "8px 12px",
|
|
48
|
+
borderRadius: "8px",
|
|
75
49
|
fontSize: "13px",
|
|
76
|
-
|
|
77
|
-
maxWidth: "
|
|
78
|
-
|
|
50
|
+
alignSelf: "flex-end",
|
|
51
|
+
maxWidth: "85%",
|
|
52
|
+
border: "1px solid #3a3a6a",
|
|
79
53
|
},
|
|
80
|
-
|
|
54
|
+
inputRow: {
|
|
81
55
|
display: "flex",
|
|
56
|
+
flexDirection: "column",
|
|
82
57
|
gap: "8px",
|
|
83
58
|
},
|
|
84
59
|
input: {
|
|
85
|
-
flex: 1,
|
|
86
60
|
background: "#0d1117",
|
|
87
61
|
border: "1px solid #2a2a4a",
|
|
88
|
-
borderRadius: "
|
|
89
|
-
padding: "
|
|
90
|
-
color: "#
|
|
62
|
+
borderRadius: "6px",
|
|
63
|
+
padding: "8px 12px",
|
|
64
|
+
color: "#fff",
|
|
91
65
|
fontSize: "13px",
|
|
92
|
-
|
|
66
|
+
fontFamily: "inherit",
|
|
93
67
|
},
|
|
94
|
-
|
|
95
|
-
background: "#
|
|
68
|
+
btn: {
|
|
69
|
+
background: "linear-gradient(135deg, #00c853, #1b5e20)",
|
|
96
70
|
border: "none",
|
|
97
|
-
borderRadius: "
|
|
98
|
-
padding: "10px
|
|
71
|
+
borderRadius: "6px",
|
|
72
|
+
padding: "10px 16px",
|
|
99
73
|
color: "#fff",
|
|
100
74
|
fontSize: "13px",
|
|
101
75
|
fontWeight: 600,
|
|
102
76
|
cursor: "pointer",
|
|
103
77
|
},
|
|
104
|
-
timeLabel: {
|
|
105
|
-
fontSize: "10px",
|
|
106
|
-
color: "#555",
|
|
107
|
-
padding: "4px 0",
|
|
108
|
-
},
|
|
109
78
|
}
|
|
110
79
|
|
|
111
80
|
export function TextPreview() {
|
|
81
|
+
const [recipient, setRecipient] = useState("+1-555-0199")
|
|
82
|
+
const [message, setMessage] = useState("")
|
|
83
|
+
const [messages, setMessages] = useState<Array<{ text: string; time: string }>>([
|
|
84
|
+
{ text: "Total Recall SMS Bridge initialized.", time: "10:00 AM" }
|
|
85
|
+
])
|
|
86
|
+
const [sending, setSending] = useState(false)
|
|
87
|
+
|
|
88
|
+
const handleSend = async () => {
|
|
89
|
+
if (!message.trim()) return
|
|
90
|
+
setSending(true)
|
|
91
|
+
const newMsg = { text: message.trim(), time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) }
|
|
92
|
+
setMessages((prev) => [...prev, newMsg])
|
|
93
|
+
const body = message.trim()
|
|
94
|
+
setMessage("")
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
await runPluginCommand("text", "send", [recipient, body])
|
|
98
|
+
} catch {
|
|
99
|
+
// handled gracefully in thread
|
|
100
|
+
} finally {
|
|
101
|
+
setSending(false)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
112
105
|
return (
|
|
113
106
|
<div style={styles.container}>
|
|
114
107
|
<div style={styles.header}>
|
|
115
|
-
<span style={styles.label}>SMS Messaging</span>
|
|
116
|
-
<span style={styles.badge}>
|
|
108
|
+
<span style={styles.label}>SMS & Conversational Messaging</span>
|
|
109
|
+
<span style={styles.badge}>{sending ? "Sending…" : "Connected"}</span>
|
|
117
110
|
</div>
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
<div style={styles.
|
|
122
|
-
|
|
123
|
-
|
|
111
|
+
|
|
112
|
+
<div style={styles.threadBox}>
|
|
113
|
+
{messages.map((m, i) => (
|
|
114
|
+
<div key={i} style={styles.msgBubble}>
|
|
115
|
+
<div>{m.text}</div>
|
|
116
|
+
<div style={{ fontSize: "10px", color: "#888", textAlign: "right", marginTop: "4px" }}>{m.time}</div>
|
|
117
|
+
</div>
|
|
118
|
+
))}
|
|
124
119
|
</div>
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
<div style={
|
|
134
|
-
|
|
135
|
-
|
|
120
|
+
|
|
121
|
+
<div style={styles.inputRow}>
|
|
122
|
+
<input
|
|
123
|
+
style={styles.input}
|
|
124
|
+
value={recipient}
|
|
125
|
+
onChange={(e) => setRecipient(e.target.value)}
|
|
126
|
+
placeholder="Recipient Phone Number"
|
|
127
|
+
/>
|
|
128
|
+
<div style={{ display: "flex", gap: "8px" }}>
|
|
129
|
+
<input
|
|
130
|
+
style={{ ...styles.input, flex: 1 }}
|
|
131
|
+
value={message}
|
|
132
|
+
onChange={(e) => setMessage(e.target.value)}
|
|
133
|
+
placeholder="Type SMS message..."
|
|
134
|
+
onKeyDown={(e) => e.key === "Enter" && handleSend()}
|
|
135
|
+
/>
|
|
136
|
+
<button style={styles.btn} onClick={handleSend} disabled={sending || !message.trim()}>
|
|
137
|
+
Send
|
|
138
|
+
</button>
|
|
136
139
|
</div>
|
|
137
140
|
</div>
|
|
138
|
-
<div style={styles.inputBar}>
|
|
139
|
-
<input style={styles.input} placeholder="Type a message..." />
|
|
140
|
-
<button style={styles.sendBtn}>Send</button>
|
|
141
|
-
</div>
|
|
142
141
|
</div>
|
|
143
142
|
)
|
|
144
143
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useEffect, useState, type CSSProperties } from 'react'
|
|
2
|
+
|
|
3
|
+
const tokens = {
|
|
4
|
+
'--color-text': 'var(--text-primary)',
|
|
5
|
+
'--color-text-secondary': 'var(--text-secondary)',
|
|
6
|
+
'--color-surface': 'var(--bg-secondary)',
|
|
7
|
+
'--color-border': 'var(--border)',
|
|
8
|
+
'--color-success': 'var(--success)',
|
|
9
|
+
'--color-error': 'var(--error)',
|
|
10
|
+
'--spacing-md': '12px',
|
|
11
|
+
'--radius-md': '8px',
|
|
12
|
+
} as CSSProperties
|
|
13
|
+
|
|
14
|
+
export function UserAutomationsPreview() {
|
|
15
|
+
const [error, setError] = useState('')
|
|
16
|
+
const [ready, setReady] = useState(false)
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
let active = true
|
|
19
|
+
const moduleUrl = '/api/plugins/user-automations/ui/automations'
|
|
20
|
+
import(/* @vite-ignore */ moduleUrl)
|
|
21
|
+
.then(() => { if (active) setReady(true) })
|
|
22
|
+
.catch((cause) => { if (active) setError(cause instanceof Error ? cause.message : String(cause)) })
|
|
23
|
+
return () => { active = false }
|
|
24
|
+
}, [])
|
|
25
|
+
if (error) return <p role="alert">Automation plugin unavailable: {error}</p>
|
|
26
|
+
if (!ready) return <p>Loading user automations…</p>
|
|
27
|
+
return <div style={tokens} ref={(element) => {
|
|
28
|
+
if (element && !element.firstChild) element.append(document.createElement('tr-user-automations'))
|
|
29
|
+
}} />
|
|
30
|
+
}
|
|
@@ -14,6 +14,8 @@ import { TextPreview } from "./TextPreview"
|
|
|
14
14
|
import { CodeQualityPreview } from "./CodeQualityPreview"
|
|
15
15
|
import { ComposableCliPreview } from "./ComposableCliPreview"
|
|
16
16
|
import { DecisionPreview } from "./DecisionPreview"
|
|
17
|
+
import { ImageGeneratorPreview } from "./ImageGeneratorPreview"
|
|
18
|
+
import { UserAutomationsPreview } from "./UserAutomationsPreview"
|
|
17
19
|
import type { FC } from "react"
|
|
18
20
|
|
|
19
21
|
/**
|
|
@@ -40,6 +42,9 @@ export const previewRegistry: Record<string, FC> = {
|
|
|
40
42
|
"composable-cli": ComposableCliPreview,
|
|
41
43
|
"tr-plugin-decision": DecisionPreview,
|
|
42
44
|
"decision": DecisionPreview,
|
|
45
|
+
"image-generator": ImageGeneratorPreview,
|
|
46
|
+
"tr-plugin-image-generator": ImageGeneratorPreview,
|
|
47
|
+
"user-automations": UserAutomationsPreview,
|
|
43
48
|
}
|
|
44
49
|
|
|
45
50
|
/**
|
|
@@ -80,4 +85,4 @@ export function PreviewFallback({ pluginId }: { pluginId: string }) {
|
|
|
80
85
|
</div>
|
|
81
86
|
</div>
|
|
82
87
|
)
|
|
83
|
-
}
|
|
88
|
+
}
|