total-recall-brain 3.41.5 → 3.41.6

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 (131) hide show
  1. package/bin/total-recall.mjs +7 -4
  2. package/frontend/dist/assets/index-4tGQfTa2.js +5605 -0
  3. package/frontend/dist/assets/index-DtwsDyFM.css +1 -0
  4. package/frontend/dist/index.html +2 -2
  5. package/frontend/package.json +11 -0
  6. package/frontend/src/App.tsx +47 -122
  7. package/frontend/src/components/plugins/plugin-frame.ts +1 -0
  8. package/frontend/src/index.css +152 -86
  9. package/frontend/src/pages/HelpPage.tsx +13 -10
  10. package/frontend/src/pages/MemoryPage.tsx +28 -30
  11. package/frontend/src/pages/NetworkPage.tsx +3 -3
  12. package/frontend/src/pages/PluginsPage.tsx +6 -5
  13. package/frontend/src/pages/RulesPage.tsx +16 -12
  14. package/package.json +3 -2
  15. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +8 -8
  16. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +3 -0
  17. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +8 -8
  18. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +3 -0
  19. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +8 -8
  20. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +3 -0
  21. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +8 -8
  22. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +3 -0
  23. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +8 -8
  24. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +4 -1
  25. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +1 -1
  26. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +136 -7
  27. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +135 -26
  28. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +8 -8
  29. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +4 -1
  30. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +228 -9
  31. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +24 -30
  32. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +29 -16
  33. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +73 -0
  34. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +182 -365
  35. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +33 -0
  36. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +9 -3
  37. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +4 -4
  38. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/agy.mjs +187 -0
  39. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/claude.mjs +275 -0
  40. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cline.mjs +132 -0
  41. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/codex.mjs +187 -0
  42. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cursor.mjs +158 -0
  43. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/devin.mjs +157 -0
  44. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/dsh.mjs +183 -0
  45. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/grok.mjs +132 -0
  46. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/hermes.mjs +173 -0
  47. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/index.mjs +87 -0
  48. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/openclaw.mjs +173 -0
  49. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/pi.mjs +129 -0
  50. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate.mjs +12 -0
  51. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/json-reply.mjs +22 -0
  52. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +72 -70
  53. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/model-catalog.mjs +195 -0
  54. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/paths.mjs +11 -0
  55. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/pool.mjs +36 -0
  56. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/review.mjs +169 -0
  57. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +136 -346
  58. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +1 -1
  59. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/ssss-store.mjs +20 -0
  60. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/telemetry.mjs +43 -0
  61. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/threads.mjs +156 -0
  62. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +117 -35
  63. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worktree.mjs +51 -0
  64. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +398 -57
  65. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +10 -0
  66. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +3 -3
  67. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +3 -0
  68. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +42 -190
  69. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/openwiki.mjs +1 -1
  70. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/mermaid-diagrams/SKILL.md +44 -0
  71. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/write-connector/SKILL.md +56 -0
  72. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +8 -8
  73. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +3 -0
  74. package/src/cli/agent.mjs +12 -1
  75. package/src/cli/compact.mjs +2 -2
  76. package/src/cli/connect.mjs +56 -1
  77. package/src/cli/context.mjs +10 -7
  78. package/src/cli/doctor.mjs +5 -2
  79. package/src/cli/harness.mjs +62 -50
  80. package/src/cli/memory-entry.mjs +2 -2
  81. package/src/cli/preflight.mjs +152 -16
  82. package/src/cli/remember.mjs +19 -1
  83. package/src/cli/rules.mjs +54 -12
  84. package/src/cli/startup.mjs +1 -1
  85. package/src/cli/status.mjs +12 -2
  86. package/src/core/claude-hooks.mjs +41 -3
  87. package/src/core/cli-semantic-index.mjs +3 -2
  88. package/src/core/conflict-detector.mjs +23 -12
  89. package/src/core/context-compactor.mjs +2 -0
  90. package/src/core/context-policy.mjs +20 -0
  91. package/src/core/duplicate-guard.mjs +350 -0
  92. package/src/core/meta-harness.mjs +31 -11
  93. package/src/core/preflight-gate.mjs +2 -2
  94. package/src/core/preflight-receipt.mjs +28 -0
  95. package/src/core/scaffold-plugins.mjs +7 -0
  96. package/src/core/stdio-flush.mjs +23 -0
  97. package/src/core/surface.mjs +33 -10
  98. package/src/server/routes/plugins.mjs +2 -2
  99. package/frontend/dist/assets/index-BIQmqDKP.css +0 -1
  100. package/frontend/dist/assets/index-WT3gs-x6.js +0 -5631
  101. package/frontend/src/components/DaemonLogsTab.tsx +0 -54
  102. package/frontend/src/components/ResearchAgendaTab.tsx +0 -712
  103. package/frontend/src/components/TaskQueueTab.tsx +0 -193
  104. package/frontend/src/components/VoiceInput.tsx +0 -112
  105. package/frontend/src/pages/ChatPage.tsx +0 -1059
  106. package/frontend/src/pages/CollabPage.tsx +0 -470
  107. package/frontend/src/pages/DesignDocsPage.tsx +0 -621
  108. package/frontend/src/pages/FilesPage.tsx +0 -393
  109. package/frontend/src/pages/HealthPage.tsx +0 -359
  110. package/frontend/src/pages/InboxPage.tsx +0 -83
  111. package/frontend/src/pages/InstructionsPage.tsx +0 -583
  112. package/frontend/src/pages/IntegrationsPage.tsx +0 -761
  113. package/frontend/src/pages/MeshPage.css +0 -58
  114. package/frontend/src/pages/MeshPage.tsx +0 -1219
  115. package/frontend/src/pages/OkfPage.tsx +0 -535
  116. package/frontend/src/pages/SandboxPage.tsx +0 -113
  117. package/frontend/src/pages/SkillsPage.tsx +0 -1994
  118. package/frontend/src/pages/TasksPage.tsx +0 -427
  119. package/frontend/src/pages/UsagePage.tsx +0 -702
  120. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/README.md +0 -65
  121. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/cli.mjs +0 -76
  122. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/package.json +0 -19
  123. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/plugin.json +0 -266
  124. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/adapters/dsh.mjs +0 -446
  125. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/documentation.mjs +0 -152
  126. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/executor.mjs +0 -71
  127. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/runtime.mjs +0 -36
  128. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/setup.mjs +0 -35
  129. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/worker.mjs +0 -175
  130. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/DESIGN.md +0 -32
  131. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/card.js +0 -575
@@ -1,393 +0,0 @@
1
- import { useState, useEffect, useCallback } from "react"
2
- import { listFiles, listSkills, listScripts, readScript, saveScript, runScript } from "../api"
3
- import type { FileNode, ScriptFile } from "../types"
4
-
5
- function formatBytes(bytes: number) {
6
- if (bytes === 0) return "0 B"
7
- const k = 1024
8
- const sizes = ["B", "KB", "MB", "GB"]
9
- const i = Math.floor(Math.log(bytes) / Math.log(k))
10
- return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + " " + sizes[i]
11
- }
12
-
13
- export default function FilesPage() {
14
- const [activeTab, setActiveTab] = useState<"files" | "skills" | "scripts">("files")
15
- const [files, setFiles] = useState<FileNode[]>([])
16
- const [skills, setSkills] = useState<FileNode[]>([])
17
- const [loading, setLoading] = useState(true)
18
- const [error, setError] = useState("")
19
-
20
- // Scripts Tab States
21
- const [scripts, setScripts] = useState<ScriptFile[]>([])
22
- const [selectedScript, setSelectedScript] = useState<string | null>(null)
23
- const [scriptContent, setScriptContent] = useState("")
24
- const [scriptLoading, setScriptLoading] = useState(false)
25
- const [running, setRunning] = useState(false)
26
- const [terminalOutput, setTerminalOutput] = useState("")
27
- const [exitCode, setExitCode] = useState<number | null>(null)
28
- const [newScriptName, setNewScriptName] = useState("")
29
- const [isCreatingScript, setIsCreatingScript] = useState(false)
30
-
31
- const fetchFilesData = useCallback(async () => {
32
- try {
33
- const [filesData, skillsData] = await Promise.all([
34
- listFiles(),
35
- listSkills()
36
- ])
37
- setFiles(filesData)
38
- // Skills API returns { skills, repos } catalog — flatten for this page
39
- const flat = Array.isArray(skillsData)
40
- ? skillsData
41
- : (skillsData?.skills || [])
42
- setSkills(flat as import('../types').FileNode[])
43
- setError("")
44
- } catch (e) {
45
- setError((e as Error).message)
46
- } finally {
47
- setLoading(false)
48
- }
49
- }, [])
50
-
51
- const fetchScriptsList = useCallback(async () => {
52
- setLoading(true)
53
- try {
54
- const list = await listScripts()
55
- setScripts(list)
56
- } catch (e) {
57
- setError(`Failed to list scripts: ${(e as Error).message}`)
58
- } finally {
59
- setLoading(false)
60
- }
61
- }, [])
62
-
63
- useEffect(() => {
64
- if (activeTab === "files" || activeTab === "skills") {
65
- // eslint-disable-next-line react-hooks/set-state-in-effect -- legitimate file fetch on activeTab change
66
- void fetchFilesData()
67
- } else if (activeTab === "scripts") {
68
- void fetchScriptsList()
69
- }
70
- }, [activeTab, fetchFilesData, fetchScriptsList])
71
-
72
- const handleSelectScript = async (name: string) => {
73
- setSelectedScript(name)
74
- setScriptLoading(true)
75
- setTerminalOutput("")
76
- setExitCode(null)
77
- try {
78
- const data = await readScript(name)
79
- setScriptContent(data.content || "")
80
- } catch (e) {
81
- setError(`Failed to load script content: ${(e as Error).message}`)
82
- } finally {
83
- setScriptLoading(false)
84
- }
85
- }
86
-
87
- const handleSaveScript = async () => {
88
- if (!selectedScript) return
89
- setScriptLoading(true)
90
- try {
91
- await saveScript(selectedScript, scriptContent)
92
- setError("")
93
- setError(`✓ Script "${selectedScript}" saved successfully!`)
94
- void fetchScriptsList()
95
- } catch (e) {
96
- setError(`Failed to save script: ${(e as Error).message}`)
97
- } finally {
98
- setScriptLoading(false)
99
- }
100
- }
101
-
102
- const handleRunScript = async () => {
103
- if (!selectedScript) return
104
- setRunning(true)
105
- setTerminalOutput("⚡ Spawning sandboxed executor process...\n")
106
- setExitCode(null)
107
- try {
108
- const res = await runScript(selectedScript)
109
- setTerminalOutput(res.output || "Script executed with no console output.")
110
- setExitCode(res.exitCode)
111
- } catch (e) {
112
- setTerminalOutput(`❌ Execution Error: ${(e as Error).message}`)
113
- setExitCode(1)
114
- } finally {
115
- setRunning(false)
116
- }
117
- }
118
-
119
- const handleCreateScript = async () => {
120
- if (!newScriptName.trim()) return
121
- const name = newScriptName.endsWith(".mjs") || newScriptName.endsWith(".js") || newScriptName.endsWith(".py") || newScriptName.endsWith(".sh")
122
- ? newScriptName
123
- : `${newScriptName}.mjs`
124
-
125
- setScriptLoading(true)
126
- try {
127
- const defaultCode = name.endsWith(".py")
128
- ? "#!/usr/bin/env python3\nprint('Hello from Total Recall automation!')\n"
129
- : name.endsWith(".sh")
130
- ? "#!/bin/bash\necho 'Hello from Total Recall automation!'\n"
131
- : "/**\n * Total Recall skills automation script\n */\nconsole.log(\"Hello from Total Recall automation!\");\n"
132
-
133
- await saveScript(name, defaultCode)
134
- setNewScriptName("")
135
- setIsCreatingScript(false)
136
- await fetchScriptsList()
137
-
138
- // Yield to the event loop to ensure React state (scripts list)
139
- // is fully committed to the DOM before selecting it.
140
- setTimeout(() => {
141
- handleSelectScript(name).catch(console.error)
142
- }, 0)
143
- } catch (e) {
144
- setError(`Failed to create script: ${(e as Error).message}`)
145
- } finally {
146
- setScriptLoading(false)
147
- }
148
- }
149
-
150
- return (
151
- <div className="page">
152
- <div className="page-header" style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", marginBottom: 20 }}>
153
- <div>
154
- <h1>Storage & Automations</h1>
155
- <p>Manage local files, runtime skills, and automation scripts</p>
156
- </div>
157
-
158
- {/* Navigation Tabs */}
159
- <div style={{ display: "flex", background: "rgba(255,255,255,0.03)", padding: 4, borderRadius: 8, border: "1px solid var(--border)" }}>
160
- <button
161
- className={`btn btn-sm ${activeTab === "files" ? "btn-purple" : "btn-ghost"}`}
162
- onClick={() => setActiveTab("files")}
163
- style={{ borderRadius: 6, fontSize: 12, padding: "6px 12px" }}
164
- >
165
- 📁 Storage
166
- </button>
167
- <button
168
- className={`btn btn-sm ${activeTab === "skills" ? "btn-purple" : "btn-ghost"}`}
169
- onClick={() => setActiveTab("skills")}
170
- style={{ borderRadius: 6, fontSize: 12, padding: "6px 12px" }}
171
- >
172
- 🧩 Skills
173
- </button>
174
- <button
175
- className={`btn btn-sm ${activeTab === "scripts" ? "btn-cyan" : "btn-ghost"}`}
176
- onClick={() => { setActiveTab("scripts"); setSelectedScript(null); }}
177
- style={{ borderRadius: 6, fontSize: 12, padding: "6px 12px" }}
178
- >
179
- ⚡ Scripts Editor
180
- </button>
181
- </div>
182
- </div>
183
-
184
- {error && <div className="badge badge-error" style={{ marginBottom: 16 }}>⚠️ {error}</div>}
185
-
186
- {activeTab === "files" && (
187
- <div className="health-log" style={{ background: "rgba(15,23,42,0.45)", backdropFilter: "blur(12px)", border: "1px solid var(--border)", borderRadius: 12, padding: 24 }}>
188
- <h2 style={{ fontSize: 16, marginBottom: 12, borderBottom: "1px solid var(--border)", paddingBottom: 8, color: "#fff" }}>Local Files (~/.agent/files/)</h2>
189
- <table style={{ width: "100%", textAlign: "left", borderCollapse: "collapse" }}>
190
- <thead>
191
- <tr>
192
- <th style={{ padding: "8px 12px", borderBottom: "1px solid var(--border)", color: "var(--text-tertiary)" }}>Name</th>
193
- <th style={{ padding: "8px 12px", borderBottom: "1px solid var(--border)", color: "var(--text-tertiary)" }}>Size</th>
194
- <th style={{ padding: "8px 12px", borderBottom: "1px solid var(--border)", color: "var(--text-tertiary)" }}>Modified</th>
195
- </tr>
196
- </thead>
197
- <tbody>
198
- {loading ? (
199
- <tr><td colSpan={3}><div className="skeleton" style={{ height: 20, margin: "8px 0" }}/></td></tr>
200
- ) : files.length === 0 ? (
201
- <tr><td colSpan={3} style={{ textAlign: "center", padding: 24, color: "var(--text-tertiary)" }}>Directory is empty</td></tr>
202
- ) : (
203
- files.map(f => (
204
- <tr key={f.name}>
205
- <td style={{ padding: "8px 12px", borderBottom: "1px solid var(--border)", color: "#fff" }}>
206
- {f.isDirectory ? "📁 " : "📄 "}{f.name}
207
- </td>
208
- <td style={{ padding: "8px 12px", borderBottom: "1px solid var(--border)" }}>
209
- {f.isDirectory ? "-" : formatBytes(f.size)}
210
- </td>
211
- <td style={{ padding: "8px 12px", borderBottom: "1px solid var(--border)" }}>
212
- {new Date(f.modified).toLocaleString()}
213
- </td>
214
- </tr>
215
- ))
216
- )}
217
- </tbody>
218
- </table>
219
- </div>
220
- )}
221
-
222
- {activeTab === "skills" && (
223
- <div className="health-log" style={{ background: "rgba(15,23,42,0.45)", backdropFilter: "blur(12px)", border: "1px solid var(--border)", borderRadius: 12, padding: 24 }}>
224
- <h2 style={{ fontSize: 16, marginBottom: 12, borderBottom: "1px solid var(--border)", paddingBottom: 8, color: "#fff" }}>Agent Skills (~/.agent/skills/)</h2>
225
- <table style={{ width: "100%", textAlign: "left", borderCollapse: "collapse" }}>
226
- <thead>
227
- <tr>
228
- <th style={{ padding: "8px 12px", borderBottom: "1px solid var(--border)", color: "var(--text-tertiary)" }}>Name</th>
229
- <th style={{ padding: "8px 12px", borderBottom: "1px solid var(--border)", color: "var(--text-tertiary)" }}>Size</th>
230
- <th style={{ padding: "8px 12px", borderBottom: "1px solid var(--border)", color: "var(--text-tertiary)" }}>Modified</th>
231
- </tr>
232
- </thead>
233
- <tbody>
234
- {loading ? (
235
- <tr><td colSpan={3}><div className="skeleton" style={{ height: 20, margin: "8px 0" }}/></td></tr>
236
- ) : skills.length === 0 ? (
237
- <tr><td colSpan={3} style={{ textAlign: "center", padding: 24, color: "var(--text-tertiary)" }}>No skills found</td></tr>
238
- ) : (
239
- skills.map(f => (
240
- <tr key={f.name}>
241
- <td style={{ padding: "8px 12px", borderBottom: "1px solid var(--border)", color: "#fff" }}>
242
- {f.isDirectory ? "🧩 " : "📄 "}{f.name}
243
- </td>
244
- <td style={{ padding: "8px 12px", borderBottom: "1px solid var(--border)" }}>
245
- {f.isDirectory ? "-" : formatBytes(f.size)}
246
- </td>
247
- <td style={{ padding: "8px 12px", borderBottom: "1px solid var(--border)" }}>
248
- {new Date(f.modified).toLocaleString()}
249
- </td>
250
- </tr>
251
- ))
252
- )}
253
- </tbody>
254
- </table>
255
- </div>
256
- )}
257
-
258
- {activeTab === "scripts" && (
259
- <div className="memory-layout" style={{ display: "flex", gap: 20, height: "calc(100vh - 220px)" }}>
260
- {/* Left panel: scripts list */}
261
- <div className="memory-sidebar" style={{ width: 260, flexShrink: 0, overflowY: "auto", display: "flex", flexDirection: "column", gap: 10, background: "rgba(15,23,42,0.3)", borderRadius: 8, padding: 16, border: "1px solid var(--border)" }}>
262
- <h3 style={{ margin: "0 0 8px 0", color: "#fff", fontSize: 14 }}>Scripts Directory</h3>
263
-
264
- {isCreatingScript ? (
265
- <div style={{ display: "flex", flexDirection: "column", gap: 8, marginBottom: 12 }}>
266
- <input
267
- type="text"
268
- placeholder="e.g. sync-rules.mjs"
269
- value={newScriptName}
270
- onChange={e => setNewScriptName(e.target.value)}
271
- style={{ width: "100%", background: "rgba(0,0,0,0.3)", border: "1px solid var(--border)", borderRadius: 4, padding: "6px 10px", color: "#fff", fontSize: 12 }}
272
- />
273
- <div style={{ display: "flex", gap: 6 }}>
274
- <button className="btn btn-purple btn-sm" onClick={handleCreateScript} style={{ fontSize: 11, flex: 1 }}>Add</button>
275
- <button className="btn btn-ghost btn-sm" onClick={() => setIsCreatingScript(false)} style={{ fontSize: 11, flex: 1 }}>Cancel</button>
276
- </div>
277
- </div>
278
- ) : (
279
- <button
280
- className="btn btn-purple btn-sm"
281
- onClick={() => setIsCreatingScript(true)}
282
- style={{ width: "100%", fontSize: 12, marginBottom: 12 }}
283
- >
284
- ➕ Create Script
285
- </button>
286
- )}
287
-
288
- <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
289
- {scripts.length === 0 ? (
290
- <div style={{ color: "var(--text-tertiary)", fontSize: 12, textAlign: "center", padding: 20 }}>No scripts found.</div>
291
- ) : (
292
- scripts.map(s => (
293
- <button
294
- key={s.name}
295
- className={`category-btn ${selectedScript === s.name ? "active" : ""}`}
296
- onClick={() => void handleSelectScript(s.name)}
297
- style={{ justifyContent: "space-between", width: "100%" }}
298
- >
299
- <span>⚡ {s.name}</span>
300
- <span style={{ fontSize: 9, opacity: 0.6 }}>{formatBytes(s.size)}</span>
301
- </button>
302
- ))
303
- )}
304
- </div>
305
- </div>
306
-
307
- {/* Right panel: script code editor & terminal runner */}
308
- <div style={{ flex: 1, display: "flex", flexDirection: "column", gap: 16, overflowY: "auto" }}>
309
- {selectedScript ? (
310
- <div style={{ display: "flex", flexDirection: "column", gap: 16, height: "100%" }}>
311
- {/* Script actions header */}
312
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", background: "rgba(15,23,42,0.45)", backdropFilter: "blur(12px)", border: "1px solid var(--border)", padding: "12px 20px", borderRadius: 8 }}>
313
- <div>
314
- <h3 style={{ margin: 0, color: "#fff", display: "flex", alignItems: "center", gap: 8 }}>
315
- <code>{selectedScript}</code>
316
- <span style={{ fontSize: 11, background: "rgba(6,182,212,0.15)", color: "#06b6d4", padding: "2px 8px", borderRadius: 4, textTransform: "uppercase" }}>Automation</span>
317
- </h3>
318
- </div>
319
- <div style={{ display: "flex", gap: 12 }}>
320
- <button className="btn btn-ghost btn-sm" disabled={scriptLoading} onClick={handleSaveScript}>💾 Save Script</button>
321
- <button className="btn btn-cyan btn-sm" disabled={running} onClick={handleRunScript}>
322
- {running ? "⚡ Executing..." : "⚡ Run Script"}
323
- </button>
324
- </div>
325
- </div>
326
-
327
- {/* Editor textarea and Terminal outputs split screen */}
328
- <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16, flex: 1, minHeight: 400 }}>
329
- {/* Visual Dark Editor */}
330
- <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
331
- <div style={{ fontSize: 11, textTransform: "uppercase", color: "var(--text-tertiary)", letterSpacing: 0.5 }}>Source Code Editor</div>
332
- <textarea
333
- disabled={scriptLoading}
334
- value={scriptContent}
335
- onChange={e => setScriptContent(e.target.value)}
336
- style={{
337
- flex: 1,
338
- background: "#030712",
339
- border: "1px solid var(--border)",
340
- borderRadius: 8,
341
- padding: 16,
342
- color: "#10b981",
343
- fontFamily: "monospace",
344
- fontSize: 13,
345
- lineHeight: 1.6,
346
- resize: "none",
347
- outline: "none"
348
- }}
349
- />
350
- </div>
351
-
352
- {/* Terminal stdout visual Console */}
353
- <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
354
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
355
- <span style={{ fontSize: 11, textTransform: "uppercase", color: "var(--text-tertiary)", letterSpacing: 0.5 }}>Dynamic Output Terminal</span>
356
- {exitCode !== null && (
357
- <span style={{ fontSize: 11, background: exitCode === 0 ? "rgba(34,197,94,0.15)" : "rgba(239,68,68,0.15)", color: exitCode === 0 ? "#22c55e" : "#ef4444", padding: "1px 6px", borderRadius: 4 }}>
358
- Exit Code: {exitCode}
359
- </span>
360
- )}
361
- </div>
362
- <pre style={{
363
- flex: 1,
364
- background: "#020617",
365
- border: "1px solid #1e293b",
366
- borderRadius: 8,
367
- padding: 16,
368
- color: "#38bdf8",
369
- fontFamily: "monospace",
370
- fontSize: 13,
371
- lineHeight: 1.6,
372
- overflowY: "auto",
373
- margin: 0,
374
- whiteSpace: "pre-wrap"
375
- }}>
376
- {terminalOutput || "Interactive runner ready. Click ⚡ Run Script to execute automations."}
377
- </pre>
378
- </div>
379
- </div>
380
- </div>
381
- ) : (
382
- <div style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", border: "1px dashed var(--border)", borderRadius: 8, color: "var(--text-tertiary)" }}>
383
- <span style={{ fontSize: 40, marginBottom: 12 }}>⚡</span>
384
- <h3>Automations Hub</h3>
385
- <p>Select a script from the sidebar directory to edit, update, or run securely inside the local sandbox environment.</p>
386
- </div>
387
- )}
388
- </div>
389
- </div>
390
- )}
391
- </div>
392
- )
393
- }