total-recall-brain 3.35.0 → 3.37.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 (72) hide show
  1. package/bin/total-recall.mjs +17 -4
  2. package/frontend/dist/assets/index-CpvEw3iA.js +5786 -0
  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/agent.mjs +59 -18
  22. package/src/cli/plugin/create.mjs +266 -13
  23. package/src/cli/plugin/index.mjs +5 -0
  24. package/src/cli/secret.mjs +28 -1
  25. package/src/core/agent-manager.mjs +47 -6
  26. package/src/core/cache-prune.mjs +60 -2
  27. package/src/core/embeddings.mjs +2 -0
  28. package/src/core/meta-harness.mjs +93 -6
  29. package/src/core/plugin-loader.mjs +20 -4
  30. package/src/core/plugin-store.mjs +122 -11
  31. package/src/core/surface.mjs +29 -1
  32. package/src/core/vault.mjs +6 -2
  33. package/src/server/route-manifest.json +22 -2
  34. package/src/server/routes/plugins-mesh.mjs +9 -1
  35. package/src/server/routes/plugins.mjs +65 -1
  36. package/frontend/dist/assets/index-BPrkIYkZ.js +0 -5786
  37. package/frontend/src/pages/AutomationsPage.spec.tsx +0 -61
  38. package/frontend/src/pages/AutomationsPage.tsx +0 -354
  39. package/plugins/creative-search/README.md +0 -33
  40. package/plugins/creative-search/cli.mjs +0 -415
  41. package/plugins/creative-search/config.mjs +0 -129
  42. package/plugins/creative-search/generator.mjs +0 -13
  43. package/plugins/creative-search/plugin.json +0 -61
  44. package/plugins/creative-search/ui/DESIGN.md +0 -50
  45. package/plugins/creative-search/ui/csearch-main.js +0 -314
  46. package/plugins/creative-search/ui/csearch-settings.js +0 -392
  47. package/plugins/creative-search/ui/index.js +0 -2
  48. package/plugins/creative-search/ui/tokens.css +0 -34
  49. package/plugins/dsh/README.md +0 -20
  50. package/plugins/dsh/cli.mjs +0 -232
  51. package/plugins/dsh/generator.mjs +0 -65
  52. package/plugins/dsh/plugin.json +0 -57
  53. package/plugins/dsh/ui/DESIGN.md +0 -48
  54. package/plugins/dsh/ui/dsh-main.js +0 -226
  55. package/plugins/dsh/ui/dsh-status.js +0 -265
  56. package/plugins/dsh/ui/index.js +0 -2
  57. package/plugins/dsh/ui/tokens.css +0 -32
  58. package/plugins/git-sentinel/README.md +0 -29
  59. package/plugins/git-sentinel/cli.mjs +0 -89
  60. package/plugins/git-sentinel/plugin.json +0 -18
  61. package/plugins/operator-alerts/README.md +0 -32
  62. package/plugins/operator-alerts/cli.mjs +0 -57
  63. package/plugins/operator-alerts/notify-core.mjs +0 -216
  64. package/plugins/operator-alerts/plugin.json +0 -20
  65. package/plugins/skill-manager/README.md +0 -57
  66. package/plugins/skill-manager/cli.mjs +0 -123
  67. package/plugins/skill-manager/plugin.json +0 -25
  68. package/plugins/skill-manager/route.mjs +0 -106
  69. package/plugins/system-monitor/README.md +0 -28
  70. package/plugins/system-monitor/cli.mjs +0 -80
  71. package/plugins/system-monitor/generator.mjs +0 -19
  72. package/plugins/system-monitor/plugin.json +0 -29
@@ -0,0 +1,20 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
2
+ <defs>
3
+ <linearGradient id="phoneBg" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" stop-color="#10b981"/>
5
+ <stop offset="100%" stop-color="#047857"/>
6
+ </linearGradient>
7
+ <linearGradient id="phoneGleam" x1="0%" y1="0%" x2="0%" y2="100%">
8
+ <stop offset="0%" stop-color="#ffffff" stop-opacity="0.3"/>
9
+ <stop offset="100%" stop-color="#ffffff" stop-opacity="0"/>
10
+ </linearGradient>
11
+ </defs>
12
+ <rect width="64" height="64" rx="14" fill="url(#phoneBg)"/>
13
+ <rect width="64" height="32" rx="14" fill="url(#phoneGleam)"/>
14
+ <rect x="1" y="1" width="62" height="62" rx="13" fill="none" stroke="#6ee7b7" stroke-width="1.5" stroke-opacity="0.4"/>
15
+ <!-- Phone Handset -->
16
+ <path d="M22 20c0-1.1.9-2 2-2h4.5c1 0 1.9.7 2 1.7l.8 5.2c.1 1-.4 2-1.3 2.5l-2.4 1.4c1.8 3.6 4.7 6.5 8.3 8.3l1.4-2.4c.5-.9 1.5-1.4 2.5-1.3l5.2.8c1 .1 1.7 1 1.7 2V40c0 1.1-.9 2-2 2-12.7 0-23-10.3-23-23v-1z" fill="#ffffff"/>
17
+ <!-- Signal Waves -->
18
+ <path d="M37 18c3.9 1.2 7 4.3 8.2 8.2" fill="none" stroke="#a7f3d0" stroke-width="2.5" stroke-linecap="round"/>
19
+ <path d="M41 14c5.8 1.9 10.3 6.4 12.2 12.2" fill="none" stroke="#a7f3d0" stroke-width="2.5" stroke-linecap="round" stroke-opacity="0.7"/>
20
+ </svg>
@@ -17,7 +17,7 @@
17
17
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
18
18
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
19
19
  <title>Total Recall — Portable Memory</title>
20
- <script type="module" crossorigin src="/assets/index-BPrkIYkZ.js"></script>
20
+ <script type="module" crossorigin src="/assets/index-CpvEw3iA.js"></script>
21
21
  <link rel="stylesheet" crossorigin href="/assets/index-C7_Xpk27.css">
22
22
  </head>
23
23
  <body>
@@ -1,7 +1,7 @@
1
1
  import { useState, useEffect } from 'react'
2
2
  import { BrowserRouter, Routes, Route, NavLink, Navigate, useLocation } from 'react-router-dom'
3
3
  import './App.css'
4
- import { getApiBase, setApiBase, checkSession, logout, registerUnauthedCallback, fetchHealth, fetchPlugins, type PluginInfo } from './api'
4
+ import { getApiBase, setApiBase, checkSession, logout, registerUnauthedCallback, fetchHealth } from './api'
5
5
  import type { HealthData } from './types'
6
6
  import LoginPage from './pages/LoginPage'
7
7
  import ChatPage from './pages/ChatPage'
@@ -87,12 +87,6 @@ interface SidebarProps {
87
87
  const getNavLinkClass = ({ isActive }: { isActive: boolean }) => `nav-link ${isActive ? 'active' : ''}`;
88
88
 
89
89
  function Sidebar({ onLogout, health, activeBrainId, onBrainChange }: SidebarProps) {
90
- const [plugins, setPlugins] = useState<PluginInfo[]>([])
91
-
92
- useEffect(() => {
93
- fetchPlugins().then(setPlugins).catch(() => {})
94
- }, [])
95
-
96
90
  return (
97
91
  <aside className="sidebar">
98
92
  <div className="sidebar-brand" style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '16px 14px' }}>
@@ -148,6 +142,7 @@ function Sidebar({ onLogout, health, activeBrainId, onBrainChange }: SidebarProp
148
142
  Tasks
149
143
  </NavLink>
150
144
 
145
+
151
146
  <div className="nav-section-label">Connect</div>
152
147
  <NavLink to="/integrations" className={getNavLinkClass} id="nav-integrations">
153
148
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
@@ -178,28 +173,6 @@ function Sidebar({ onLogout, health, activeBrainId, onBrainChange }: SidebarProp
178
173
  Plugins
179
174
  </NavLink>
180
175
 
181
- {plugins.length > 0 && (
182
- <>
183
- <div className="nav-section-label">Plugins</div>
184
- {plugins.map((p) => (
185
- <NavLink
186
- key={p.id}
187
- to={`/plugins?id=${encodeURIComponent(p.id)}`}
188
- className={getNavLinkClass}
189
- id={`nav-plugin-${p.id}`}
190
- title={p.description}
191
- >
192
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
193
- <path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
194
- <polyline points="3.27 6.96 12 12.01 20.73 6.96" />
195
- <line x1="12" y1="22.08" x2="12" y2="12" />
196
- </svg>
197
- {p.name}
198
- </NavLink>
199
- ))}
200
- </>
201
- )}
202
-
203
176
  <div className="nav-section-label">Account</div>
204
177
  <NavLink to="/network" className={getNavLinkClass} id="nav-network">
205
178
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
@@ -450,7 +423,7 @@ function MainContent({ activeBrainId, onBrainChange }: { activeBrainId: string;
450
423
  {/* Legacy OS-control-plane routes → core product */}
451
424
  <Route path="/vault" element={<Navigate to="/memory" replace />} />
452
425
  <Route path="/inbox" element={<Navigate to="/tasks" replace />} />
453
- <Route path="/automations" element={<Navigate to="/tasks" replace />} />
426
+ <Route path="/automations" element={<Navigate to="/plugins?id=user-automations" replace />} />
454
427
  <Route path="/files" element={<Navigate to="/memory" replace />} />
455
428
  <Route path="/sandbox" element={<Navigate to="/memory" replace />} />
456
429
  <Route path="/models" element={<Navigate to="/settings" replace />} />
@@ -50,6 +50,10 @@ export interface PluginInfo {
50
50
  openwiki_hubs: Array<{ title?: string; path: string }>
51
51
  cli: { command: string | null; subcommands: Array<{ name: string; description?: string }> } | null
52
52
  has_generator: boolean
53
+ branding?: { icon?: string | null; image?: string | null; color?: string | null; badge?: string | null }
54
+ locked?: boolean
55
+ store_deployed?: boolean
56
+ secrets?: Array<{ key: string; description?: string; required?: boolean }>
53
57
  manifest?: Record<string, unknown>
54
58
  }
55
59
 
@@ -63,6 +67,8 @@ export interface BundledPlugin {
63
67
  tasks: Array<{ intent: string; schedule: string; command: string }>
64
68
  cli: { command: string; subcommands: Array<{ name: string; description?: string }> } | null
65
69
  installed: boolean
70
+ branding?: { icon?: string | null; color?: string | null; badge?: string | null }
71
+ locked?: boolean
66
72
  }
67
73
 
68
74
  export interface PeerPlugin {
@@ -177,6 +183,18 @@ export function setPluginShared(id: string, shared: boolean): Promise<Result> {
177
183
  return post(`${API_BASE}/api/plugins/${encodeURIComponent(id)}/share`, { shared })
178
184
  }
179
185
 
186
+ export function updatePluginBranding(id: string, branding: { icon?: string; image?: string; color?: string; badge?: string }): Promise<Result> {
187
+ return post(`${API_BASE}/api/plugins/${encodeURIComponent(id)}/branding`, { branding })
188
+ }
189
+
190
+ export function setPluginLocked(id: string, locked: boolean): Promise<Result> {
191
+ return post(`${API_BASE}/api/plugins/${encodeURIComponent(id)}/lock`, { locked })
192
+ }
193
+
194
+ export function deployPluginToStore(id: string, autoLock = true): Promise<Result & { storePackage?: any }> {
195
+ return post(`${API_BASE}/api/plugins/${encodeURIComponent(id)}/deploy-store`, { autoLock })
196
+ }
197
+
180
198
  export async function runPluginCommand(
181
199
  id: string,
182
200
  subcommand = "",
@@ -1,4 +1,5 @@
1
- import { type CSSProperties } from "react"
1
+ import { useState, useEffect, useCallback, 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: {
@@ -21,110 +23,100 @@ const styles: Record<string, CSSProperties> = {
21
23
  letterSpacing: "1px",
22
24
  },
23
25
  badge: {
24
- background: "#1a2a1a",
25
- color: "#4caf50",
26
26
  padding: "4px 10px",
27
27
  borderRadius: "20px",
28
28
  fontSize: "11px",
29
+ fontWeight: 600,
29
30
  },
30
- summary: {
31
+ controls: {
31
32
  display: "flex",
32
- gap: "16px",
33
+ gap: "8px",
33
34
  marginBottom: "16px",
34
35
  },
35
- statCard: {
36
- background: "#0d1117",
36
+ button: {
37
+ background: "linear-gradient(135deg, #1976d2, #0d47a1)",
38
+ border: "none",
39
+ borderRadius: "6px",
40
+ padding: "8px 16px",
41
+ color: "#fff",
42
+ fontSize: "12px",
43
+ fontWeight: 600,
44
+ cursor: "pointer",
45
+ },
46
+ rawOutput: {
47
+ background: "#090d13",
37
48
  border: "1px solid #2a2a4a",
38
49
  borderRadius: "8px",
39
- padding: "12px 16px",
40
- flex: 1,
41
- },
42
- statValue: {
43
- fontSize: "20px",
44
- fontWeight: 700,
45
- },
46
- statLabel: {
47
- fontSize: "10px",
48
- color: "#888",
49
- textTransform: "uppercase" as const,
50
- letterSpacing: "1px",
51
- marginTop: "4px",
52
- },
53
- gateTable: {
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
- },
65
- td: {
66
- padding: "10px 12px",
50
+ padding: "14px",
67
51
  fontSize: "12px",
68
- borderBottom: "1px solid #1a1a2e",
69
- },
70
- pass: {
71
- color: "#4caf50",
72
- },
73
- fail: {
74
- color: "#ff5252",
52
+ lineHeight: 1.5,
53
+ maxHeight: "260px",
54
+ overflowY: "auto" as const,
55
+ whiteSpace: "pre-wrap" as const,
56
+ color: "#cfd8dc",
75
57
  },
76
58
  }
77
59
 
78
- const gates = [
79
- { name: "TypeScript", status: "pass", detail: "0 errors" },
80
- { name: "ESLint", status: "pass", detail: "0 warnings" },
81
- { name: "Vitest", status: "pass", detail: "42/42 tests" },
82
- { name: "Bundle Size", status: "pass", detail: "12.4 kB" },
83
- { name: "SSSS Schema", status: "fail", detail: "1 warning" },
84
- { name: "Mesh Sync", status: "pass", detail: "2 peers synced" },
85
- ]
86
-
87
60
  export function CodeQualityPreview() {
61
+ const [running, setRunning] = useState(false)
62
+ const [output, setOutput] = useState<string>("Click 'Run Quality Report' to inspect current gate status.")
63
+ const [passCount, setPassCount] = useState<number | null>(null)
64
+ const [failCount, setFailCount] = useState<number | null>(null)
65
+
66
+ const runCheck = useCallback(async () => {
67
+ setRunning(true)
68
+ try {
69
+ const res = await runPluginCommand("code-quality", "report", [])
70
+ const text = res.output || res.error || "No report output returned."
71
+ setOutput(text)
72
+
73
+ // Parse findings count honestly
74
+ if (text.includes("0 finding(s)") || text.includes("No findings")) {
75
+ setPassCount(5)
76
+ setFailCount(0)
77
+ } else {
78
+ const match = text.match(/(\d+)\s+finding\(s\)/)
79
+ if (match) {
80
+ const findings = parseInt(match[1], 10)
81
+ setFailCount(findings)
82
+ setPassCount(Math.max(0, 5 - findings))
83
+ }
84
+ }
85
+ } catch (err: any) {
86
+ setOutput(`Error running quality gate: ${err?.message || "Execution failed"}`)
87
+ } finally {
88
+ setRunning(false)
89
+ }
90
+ }, [])
91
+
92
+ useEffect(() => {
93
+ runCheck()
94
+ }, [runCheck])
95
+
88
96
  return (
89
97
  <div style={styles.container}>
90
98
  <div style={styles.header}>
91
- <span style={styles.label}>Gate Report</span>
92
- <span style={styles.badge}>5/6 passing</span>
99
+ <span style={styles.label}>Code Quality Gate Console</span>
100
+ <span
101
+ style={{
102
+ ...styles.badge,
103
+ background: failCount === 0 ? "#1a3a1a" : failCount === null ? "#2a2a3a" : "#3a1a1a",
104
+ color: failCount === 0 ? "#4caf50" : failCount === null ? "#8888ff" : "#ff5252",
105
+ }}
106
+ >
107
+ {running ? "Checking…" : failCount === 0 ? `All Clean (${passCount ?? 5} Passing)` : failCount ? `${failCount} Findings (${passCount ?? 0} Passing)` : "Ready"}
108
+ </span>
93
109
  </div>
94
- <div style={styles.summary}>
95
- <div style={{ ...styles.statCard, borderColor: "#1a3a1a" }}>
96
- <div style={{ ...styles.statValue, color: "#4caf50" }}>5</div>
97
- <div style={styles.statLabel}>Passing</div>
98
- </div>
99
- <div style={styles.statCard}>
100
- <div style={{ ...styles.statValue, color: "#ff5252" }}>1</div>
101
- <div style={styles.statLabel}>Failing</div>
102
- </div>
103
- <div style={styles.statCard}>
104
- <div style={{ ...styles.statValue, color: "#64b5f6" }}>6</div>
105
- <div style={styles.statLabel}>Total Gates</div>
106
- </div>
110
+
111
+ <div style={styles.controls}>
112
+ <button style={styles.button} onClick={runCheck} disabled={running}>
113
+ {running ? "Executing Check…" : "Refresh Gate Report"}
114
+ </button>
115
+ </div>
116
+
117
+ <div style={styles.rawOutput}>
118
+ {output}
107
119
  </div>
108
- <table style={styles.gateTable}>
109
- <thead>
110
- <tr>
111
- <th style={styles.th}>Gate</th>
112
- <th style={styles.th}>Status</th>
113
- <th style={styles.th}>Detail</th>
114
- </tr>
115
- </thead>
116
- <tbody>
117
- {gates.map((g, i) => (
118
- <tr key={i}>
119
- <td style={styles.td}>{g.name}</td>
120
- <td style={{ ...styles.td, ...(g.status === "pass" ? styles.pass : styles.fail) }}>
121
- {g.status === "pass" ? "✓" : "✗"}
122
- </td>
123
- <td style={styles.td}>{g.detail}</td>
124
- </tr>
125
- ))}
126
- </tbody>
127
- </table>
128
120
  </div>
129
121
  )
130
122
  }
@@ -1,17 +1,19 @@
1
1
  import { useState, type CSSProperties } from "react"
2
+ import { runPluginCommand } from "../../../api"
2
3
 
3
4
  const styles: Record<string, CSSProperties> = {
4
5
  container: {
5
- background: "linear-gradient(135deg, #0d1117, #1a1a2e)",
6
+ background: "linear-gradient(135deg, #0a1628, #1a1a2e)",
6
7
  borderRadius: "12px",
7
8
  padding: "24px",
8
- fontFamily: "var(--font-mono, 'SF Mono', 'Fira Code', monospace)",
9
+ fontFamily: "var(--font-mono, 'SF Mono', monospace)",
9
10
  color: "#e0e0e0",
10
- maxWidth: "520px",
11
+ maxWidth: "580px",
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,110 +23,98 @@ const styles: Record<string, CSSProperties> = {
21
23
  letterSpacing: "1px",
22
24
  },
23
25
  badge: {
24
- background: "#1a2a3a",
25
- color: "#64b5f6",
26
+ background: "#1a3a3a",
27
+ color: "#00bfa5",
26
28
  padding: "4px 10px",
27
29
  borderRadius: "20px",
28
30
  fontSize: "11px",
31
+ fontWeight: 600,
29
32
  },
30
- terminal: {
31
- background: "#0a0a1a",
32
- border: "1px solid #2a2a4a",
33
- borderRadius: "8px",
34
- padding: "12px",
33
+ row: {
34
+ display: "flex",
35
+ gap: "8px",
35
36
  marginBottom: "12px",
36
- minHeight: "100px",
37
- overflow: "auto" as const,
38
37
  },
39
- line: {
40
- fontSize: "12px",
41
- lineHeight: 1.6,
42
- whiteSpace: "pre-wrap" as const,
43
- },
44
- prompt: {
45
- color: "#4caf50",
46
- },
47
- cmd: {
48
- color: "#e0e0e0",
49
- },
50
- output: {
51
- color: "#888",
52
- },
53
- inputRow: {
54
- display: "flex",
55
- alignItems: "center",
56
- gap: "6px",
57
- background: "#0a0a1a",
38
+ input: {
39
+ background: "#0d1117",
58
40
  border: "1px solid #2a2a4a",
59
- borderRadius: "8px",
41
+ borderRadius: "6px",
60
42
  padding: "8px 12px",
61
- },
62
- input: {
43
+ color: "#fff",
44
+ fontSize: "13px",
45
+ fontFamily: "inherit",
63
46
  flex: 1,
64
- background: "transparent",
47
+ },
48
+ btn: {
49
+ background: "linear-gradient(135deg, #00897b, #004d40)",
65
50
  border: "none",
66
- color: "#4caf50",
67
- fontFamily: "var(--font-mono, 'SF Mono', monospace)",
51
+ borderRadius: "6px",
52
+ padding: "8px 16px",
53
+ color: "#fff",
68
54
  fontSize: "12px",
69
- outline: "none",
70
- },
71
- commands: {
72
- display: "flex",
73
- flexWrap: "wrap" as const,
74
- gap: "6px",
75
- marginTop: "12px",
55
+ fontWeight: 600,
56
+ cursor: "pointer",
76
57
  },
77
- cmdChip: {
78
- background: "#1e1e3a",
58
+ previewBox: {
59
+ background: "#090d13",
79
60
  border: "1px solid #2a2a4a",
80
- borderRadius: "6px",
81
- padding: "4px 10px",
82
- fontSize: "11px",
83
- color: "#aaa",
84
- cursor: "pointer",
61
+ borderRadius: "8px",
62
+ padding: "14px",
63
+ fontSize: "12px",
64
+ lineHeight: 1.5,
65
+ maxHeight: "220px",
66
+ overflowY: "auto" as const,
67
+ whiteSpace: "pre-wrap" as const,
68
+ color: "#80cbc4",
85
69
  },
86
70
  }
87
71
 
88
- const initialLines = [
89
- { kind: "prompt", text: "total-recall@mesh:~$ " },
90
- { kind: "cmd", text: "total-recall --help" },
91
- { kind: "output", text: "\nTotal Recall Composable CLI v2.1.0" },
92
- { kind: "output", text: "\nCommands:" },
93
- { kind: "output", text: "\n recall <query> Search memory" },
94
- { kind: "output", text: "\n remember <category> Write memory" },
95
- { kind: "output", text: "\n compile Rebuild surfaces" },
96
- { kind: "output", text: "\n mesh nodes List mesh peers" },
97
- { kind: "output", text: "\n plugin list Show installed plugins" },
98
- { kind: "output", text: "\n vercel-rotate Rotate API token" },
99
- { kind: "prompt", text: "\ntotal-recall@mesh:~$ " },
100
- ]
101
-
102
72
  export function ComposableCliPreview() {
103
- const [cmdHistory, _setCmdHistory] = useState(initialLines)
73
+ const [subcommand, setSubcommand] = useState("inspect")
74
+ const [argument, setArgument] = useState("--format=json")
75
+ const [executing, setExecuting] = useState(false)
76
+ const [result, setResult] = useState<string>("total-recall composable-cli inspect --format=json")
77
+
78
+ const handleExecute = async () => {
79
+ setExecuting(true)
80
+ const args = argument.trim() ? argument.trim().split(/\s+/) : []
81
+ try {
82
+ const res = await runPluginCommand("composable-cli", subcommand, args)
83
+ setResult(res.output || res.error || `Executed successfully: total-recall composable-cli ${subcommand} ${args.join(" ")}`)
84
+ } catch (err: any) {
85
+ setResult(`Execution error: ${err?.message || "Check composable-cli handler"}`)
86
+ } finally {
87
+ setExecuting(false)
88
+ }
89
+ }
104
90
 
105
91
  return (
106
92
  <div style={styles.container}>
107
93
  <div style={styles.header}>
108
- <span style={styles.label}>Composable CLI</span>
109
- <span style={styles.badge}>Active</span>
110
- </div>
111
- <div style={styles.terminal}>
112
- {cmdHistory.map((l, i) => (
113
- <div key={i} style={styles.line}>
114
- {l.kind === "prompt" && <span style={styles.prompt}>{l.text}</span>}
115
- {l.kind === "cmd" && <span style={styles.cmd}>{l.text}</span>}
116
- {l.kind === "output" && <span style={styles.output}>{l.text}</span>}
117
- </div>
118
- ))}
94
+ <span style={styles.label}>Dynamic Command Orchestrator</span>
95
+ <span style={styles.badge}>Live CLI</span>
119
96
  </div>
120
- <div style={styles.inputRow}>
121
- <span style={{ ...styles.prompt, fontSize: "12px" }}>$</span>
122
- <input style={styles.input} placeholder="Type a command..." readOnly />
97
+
98
+ <div style={styles.row}>
99
+ <input
100
+ style={{ ...styles.input, flex: "0 0 140px" }}
101
+ value={subcommand}
102
+ onChange={(e) => setSubcommand(e.target.value)}
103
+ placeholder="subcommand"
104
+ />
105
+ <input
106
+ style={styles.input}
107
+ value={argument}
108
+ onChange={(e) => setArgument(e.target.value)}
109
+ placeholder="args (e.g. --json)"
110
+ />
111
+ <button style={styles.btn} onClick={handleExecute} disabled={executing}>
112
+ {executing ? "Running…" : "Execute"}
113
+ </button>
123
114
  </div>
124
- <div style={styles.commands}>
125
- {["help", "recall", "remember", "compile", "mesh", "plugins"].map((c) => (
126
- <span key={c} style={styles.cmdChip}>{c}</span>
127
- ))}
115
+
116
+ <div style={styles.previewBox}>
117
+ {result}
128
118
  </div>
129
119
  </div>
130
120
  )