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.
Files changed (66) hide show
  1. package/bin/total-recall.mjs +17 -4
  2. package/frontend/dist/assets/{index-BPrkIYkZ.js → index-DZ4ypNEl.js} +135 -135
  3. package/frontend/dist/brand/plugins/phone.svg +20 -0
  4. package/frontend/dist/index.html +1 -1
  5. package/frontend/src/App.tsx +3 -30
  6. package/frontend/src/api/plugins.ts +18 -0
  7. package/frontend/src/components/plugins/previews/CodeQualityPreview.tsx +78 -86
  8. package/frontend/src/components/plugins/previews/ComposableCliPreview.tsx +74 -84
  9. package/frontend/src/components/plugins/previews/DecisionPreview.tsx +158 -106
  10. package/frontend/src/components/plugins/previews/DesignPreview.tsx +109 -75
  11. package/frontend/src/components/plugins/previews/DomainsPreview.tsx +69 -88
  12. package/frontend/src/components/plugins/previews/ImageGeneratorPreview.tsx +286 -0
  13. package/frontend/src/components/plugins/previews/PhonePreview.tsx +490 -76
  14. package/frontend/src/components/plugins/previews/SigningPreview.tsx +164 -50
  15. package/frontend/src/components/plugins/previews/TextPreview.tsx +85 -86
  16. package/frontend/src/components/plugins/previews/UserAutomationsPreview.tsx +30 -0
  17. package/frontend/src/components/plugins/previews/index.tsx +6 -1
  18. package/frontend/src/pages/PluginsPage.tsx +603 -136
  19. package/package.json +2 -5
  20. package/scaffold/.agent/skills/plugins/SKILL.md +200 -6
  21. package/src/cli/plugin/create.mjs +156 -11
  22. package/src/cli/plugin/index.mjs +5 -0
  23. package/src/core/embeddings.mjs +2 -0
  24. package/src/core/plugin-loader.mjs +18 -3
  25. package/src/core/plugin-store.mjs +122 -11
  26. package/src/core/surface.mjs +29 -1
  27. package/src/core/vault.mjs +6 -2
  28. package/src/server/route-manifest.json +22 -2
  29. package/src/server/routes/plugins-mesh.mjs +9 -1
  30. package/src/server/routes/plugins.mjs +65 -1
  31. package/frontend/src/pages/AutomationsPage.spec.tsx +0 -61
  32. package/frontend/src/pages/AutomationsPage.tsx +0 -354
  33. package/plugins/creative-search/README.md +0 -33
  34. package/plugins/creative-search/cli.mjs +0 -415
  35. package/plugins/creative-search/config.mjs +0 -129
  36. package/plugins/creative-search/generator.mjs +0 -13
  37. package/plugins/creative-search/plugin.json +0 -61
  38. package/plugins/creative-search/ui/DESIGN.md +0 -50
  39. package/plugins/creative-search/ui/csearch-main.js +0 -314
  40. package/plugins/creative-search/ui/csearch-settings.js +0 -392
  41. package/plugins/creative-search/ui/index.js +0 -2
  42. package/plugins/creative-search/ui/tokens.css +0 -34
  43. package/plugins/dsh/README.md +0 -20
  44. package/plugins/dsh/cli.mjs +0 -232
  45. package/plugins/dsh/generator.mjs +0 -65
  46. package/plugins/dsh/plugin.json +0 -57
  47. package/plugins/dsh/ui/DESIGN.md +0 -48
  48. package/plugins/dsh/ui/dsh-main.js +0 -226
  49. package/plugins/dsh/ui/dsh-status.js +0 -265
  50. package/plugins/dsh/ui/index.js +0 -2
  51. package/plugins/dsh/ui/tokens.css +0 -32
  52. package/plugins/git-sentinel/README.md +0 -29
  53. package/plugins/git-sentinel/cli.mjs +0 -89
  54. package/plugins/git-sentinel/plugin.json +0 -18
  55. package/plugins/operator-alerts/README.md +0 -32
  56. package/plugins/operator-alerts/cli.mjs +0 -57
  57. package/plugins/operator-alerts/notify-core.mjs +0 -216
  58. package/plugins/operator-alerts/plugin.json +0 -20
  59. package/plugins/skill-manager/README.md +0 -57
  60. package/plugins/skill-manager/cli.mjs +0 -123
  61. package/plugins/skill-manager/plugin.json +0 -25
  62. package/plugins/skill-manager/route.mjs +0 -106
  63. package/plugins/system-monitor/README.md +0 -28
  64. package/plugins/system-monitor/cli.mjs +0 -80
  65. package/plugins/system-monitor/generator.mjs +0 -19
  66. package/plugins/system-monitor/plugin.json +0 -29
@@ -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: {
@@ -12,6 +13,7 @@ const styles: Record<string, CSSProperties> = {
12
13
  header: {
13
14
  display: "flex",
14
15
  justifyContent: "space-between",
16
+ alignItems: "center",
15
17
  marginBottom: "16px",
16
18
  },
17
19
  label: {
@@ -26,114 +28,93 @@ const styles: Record<string, CSSProperties> = {
26
28
  padding: "4px 10px",
27
29
  borderRadius: "20px",
28
30
  fontSize: "11px",
31
+ fontWeight: 600,
29
32
  },
30
- toolbar: {
33
+ inputRow: {
31
34
  display: "flex",
32
35
  gap: "8px",
33
- marginBottom: "12px",
36
+ marginBottom: "16px",
34
37
  },
35
- filterBtn: {
36
- background: "#1e1e3a",
38
+ input: {
39
+ flex: 1,
40
+ background: "#0d1117",
37
41
  border: "1px solid #2a2a4a",
38
42
  borderRadius: "6px",
39
- padding: "6px 14px",
40
- color: "#aaa",
41
- fontSize: "12px",
42
- cursor: "pointer",
43
+ padding: "8px 12px",
44
+ color: "#fff",
45
+ fontSize: "13px",
46
+ fontFamily: "inherit",
43
47
  },
44
- filterBtnActive: {
45
- background: "#2a2a5a",
46
- border: "1px solid #5a5a9a",
48
+ button: {
49
+ background: "linear-gradient(135deg, #0288d1, #01579b)",
50
+ border: "none",
47
51
  borderRadius: "6px",
48
- padding: "6px 14px",
49
- color: "#c0c0ff",
52
+ padding: "8px 16px",
53
+ color: "#fff",
50
54
  fontSize: "12px",
55
+ fontWeight: 600,
51
56
  cursor: "pointer",
52
57
  },
53
- table: {
54
- width: "100%",
55
- borderCollapse: "collapse" as const,
56
- },
57
- th: {
58
- color: "#888",
59
- fontSize: "11px",
60
- textTransform: "uppercase" as const,
61
- padding: "8px 12px",
62
- textAlign: "left" as const,
63
- borderBottom: "1px solid #2a2a4a",
64
- letterSpacing: "1px",
65
- },
66
- td: {
67
- padding: "10px 12px",
68
- fontSize: "13px",
69
- borderBottom: "1px solid #1a1a2e",
70
- },
71
- typeA: { color: "#64b5f6" },
72
- typeAAAA: { color: "#ce93d8" },
73
- typeCname: { color: "#4caf50" },
74
- typeMx: { color: "#ffb74d" },
75
- typeTxt: { color: "#e0e0e0" },
76
- ttl: {
77
- color: "#666",
78
- fontSize: "11px",
58
+ resultBox: {
59
+ background: "#090d13",
60
+ border: "1px solid #2a2a4a",
61
+ borderRadius: "8px",
62
+ padding: "14px",
63
+ fontSize: "12px",
64
+ lineHeight: 1.5,
65
+ maxHeight: "260px",
66
+ overflowY: "auto" as const,
67
+ whiteSpace: "pre-wrap" as const,
68
+ color: "#b0bec5",
79
69
  },
80
70
  }
81
71
 
82
- interface RecordRow {
83
- type: string
84
- name: string
85
- value: string
86
- ttl: string
87
- }
88
-
89
- const records: RecordRow[] = [
90
- { type: "A", name: "@", value: "192.168.1.10", ttl: "300" },
91
- { type: "AAAA", name: "@", value: "fd12::1", ttl: "300" },
92
- { type: "CNAME", name: "mail", value: "mail.example.com", ttl: "3600" },
93
- { type: "MX", name: "@", value: "mail.example.com (priority 10)", ttl: "3600" },
94
- { type: "TXT", name: "@", value: '"v=spf1 include:_spf.example.com ~all"', ttl: "86400" },
95
- ]
72
+ export function DomainsPreview() {
73
+ const [domain, setDomain] = useState("localhost")
74
+ const [loading, setLoading] = useState(false)
75
+ const [result, setResult] = useState<string>("Enter a domain name to inspect DNS routing and registrar status.")
96
76
 
97
- const typeStyles: Record<string, CSSProperties> = {
98
- A: styles.typeA,
99
- AAAA: styles.typeAAAA,
100
- CNAME: styles.typeCname,
101
- MX: styles.typeMx,
102
- TXT: styles.typeTxt,
103
- }
77
+ const handleLookup = async () => {
78
+ if (!domain.trim()) return
79
+ setLoading(true)
80
+ setResult(`Querying DNS records for ${domain.trim()}...`)
81
+ try {
82
+ const res = await runPluginCommand("domains", "inspect", [domain.trim()])
83
+ if (res.success && res.output) {
84
+ setResult(res.output)
85
+ } else {
86
+ setResult(res.output || res.error || `No records found or command executed: total-recall domains inspect ${domain.trim()}`)
87
+ }
88
+ } catch (err: any) {
89
+ setResult(`Lookup failed: ${err?.message || "Verify network connection"}`)
90
+ } finally {
91
+ setLoading(false)
92
+ }
93
+ }
104
94
 
105
- export function DomainsPreview() {
106
95
  return (
107
96
  <div style={styles.container}>
108
97
  <div style={styles.header}>
109
- <span style={styles.label}>DNS Records</span>
110
- <span style={styles.badge}>Vercel DNS</span>
98
+ <span style={styles.label}>DNS & Domain Resolution</span>
99
+ <span style={styles.badge}>{loading ? "Querying…" : "Online"}</span>
111
100
  </div>
112
- <div style={styles.toolbar}>
113
- {["All", "A", "AAAA", "CNAME", "MX", "TXT"].map((f) => (
114
- <span key={f} style={f === "All" ? styles.filterBtnActive : styles.filterBtn}>{f}</span>
115
- ))}
101
+
102
+ <div style={styles.inputRow}>
103
+ <input
104
+ style={styles.input}
105
+ value={domain}
106
+ onChange={(e) => setDomain(e.target.value)}
107
+ placeholder="example.com"
108
+ onKeyDown={(e) => e.key === "Enter" && handleLookup()}
109
+ />
110
+ <button style={styles.button} onClick={handleLookup} disabled={loading || !domain.trim()}>
111
+ {loading ? "Inspecting…" : "Inspect DNS"}
112
+ </button>
113
+ </div>
114
+
115
+ <div style={styles.resultBox}>
116
+ {result}
116
117
  </div>
117
- <table style={styles.table}>
118
- <thead>
119
- <tr>
120
- <th style={styles.th}>Type</th>
121
- <th style={styles.th}>Name</th>
122
- <th style={styles.th}>Value</th>
123
- <th style={styles.th}>TTL</th>
124
- </tr>
125
- </thead>
126
- <tbody>
127
- {records.map((r, i) => (
128
- <tr key={i}>
129
- <td style={{ ...styles.td, ...typeStyles[r.type] }}>{r.type}</td>
130
- <td style={styles.td}>{r.name}</td>
131
- <td style={{ ...styles.td, ...typeStyles[r.type] }}>{r.value}</td>
132
- <td style={{ ...styles.td, ...styles.ttl }}>{r.ttl}s</td>
133
- </tr>
134
- ))}
135
- </tbody>
136
- </table>
137
118
  </div>
138
119
  )
139
120
  }
@@ -0,0 +1,286 @@
1
+ import { useState, type CSSProperties } from "react"
2
+ import { runPluginCommand } from "../../../api"
3
+
4
+ const styles: Record<string, CSSProperties> = {
5
+ container: {
6
+ background: "linear-gradient(135deg, #0f172a, #1e1b4b)",
7
+ borderRadius: "12px",
8
+ padding: "24px",
9
+ fontFamily: "var(--font-sans, system-ui, sans-serif)",
10
+ color: "#e2e8f0",
11
+ maxWidth: "600px",
12
+ },
13
+ header: {
14
+ display: "flex",
15
+ justifyContent: "space-between",
16
+ alignItems: "center",
17
+ marginBottom: "16px",
18
+ },
19
+ label: {
20
+ color: "#94a3b8",
21
+ fontSize: "11px",
22
+ textTransform: "uppercase" as const,
23
+ letterSpacing: "1px",
24
+ fontWeight: 600,
25
+ },
26
+ badge: {
27
+ background: "rgba(244, 63, 94, 0.2)",
28
+ color: "#f43f5e",
29
+ border: "1px solid rgba(244, 63, 94, 0.4)",
30
+ padding: "4px 10px",
31
+ borderRadius: "20px",
32
+ fontSize: "11px",
33
+ fontWeight: 600,
34
+ },
35
+ controlGroup: {
36
+ display: "flex",
37
+ flexDirection: "column",
38
+ gap: "6px",
39
+ marginBottom: "14px",
40
+ },
41
+ ctlLabel: {
42
+ fontSize: "12px",
43
+ color: "#94a3b8",
44
+ fontWeight: 500,
45
+ },
46
+ select: {
47
+ background: "#090d16",
48
+ border: "1px solid #334155",
49
+ borderRadius: "8px",
50
+ padding: "10px 12px",
51
+ color: "#f8fafc",
52
+ fontSize: "13px",
53
+ cursor: "pointer",
54
+ },
55
+ textarea: {
56
+ background: "#090d16",
57
+ border: "1px solid #334155",
58
+ borderRadius: "8px",
59
+ padding: "10px 12px",
60
+ color: "#f8fafc",
61
+ fontSize: "13px",
62
+ fontFamily: "inherit",
63
+ minHeight: "72px",
64
+ resize: "vertical" as const,
65
+ },
66
+ chipsRow: {
67
+ display: "flex",
68
+ gap: "6px",
69
+ flexWrap: "wrap",
70
+ marginTop: "4px",
71
+ },
72
+ chip: {
73
+ background: "#1e293b",
74
+ border: "1px solid #334155",
75
+ borderRadius: "6px",
76
+ padding: "4px 10px",
77
+ fontSize: "11px",
78
+ color: "#cbd5e1",
79
+ cursor: "pointer",
80
+ },
81
+ actions: {
82
+ display: "flex",
83
+ gap: "10px",
84
+ marginTop: "16px",
85
+ },
86
+ generateBtn: {
87
+ background: "linear-gradient(135deg, #f43f5e, #be123c)",
88
+ border: "none",
89
+ borderRadius: "8px",
90
+ padding: "12px 24px",
91
+ color: "#fff",
92
+ fontSize: "13px",
93
+ fontWeight: 600,
94
+ cursor: "pointer",
95
+ flex: 1,
96
+ display: "flex",
97
+ alignItems: "center",
98
+ justifyContent: "center",
99
+ gap: "8px",
100
+ },
101
+ previewCard: {
102
+ background: "#090d16",
103
+ border: "1px solid #334155",
104
+ borderRadius: "10px",
105
+ padding: "16px",
106
+ marginTop: "18px",
107
+ display: "flex",
108
+ flexDirection: "column",
109
+ alignItems: "center",
110
+ gap: "12px",
111
+ },
112
+ image: {
113
+ maxWidth: "100%",
114
+ maxHeight: "320px",
115
+ borderRadius: "8px",
116
+ objectFit: "contain" as const,
117
+ boxShadow: "0 8px 30px rgba(0,0,0,0.5)",
118
+ },
119
+ }
120
+
121
+ const MODELS = [
122
+ { id: "fal-ai/flux/schnell", name: "FLUX.1 [schnell] — Ultra-Fast (Recommended)" },
123
+ { id: "fal-ai/flux/dev", name: "FLUX.1 [dev] — Detailed High Quality" },
124
+ { id: "fal-ai/flux-pro/v1.1", name: "FLUX 1.1 [pro] — Professional Studio" },
125
+ { id: "fal-ai/recraft-v3", name: "Recraft v3 — Vector & Logo Design" },
126
+ { id: "fal-ai/fast-sdxl", name: "Fast SDXL — Lightweight Diffusion" },
127
+ ]
128
+
129
+ export function ImageGeneratorPreview() {
130
+ const [model, setModel] = useState("fal-ai/flux/schnell")
131
+ const [prompt, setPrompt] = useState("minimal vector brand logo for phone dialer on dark sleek background")
132
+ const [size, setSize] = useState("square_hd")
133
+ const [loading, setLoading] = useState(false)
134
+ const [generatedUrl, setGeneratedUrl] = useState<string | null>(null)
135
+ const [statusMessage, setStatusMessage] = useState<string | null>(null)
136
+
137
+ const handleGenerate = async () => {
138
+ if (!prompt.trim()) return
139
+ setLoading(true)
140
+ setStatusMessage("Submitting inference request to fal.ai...")
141
+
142
+ try {
143
+ const args = ["--prompt", prompt.trim(), "--model", model, "--size", size, "--json"]
144
+ const res = await runPluginCommand("image-generator", "generate", args)
145
+
146
+ if (res.output) {
147
+ try {
148
+ const parsed = JSON.parse(res.output)
149
+ if (parsed.url) {
150
+ setGeneratedUrl(parsed.url)
151
+ setStatusMessage(`Successfully generated via ${model}`)
152
+ return
153
+ }
154
+ } catch {
155
+ // not json, inspect raw text
156
+ }
157
+
158
+ const match = res.output.match(/URL:\s*(https?:\/\/[^\s]+)/)
159
+ if (match) {
160
+ setGeneratedUrl(match[1])
161
+ setStatusMessage(`Successfully generated via ${model}`)
162
+ return
163
+ }
164
+ }
165
+
166
+ if (res.error) {
167
+ setStatusMessage(`Inference error: ${res.error}`)
168
+ } else {
169
+ setStatusMessage(res.output || "Generated without output URL")
170
+ }
171
+ } catch (err: any) {
172
+ setStatusMessage(`Generation failed: ${err?.message || "Check network/FAL_KEY"}`)
173
+ } finally {
174
+ setLoading(false)
175
+ }
176
+ }
177
+
178
+ return (
179
+ <div style={styles.container}>
180
+ <div style={styles.header}>
181
+ <span style={styles.label}>fal.ai Generative Media Console</span>
182
+ <span style={styles.badge}>Live Inference</span>
183
+ </div>
184
+
185
+ {/* Model Selector Front & Center */}
186
+ <div style={styles.controlGroup}>
187
+ <label style={styles.ctlLabel}>Inference Model</label>
188
+ <select
189
+ style={styles.select}
190
+ value={model}
191
+ onChange={(e) => setModel(e.target.value)}
192
+ disabled={loading}
193
+ >
194
+ {MODELS.map((m) => (
195
+ <option key={m.id} value={m.id}>
196
+ {m.name}
197
+ </option>
198
+ ))}
199
+ </select>
200
+ </div>
201
+
202
+ {/* Prompt input */}
203
+ <div style={styles.controlGroup}>
204
+ <label style={styles.ctlLabel}>Prompt Description</label>
205
+ <textarea
206
+ style={styles.textarea}
207
+ value={prompt}
208
+ onChange={(e) => setPrompt(e.target.value)}
209
+ placeholder="Describe the branding image, logo, or icon to generate..."
210
+ disabled={loading}
211
+ />
212
+ <div style={styles.chipsRow}>
213
+ <button
214
+ type="button"
215
+ style={styles.chip}
216
+ onClick={() => setPrompt("sleek modern app icon for telecom dialer, minimal geometry on obsidian backdrop")}
217
+ >
218
+ 📞 App Icon
219
+ </button>
220
+ <button
221
+ type="button"
222
+ style={styles.chip}
223
+ onClick={() => setPrompt("vector brand emblem for cryptographic document signing, purple gradient, crisp lines")}
224
+ >
225
+ ✍️ Brand Seal
226
+ </button>
227
+ <button
228
+ type="button"
229
+ style={styles.chip}
230
+ onClick={() => setPrompt("minimalist globe DNS network icon with glowing cyan nodes and dark glass badge")}
231
+ >
232
+ 🌐 DNS Badge
233
+ </button>
234
+ </div>
235
+ </div>
236
+
237
+ {/* Size Selector */}
238
+ <div style={styles.controlGroup}>
239
+ <label style={styles.ctlLabel}>Aspect Ratio / Dimensions</label>
240
+ <select
241
+ style={styles.select}
242
+ value={size}
243
+ onChange={(e) => setSize(e.target.value)}
244
+ disabled={loading}
245
+ >
246
+ <option value="square_hd">Square HD (1024 × 1024) — Best for Logos & Icons</option>
247
+ <option value="landscape_16_9">Landscape 16:9 — Best for Banners</option>
248
+ <option value="portrait_16_9">Portrait 9:16 — Best for Mobile</option>
249
+ </select>
250
+ </div>
251
+
252
+ <div style={styles.actions}>
253
+ <button
254
+ style={styles.generateBtn}
255
+ onClick={handleGenerate}
256
+ disabled={loading || !prompt.trim()}
257
+ >
258
+ {loading ? "Generating Image with fal.ai…" : "✨ Generate Asset"}
259
+ </button>
260
+ </div>
261
+
262
+ {statusMessage && (
263
+ <div style={{ marginTop: "12px", fontSize: "12px", color: "#94a3b8", textAlign: "center" }}>
264
+ {statusMessage}
265
+ </div>
266
+ )}
267
+
268
+ {generatedUrl && (
269
+ <div style={styles.previewCard}>
270
+ <img src={generatedUrl} alt="Generated Asset" style={styles.image} />
271
+ <div style={{ display: "flex", gap: "8px", width: "100%", justifyContent: "center" }}>
272
+ <a
273
+ href={generatedUrl}
274
+ target="_blank"
275
+ rel="noreferrer"
276
+ className="btn btn-ghost btn-sm"
277
+ style={{ fontSize: "12px", textDecoration: "none" }}
278
+ >
279
+ Open Full Resolution ↗
280
+ </a>
281
+ </div>
282
+ </div>
283
+ )}
284
+ </div>
285
+ )
286
+ }