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,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
- }