total-recall-brain 3.41.4 → 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 (147) hide show
  1. package/bin/total-recall.mjs +10 -6
  2. package/docs/reference/cli-reference.md +18 -0
  3. package/frontend/dist/assets/index-4tGQfTa2.js +5605 -0
  4. package/frontend/dist/assets/index-DtwsDyFM.css +1 -0
  5. package/frontend/dist/index.html +2 -2
  6. package/frontend/package.json +11 -0
  7. package/frontend/src/App.tsx +47 -122
  8. package/frontend/src/components/plugins/plugin-frame.ts +1 -0
  9. package/frontend/src/index.css +152 -86
  10. package/frontend/src/pages/HelpPage.tsx +13 -10
  11. package/frontend/src/pages/MemoryPage.tsx +28 -30
  12. package/frontend/src/pages/NetworkPage.tsx +3 -3
  13. package/frontend/src/pages/PluginsPage.tsx +6 -5
  14. package/frontend/src/pages/RulesPage.tsx +16 -12
  15. package/package.json +4 -3
  16. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +3114 -36
  17. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +4 -1
  18. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +3114 -36
  19. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +4 -1
  20. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +3121 -33
  21. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +4 -1
  22. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +3122 -34
  23. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +4 -1
  24. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +3127 -49
  25. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +5 -2
  26. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +1 -1
  27. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +136 -7
  28. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +135 -26
  29. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +3121 -33
  30. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +5 -2
  31. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +228 -9
  32. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +24 -30
  33. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +29 -16
  34. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +73 -0
  35. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +182 -365
  36. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +33 -0
  37. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +40 -14
  38. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +4 -4
  39. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/agy.mjs +187 -0
  40. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/claude.mjs +275 -0
  41. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cline.mjs +132 -0
  42. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/codex.mjs +187 -0
  43. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cursor.mjs +158 -0
  44. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/devin.mjs +157 -0
  45. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/dsh.mjs +183 -0
  46. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/grok.mjs +132 -0
  47. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/hermes.mjs +173 -0
  48. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/index.mjs +87 -0
  49. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/openclaw.mjs +173 -0
  50. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/pi.mjs +129 -0
  51. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate.mjs +12 -0
  52. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/json-reply.mjs +22 -0
  53. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +72 -70
  54. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/model-catalog.mjs +195 -0
  55. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/paths.mjs +11 -0
  56. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/pool.mjs +36 -0
  57. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/review.mjs +169 -0
  58. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +136 -346
  59. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +1 -1
  60. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/ssss-store.mjs +20 -0
  61. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/telemetry.mjs +43 -0
  62. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/threads.mjs +156 -0
  63. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +117 -35
  64. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worktree.mjs +51 -0
  65. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +398 -57
  66. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +304 -46
  67. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +367 -41
  68. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +5 -2
  69. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +33 -0
  70. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/config.mjs +2 -2
  71. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/generate.mjs +159 -0
  72. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/graph.mjs +197 -0
  73. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/lint.mjs +153 -0
  74. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/mesh-vaults.mjs +261 -0
  75. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +151 -4
  76. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/search.mjs +114 -0
  77. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/token.mjs +96 -0
  78. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +899 -662
  79. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/openwiki.mjs +8987 -0
  80. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/mermaid-diagrams/SKILL.md +44 -0
  81. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/write-connector/SKILL.md +56 -0
  82. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +3097 -81
  83. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +4 -1
  84. package/src/cli/agent.mjs +12 -1
  85. package/src/cli/compact.mjs +108 -0
  86. package/src/cli/connect.mjs +56 -1
  87. package/src/cli/context.mjs +55 -23
  88. package/src/cli/doctor.mjs +5 -2
  89. package/src/cli/forget.mjs +2 -0
  90. package/src/cli/harness.mjs +62 -50
  91. package/src/cli/memory-entry.mjs +2 -2
  92. package/src/cli/preflight.mjs +152 -16
  93. package/src/cli/release.mjs +386 -0
  94. package/src/cli/remember.mjs +19 -1
  95. package/src/cli/rules.mjs +54 -12
  96. package/src/cli/startup.mjs +1 -1
  97. package/src/cli/status.mjs +12 -2
  98. package/src/core/claude-hooks.mjs +41 -3
  99. package/src/core/cli-commands.mjs +2 -0
  100. package/src/core/cli-semantic-index.mjs +3 -2
  101. package/src/core/conflict-detector.mjs +23 -12
  102. package/src/core/context-compactor.mjs +145 -0
  103. package/src/core/context-policy.mjs +20 -0
  104. package/src/core/duplicate-guard.mjs +350 -0
  105. package/src/core/meta-harness.mjs +31 -11
  106. package/src/core/preflight-gate.mjs +2 -2
  107. package/src/core/preflight-receipt.mjs +29 -1
  108. package/src/core/scaffold-plugins.mjs +7 -0
  109. package/src/core/stdio-flush.mjs +23 -0
  110. package/src/core/surface.mjs +33 -10
  111. package/src/server/invoke-durability.mjs +39 -0
  112. package/src/server/invoke-write-child.mjs +25 -0
  113. package/src/server/routes/invoke.mjs +7 -0
  114. package/src/server/routes/plugins.mjs +2 -2
  115. package/frontend/dist/assets/index-BIQmqDKP.css +0 -1
  116. package/frontend/dist/assets/index-CRzjQLu7.js +0 -5631
  117. package/frontend/src/components/DaemonLogsTab.tsx +0 -54
  118. package/frontend/src/components/ResearchAgendaTab.tsx +0 -712
  119. package/frontend/src/components/TaskQueueTab.tsx +0 -193
  120. package/frontend/src/components/VoiceInput.tsx +0 -112
  121. package/frontend/src/pages/ChatPage.tsx +0 -1059
  122. package/frontend/src/pages/CollabPage.tsx +0 -470
  123. package/frontend/src/pages/DesignDocsPage.tsx +0 -621
  124. package/frontend/src/pages/FilesPage.tsx +0 -393
  125. package/frontend/src/pages/HealthPage.tsx +0 -359
  126. package/frontend/src/pages/InboxPage.tsx +0 -83
  127. package/frontend/src/pages/InstructionsPage.tsx +0 -583
  128. package/frontend/src/pages/IntegrationsPage.tsx +0 -761
  129. package/frontend/src/pages/MeshPage.css +0 -58
  130. package/frontend/src/pages/MeshPage.tsx +0 -1219
  131. package/frontend/src/pages/OkfPage.tsx +0 -535
  132. package/frontend/src/pages/SandboxPage.tsx +0 -113
  133. package/frontend/src/pages/SkillsPage.tsx +0 -1994
  134. package/frontend/src/pages/TasksPage.tsx +0 -427
  135. package/frontend/src/pages/UsagePage.tsx +0 -702
  136. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/README.md +0 -65
  137. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/cli.mjs +0 -76
  138. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/package.json +0 -19
  139. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/plugin.json +0 -266
  140. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/adapters/dsh.mjs +0 -446
  141. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/documentation.mjs +0 -152
  142. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/executor.mjs +0 -71
  143. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/runtime.mjs +0 -36
  144. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/setup.mjs +0 -35
  145. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/worker.mjs +0 -175
  146. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/DESIGN.md +0 -32
  147. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/card.js +0 -575
@@ -1,712 +0,0 @@
1
- import React, { Fragment, useState, useRef } from 'react'
2
- import { renderMarkdown, extractSources } from './MarkdownUtils'
3
- import type { MemoryNode } from '../types'
4
- import { patchResearch, deleteResearch, shareToApi } from '../api'
5
-
6
- export interface ResearchItem {
7
- id: string
8
- topic: string
9
- status: 'pending' | 'in_progress' | 'done' | 'failed' | 'paused'
10
- priority: 'low' | 'medium' | 'high' | 'critical'
11
- notes: string | null
12
- node_slug?: string | null
13
- research_phase?: string
14
- created_at: string
15
- updated_at: string
16
- /** 'user' = a human asked; 'autonomous' = background research for a project; 'legacy' = predates provenance. */
17
- origin?: 'user' | 'autonomous' | 'legacy'
18
- requested_via?: string | null
19
- project?: string | null
20
- rationale?: string | null
21
- }
22
-
23
- interface ResearchAgendaTabProps {
24
- researchItems: ResearchItem[]
25
- loading: boolean
26
- showResearchForm: boolean
27
- setShowResearchForm: (v: boolean) => void
28
- researchTopic: string
29
- setResearchTopic: (v: string) => void
30
- researchPriority: 'low' | 'medium' | 'high' | 'critical'
31
- setResearchPriority: (v: 'low' | 'medium' | 'high' | 'critical') => void
32
- researchNotes: string
33
- setResearchNotes: (v: string) => void
34
- researchSubmitting: boolean
35
- handleCreateResearch: (e: React.FormEvent) => void
36
- expandedResearchId: string | null
37
- handleToggleExpand: (item: ResearchItem) => void
38
- loadedDiscoveries: Record<string, MemoryNode | null>
39
- loadingNodeSlugs: Record<string, boolean>
40
- refreshResearch?: () => void
41
- }
42
-
43
- export default function ResearchAgendaTab(props: ResearchAgendaTabProps) {
44
- const {
45
- researchItems,
46
- loading,
47
- showResearchForm,
48
- setShowResearchForm,
49
- researchTopic,
50
- setResearchTopic,
51
- researchPriority,
52
- setResearchPriority,
53
- researchNotes,
54
- setResearchNotes,
55
- researchSubmitting,
56
- handleCreateResearch,
57
- expandedResearchId,
58
- handleToggleExpand,
59
- loadedDiscoveries,
60
- loadingNodeSlugs,
61
- refreshResearch,
62
- } = props
63
-
64
- const [steerTarget, setSteerTarget] = useState<string | null>(null)
65
- const steerRef = useRef<HTMLTextAreaElement>(null)
66
- const [expandedReports, setExpandedReports] = useState<Record<string, boolean>>({})
67
-
68
- const handlePatch = async (id: string, updates: Record<string, unknown>) => {
69
- try {
70
- await patchResearch(id, updates)
71
- refreshResearch?.()
72
- } catch (err) {
73
- console.error('Failed to update research:', err)
74
- }
75
- }
76
-
77
- const handleDelete = async (id: string) => {
78
- if (!confirm('Cancel this research project?')) return
79
- try {
80
- await deleteResearch(id)
81
- refreshResearch?.()
82
- } catch (err) {
83
- console.error('Failed to delete research:', err)
84
- }
85
- }
86
-
87
- const handleSteerSubmit = async () => {
88
- if (!steerTarget || !steerRef.current) return
89
- const direction = steerRef.current.value.trim()
90
- if (!direction) return
91
- try {
92
- await patchResearch(steerTarget, { notes: direction })
93
- setSteerTarget(null)
94
- refreshResearch?.()
95
- } catch (err) {
96
- console.error('Failed to steer research:', err)
97
- }
98
- }
99
-
100
-
101
- return (
102
- <div>
103
- <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
104
- <h3 style={{ margin: 0 }}>Vector Research agenda</h3>
105
- <button
106
- className="btn btn-sm btn-ghost"
107
- onClick={() => setShowResearchForm(!showResearchForm)}
108
- style={{ borderColor: 'var(--border)' }}
109
- >
110
- {showResearchForm ? 'Cancel' : '+ Queue Research Topic'}
111
- </button>
112
- </div>
113
-
114
- {/* Collapsible Research Form */}
115
- {showResearchForm && (
116
- <form onSubmit={handleCreateResearch} style={{
117
- background: 'var(--bg-secondary)',
118
- border: '1px solid var(--border)',
119
- borderRadius: 12,
120
- padding: 20,
121
- marginBottom: 20,
122
- display: 'flex',
123
- flexDirection: 'column',
124
- gap: 12
125
- }}>
126
- <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 16 }}>
127
- <label style={{ display: 'flex', flexDirection: 'column', gap: 6, fontSize: 12, color: 'var(--text-secondary)' }}>
128
- Research Query / Topic
129
- <input
130
- type="text"
131
- required
132
- placeholder="e.g. Bun vs Node.js HTTP clustering performance benchmarks"
133
- value={researchTopic}
134
- onChange={e => setResearchTopic(e.target.value)}
135
- style={{
136
- padding: '8px 10px',
137
- borderRadius: 8,
138
- background: 'var(--bg-primary)',
139
- color: 'var(--text-primary)',
140
- border: '1px solid var(--border)',
141
- outline: 'none'
142
- }}
143
- />
144
- </label>
145
- <label style={{ display: 'flex', flexDirection: 'column', gap: 6, fontSize: 12, color: 'var(--text-secondary)' }}>
146
- Agenda Priority
147
- <select
148
- value={researchPriority}
149
- onChange={e => setResearchPriority(e.target.value as 'low' | 'medium' | 'high' | 'critical')}
150
- style={{
151
- padding: '8px 10px',
152
- borderRadius: 8,
153
- background: 'var(--bg-primary)',
154
- color: 'var(--text-primary)',
155
- border: '1px solid var(--border)',
156
- outline: 'none'
157
- }}
158
- >
159
- <option value="low">Low</option>
160
- <option value="medium">Medium</option>
161
- <option value="high">High</option>
162
- <option value="critical">Critical</option>
163
- </select>
164
- </label>
165
- </div>
166
- <label style={{ display: 'flex', flexDirection: 'column', gap: 6, fontSize: 12, color: 'var(--text-secondary)' }}>
167
- Target Gaps / Reference Notes
168
- <textarea
169
- placeholder="Identify specific APIs, libraries or cutoff dates..."
170
- value={researchNotes}
171
- onChange={e => setResearchNotes(e.target.value)}
172
- style={{
173
- padding: '10px',
174
- borderRadius: 8,
175
- background: 'var(--bg-primary)',
176
- color: 'var(--text-primary)',
177
- border: '1px solid var(--border)',
178
- outline: 'none',
179
- minHeight: 80,
180
- resize: 'vertical'
181
- }}
182
- />
183
- </label>
184
- <button
185
- type="submit"
186
- className="btn btn-primary"
187
- disabled={researchSubmitting || !researchTopic.trim()}
188
- style={{ alignSelf: 'flex-end', minWidth: 120 }}
189
- >
190
- {researchSubmitting ? 'Queueing...' : 'Add to Agenda'}
191
- </button>
192
- </form>
193
- )}
194
-
195
- {/* Research Agenda Table */}
196
- <div style={{ overflowX: 'auto', border: '1px solid var(--border)', borderRadius: 12, background: 'var(--bg-secondary)' }}>
197
- <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
198
- <thead>
199
- <tr style={{ borderBottom: '1px solid var(--border)', color: 'var(--text-secondary)', textAlign: 'left', background: 'rgba(255, 255, 255, 0.02)' }}>
200
- <th style={{ padding: '12px 16px', width: 40, textAlign: 'center' }}></th>
201
- <th style={{ padding: '12px 16px' }}>Research Topic</th>
202
- <th style={{ padding: '12px 16px', width: 100 }}>Priority</th>
203
- <th style={{ padding: '12px 16px', width: 120 }}>Status</th>
204
- <th style={{ padding: '12px 16px', width: 160 }}>Updated At</th>
205
- </tr>
206
- </thead>
207
- <tbody>
208
- {loading && researchItems.length === 0 ? (
209
- <tr>
210
- <td colSpan={5} style={{ textAlign: 'center', padding: 24, color: 'var(--text-tertiary)' }}>Loading agenda...</td>
211
- </tr>
212
- ) : researchItems.length === 0 ? (
213
- <tr>
214
- <td colSpan={5} style={{ textAlign: 'center', padding: 40, color: 'var(--text-tertiary)' }}>
215
- No active research topics queued.
216
- </td>
217
- </tr>
218
- ) : (
219
- researchItems.map(item => {
220
- const isExpanded = expandedResearchId === item.id;
221
- const node = item.node_slug ? loadedDiscoveries[item.node_slug] : null;
222
- const isNodeLoading = item.node_slug ? loadingNodeSlugs[item.node_slug] : false;
223
-
224
- return (
225
- <Fragment key={item.id}>
226
- <tr
227
- onClick={() => handleToggleExpand(item)}
228
- style={{
229
- borderBottom: isExpanded ? 'none' : '1px solid var(--border)',
230
- cursor: 'pointer',
231
- background: isExpanded ? 'rgba(255, 255, 255, 0.015)' : 'transparent',
232
- transition: 'background 0.2s ease',
233
- }}
234
- >
235
- <td style={{ padding: '14px 16px', textAlign: 'center', color: 'var(--text-tertiary)' }}>
236
- <span style={{
237
- display: 'inline-block',
238
- transform: isExpanded ? 'rotate(90deg)' : 'rotate(0deg)',
239
- transition: 'transform 0.2s',
240
- fontSize: 10
241
- }}>
242
- ▶
243
- </span>
244
- </td>
245
- <td style={{ padding: '14px 16px' }}>
246
- <div style={{ fontWeight: 600, color: 'var(--text-primary)' }}>{item.topic}</div>
247
- {(item.origin === 'autonomous' || item.origin === 'user') && (
248
- <div
249
- style={{ fontSize: 11, color: 'var(--text-tertiary)', marginTop: 2 }}
250
- title={item.origin === 'autonomous' ? item.rationale || undefined : undefined}
251
- >
252
- {item.origin === 'autonomous'
253
- ? `Background research${item.project ? ` for ${item.project}` : ''}`
254
- : `You asked${item.requested_via ? ` · ${item.requested_via}` : ''}`}
255
- </div>
256
- )}
257
- {item.notes && (
258
- <div style={{ fontSize: 12, color: 'var(--text-secondary)', marginTop: 4 }}>
259
- {item.notes}
260
- </div>
261
- )}
262
- </td>
263
- <td style={{ padding: '14px 16px' }}>
264
- <span className={`badge ${
265
- item.priority === 'critical' ? 'badge-error' :
266
- item.priority === 'high' ? 'badge-accent' :
267
- item.priority === 'medium' ? 'badge-warning' :
268
- 'badge-ghost'
269
- }`} style={{ fontSize: 11, textTransform: 'capitalize' }}>
270
- {item.priority}
271
- </span>
272
- </td>
273
- <td style={{ padding: '14px 16px' }}>
274
- <span className={`badge ${
275
- (item.node_slug && (item.status === 'pending' || item.status === 'in_progress')) || item.status === 'done' ? 'badge-success' :
276
- item.status === 'in_progress' ? 'badge-accent' :
277
- item.status === 'failed' ? 'badge-error' :
278
- 'badge-warning'
279
- }`} style={{ textTransform: 'capitalize', fontSize: 11 }}>
280
- {item.node_slug && (item.status === 'pending' || item.status === 'in_progress') ? 'Researched' : item.status.replace('_', ' ')}
281
- </span>
282
- </td>
283
- <td style={{ padding: '14px 16px', color: 'var(--text-tertiary)', fontSize: 12 }}>
284
- {new Date(item.updated_at).toLocaleString([], { dateStyle: 'short', timeStyle: 'short' })}
285
- </td>
286
- </tr>
287
- {isExpanded && (
288
- <tr style={{ borderBottom: '1px solid var(--border)', background: 'rgba(255, 255, 255, 0.015)' }}>
289
- <td colSpan={5} style={{ padding: '0 24px 20px 24px' }}>
290
- <div style={{
291
- border: '1px solid rgba(255, 255, 255, 0.06)',
292
- borderRadius: 12,
293
- background: 'rgba(10, 10, 15, 0.4)',
294
- padding: 20,
295
- boxShadow: 'inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 4px 20px rgba(0, 0, 0, 0.3)',
296
- }}>
297
- <style dangerouslySetInnerHTML={{__html: `
298
- @keyframes pulse {
299
- 0% { transform: scale(0.95); opacity: 0.5; }
300
- 50% { transform: scale(1.05); opacity: 1; }
301
- 100% { transform: scale(0.95); opacity: 0.5; }
302
- }
303
- `}} />
304
-
305
- {/* Cognitive Stepper */}
306
- <div style={{ marginBottom: 20 }}>
307
- <div style={{ fontSize: 11, color: 'var(--text-tertiary)', textTransform: 'uppercase', letterSpacing: '0.05em', fontWeight: 600, marginBottom: 12 }}>
308
- Cognitive Research Engine Progress
309
- </div>
310
- <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(160px, 1fr))', gap: 12 }}>
311
- {[
312
- {
313
- title: 'Data Acquisition',
314
- phase: 'acquisition',
315
- icon: '🔍',
316
- desc: 'Deep multi-source crawling & LLM synthesis'
317
- },
318
- {
319
- title: 'Cognitive Deliberation',
320
- phase: 'deliberation',
321
- icon: '🧠',
322
- desc: 'System 2 context evaluation & insights'
323
- },
324
- {
325
- title: 'Clarity Auditing',
326
- phase: 'improvement',
327
- icon: '✨',
328
- desc: 'Markdown polish & premium layout restructuring'
329
- },
330
- ].map((step, idx) => {
331
- // Research ends after improvement: it never re-monitors or
332
- // spawns tangents (RESEARCH_SYSTEM2).
333
- const phases = ['acquisition', 'deliberation', 'improvement']
334
- const activePhase = item.research_phase || 'acquisition'
335
- const activeIndex = phases.indexOf(activePhase)
336
-
337
- let state: 'completed' | 'active' | 'waiting' | 'failed' | 'upcoming' = 'upcoming'
338
- if (item.status === 'done' || idx < activeIndex) {
339
- state = 'completed'
340
- } else if (idx === activeIndex) {
341
- if (item.status === 'in_progress') state = 'active'
342
- else if (item.status === 'pending') state = 'waiting'
343
- else if (item.status === 'failed') state = 'failed'
344
- else state = 'waiting'
345
- }
346
-
347
- let borderColor = 'rgba(255, 255, 255, 0.04)'
348
- let bgColor = 'rgba(255, 255, 255, 0.01)'
349
- let titleColor = 'var(--text-secondary)'
350
- let badgeBg = 'rgba(255, 255, 255, 0.02)'
351
- let statusText = 'Locked'
352
- let statusColor = 'var(--text-tertiary)'
353
- let isPulse = false
354
-
355
- if (state === 'completed') {
356
- borderColor = 'rgba(46, 204, 113, 0.25)'
357
- bgColor = 'rgba(46, 204, 113, 0.02)'
358
- titleColor = '#fff'
359
- badgeBg = 'rgba(46, 204, 113, 0.12)'
360
- statusText = '✓ Completed'
361
- statusColor = '#2ecc71'
362
- } else if (state === 'active') {
363
- borderColor = 'rgba(108, 92, 231, 0.45)'
364
- bgColor = 'rgba(108, 92, 231, 0.05)'
365
- titleColor = '#fff'
366
- badgeBg = 'rgba(108, 92, 231, 0.18)'
367
- statusText = '⚡ Running'
368
- statusColor = 'var(--accent)'
369
- isPulse = true
370
- } else if (state === 'waiting') {
371
- borderColor = 'rgba(241, 196, 15, 0.25)'
372
- bgColor = 'rgba(241, 196, 15, 0.02)'
373
- titleColor = 'var(--text-primary)'
374
- badgeBg = 'rgba(241, 196, 15, 0.1)'
375
- statusText = '⏳ Queued'
376
- statusColor = '#f1c40f'
377
- } else if (state === 'failed') {
378
- borderColor = 'rgba(231, 76, 60, 0.25)'
379
- bgColor = 'rgba(231, 76, 60, 0.02)'
380
- titleColor = 'var(--text-primary)'
381
- badgeBg = 'rgba(231, 76, 60, 0.1)'
382
- statusText = '⚠️ Failed'
383
- statusColor = '#e74c3c'
384
- }
385
-
386
- return (
387
- <div key={idx} style={{
388
- border: `1px solid ${borderColor}`,
389
- background: bgColor,
390
- borderRadius: 10,
391
- padding: 12,
392
- display: 'flex',
393
- flexDirection: 'column',
394
- gap: 6,
395
- transition: 'all 0.3s ease',
396
- position: 'relative'
397
- }}>
398
- <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
399
- <span style={{
400
- display: 'inline-flex',
401
- alignItems: 'center',
402
- justifyContent: 'center',
403
- width: 24,
404
- height: 24,
405
- borderRadius: '50%',
406
- background: badgeBg,
407
- fontSize: 12
408
- }}>
409
- {step.icon}
410
- </span>
411
- <span style={{
412
- fontSize: 10,
413
- fontWeight: 700,
414
- color: statusColor,
415
- display: 'inline-flex',
416
- alignItems: 'center',
417
- gap: 4
418
- }}>
419
- {isPulse && (
420
- <span style={{
421
- width: 6,
422
- height: 6,
423
- borderRadius: '50%',
424
- background: 'var(--accent)',
425
- animation: 'pulse 1.5s infinite ease-in-out'
426
- }} />
427
- )}
428
- {statusText}
429
- </span>
430
- </div>
431
- <div style={{ fontSize: 12, fontWeight: 600, color: titleColor }}>
432
- {idx + 1}. {step.title}
433
- </div>
434
- <div style={{ fontSize: 10, color: 'var(--text-tertiary)', lineHeight: 1.3 }}>
435
- {step.desc}
436
- </div>
437
- </div>
438
- )
439
- })}
440
- </div>
441
- </div>
442
-
443
- <hr style={{ border: 'none', borderTop: '1px solid rgba(255, 255, 255, 0.06)', margin: '20px 0' }} />
444
-
445
- {/* Lifecycle Control Buttons */}
446
- <div style={{ display: 'flex', gap: '8px', padding: '0 0 16px', flexWrap: 'wrap' }}>
447
- {item.status === 'in_progress' && (
448
- <button className="btn btn-sm" onClick={(e) => { e.stopPropagation(); handlePatch(item.id, { status: 'paused' }) }}>⏸ Pause</button>
449
- )}
450
- {(item.status === 'paused' || item.status === 'failed') && (
451
- <button className="btn btn-sm" onClick={(e) => { e.stopPropagation(); handlePatch(item.id, { status: 'pending' }) }}>▶️ Resume</button>
452
- )}
453
- {item.status === 'done' && (
454
- <button className="btn btn-sm" onClick={(e) => { e.stopPropagation(); handlePatch(item.id, { status: 'pending', research_phase: 'acquisition' }) }}>🔄 Re-run</button>
455
- )}
456
- <button className="btn btn-sm" onClick={(e) => { e.stopPropagation(); setSteerTarget(item.id) }}>🎯 Steer</button>
457
- {item.status !== 'done' && (
458
- <button className="btn btn-sm" onClick={(e) => { e.stopPropagation(); handlePatch(item.id, { status: 'done' }) }}>✅ Conclude</button>
459
- )}
460
- <button className="btn btn-sm" style={{ borderColor: 'var(--error)', color: 'var(--error)' }} onClick={(e) => { e.stopPropagation(); handleDelete(item.id) }}>❌ Cancel</button>
461
- </div>
462
-
463
- {item.node_slug ? (
464
- <>
465
- {isNodeLoading ? (
466
- <div style={{ display: 'flex', alignItems: 'center', gap: 10, color: 'var(--text-secondary)' }}>
467
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" style={{ animation: 'spin 1s linear infinite' }}>
468
- <path d="M21 12a9 9 0 1 1-6.219-8.56"/>
469
- </svg>
470
- <span>Reading memory node and cataloging discoveries...</span>
471
- </div>
472
- ) : node ? (
473
- <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
474
- {item.status === 'in_progress' && (
475
- <div style={{
476
- display: 'flex',
477
- alignItems: 'center',
478
- gap: 8,
479
- background: 'rgba(108, 92, 231, 0.1)',
480
- border: '1px solid rgba(108, 92, 231, 0.2)',
481
- borderRadius: 8,
482
- padding: '8px 12px',
483
- fontSize: 12,
484
- color: 'var(--accent)',
485
- marginBottom: 4
486
- }}>
487
- <span className="pulse" style={{ background: 'var(--accent)', width: 8, height: 8, borderRadius: '50%', display: 'inline-block' }} />
488
- <span>Fact-seeker agents are currently updating this topic in the background. Previous discoveries are displayed below.</span>
489
- </div>
490
- )}
491
- {item.status === 'pending' && (
492
- <div style={{
493
- display: 'flex',
494
- alignItems: 'center',
495
- gap: 8,
496
- background: 'rgba(241, 196, 15, 0.1)',
497
- border: '1px solid rgba(241, 196, 15, 0.2)',
498
- borderRadius: 8,
499
- padding: '8px 12px',
500
- fontSize: 12,
501
- color: 'var(--warning)',
502
- marginBottom: 4
503
- }}>
504
- <span>⏳</span>
505
- <span>Scheduled for automatic refresh. Previous discoveries are displayed below.</span>
506
- </div>
507
- )}
508
- <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', flexWrap: 'wrap', gap: 12, borderBottom: '1px solid rgba(255, 255, 255, 0.06)', paddingBottom: 12 }}>
509
- <div>
510
- <h4 style={{ margin: 0, fontSize: 15, fontWeight: 700, color: '#fff' }}>{node.title}</h4>
511
- <div style={{ display: 'flex', gap: 8, marginTop: 6, alignItems: 'center' }}>
512
- <span className="badge badge-accent" style={{ fontSize: 10, padding: '2px 8px' }}>{node.category}</span>
513
- {node.modality && <span className="badge" style={{ fontSize: 10, padding: '2px 8px', background: 'rgba(255,255,255,0.06)', color: 'var(--text-secondary)' }}>{node.modality}</span>}
514
- </div>
515
- </div>
516
-
517
- <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
518
- {node.importance !== undefined && (
519
- <div style={{ display: 'flex', alignItems: 'center', gap: 4, background: 'rgba(255, 255, 255, 0.03)', padding: '4px 8px', borderRadius: 6, fontSize: 11, color: 'var(--text-secondary)', border: '1px solid rgba(255,255,255,0.04)' }}>
520
- <span>⭐ Importance:</span>
521
- <span style={{ fontWeight: 600, color: '#fff' }}>{node.importance}/5</span>
522
- </div>
523
- )}
524
- {node.confidence !== undefined && (
525
- <div style={{
526
- display: 'flex',
527
- alignItems: 'center',
528
- gap: 4,
529
- background: node.confidence >= 0.9 ? 'rgba(0, 206, 201, 0.08)' : 'rgba(108, 92, 231, 0.08)',
530
- border: `1px solid ${node.confidence >= 0.9 ? 'rgba(0, 206, 201, 0.3)' : 'rgba(108, 92, 231, 0.3)'}`,
531
- borderRadius: 6,
532
- padding: '4px 8px',
533
- fontSize: 11,
534
- color: node.confidence >= 0.9 ? 'var(--success)' : 'var(--accent)'
535
- }}>
536
- <span>✓ Confidence:</span>
537
- <span style={{ fontWeight: 600 }}>{(node.confidence * 100).toFixed(0)}%</span>
538
- </div>
539
- )}
540
- </div>
541
- </div>
542
-
543
- <div style={{ position: 'relative' }}>
544
- <div style={{
545
- maxHeight: expandedReports[item.id] ? 'none' : 500,
546
- overflow: 'hidden',
547
- paddingRight: 8,
548
- transition: 'max-height 0.3s ease',
549
- }}>
550
- <div style={{ fontSize: 13, color: 'var(--text-secondary)' }}>
551
- {renderMarkdown(node.content || node.body || '')}
552
- </div>
553
- </div>
554
- {!expandedReports[item.id] && (node.content || node.body || '').length > 800 && (
555
- <div style={{
556
- position: 'absolute',
557
- bottom: 0,
558
- left: 0,
559
- right: 0,
560
- height: 80,
561
- background: 'linear-gradient(transparent, rgba(10, 10, 15, 0.95))',
562
- pointerEvents: 'none',
563
- }} />
564
- )}
565
- </div>
566
- {(node.content || node.body || '').length > 800 && (
567
- <button
568
- className="btn btn-sm btn-ghost"
569
- onClick={(e) => {
570
- e.stopPropagation()
571
- setExpandedReports(prev => ({ ...prev, [item.id]: !prev[item.id] }))
572
- }}
573
- style={{ alignSelf: 'flex-start', marginTop: 8, fontSize: 12, color: 'var(--accent)' }}
574
- >
575
- {expandedReports[item.id] ? '▲ Show less' : '▼ Show more'}
576
- </button>
577
- )}
578
-
579
- {extractSources(node.content || node.body).length > 0 && (
580
- <div style={{ borderTop: '1px solid rgba(255, 255, 255, 0.06)', paddingTop: 12 }}>
581
- <div style={{ fontSize: 11, color: 'var(--text-tertiary)', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600, marginBottom: 8 }}>Sources & Citations</div>
582
- <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
583
- {extractSources(node.content || node.body).map((src, idx) => {
584
- const domain = (() => { try { return new URL(src.url).hostname.replace(/^www\./, '') } catch { return src.url } })()
585
- return (
586
- <div
587
- key={idx}
588
- style={{
589
- display: 'flex',
590
- alignItems: 'center',
591
- gap: 10,
592
- background: 'rgba(108, 92, 231, 0.06)',
593
- border: '1px solid rgba(108, 92, 231, 0.2)',
594
- borderRadius: 10,
595
- padding: '8px 14px',
596
- fontSize: 12,
597
- transition: 'all 0.2s',
598
- }}
599
- >
600
- <img
601
- src={`https://www.google.com/s2/favicons?domain=${domain}&sz=16`}
602
- width={16}
603
- height={16}
604
- alt=""
605
- style={{ borderRadius: 2, flexShrink: 0 }}
606
- />
607
- <div style={{ display: 'flex', flexDirection: 'column', gap: 2, flex: 1, minWidth: 0 }}>
608
- <span style={{ fontWeight: 600, color: 'var(--text-primary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{src.text}</span>
609
- <span style={{ fontSize: 11, color: 'var(--text-tertiary)' }}>{domain}</span>
610
- </div>
611
- <a
612
- href={src.url}
613
- target="_blank"
614
- rel="noopener noreferrer"
615
- className="btn btn-sm"
616
- style={{ fontSize: 11, padding: '3px 10px', textDecoration: 'none', flexShrink: 0 }}
617
- onClick={(e) => e.stopPropagation()}
618
- >
619
- Open
620
- </a>
621
- <button
622
- className="btn btn-sm"
623
- style={{ fontSize: 11, padding: '3px 10px', flexShrink: 0 }}
624
- onClick={(e) => {
625
- e.stopPropagation()
626
- shareToApi({ url: src.url, action: 'research', title: src.text }).catch(console.error)
627
- }}
628
- >
629
- 🔬 Research deeper
630
- </button>
631
- </div>
632
- )
633
- })}
634
- </div>
635
- </div>
636
- )}
637
- </div>
638
- ) : (
639
- <div style={{ color: 'var(--text-tertiary)', fontSize: 13 }}>
640
- No memory synthesis node found for slug: <code>{item.node_slug}</code>
641
- </div>
642
- )}
643
- </>
644
- ) : (
645
- <>
646
- {item.status === 'pending' && (
647
- <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
648
- <div style={{ display: 'flex', alignItems: 'center', gap: 8, color: 'var(--warning)', fontWeight: 600, fontSize: 14 }}>
649
- <span>⏳</span> Queued for Ingestion
650
- </div>
651
- <p style={{ color: 'var(--text-secondary)', fontSize: 13, margin: 0 }}>
652
- This research topic is enqueued in the Cognitive Scheduler. The background fact-seeker daemon will systematically synthesize findings and catalog discoveries when processing background gaps.
653
- </p>
654
- </div>
655
- )}
656
-
657
- {item.status === 'in_progress' && (
658
- <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
659
- <div style={{ display: 'flex', alignItems: 'center', gap: 8, color: 'var(--accent)', fontWeight: 600, fontSize: 14 }}>
660
- <span className="pulse" style={{ background: 'var(--accent)' }} />
661
- Synthesizing Deep Discoveries...
662
- </div>
663
- <p style={{ color: 'var(--text-secondary)', fontSize: 13, margin: 0 }}>
664
- Fact-seeker agents are actively searching vector indexes, crawling target APIs, and structuring new domain schemas. Results will be verified by the System 2 consensus writer.
665
- </p>
666
- </div>
667
- )}
668
-
669
- {item.status === 'failed' && (
670
- <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
671
- <div style={{ display: 'flex', alignItems: 'center', gap: 8, color: 'var(--error)', fontWeight: 600, fontSize: 14 }}>
672
- <span>⚠️</span> Ingestion Boundary Encountered
673
- </div>
674
- <p style={{ color: 'var(--text-secondary)', fontSize: 13, margin: 0 }}>
675
- The research pipeline failed to produce high-confidence consensus conclusions or hit an instruction boundary. Check live cognitive console logs for execution specifics.
676
- </p>
677
- </div>
678
- )}
679
- </>
680
- )}
681
- </div>
682
- </td>
683
- </tr>
684
- )}
685
- </Fragment>
686
- )
687
- })
688
- )}
689
- </tbody>
690
- </table>
691
- </div>
692
-
693
- {/* Steer Modal Overlay */}
694
- {steerTarget && (
695
- <div style={{ position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, background: 'rgba(0,0,0,0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 1000 }}>
696
- <div style={{ background: 'var(--bg-secondary, #1e1e2e)', borderRadius: '12px', padding: '24px', maxWidth: '500px', width: '90%', border: '1px solid var(--border)' }}>
697
- <h3 style={{ margin: '0 0 12px' }}>🎯 Steer Research</h3>
698
- <textarea
699
- ref={steerRef}
700
- placeholder="Add direction... e.g. 'Focus more on pricing comparisons'"
701
- style={{ width: '100%', minHeight: '100px', borderRadius: '8px', padding: '12px', background: 'var(--bg-primary, #11111b)', color: 'inherit', border: '1px solid var(--border, #333)', outline: 'none', resize: 'vertical', boxSizing: 'border-box' }}
702
- />
703
- <div style={{ display: 'flex', gap: '8px', marginTop: '12px', justifyContent: 'flex-end' }}>
704
- <button className="btn btn-sm btn-ghost" onClick={() => setSteerTarget(null)}>Cancel</button>
705
- <button className="btn btn-sm btn-primary" onClick={handleSteerSubmit}>Submit</button>
706
- </div>
707
- </div>
708
- </div>
709
- )}
710
- </div>
711
- )
712
- }