total-recall-brain 3.4.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/antigravity.mjs +19 -8
- package/bin/total-recall.mjs +3 -0
- package/extension/content-script.js +354 -11
- package/extension/popup/popup.html +5 -0
- package/extension/popup/popup.js +25 -0
- package/frontend/src/App.tsx +29 -0
- package/frontend/src/api.ts +40 -0
- package/frontend/src/pages/ChatPage.tsx +101 -8
- package/frontend/src/pages/CollabPage.tsx +470 -0
- package/frontend/src/pages/GraphPage.tsx +62 -0
- package/frontend/src/pages/HealthPage.tsx +185 -8
- package/frontend/src/pages/HelpPage.tsx +141 -0
- package/frontend/src/pages/SettingsPage.tsx +197 -2
- package/frontend/src/types.ts +16 -0
- package/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/research-queue.jsonl +1 -0
- package/src/cli/collab.mjs +49 -0
- package/src/cli/help.mjs +1 -1
- package/src/core/dream.mjs +41 -0
- package/src/core/runtime.mjs +30 -7
- package/src/core/schema.mjs +481 -0
- package/src/core/source-adapters.mjs +14 -6
- package/src/server/index.mjs +21 -1
- package/src/server/rest.mjs +158 -3
- package/src/server/route-manifest.json +12 -0
- package/src/server/routes/collab.mjs +286 -0
package/frontend/src/types.ts
CHANGED
|
@@ -159,5 +159,21 @@ export interface ConfigJson {
|
|
|
159
159
|
brain?: {
|
|
160
160
|
preferred_agent?: string
|
|
161
161
|
}
|
|
162
|
+
secrets?: {
|
|
163
|
+
google_api_key?: string
|
|
164
|
+
anthropic_api_key?: string
|
|
165
|
+
openai_api_key?: string
|
|
166
|
+
tavily_api_key?: string
|
|
167
|
+
brave_api_key?: string
|
|
168
|
+
exa_api_key?: string
|
|
169
|
+
serper_api_key?: string
|
|
170
|
+
github_token?: string
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface UpdateCheckResult {
|
|
175
|
+
currentVersion: string
|
|
176
|
+
latestVersion: string
|
|
177
|
+
updateAvailable: boolean
|
|
162
178
|
}
|
|
163
179
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "total-recall-brain",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "Sovereign AI system — database-free, SSSS-powered personal intelligence engine deployable to any POSIX host.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -65,7 +65,8 @@
|
|
|
65
65
|
"jsonwebtoken": "^9.0.3",
|
|
66
66
|
"natural": "^8.1.1",
|
|
67
67
|
"yaml": "^2.9.0",
|
|
68
|
-
"zod": "^4.4.3"
|
|
68
|
+
"zod": "^4.4.3",
|
|
69
|
+
"ws": "^8.18.0"
|
|
69
70
|
},
|
|
70
71
|
"devDependencies": {
|
|
71
72
|
"skills": "^1.5.7",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"id":"0efa65c2-0231-4267-a304-e0285e50011e","topic":"Total Recall repository improvement research: SSSS validated write pipeline, filesystem-native memory engines, local-first semantic indexing, Express 5 API hardening, 2026 agent memory architecture patterns","status":"pending","priority":"high","notes":"Queued from repo-wide analysis request on 2026-06-01. Focus on current best practices and meta-patterns for filesystem-native memory OS, validated operation envelopes, append-only logs, cache invalidation, research queue architecture, and secure local-first AI tools.","node_slug":null,"research_phase":"acquisition","created_at":"2026-06-01T06:07:40.102Z","updated_at":"2026-06-01T06:07:40.126Z","completed_at":null,"summary":{"id":"0efa65c2-0231-4267-a304-e0285e50011e","topic":"Total Recall repository improvement research: SSSS validated write pipeline, filesystem-native memory engines, local-first semantic indexing, Express 5 API hardening, 2026 agent memory architecture patterns","status":"pending","phase":"acquisition","last_updated":"2026-06-01T06:07:40.126Z","conclusions":[],"ongoing_directions":["Research project is enqueued / in progress in phase: acquisition"],"sources_count":0}}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* total-recall collab
|
|
3
|
+
*
|
|
4
|
+
* Start the collaboration backend server and frontend development portal.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx total-recall collab
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { spawn } from 'node:child_process';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
|
|
14
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const COLLAB_DIR = path.join(__dirname, '..', '..', 'collab');
|
|
16
|
+
|
|
17
|
+
export default function collab(args) {
|
|
18
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
19
|
+
console.log(`
|
|
20
|
+
total-recall collab — Start collaboration workspace
|
|
21
|
+
|
|
22
|
+
Usage: total-recall collab [options]
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
--help Show this help
|
|
26
|
+
|
|
27
|
+
Starts the Express/WebSockets backend server and Vite frontend portal.
|
|
28
|
+
`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
console.log(` ⚡ Starting Total Recall collaboration workspace...`);
|
|
33
|
+
console.log(` Press Ctrl+C to stop.\n`);
|
|
34
|
+
|
|
35
|
+
const child = spawn('npm', ['run', 'dev'], {
|
|
36
|
+
cwd: COLLAB_DIR,
|
|
37
|
+
stdio: 'inherit',
|
|
38
|
+
shell: true,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
process.on('SIGINT', () => {
|
|
42
|
+
child.kill('SIGINT');
|
|
43
|
+
process.exit(0);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
child.on('exit', (code) => {
|
|
47
|
+
process.exit(code ?? 0);
|
|
48
|
+
});
|
|
49
|
+
}
|
package/src/cli/help.mjs
CHANGED
|
@@ -148,6 +148,6 @@ function printGeneralHelp() {
|
|
|
148
148
|
\x1b[1mAll Commands Available:\x1b[0m
|
|
149
149
|
\x1b[33minit\x1b[0m, \x1b[33msetup\x1b[0m, \x1b[33mstart\x1b[0m, \x1b[33mdeploy\x1b[0m, \x1b[33mdoctor\x1b[0m, \x1b[33mdream\x1b[0m, \x1b[33mlint\x1b[0m, \x1b[33mdaemon\x1b[0m, \x1b[33mbackup\x1b[0m, \x1b[33mrestore\x1b[0m, \x1b[33msync\x1b[0m, \x1b[33mstatus\x1b[0m,
|
|
150
150
|
\x1b[33mgenerate-pat\x1b[0m, \x1b[33mhash-password\x1b[0m, \x1b[33mreset-password\x1b[0m, \x1b[33mcompile\x1b[0m, \x1b[33mrebuild\x1b[0m, \x1b[33msnapshot\x1b[0m, \x1b[33mmigrate\x1b[0m,
|
|
151
|
-
\x1b[33mimport\x1b[0m, \x1b[33mingest\x1b[0m, \x1b[33mconnect\x1b[0m, \x1b[33mrelay\x1b[0m, \x1b[33muninstall\x1b[0m, \x1b[33mchat\x1b[0m, \x1b[33mremember\x1b[0m, \x1b[33mrecall\x1b[0m, \x1b[33mresearch\x1b[0m, \x1b[33mmap\x1b[0m, \x1b[33mbrain\x1b[0m, \x1b[33mskill\x1b[0m
|
|
151
|
+
\x1b[33mimport\x1b[0m, \x1b[33mingest\x1b[0m, \x1b[33mconnect\x1b[0m, \x1b[33mrelay\x1b[0m, \x1b[33muninstall\x1b[0m, \x1b[33mchat\x1b[0m, \x1b[33mremember\x1b[0m, \x1b[33mrecall\x1b[0m, \x1b[33mresearch\x1b[0m, \x1b[33mmap\x1b[0m, \x1b[33mbrain\x1b[0m, \x1b[33mskill\x1b[0m, \x1b[33mcollab\x1b[0m
|
|
152
152
|
`);
|
|
153
153
|
}
|
package/src/core/dream.mjs
CHANGED
|
@@ -137,6 +137,47 @@ export function autoPruneStorage(brainDir, vaultDir, conflictsDir) {
|
|
|
137
137
|
pruneDir(inboxDir, draftMaxAgeMs); // Keeps the local dev inbox fully clean of automatic research noise
|
|
138
138
|
if (conflictsDir) pruneDir(conflictsDir, draftMaxAgeMs);
|
|
139
139
|
|
|
140
|
+
// Prune scheduler tasks queue: move completed/failed ones to archive, delete archives older than logMaxAgeMs
|
|
141
|
+
const tasksQueueDir = path.join(brainDir, 'scheduler', 'queue');
|
|
142
|
+
const tasksArchiveDir = path.join(tasksQueueDir, 'archive');
|
|
143
|
+
if (fs.existsSync(tasksQueueDir)) {
|
|
144
|
+
try {
|
|
145
|
+
if (!fs.existsSync(tasksArchiveDir)) {
|
|
146
|
+
fs.mkdirSync(tasksArchiveDir, { recursive: true });
|
|
147
|
+
}
|
|
148
|
+
const files = fs.readdirSync(tasksQueueDir);
|
|
149
|
+
for (const file of files) {
|
|
150
|
+
if (!file.endsWith('.md')) continue;
|
|
151
|
+
const fullPath = path.join(tasksQueueDir, file);
|
|
152
|
+
try {
|
|
153
|
+
const raw = fs.readFileSync(fullPath, 'utf8');
|
|
154
|
+
const { data } = matter(raw);
|
|
155
|
+
if (data.status === 'completed' || data.status === 'failed') {
|
|
156
|
+
fs.renameSync(fullPath, path.join(tasksArchiveDir, file));
|
|
157
|
+
}
|
|
158
|
+
} catch (e) {
|
|
159
|
+
// ignore parsing/permission errors for individual files
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const archiveFiles = fs.readdirSync(tasksArchiveDir);
|
|
164
|
+
for (const file of archiveFiles) {
|
|
165
|
+
if (!file.endsWith('.md')) continue;
|
|
166
|
+
const fullPath = path.join(tasksArchiveDir, file);
|
|
167
|
+
try {
|
|
168
|
+
const stat = fs.statSync(fullPath);
|
|
169
|
+
if (now - stat.mtimeMs > logMaxAgeMs) {
|
|
170
|
+
fs.unlinkSync(fullPath);
|
|
171
|
+
}
|
|
172
|
+
} catch (e) {
|
|
173
|
+
// ignore
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
} catch (err) {
|
|
177
|
+
logger.warn('dream', `Failed to prune scheduler tasks: ${err.message}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
140
181
|
// Automatically prune transient planning files in every active/historical conversation folder,
|
|
141
182
|
// while permanently preserving the conversations/threads themselves (.system_generated)
|
|
142
183
|
try {
|
package/src/core/runtime.mjs
CHANGED
|
@@ -254,6 +254,27 @@ export async function callLocalRuntime(prompt, system, config) {
|
|
|
254
254
|
|
|
255
255
|
let lastError;
|
|
256
256
|
|
|
257
|
+
// Load dynamic secrets from secrets.enc to ensure changes take effect immediately without server restart
|
|
258
|
+
let dynamicSecrets = {};
|
|
259
|
+
try {
|
|
260
|
+
const pathsToCheck = [
|
|
261
|
+
path.join(process.cwd(), '.agent', 'secrets.enc'),
|
|
262
|
+
path.join(agentDir, 'secrets.enc'),
|
|
263
|
+
path.join(os.homedir(), '.agent', 'skills', 'total-recall', 'config', 'secrets.enc'),
|
|
264
|
+
path.join(agentDir, 'skills', 'total-recall', 'config', 'secrets.enc'),
|
|
265
|
+
];
|
|
266
|
+
for (const p of pathsToCheck) {
|
|
267
|
+
if (fs.existsSync(p)) {
|
|
268
|
+
try {
|
|
269
|
+
dynamicSecrets = JSON.parse(fs.readFileSync(p, 'utf8') || '{}');
|
|
270
|
+
if (Object.keys(dynamicSecrets).length > 0) {
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
} catch {}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
} catch {}
|
|
277
|
+
|
|
257
278
|
// Try agents in priority order with retry budget
|
|
258
279
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
259
280
|
const agent = attempt === 0 ? resolveAgent(config) : resolveAgent({
|
|
@@ -289,13 +310,15 @@ export async function callLocalRuntime(prompt, system, config) {
|
|
|
289
310
|
maxBuffer: 10 * 1024 * 1024,
|
|
290
311
|
env: {
|
|
291
312
|
...process.env,
|
|
292
|
-
GOOGLE_API_KEY: process.env.GOOGLE_API_KEY || process.env.GEMINI_API_KEY || googleApiKey,
|
|
293
|
-
GEMINI_API_KEY: process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY || googleApiKey,
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
313
|
+
GOOGLE_API_KEY: process.env.GOOGLE_API_KEY || process.env.GEMINI_API_KEY || dynamicSecrets.google_api_key || googleApiKey,
|
|
314
|
+
GEMINI_API_KEY: process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY || dynamicSecrets.google_api_key || googleApiKey,
|
|
315
|
+
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY || dynamicSecrets.anthropic_api_key,
|
|
316
|
+
OPENAI_API_KEY: process.env.OPENAI_API_KEY || dynamicSecrets.openai_api_key,
|
|
317
|
+
TAVILY_API_KEY: process.env.TAVILY_API_KEY || dynamicSecrets.tavily_api_key || tavilyApiKey,
|
|
318
|
+
BRAVE_API_KEY: process.env.BRAVE_API_KEY || dynamicSecrets.brave_api_key || braveApiKey,
|
|
319
|
+
EXA_API_KEY: process.env.EXA_API_KEY || dynamicSecrets.exa_api_key || exaApiKey,
|
|
320
|
+
SERPER_API_KEY: process.env.SERPER_API_KEY || dynamicSecrets.serper_api_key || serperApiKey,
|
|
321
|
+
GITHUB_TOKEN: process.env.GITHUB_TOKEN || dynamicSecrets.github_token || githubToken,
|
|
299
322
|
},
|
|
300
323
|
cwd: process.cwd(),
|
|
301
324
|
});
|