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.
- package/bin/total-recall.mjs +7 -4
- package/frontend/dist/assets/index-4tGQfTa2.js +5605 -0
- package/frontend/dist/assets/index-DtwsDyFM.css +1 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/package.json +11 -0
- package/frontend/src/App.tsx +47 -122
- package/frontend/src/components/plugins/plugin-frame.ts +1 -0
- package/frontend/src/index.css +152 -86
- package/frontend/src/pages/HelpPage.tsx +13 -10
- package/frontend/src/pages/MemoryPage.tsx +28 -30
- package/frontend/src/pages/NetworkPage.tsx +3 -3
- package/frontend/src/pages/PluginsPage.tsx +6 -5
- package/frontend/src/pages/RulesPage.tsx +16 -12
- package/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +8 -8
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +3 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +8 -8
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +3 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +8 -8
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +3 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +8 -8
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +3 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +8 -8
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +4 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +136 -7
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +135 -26
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +8 -8
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +4 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +228 -9
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +24 -30
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +29 -16
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +73 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +182 -365
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +33 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +9 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/agy.mjs +187 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/claude.mjs +275 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cline.mjs +132 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/codex.mjs +187 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cursor.mjs +158 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/devin.mjs +157 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/dsh.mjs +183 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/grok.mjs +132 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/hermes.mjs +173 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/index.mjs +87 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/openclaw.mjs +173 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/pi.mjs +129 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate.mjs +12 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/json-reply.mjs +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +72 -70
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/model-catalog.mjs +195 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/paths.mjs +11 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/pool.mjs +36 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/review.mjs +169 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +136 -346
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/ssss-store.mjs +20 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/telemetry.mjs +43 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/threads.mjs +156 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +117 -35
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worktree.mjs +51 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +398 -57
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +10 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +3 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +42 -190
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/openwiki.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/mermaid-diagrams/SKILL.md +44 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/write-connector/SKILL.md +56 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +8 -8
- package/scaffold/.agent/skills/total-recall/plugins/security/package.json +3 -0
- package/src/cli/agent.mjs +12 -1
- package/src/cli/compact.mjs +2 -2
- package/src/cli/connect.mjs +56 -1
- package/src/cli/context.mjs +10 -7
- package/src/cli/doctor.mjs +5 -2
- package/src/cli/harness.mjs +62 -50
- package/src/cli/memory-entry.mjs +2 -2
- package/src/cli/preflight.mjs +152 -16
- package/src/cli/remember.mjs +19 -1
- package/src/cli/rules.mjs +54 -12
- package/src/cli/startup.mjs +1 -1
- package/src/cli/status.mjs +12 -2
- package/src/core/claude-hooks.mjs +41 -3
- package/src/core/cli-semantic-index.mjs +3 -2
- package/src/core/conflict-detector.mjs +23 -12
- package/src/core/context-compactor.mjs +2 -0
- package/src/core/context-policy.mjs +20 -0
- package/src/core/duplicate-guard.mjs +350 -0
- package/src/core/meta-harness.mjs +31 -11
- package/src/core/preflight-gate.mjs +2 -2
- package/src/core/preflight-receipt.mjs +28 -0
- package/src/core/scaffold-plugins.mjs +7 -0
- package/src/core/stdio-flush.mjs +23 -0
- package/src/core/surface.mjs +33 -10
- package/src/server/routes/plugins.mjs +2 -2
- package/frontend/dist/assets/index-BIQmqDKP.css +0 -1
- package/frontend/dist/assets/index-WT3gs-x6.js +0 -5631
- package/frontend/src/components/DaemonLogsTab.tsx +0 -54
- package/frontend/src/components/ResearchAgendaTab.tsx +0 -712
- package/frontend/src/components/TaskQueueTab.tsx +0 -193
- package/frontend/src/components/VoiceInput.tsx +0 -112
- package/frontend/src/pages/ChatPage.tsx +0 -1059
- package/frontend/src/pages/CollabPage.tsx +0 -470
- package/frontend/src/pages/DesignDocsPage.tsx +0 -621
- package/frontend/src/pages/FilesPage.tsx +0 -393
- package/frontend/src/pages/HealthPage.tsx +0 -359
- package/frontend/src/pages/InboxPage.tsx +0 -83
- package/frontend/src/pages/InstructionsPage.tsx +0 -583
- package/frontend/src/pages/IntegrationsPage.tsx +0 -761
- package/frontend/src/pages/MeshPage.css +0 -58
- package/frontend/src/pages/MeshPage.tsx +0 -1219
- package/frontend/src/pages/OkfPage.tsx +0 -535
- package/frontend/src/pages/SandboxPage.tsx +0 -113
- package/frontend/src/pages/SkillsPage.tsx +0 -1994
- package/frontend/src/pages/TasksPage.tsx +0 -427
- package/frontend/src/pages/UsagePage.tsx +0 -702
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/README.md +0 -65
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/cli.mjs +0 -76
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/package.json +0 -19
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/plugin.json +0 -266
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/adapters/dsh.mjs +0 -446
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/documentation.mjs +0 -152
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/executor.mjs +0 -71
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/runtime.mjs +0 -36
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/setup.mjs +0 -35
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/worker.mjs +0 -175
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/DESIGN.md +0 -32
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/card.js +0 -575
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react'
|
|
2
|
-
import { fetchHealth, checkUpdate, runUpdate, restartDaemon } from '../api'
|
|
3
|
-
import type { HealthData, UpdateCheckResult } from '../types'
|
|
4
|
-
|
|
5
|
-
function formatUptime(seconds: number): string {
|
|
6
|
-
const d = Math.floor(seconds / 86400)
|
|
7
|
-
const h = Math.floor((seconds % 86400) / 3600)
|
|
8
|
-
const m = Math.floor((seconds % 3600) / 60)
|
|
9
|
-
if (d > 0) return `${d}d ${h}h ${m}m`
|
|
10
|
-
if (h > 0) return `${h}h ${m}m`
|
|
11
|
-
return `${m}m ${seconds % 60}s`
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export default function HealthPage() {
|
|
15
|
-
const [health, setHealth] = useState<HealthData | null>(null)
|
|
16
|
-
const [error, setError] = useState('')
|
|
17
|
-
const [lastPoll, setLastPoll] = useState<Date | null>(null)
|
|
18
|
-
|
|
19
|
-
// Auto-Update States
|
|
20
|
-
const [updateInfo, setUpdateInfo] = useState<UpdateCheckResult | null>(null)
|
|
21
|
-
const [isUpdating, setIsUpdating] = useState(false)
|
|
22
|
-
const [showConfirmModal, setShowConfirmModal] = useState(false)
|
|
23
|
-
const [updateError, setUpdateError] = useState('')
|
|
24
|
-
const [isCheckingUpdate, setIsCheckingUpdate] = useState(false)
|
|
25
|
-
const [checkMessage, setCheckMessage] = useState('')
|
|
26
|
-
const [isRestartingDaemon, setIsRestartingDaemon] = useState(false)
|
|
27
|
-
const [daemonMessage, setDaemonMessage] = useState('')
|
|
28
|
-
|
|
29
|
-
const handleRestartDaemon = async () => {
|
|
30
|
-
setIsRestartingDaemon(true)
|
|
31
|
-
setDaemonMessage('')
|
|
32
|
-
try {
|
|
33
|
-
const res = await restartDaemon()
|
|
34
|
-
setDaemonMessage(res.message || 'Daemon restarted successfully')
|
|
35
|
-
setTimeout(() => setDaemonMessage(''), 4000)
|
|
36
|
-
const data = await fetchHealth()
|
|
37
|
-
setHealth(data)
|
|
38
|
-
} catch (e) {
|
|
39
|
-
setDaemonMessage(`Failed to restart daemon: ${(e as Error).message}`)
|
|
40
|
-
} finally {
|
|
41
|
-
setIsRestartingDaemon(false)
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const handleManualCheckUpdate = async () => {
|
|
46
|
-
setIsCheckingUpdate(true)
|
|
47
|
-
setCheckMessage('')
|
|
48
|
-
setUpdateError('')
|
|
49
|
-
try {
|
|
50
|
-
const data = await checkUpdate()
|
|
51
|
-
setUpdateInfo(data)
|
|
52
|
-
if (!data.updateAvailable) {
|
|
53
|
-
setCheckMessage(data.previewFeatures ? 'Preview features — running ahead of the public release.' : data.latestVersion ? 'Host package is up to date.' : 'Public release status unavailable.')
|
|
54
|
-
setTimeout(() => setCheckMessage(''), 3000)
|
|
55
|
-
}
|
|
56
|
-
} catch (e) {
|
|
57
|
-
setUpdateError(`Failed to check updates: ${(e as Error).message}`)
|
|
58
|
-
} finally {
|
|
59
|
-
setIsCheckingUpdate(false)
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
useEffect(() => {
|
|
64
|
-
let active = true
|
|
65
|
-
const poll = async () => {
|
|
66
|
-
try {
|
|
67
|
-
const data = await fetchHealth()
|
|
68
|
-
if (active) {
|
|
69
|
-
setHealth(data)
|
|
70
|
-
setError('')
|
|
71
|
-
setLastPoll(new Date())
|
|
72
|
-
}
|
|
73
|
-
} catch (e) {
|
|
74
|
-
if (active) setError((e as Error).message)
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
poll()
|
|
79
|
-
const interval = setInterval(poll, 5000)
|
|
80
|
-
|
|
81
|
-
// Check for updates
|
|
82
|
-
const checkVersion = async () => {
|
|
83
|
-
try {
|
|
84
|
-
const data = await checkUpdate()
|
|
85
|
-
if (active) setUpdateInfo(data)
|
|
86
|
-
} catch (e) {
|
|
87
|
-
console.error('Failed to check updates', e)
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
checkVersion()
|
|
91
|
-
const updateInterval = setInterval(checkVersion, 3600000)
|
|
92
|
-
|
|
93
|
-
return () => {
|
|
94
|
-
active = false;
|
|
95
|
-
clearInterval(interval);
|
|
96
|
-
clearInterval(updateInterval);
|
|
97
|
-
}
|
|
98
|
-
}, [])
|
|
99
|
-
|
|
100
|
-
const handleStartUpdate = async () => {
|
|
101
|
-
setShowConfirmModal(false)
|
|
102
|
-
setIsUpdating(true)
|
|
103
|
-
setUpdateError('')
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
const result = await runUpdate()
|
|
107
|
-
if (!result.success) {
|
|
108
|
-
setUpdateError(result.message || 'Package auto-update reported failures')
|
|
109
|
-
setIsUpdating(false)
|
|
110
|
-
return
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Multi-repo npm update does not reboot this host — show success, optional reload
|
|
114
|
-
setIsUpdating(false)
|
|
115
|
-
setCheckMessage(
|
|
116
|
-
result.message ||
|
|
117
|
-
'Registered projects updated. Restart daemon if you need new code running.',
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
// Refresh version check immediately so banner / badge clears
|
|
121
|
-
const refreshed = await checkUpdate().catch(() => null)
|
|
122
|
-
if (refreshed) {
|
|
123
|
-
setUpdateInfo(refreshed)
|
|
124
|
-
}
|
|
125
|
-
} catch (e) {
|
|
126
|
-
setUpdateError((e as Error).message)
|
|
127
|
-
setIsUpdating(false)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return (
|
|
132
|
-
<div className="page" style={{ position: 'relative' }}>
|
|
133
|
-
{isUpdating && (
|
|
134
|
-
<div style={{
|
|
135
|
-
position: 'fixed',
|
|
136
|
-
inset: 0,
|
|
137
|
-
background: 'rgba(13, 17, 23, 0.9)',
|
|
138
|
-
zIndex: 1000,
|
|
139
|
-
display: 'flex',
|
|
140
|
-
flexDirection: 'column',
|
|
141
|
-
alignItems: 'center',
|
|
142
|
-
justifyContent: 'center',
|
|
143
|
-
backdropFilter: 'blur(8px)',
|
|
144
|
-
animation: 'fadeIn 0.3s ease'
|
|
145
|
-
}}>
|
|
146
|
-
<div className="spinner" style={{
|
|
147
|
-
width: 50,
|
|
148
|
-
height: 50,
|
|
149
|
-
border: '4px solid var(--border)',
|
|
150
|
-
borderTopColor: 'var(--accent)',
|
|
151
|
-
borderRadius: '50%',
|
|
152
|
-
animation: 'spin 1s linear infinite',
|
|
153
|
-
marginBottom: 20
|
|
154
|
-
}} />
|
|
155
|
-
<h2 style={{ color: 'var(--text-primary)', marginBottom: 8 }}>Updating Total Recall...</h2>
|
|
156
|
-
<p style={{ color: 'var(--text-muted)', fontSize: 14 }}>Applying git changes, installing npm modules, and restarting daemon.</p>
|
|
157
|
-
<p style={{ color: 'var(--accent)', fontSize: 13, marginTop: 10 }}>Please do not close this window.</p>
|
|
158
|
-
</div>
|
|
159
|
-
)}
|
|
160
|
-
|
|
161
|
-
{showConfirmModal && (
|
|
162
|
-
<div style={{
|
|
163
|
-
position: 'fixed',
|
|
164
|
-
inset: 0,
|
|
165
|
-
background: 'rgba(0, 0, 0, 0.7)',
|
|
166
|
-
zIndex: 900,
|
|
167
|
-
display: 'flex',
|
|
168
|
-
alignItems: 'center',
|
|
169
|
-
justifyContent: 'center',
|
|
170
|
-
backdropFilter: 'blur(4px)',
|
|
171
|
-
padding: 20
|
|
172
|
-
}}>
|
|
173
|
-
<div className="card" style={{
|
|
174
|
-
maxWidth: 450,
|
|
175
|
-
width: '100%',
|
|
176
|
-
backgroundColor: 'var(--bg-surface)',
|
|
177
|
-
border: '1px solid var(--border)',
|
|
178
|
-
borderRadius: 12,
|
|
179
|
-
padding: 24,
|
|
180
|
-
boxShadow: '0 20px 40px rgba(0, 0, 0, 0.5)'
|
|
181
|
-
}}>
|
|
182
|
-
<h3 style={{ marginBottom: 12, color: 'var(--text-primary)' }}>Confirm Core Self-Update</h3>
|
|
183
|
-
<p style={{ color: 'var(--text-muted)', marginBottom: 20, fontSize: 14, lineHeight: 1.5 }}>
|
|
184
|
-
Install Total Recall {updateInfo?.latestVersion} where an update is needed. Newer preview versions are retained.
|
|
185
|
-
</p>
|
|
186
|
-
<div style={{ display: 'flex', gap: 12, justifyContent: 'flex-end' }}>
|
|
187
|
-
<button
|
|
188
|
-
className="btn btn-secondary"
|
|
189
|
-
onClick={() => setShowConfirmModal(false)}
|
|
190
|
-
style={{ padding: '8px 16px', borderRadius: 8 }}
|
|
191
|
-
>
|
|
192
|
-
Cancel
|
|
193
|
-
</button>
|
|
194
|
-
<button
|
|
195
|
-
className="btn btn-primary"
|
|
196
|
-
onClick={handleStartUpdate}
|
|
197
|
-
style={{ padding: '8px 16px', borderRadius: 8, background: 'var(--accent)' }}
|
|
198
|
-
>
|
|
199
|
-
Update Now
|
|
200
|
-
</button>
|
|
201
|
-
</div>
|
|
202
|
-
</div>
|
|
203
|
-
</div>
|
|
204
|
-
)}
|
|
205
|
-
|
|
206
|
-
<div className="page-header" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
207
|
-
<div>
|
|
208
|
-
<h1>System Health</h1>
|
|
209
|
-
<p>Live monitoring of your memory brain {lastPoll && <span>· Last poll: {lastPoll.toLocaleTimeString()}</span>}</p>
|
|
210
|
-
</div>
|
|
211
|
-
{updateInfo?.updateAvailable ? (
|
|
212
|
-
<div className="badge badge-success" style={{
|
|
213
|
-
display: 'flex',
|
|
214
|
-
alignItems: 'center',
|
|
215
|
-
gap: 12,
|
|
216
|
-
padding: '12px 18px',
|
|
217
|
-
borderRadius: 12,
|
|
218
|
-
background: 'rgba(63, 185, 80, 0.1)',
|
|
219
|
-
border: '1px solid rgba(63, 185, 80, 0.3)',
|
|
220
|
-
animation: 'pulse 2s infinite'
|
|
221
|
-
}}>
|
|
222
|
-
<span style={{ fontSize: 14, color: 'var(--text-primary)', fontWeight: 600 }}>
|
|
223
|
-
New version available: {updateInfo.latestVersion}
|
|
224
|
-
</span>
|
|
225
|
-
<button
|
|
226
|
-
className="btn btn-primary"
|
|
227
|
-
onClick={() => setShowConfirmModal(true)}
|
|
228
|
-
style={{
|
|
229
|
-
fontSize: 12,
|
|
230
|
-
padding: '6px 12px',
|
|
231
|
-
borderRadius: 6,
|
|
232
|
-
backgroundColor: '#3fb950',
|
|
233
|
-
color: '#fff',
|
|
234
|
-
border: 'none',
|
|
235
|
-
cursor: 'pointer',
|
|
236
|
-
fontWeight: 600
|
|
237
|
-
}}
|
|
238
|
-
>
|
|
239
|
-
Update Now
|
|
240
|
-
</button>
|
|
241
|
-
</div>
|
|
242
|
-
) : (
|
|
243
|
-
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
|
244
|
-
{checkMessage && (
|
|
245
|
-
<span style={{ color: '#3fb950', fontSize: 14, fontWeight: 500, animation: 'fadeIn 0.3s ease' }}>
|
|
246
|
-
{checkMessage}
|
|
247
|
-
</span>
|
|
248
|
-
)}
|
|
249
|
-
<button
|
|
250
|
-
className="btn btn-secondary"
|
|
251
|
-
disabled={isCheckingUpdate}
|
|
252
|
-
onClick={handleManualCheckUpdate}
|
|
253
|
-
style={{
|
|
254
|
-
fontSize: 13,
|
|
255
|
-
padding: '8px 16px',
|
|
256
|
-
borderRadius: 8,
|
|
257
|
-
cursor: 'pointer',
|
|
258
|
-
display: 'flex',
|
|
259
|
-
alignItems: 'center',
|
|
260
|
-
gap: 6
|
|
261
|
-
}}
|
|
262
|
-
>
|
|
263
|
-
{isCheckingUpdate ? 'Checking...' : 'Check for Updates'}
|
|
264
|
-
</button>
|
|
265
|
-
</div>
|
|
266
|
-
)}
|
|
267
|
-
</div>
|
|
268
|
-
|
|
269
|
-
{error && <div className="badge badge-error" style={{ marginBottom: 16 }}>⚠️ {error}</div>}
|
|
270
|
-
{updateError && <div className="badge badge-error" style={{ marginBottom: 16 }}>⚠️ Update failed: {updateError}</div>}
|
|
271
|
-
|
|
272
|
-
{health ? (
|
|
273
|
-
<>
|
|
274
|
-
<div className="health-grid">
|
|
275
|
-
<div className="stat-card healthy">
|
|
276
|
-
<div className="value" style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8 }}>
|
|
277
|
-
<span className="pulse" /> {health.status}
|
|
278
|
-
</div>
|
|
279
|
-
<div className="label">Status</div>
|
|
280
|
-
</div>
|
|
281
|
-
<div className="stat-card">
|
|
282
|
-
<div className="value" style={{ color: 'var(--accent)' }}>
|
|
283
|
-
{health.version} {updateInfo?.previewFeatures
|
|
284
|
-
? <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>(Preview features)</span>
|
|
285
|
-
: updateInfo?.latestVersion && !updateInfo.updateAvailable && <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>(Latest)</span>}
|
|
286
|
-
</div>
|
|
287
|
-
<div className="label">Version</div>
|
|
288
|
-
</div>
|
|
289
|
-
<div className="stat-card">
|
|
290
|
-
<div className="value" style={{ color: 'var(--text-primary)' }}>{formatUptime(health.uptime_seconds)}</div>
|
|
291
|
-
<div className="label">Uptime</div>
|
|
292
|
-
</div>
|
|
293
|
-
<div className="stat-card">
|
|
294
|
-
<div className="value" style={{ color: 'var(--text-primary)', fontSize: 16 }}>{new Date(health.timestamp).toLocaleString()}</div>
|
|
295
|
-
<div className="label">Server Time</div>
|
|
296
|
-
</div>
|
|
297
|
-
</div>
|
|
298
|
-
|
|
299
|
-
<div className="health-log">
|
|
300
|
-
<h3>System Info</h3>
|
|
301
|
-
<table>
|
|
302
|
-
<tbody>
|
|
303
|
-
<tr><th>Status</th><td>{health.status}</td></tr>
|
|
304
|
-
<tr><th>Version</th><td>{health.version}</td></tr>
|
|
305
|
-
<tr><th>Uptime</th><td>{formatUptime(health.uptime_seconds)}</td></tr>
|
|
306
|
-
<tr><th>Timestamp</th><td>{health.timestamp}</td></tr>
|
|
307
|
-
<tr>
|
|
308
|
-
<th>Daemon Status</th>
|
|
309
|
-
<td>
|
|
310
|
-
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>
|
|
311
|
-
<span style={{ fontWeight: 600 }}>{health.daemon || 'unknown'}</span>
|
|
312
|
-
<button
|
|
313
|
-
className="btn btn-secondary"
|
|
314
|
-
onClick={handleRestartDaemon}
|
|
315
|
-
disabled={isRestartingDaemon}
|
|
316
|
-
style={{
|
|
317
|
-
fontSize: 12,
|
|
318
|
-
padding: '4px 12px',
|
|
319
|
-
borderRadius: 6,
|
|
320
|
-
cursor: 'pointer'
|
|
321
|
-
}}
|
|
322
|
-
>
|
|
323
|
-
{isRestartingDaemon ? 'Restarting…' : 'Restart Daemon'}
|
|
324
|
-
</button>
|
|
325
|
-
</div>
|
|
326
|
-
{daemonMessage && (
|
|
327
|
-
<div style={{ fontSize: 12, color: daemonMessage.includes('Failed') ? '#ef4444' : '#3fb950', marginTop: 4 }}>
|
|
328
|
-
{daemonMessage}
|
|
329
|
-
</div>
|
|
330
|
-
)}
|
|
331
|
-
</td>
|
|
332
|
-
</tr>
|
|
333
|
-
{health.cli_agents && (
|
|
334
|
-
<tr><th>CLI Agents</th><td>{health.cli_agents.join(', ')}</td></tr>
|
|
335
|
-
)}
|
|
336
|
-
<tr><th>Polling</th><td>Every 5 seconds</td></tr>
|
|
337
|
-
</tbody>
|
|
338
|
-
</table>
|
|
339
|
-
</div>
|
|
340
|
-
</>
|
|
341
|
-
) : !error ? (
|
|
342
|
-
<div className="health-grid">
|
|
343
|
-
{[1, 2, 3, 4].map(i => <div key={i} className="skeleton" style={{ height: 100 }} />)}
|
|
344
|
-
</div>
|
|
345
|
-
) : null}
|
|
346
|
-
|
|
347
|
-
<style>{`
|
|
348
|
-
@keyframes spin {
|
|
349
|
-
0% { transform: rotate(0deg); }
|
|
350
|
-
100% { transform: rotate(360deg); }
|
|
351
|
-
}
|
|
352
|
-
@keyframes fadeIn {
|
|
353
|
-
from { opacity: 0; }
|
|
354
|
-
to { opacity: 1; }
|
|
355
|
-
}
|
|
356
|
-
`}</style>
|
|
357
|
-
</div>
|
|
358
|
-
)
|
|
359
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect, useCallback } from "react"
|
|
2
|
-
import { fetchDocs, readDoc, updateDoc, postDecision, type VaultDocument } from "../api"
|
|
3
|
-
import { DocumentTable } from "../components/DocumentTable"
|
|
4
|
-
|
|
5
|
-
export default function InboxPage({ activeBrainId }: { activeBrainId?: string }) {
|
|
6
|
-
const [items, setItems] = useState<VaultDocument[]>([])
|
|
7
|
-
const [loading, setLoading] = useState(true)
|
|
8
|
-
const [error, setError] = useState("")
|
|
9
|
-
|
|
10
|
-
const loadData = useCallback(async () => {
|
|
11
|
-
try {
|
|
12
|
-
setLoading(true)
|
|
13
|
-
const data = await fetchDocs(activeBrainId, { status: "pending_approval" })
|
|
14
|
-
setItems(data.docs)
|
|
15
|
-
} catch (err: unknown) {
|
|
16
|
-
setError(err instanceof Error ? err.message : "Failed to load the approval inbox")
|
|
17
|
-
} finally {
|
|
18
|
-
setLoading(false)
|
|
19
|
-
}
|
|
20
|
-
}, [activeBrainId])
|
|
21
|
-
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
const timer = window.setTimeout(() => { void loadData() }, 0)
|
|
24
|
-
return () => window.clearTimeout(timer)
|
|
25
|
-
}, [loadData])
|
|
26
|
-
|
|
27
|
-
const handleDecision = async (path: string, action: string) => {
|
|
28
|
-
setError("")
|
|
29
|
-
try {
|
|
30
|
-
const doc = await readDoc(path, activeBrainId)
|
|
31
|
-
// Extract proposal ID from path (e.g. proposals/p2.md -> p2)
|
|
32
|
-
const idMatch = path.match(/proposals\/(.+?)\.md$/)
|
|
33
|
-
if (idMatch) {
|
|
34
|
-
const id = idMatch[1]
|
|
35
|
-
// This hits the proxy, which forwards to droplet and runs sync
|
|
36
|
-
await postDecision(id, action)
|
|
37
|
-
} else {
|
|
38
|
-
// Fallback for non-proposal docs (just optimistic update)
|
|
39
|
-
const newBody = doc.raw.replace(/status:.*$/m, `status: ${action}`)
|
|
40
|
-
await updateDoc(path, newBody, activeBrainId)
|
|
41
|
-
}
|
|
42
|
-
loadData()
|
|
43
|
-
} catch (err: unknown) {
|
|
44
|
-
setError("Decision failed: " + (err instanceof Error ? err.message : "Unknown error"))
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<div style={{ padding: '20px', maxWidth: '1200px', margin: '0 auto', color: 'white' }}>
|
|
50
|
-
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
|
|
51
|
-
<h1 style={{ margin: 0, fontSize: '24px' }}>Approval Inbox</h1>
|
|
52
|
-
<button onClick={loadData} style={{ padding: '8px 16px', background: 'rgba(255,255,255,0.1)', border: 'none', color: 'white', cursor: 'pointer', borderRadius: '4px' }}>Refresh</button>
|
|
53
|
-
</div>
|
|
54
|
-
|
|
55
|
-
{loading && <p>Loading inbox items...</p>}
|
|
56
|
-
{error && <p style={{ color: 'red' }}>Error: {error}</p>}
|
|
57
|
-
|
|
58
|
-
{!loading && !error && (
|
|
59
|
-
<div style={{ display: 'grid', gridTemplateColumns: '1fr', gap: '30px' }}>
|
|
60
|
-
<div>
|
|
61
|
-
<DocumentTable
|
|
62
|
-
data={items}
|
|
63
|
-
emptyMessage="No items pending approval."
|
|
64
|
-
columns={[
|
|
65
|
-
{ key: 'type', header: 'Type', render: (d) => <span style={{ opacity: 0.6 }}>{d.type}</span> },
|
|
66
|
-
{ key: 'name', header: 'Name', render: (d) => d.name },
|
|
67
|
-
{ key: 'status', header: 'Status', render: (d) => <span style={{ fontSize: '0.8em', background: 'rgba(234,179,8,0.15)', color: '#eab308', padding: '2px 6px', borderRadius: '4px' }}>{d.status || 'pending'}</span> },
|
|
68
|
-
{ key: 'updated', header: 'Last Updated', render: (d) => d.updatedAt ? new Date(d.updatedAt).toLocaleDateString() : '-' },
|
|
69
|
-
{ key: 'actions', header: 'Actions', render: (d) => (
|
|
70
|
-
<>
|
|
71
|
-
<button onClick={() => handleDecision(d.path, 'approved')} style={{ marginRight: '10px', background: '#22c55e', border: 'none', color: 'white', padding: '4px 8px', borderRadius: '4px', cursor: 'pointer' }}>Approve</button>
|
|
72
|
-
<button onClick={() => handleDecision(d.path, 'rejected')} style={{ background: '#e22b22', border: 'none', color: 'white', padding: '4px 8px', borderRadius: '4px', cursor: 'pointer' }}>Reject</button>
|
|
73
|
-
</>
|
|
74
|
-
)
|
|
75
|
-
}
|
|
76
|
-
]}
|
|
77
|
-
/>
|
|
78
|
-
</div>
|
|
79
|
-
</div>
|
|
80
|
-
)}
|
|
81
|
-
</div>
|
|
82
|
-
)
|
|
83
|
-
}
|