total-recall-brain 3.1.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.
Files changed (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +173 -0
  3. package/bin/antigravity.mjs +212 -0
  4. package/bin/init.mjs +36 -0
  5. package/bin/oci-sniper.sh +69 -0
  6. package/bin/total-recall.mjs +229 -0
  7. package/docs/ARCHITECTURE.md +251 -0
  8. package/docs/IDE_INTEGRATION.md +112 -0
  9. package/package.json +71 -0
  10. package/scaffold/.agent/skills/total-recall/SKILL.md +195 -0
  11. package/scaffold/.agent/skills/total-recall/evals/evals.json +20 -0
  12. package/scaffold/.agent/skills/total-recall/memory-vault/concepts/cli-help-reference.md +145 -0
  13. package/scaffold/.agent/skills/total-recall/memory-vault/invariants/operating-instructions.md +75 -0
  14. package/scaffold/.agent/skills/total-recall/memory-vault/preferences/always-websearch-gap.md +16 -0
  15. package/scaffold/.agent/skills/total-recall/memory-vault/preferences/topic-research-sop.md +17 -0
  16. package/scaffold/.agent/skills/total-recall/references/api-reference.md +187 -0
  17. package/scaffold/.agent/skills/total-recall/references/architecture-reference.md +81 -0
  18. package/scaffold/.agent/skills/total-recall/references/cli-reference.md +103 -0
  19. package/scaffold/.agent/skills/total-recall/references/ssss-reference.md +88 -0
  20. package/scaffold/.agent/skills/total-recall/references/troubleshooting.md +68 -0
  21. package/scaffold/.agent/skills/total-recall/scripts/sync-repo.mjs +83 -0
  22. package/scaffold/.agent/skills/total-recall/skills/cli-agents/SKILL.md +122 -0
  23. package/scaffold/.agent/skills/total-recall/skills/cli-agents/agents.yml +27 -0
  24. package/scaffold/.agent/skills/total-recall/skills/cli-agents/references/antigravity.txt +20 -0
  25. package/scaffold/.agent/skills/total-recall/skills/cli-agents/references/claude.txt +58 -0
  26. package/scaffold/.agent/skills/total-recall/skills/cli-agents/references/codex.txt +81 -0
  27. package/scaffold/.agent/skills/total-recall/skills/cli-agents/references/gemini.txt +44 -0
  28. package/scaffold/.agent/skills/total-recall/skills/research/SKILL.md +337 -0
  29. package/scaffold/.agent/skills/total-recall/skills/skill/SKILL.md +281 -0
  30. package/scaffold/.agent/skills/total-recall/skills/skill/assets/skill-template/SKILL.md +20 -0
  31. package/scaffold/.agent/skills/total-recall/skills/skill/evals/evals.json +20 -0
  32. package/scaffold/.agent/skills/total-recall/skills/skill/hooks/on-skill-add.sh +14 -0
  33. package/scaffold/.agent/skills/total-recall/skills/skill/hooks/on-skill-delete.sh +14 -0
  34. package/scaffold/.agent/skills/total-recall/skills/skill/learnings/.gitkeep +0 -0
  35. package/scaffold/.agent/skills/total-recall/skills/skill/references/.gitkeep +0 -0
  36. package/scaffold/.agent/skills/total-recall/skills/skill/scripts/.gitkeep +0 -0
  37. package/scaffold/.agent/skills/total-recall/skills/skill/scripts/create-skill.sh +65 -0
  38. package/scaffold/.agent/skills/total-recall/skills/skill/scripts/enforce-skill-optimization.mjs +135 -0
  39. package/scaffold/.agent/skills/total-recall/skills/skill/scripts/find-skills.mjs +124 -0
  40. package/scaffold/.agent/skills/total-recall/skills/skill/scripts/scan-skill.mjs +207 -0
  41. package/scaffold/.agent/skills/total-recall/skills/skill/scripts/skill-watcher.mjs +64 -0
  42. package/scaffold/.agent/skills/total-recall/skills/skill/subagents/audit-all-skills.md +62 -0
  43. package/scaffold/.agent/skills/total-recall/skills/ssss/SKILL.md +27 -0
  44. package/scaffold/.agent/skills/total-recall/skills/ssss/evals/evals.json +17 -0
  45. package/scaffold/.agent/skills/total-recall/skills/ssss/references/ssss-spec.md +117 -0
  46. package/scaffold/.agent/skills/total-recall/skills/ssss/scripts/validate-schema.mjs +54 -0
  47. package/scaffold/.agent/skills/total-recall/skills/ssss/subagents/audit-ssss-node.md +9 -0
  48. package/scaffold/.agent/skills/total-recall/subagents/total-recall-diagnostician.md +13 -0
  49. package/src/cli/agent-dir.mjs +105 -0
  50. package/src/cli/backup.mjs +313 -0
  51. package/src/cli/brain.mjs +224 -0
  52. package/src/cli/chat.mjs +74 -0
  53. package/src/cli/config.mjs +247 -0
  54. package/src/cli/connect.mjs +872 -0
  55. package/src/cli/daemon.mjs +228 -0
  56. package/src/cli/deploy-ui.mjs +1793 -0
  57. package/src/cli/deploy.mjs +1726 -0
  58. package/src/cli/doctor.mjs +254 -0
  59. package/src/cli/dream.mjs +80 -0
  60. package/src/cli/forget.mjs +92 -0
  61. package/src/cli/friction.mjs +21 -0
  62. package/src/cli/generate-pat.mjs +65 -0
  63. package/src/cli/hash-password.mjs +22 -0
  64. package/src/cli/help.mjs +153 -0
  65. package/src/cli/import-rules.mjs +102 -0
  66. package/src/cli/ingest/index.mjs +318 -0
  67. package/src/cli/ingest/parsers/chrome-bookmarks.mjs +238 -0
  68. package/src/cli/ingest/parsers/google-keep.mjs +147 -0
  69. package/src/cli/ingest/parsers/search-history.mjs +142 -0
  70. package/src/cli/ingest/parsers/youtube-history.mjs +181 -0
  71. package/src/cli/ingest/utils/dedup.mjs +69 -0
  72. package/src/cli/ingest/utils/takeout-walker.mjs +101 -0
  73. package/src/cli/ingest.mjs +102 -0
  74. package/src/cli/init.mjs +736 -0
  75. package/src/cli/integration-dispatcher.mjs +128 -0
  76. package/src/cli/lint.mjs +166 -0
  77. package/src/cli/map.mjs +194 -0
  78. package/src/cli/migrate.mjs +87 -0
  79. package/src/cli/rebuild.mjs +88 -0
  80. package/src/cli/recall.mjs +219 -0
  81. package/src/cli/relay.mjs +518 -0
  82. package/src/cli/remember.mjs +306 -0
  83. package/src/cli/research.mjs +381 -0
  84. package/src/cli/reset-password.mjs +75 -0
  85. package/src/cli/restore.mjs +135 -0
  86. package/src/cli/setup.mjs +616 -0
  87. package/src/cli/share.mjs +180 -0
  88. package/src/cli/skill.mjs +313 -0
  89. package/src/cli/snapshot.mjs +108 -0
  90. package/src/cli/start.mjs +63 -0
  91. package/src/cli/status.mjs +296 -0
  92. package/src/cli/sync.mjs +383 -0
  93. package/src/cli/uninstall.mjs +613 -0
  94. package/src/cli/upgrade.mjs +141 -0
  95. package/src/cli/wizard.html +3682 -0
  96. package/src/core/blackboard.mjs +54 -0
  97. package/src/core/clarity-rewriter.mjs +770 -0
  98. package/src/core/conclusion-writer.mjs +259 -0
  99. package/src/core/config.mjs +277 -0
  100. package/src/core/conflict-detector.mjs +536 -0
  101. package/src/core/crypto.mjs +107 -0
  102. package/src/core/daemon-control.mjs +158 -0
  103. package/src/core/daemon-loop.mjs +364 -0
  104. package/src/core/dream.mjs +347 -0
  105. package/src/core/drift-detector.mjs +143 -0
  106. package/src/core/embeddings.mjs +632 -0
  107. package/src/core/emergency-alerts.mjs +137 -0
  108. package/src/core/evolution.mjs +107 -0
  109. package/src/core/fact-seeker.mjs +1602 -0
  110. package/src/core/friction.mjs +95 -0
  111. package/src/core/import-rules.mjs +308 -0
  112. package/src/core/inference-engine.mjs +367 -0
  113. package/src/core/logger.mjs +75 -0
  114. package/src/core/memory-layers.mjs +96 -0
  115. package/src/core/migrate.mjs +116 -0
  116. package/src/core/notifications.mjs +77 -0
  117. package/src/core/operation-validator.mjs +272 -0
  118. package/src/core/optimizer.mjs +330 -0
  119. package/src/core/pattern_detector.mjs +113 -0
  120. package/src/core/post-mortem.mjs +413 -0
  121. package/src/core/protect-instructions.mjs +148 -0
  122. package/src/core/quick-capture.mjs +145 -0
  123. package/src/core/research-queue.mjs +431 -0
  124. package/src/core/research.mjs +461 -0
  125. package/src/core/runtime.mjs +515 -0
  126. package/src/core/sandbox.mjs +163 -0
  127. package/src/core/scheduler.mjs +569 -0
  128. package/src/core/schema.mjs +333 -0
  129. package/src/core/search.mjs +219 -0
  130. package/src/core/semantic-index.mjs +276 -0
  131. package/src/core/session-watcher.mjs +850 -0
  132. package/src/core/snapshot.mjs +133 -0
  133. package/src/core/source-adapters.mjs +1038 -0
  134. package/src/core/steering.mjs +137 -0
  135. package/src/core/surface.mjs +444 -0
  136. package/src/core/task_runner.mjs +125 -0
  137. package/src/core/tts.mjs +142 -0
  138. package/src/core/usage-tracker.mjs +349 -0
  139. package/src/core/vault-cache.mjs +76 -0
  140. package/src/core/vault.mjs +273 -0
  141. package/src/core/watchdog.mjs +236 -0
  142. package/src/server/api.mjs +944 -0
  143. package/src/server/auth.mjs +410 -0
  144. package/src/server/index.mjs +868 -0
  145. package/src/server/keys.mjs +181 -0
  146. package/src/server/rest.mjs +1652 -0
  147. package/src/server/route-manifest.json +77 -0
  148. package/src/server/routes/_shared.mjs +93 -0
  149. package/src/server/routes/keys.mjs +55 -0
  150. package/src/server/routes/memory.mjs +249 -0
  151. package/src/server/routes/sessions.mjs +336 -0
  152. package/src/server/routes/share.mjs +138 -0
  153. package/src/server/tools.mjs +618 -0
  154. package/templates/Caddyfile +37 -0
  155. package/templates/com.totalrecall.backup.plist +42 -0
  156. package/templates/com.totalrecall.daemon.plist +40 -0
  157. package/templates/com.totalrecall.duckdns.plist +23 -0
  158. package/templates/com.totalrecall.server.plist +46 -0
  159. package/templates/default-config/budget.yml +6 -0
  160. package/templates/default-config/runtime.yml +11 -0
  161. package/templates/default-config/security.yml +53 -0
  162. package/templates/default-config/voice.yml +34 -0
  163. package/templates/obsidian-queries/conflicts.md +26 -0
  164. package/templates/obsidian-queries/daily.md +17 -0
  165. package/templates/obsidian-queries/index.md +38 -0
  166. package/templates/obsidian-queries/skills.md +14 -0
  167. package/templates/onboarding-interview.md +72 -0
  168. package/templates/skill_engineering.md +40 -0
  169. package/templates/total-recall-daemon.service +21 -0
  170. package/templates/total-recall-server.service +20 -0
@@ -0,0 +1,254 @@
1
+ /**
2
+ * total-recall doctor
3
+ *
4
+ * System diagnostic utility to pre-flight check all dependencies,
5
+ * hardware requirements, software binaries, port conflicts, and model servers
6
+ * before doing a full deployment or initialization.
7
+ *
8
+ * Usage:
9
+ * npx total-recall doctor
10
+ */
11
+
12
+ import fs from 'node:fs';
13
+ import os from 'node:os';
14
+ import path from 'node:path';
15
+ import net from 'node:net';
16
+ import child_process from 'node:child_process';
17
+
18
+ // ─── Formatting & UI Helpers ────────────────────────────────────────────────
19
+ function log(msg) { console.log(` ${msg}`); }
20
+ function logOk(msg) { console.log(` ✅ \x1b[32m${msg}\x1b[0m`); }
21
+ function logWarn(msg) { console.log(` ⚠️ \x1b[33m${msg}\x1b[0m`); }
22
+ function logFail(msg) { console.log(` ❌ \x1b[31m${msg}\x1b[0m`); }
23
+ function logInfo(msg) { console.log(` ℹ \x1b[34m${msg}\x1b[0m`); }
24
+
25
+ function hr() {
26
+ console.log(' ' + '─'.repeat(58));
27
+ }
28
+
29
+ function commandExists(cmd) {
30
+ if (!cmd || !/^[a-zA-Z0-9_-]+$/.test(cmd)) {
31
+ return false;
32
+ }
33
+ try {
34
+ child_process.execFileSync('which', [cmd], { stdio: 'ignore' });
35
+ return true;
36
+ } catch {
37
+ return false;
38
+ }
39
+ }
40
+
41
+ function getSystemRamGb() {
42
+ return Math.round(os.totalmem() / (1024 * 1024 * 1024));
43
+ }
44
+
45
+ function checkPort(port) {
46
+ return new Promise((resolve) => {
47
+ const server = net.createServer();
48
+ server.once('error', (err) => {
49
+ if (err.code === 'EADDRINUSE') {
50
+ resolve(false); // Port taken
51
+ } else {
52
+ resolve(true); // Other error (e.g. permission), treat as unavailable for binding
53
+ }
54
+ });
55
+ server.once('listening', () => {
56
+ server.close(() => resolve(true)); // Port free
57
+ });
58
+ server.listen(port, '127.0.0.1');
59
+ });
60
+ }
61
+
62
+ // ─── Main Doctor Routine ─────────────────────────────────────────────────────
63
+ export default async function doctor() {
64
+ console.log(`
65
+ ┌─────────────────────────────────────────────────────────┐
66
+ │ Total Recall System Doctor │
67
+ │ Pre-flighting sovereign runtime diagnostics... │
68
+ └─────────────────────────────────────────────────────────┘
69
+ `);
70
+
71
+ let warnings = 0;
72
+ let failures = 0;
73
+
74
+ // ── Step 1: System Hardware Check ──
75
+ hr();
76
+ logInfo('1. HARDWARE COMPATIBILITY DIAGNOSTICS');
77
+
78
+ const platform = os.platform();
79
+ const arch = os.arch();
80
+ const cpus = os.cpus().length;
81
+ const ramGb = getSystemRamGb();
82
+
83
+ log(`Platform: ${platform} (${arch})`);
84
+ log(`CPU Cores: ${cpus} threads`);
85
+ log(`Total Memory: ${ramGb} GB RAM`);
86
+
87
+ if (ramGb >= 4) {
88
+ logOk('System RAM is fully sufficient for headless CLI agent dispatch (≥4 GB)');
89
+ } else if (ramGb >= 2) {
90
+ logWarn(`System RAM (${ramGb} GB) is slightly low, but sufficient for headless execution.`);
91
+ warnings++;
92
+ } else {
93
+ logFail(`System RAM (${ramGb} GB) is critically low.`);
94
+ failures++;
95
+ }
96
+
97
+ // ── Step 2: Binary Dependencies ──
98
+ hr();
99
+ logInfo('2. SOFTWARE DEPENDENCY CHECK');
100
+
101
+ const dependencies = [
102
+ { name: 'git', required: true, desc: 'sync and backup operations' },
103
+ { name: 'curl', required: true, desc: 'REST communications & API fetches' },
104
+ { name: 'python3', required: true, desc: 'native SearXNG search engine' },
105
+ { name: 'pip3', required: false, desc: 'SearXNG package installation (fallback to python3 -m pip)' },
106
+ { name: 'caddy', required: false, desc: 'auto-TLS reverse proxying' },
107
+ { name: 'docker', required: false, desc: 'containerized fallback services' },
108
+ ];
109
+
110
+ for (const dep of dependencies) {
111
+ const present = commandExists(dep.name === 'pip3' ? 'pip' : dep.name);
112
+ if (present) {
113
+ logOk(`${dep.name.padEnd(8)}: Present`);
114
+ } else {
115
+ if (dep.required) {
116
+ logFail(`${dep.name.padEnd(8)}: MISSING — Required for ${dep.desc}`);
117
+ failures++;
118
+ } else {
119
+ logWarn(`${dep.name.padEnd(8)}: Missing (Optional — used for ${dep.desc})`);
120
+ warnings++;
121
+ }
122
+ }
123
+ }
124
+
125
+ // Check python venv capability
126
+ if (commandExists('python3')) {
127
+ try {
128
+ child_process.execSync('python3 -c "import venv"', { stdio: 'ignore' });
129
+ logOk('python-venv: Installed');
130
+ } catch {
131
+ logFail('python-venv: MISSING — Required for local SearXNG deployment');
132
+ log(' Tip: Run: apt-get install -y python3-venv');
133
+ failures++;
134
+ }
135
+ }
136
+
137
+ // ── Step 3: Network Port Conflicts ──
138
+ hr();
139
+ logInfo('3. NETWORKING PORT AVAILABILITY');
140
+
141
+ const ports = [
142
+ { num: 3000, desc: 'Total Recall API Server', critical: true },
143
+ { num: 8888, desc: 'SearXNG Web Search Engine', critical: false },
144
+ { num: 80, desc: 'HTTP Caddy redirection (Let\'s Encrypt)', critical: false },
145
+ { num: 443, desc: 'HTTPS Caddy TLS ingress', critical: false },
146
+ ];
147
+
148
+ for (const port of ports) {
149
+ const free = await checkPort(port.num);
150
+ if (free) {
151
+ logOk(`Port ${String(port.num).padEnd(5)}: Free (${port.desc})`);
152
+ } else {
153
+ if (port.critical) {
154
+ logFail(`Port ${String(port.num).padEnd(5)}: CONFLICT — Already bound by another service (${port.desc})`);
155
+ failures++;
156
+ } else {
157
+ logWarn(`Port ${String(port.num).padEnd(5)}: In use (${port.desc})`);
158
+ warnings++;
159
+ }
160
+ }
161
+ }
162
+
163
+ // ── Step 4: CLI Agents & Embeddings Providers ──
164
+ hr();
165
+ logInfo('4. CLI AGENTS & EMBEDDINGS PROVIDERS');
166
+
167
+ const { loadRuntimeConfig } = await import('../core/runtime.mjs');
168
+ let config;
169
+ try {
170
+ config = loadRuntimeConfig();
171
+ } catch (err) {
172
+ config = { agents: [] };
173
+ }
174
+ const agents = config.agents || [];
175
+
176
+ if (agents.length > 0) {
177
+ let healthyCount = 0;
178
+ for (const agent of agents) {
179
+ const exists = commandExists(agent.binary);
180
+ if (exists) {
181
+ logOk(`Agent ${agent.name.padEnd(8)}: Available (Binary: ${agent.binary})`);
182
+ healthyCount++;
183
+ } else {
184
+ logWarn(`Agent ${agent.name.padEnd(8)}: NOT FOUND in PATH (Binary: ${agent.binary})`);
185
+ warnings++;
186
+ }
187
+ }
188
+ } else {
189
+ logWarn('No CLI agents found in registry configuration.');
190
+ warnings++;
191
+ }
192
+
193
+ const googleKey = process.env.GOOGLE_API_KEY;
194
+ const openaiKey = process.env.OPENAI_API_KEY;
195
+
196
+ if (googleKey) {
197
+ logOk('GOOGLE_API_KEY environment variable is configured (Primary Embeddings)');
198
+ } else if (openaiKey) {
199
+ logOk('OPENAI_API_KEY environment variable is configured (Fallback Embeddings)');
200
+ } else {
201
+ logWarn('Neither GOOGLE_API_KEY nor OPENAI_API_KEY is configured in the environment.');
202
+ log(' Tip: Configure GOOGLE_API_KEY to use gemini-embedding-2 (free tier).');
203
+ warnings++;
204
+ }
205
+
206
+ // ── Step 5: Privilege & Workspace Environment ──
207
+ hr();
208
+ logInfo('5. SECURITY & WORKSPACE INTEGRITY');
209
+
210
+ // VFS permissions
211
+ const home = os.homedir();
212
+ const vfsPath = path.join(home, '.agent');
213
+ if (fs.existsSync(vfsPath)) {
214
+ try {
215
+ fs.accessSync(vfsPath, fs.constants.R_OK | fs.constants.W_OK);
216
+ logOk('VFS folder permissions (~/.agent): Read/Write Stable');
217
+ } catch {
218
+ logFail('VFS folder permissions (~/.agent): ACCESS DENIED');
219
+ failures++;
220
+ }
221
+ } else {
222
+ logOk('VFS folder (~/.agent): Ready to scaffold');
223
+ }
224
+
225
+ // Sudo access (non-blocking check)
226
+ if (platform === 'linux') {
227
+ try {
228
+ child_process.execSync('sudo -n true', { stdio: 'ignore' });
229
+ logOk('Sudo access: Passwordless sudo enabled (ideal for automated deploy)');
230
+ } catch {
231
+ logWarn('Sudo access: Passwordless sudo disabled (deployment will prompt for root password)');
232
+ warnings++;
233
+ }
234
+ }
235
+
236
+ // ── Diagnostics Summary ──
237
+ hr();
238
+ console.log('\n ┌─────────────────────────────────────────────────────────┐');
239
+ if (failures === 0 && warnings === 0) {
240
+ console.log(' │ 🎉 Diagnostics Passed! System is perfectly healthy. │');
241
+ console.log(' │ Ready for npx total-recall setup or deploy. │');
242
+ } else if (failures === 0) {
243
+ console.log(` │ ⚠️ Diagnostics passed with ${warnings} warning(s). │`);
244
+ console.log(' │ System is ready, but check recommendations above. │');
245
+ } else {
246
+ console.log(` │ ❌ Diagnostics failed with ${failures} error(s) and ${warnings} warning(s). │`);
247
+ console.log(' │ Please resolve critical failures before deploying. │');
248
+ }
249
+ console.log(' └─────────────────────────────────────────────────────────┘\n');
250
+
251
+ if (failures > 0) {
252
+ process.exitCode = 1;
253
+ }
254
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * total-recall dream
3
+ *
4
+ * Manually trigger a single dream cycle (Light → REM → Deep Sleep).
5
+ *
6
+ * Usage:
7
+ * npx total-recall dream [options]
8
+ *
9
+ * Options:
10
+ * --vault <path> Override vault directory (default: ~/.agent/memory-vault)
11
+ * --help Show this help
12
+ */
13
+
14
+ import path from 'node:path';
15
+ import { fileURLToPath } from 'node:url';
16
+ import { resolveAgentDir, resolveBrainDir } from './agent-dir.mjs';
17
+
18
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
+ const AGENT_DIR = resolveAgentDir();
20
+ const BRAIN_DIR = resolveBrainDir();
21
+
22
+ function parseArgs(args) {
23
+ const opts = { vault: null, help: false };
24
+ for (let i = 0; i < args.length; i++) {
25
+ switch (args[i]) {
26
+ case '--vault': opts.vault = args[++i]; break;
27
+ case '--help': case '-h': opts.help = true; break;
28
+ }
29
+ }
30
+ return opts;
31
+ }
32
+
33
+ function printHelp() {
34
+ console.log(`
35
+ total-recall dream — Manually trigger a dream cycle
36
+
37
+ The dream cycle runs three phases:
38
+ 1. Light Sleep — Scan vault for recent modifications
39
+ 2. REM — Score, conflict-check, and promote/decay candidates
40
+ 3. Deep Sleep — Recompile the surface (indexes + INSTRUCTIONS.md)
41
+
42
+ Usage: total-recall dream [options]
43
+
44
+ Options:
45
+ --vault <path> Override vault directory (default: ~/.agent/memory-vault)
46
+ --help, -h Show this help
47
+ `);
48
+ }
49
+
50
+ export default async function dream(args) {
51
+ const opts = parseArgs(args);
52
+ if (opts.help) { printHelp(); return; }
53
+
54
+ const vaultDir = opts.vault || path.join(BRAIN_DIR, 'memory-vault');
55
+ const skillsDir = path.join(AGENT_DIR, 'skills');
56
+ const derivedDir = path.join(BRAIN_DIR, 'memory-derived');
57
+ const conflictsDir = path.join(BRAIN_DIR, 'memory-inbox', 'conflicts');
58
+ const instructionsFile = path.join(AGENT_DIR, 'INSTRUCTIONS.md');
59
+
60
+ console.error('\n 🌙 Starting dream cycle...\n');
61
+ const startTime = Date.now();
62
+
63
+ try {
64
+ const { runDreamCycle } = await import('../core/dream.mjs');
65
+ const result = await runDreamCycle({
66
+ vaultDir,
67
+ skillsDir,
68
+ derivedDir,
69
+ conflictsDir,
70
+ instructionsFile,
71
+ });
72
+
73
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
74
+ console.error(`\n ✅ Dream cycle complete (${elapsed}s) — status: ${result.status}`);
75
+ } catch (err) {
76
+ console.error(`\n ❌ Dream cycle failed: ${err.message}`);
77
+ console.error(err.stack);
78
+ process.exit(1);
79
+ }
80
+ }
@@ -0,0 +1,92 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { resolveAgentDir, resolveBrainDir, parseLayerFlag, getBothBrains } from './agent-dir.mjs';
4
+ import { compileSurface } from '../core/surface.mjs';
5
+ import { deleteNode, loadNodes } from '../core/vault.mjs';
6
+
7
+ function printHelp() {
8
+ console.log(`
9
+ total-recall forget — Delete a memory node by slug
10
+
11
+ Usage: total-recall forget <slug> [options]
12
+
13
+ Options:
14
+ --global Delete from the global brain
15
+ --project Delete from the project brain
16
+ --no-compile Skip auto-recompilation after deletion
17
+ --help, -h Show this help
18
+
19
+ If neither --global nor --project is specified, the node is searched in the
20
+ project brain first (if one exists), then falls back to global.
21
+
22
+ Examples:
23
+ npx total-recall forget test-propagation-delete-me
24
+ npx total-recall forget old-invariant --global
25
+ npx total-recall forget stale-fact --project
26
+ npx total-recall forget my-node --no-compile
27
+ `);
28
+ }
29
+
30
+ export default async function forget(args) {
31
+ const { layer: explicitLayer, remainingArgs } = parseLayerFlag(args);
32
+
33
+ const slug = remainingArgs[0];
34
+ const noCompile = remainingArgs.includes('--no-compile');
35
+
36
+ if (!slug || slug === '--help' || slug === '-h') {
37
+ printHelp();
38
+ return;
39
+ }
40
+
41
+ let layer = explicitLayer;
42
+
43
+ // Auto-detect which layer contains the node
44
+ if (layer === 'auto') {
45
+ const brains = getBothBrains();
46
+ // Check project first, then global
47
+ if (brains.project) {
48
+ const projVaultDir = path.join(brains.project.brainDir, 'memory-vault');
49
+ const projNodes = loadNodes(projVaultDir);
50
+ if (projNodes.some(n => n.slug === slug)) {
51
+ layer = 'project';
52
+ }
53
+ }
54
+ if (layer === 'auto') {
55
+ layer = 'global';
56
+ }
57
+ }
58
+
59
+ const resolvedBrainDir = resolveBrainDir(layer);
60
+ const resolvedAgentDir = resolveAgentDir(layer);
61
+ const vaultDir = path.join(resolvedBrainDir, 'memory-vault');
62
+ const derivedDir = path.join(resolvedBrainDir, 'memory-derived');
63
+ const skillsDir = path.join(resolvedAgentDir, 'skills');
64
+ const instructionsFile = path.join(resolvedAgentDir, 'INSTRUCTIONS.md');
65
+ const layerLabel = layer === 'project' ? '[project]' : '[global]';
66
+
67
+ // Attempt deletion
68
+ const deleted = deleteNode(slug, vaultDir);
69
+
70
+ if (!deleted) {
71
+ console.error(` ❌ Node "${slug}" not found in ${layerLabel} vault at ${vaultDir}`);
72
+ process.exit(1);
73
+ }
74
+
75
+ console.log(` ✅ Deleted memory node "${slug}" from ${layerLabel} vault.`);
76
+
77
+ // Recompile unless --no-compile
78
+ if (!noCompile) {
79
+ console.log(' ⏳ Recompiling active memory surfaces and indexes...');
80
+ try {
81
+ const compileResult = await compileSurface({
82
+ vaultDir,
83
+ skillsDir,
84
+ derivedDir,
85
+ instructionsFile
86
+ });
87
+ console.log(` ✅ Recompilation successful! Processed ${compileResult.nodesProcessed} SSSS nodes.`);
88
+ } catch (err) {
89
+ console.warn(` ⚠️ Node deleted, but surface recompilation failed: ${err.message}`);
90
+ }
91
+ }
92
+ }
@@ -0,0 +1,21 @@
1
+ import { detectFriction } from '../core/friction.mjs';
2
+ import path from 'path';
3
+ import { resolveBrainDir } from './agent-dir.mjs';
4
+
5
+ /**
6
+ * CLI command to run Friction Detection on logs
7
+ */
8
+ export default async function runFriction(args) {
9
+ console.log(`[Friction] 🔍 Analyzing logs for workflow bottlenecks...`);
10
+
11
+ // Default path for watchdog logs
12
+ const logPath = args[0] || path.join(resolveBrainDir(), 'logs', 'watchdog.jsonl');
13
+
14
+ const result = await detectFriction(logPath);
15
+ if (!result) {
16
+ console.log(`[Friction] No logs found at ${logPath}. Skipping analysis.`);
17
+ return;
18
+ }
19
+
20
+ console.log(`\n${result.report}`);
21
+ }
@@ -0,0 +1,65 @@
1
+ import { issueKey } from '../server/keys.mjs';
2
+
3
+ function parseName(args) {
4
+ const idx = args.indexOf('--name');
5
+ if (idx !== -1 && args[idx + 1]) return args[idx + 1];
6
+ const positional = [];
7
+ for (let i = 0; i < args.length; i++) {
8
+ if (['--scope', '--scopes', '--expires'].includes(args[i])) {
9
+ i++;
10
+ continue;
11
+ }
12
+ if (!args[i].startsWith('--')) positional.push(args[i]);
13
+ }
14
+ return positional.join(' ').trim() || 'CLI Key';
15
+ }
16
+
17
+ function parseScopes(args) {
18
+ const idx = args.indexOf('--scope');
19
+ if (idx !== -1 && args[idx + 1]) return args[idx + 1].split(',').map(scope => scope.trim());
20
+ const scopesIdx = args.indexOf('--scopes');
21
+ if (scopesIdx !== -1 && args[scopesIdx + 1]) return args[scopesIdx + 1].split(',').map(scope => scope.trim());
22
+ return ['*'];
23
+ }
24
+
25
+ function parseExpiresAt(args) {
26
+ const idx = args.indexOf('--expires');
27
+ if (idx === -1 || !args[idx + 1]) return null;
28
+ const value = args[idx + 1];
29
+ if (/^\d+d$/.test(value)) {
30
+ const days = Number(value.slice(0, -1));
31
+ return new Date(Date.now() + days * 86400000).toISOString();
32
+ }
33
+ if (/^\d{4}-\d{2}-\d{2}$/.test(value)) return value;
34
+ return value;
35
+ }
36
+
37
+ export default async function generatePat(args) {
38
+ if (args.includes('--help') || args.includes('-h')) {
39
+ console.log(`
40
+ total-recall generate-pat --name "codex"
41
+ total-recall generate-pat --name "readonly" --scope "models:read,ssss:read,memory:read"
42
+ total-recall generate-pat --name "temp" --expires 30d
43
+
44
+ Issues a Personal Access Token and stores only its hash in
45
+ ~/.agent/config/keys.jsonl. The token is printed once.
46
+
47
+ Options:
48
+ --name <name> Human-readable key name
49
+ --scope <list> Comma-separated scopes (default: *)
50
+ --scopes <list> Alias for --scope
51
+ --expires <date> ISO date or relative days, e.g. 2026-06-01 or 30d
52
+ `);
53
+ return;
54
+ }
55
+
56
+ const key = issueKey(parseName(args), {
57
+ scopes: parseScopes(args),
58
+ expires_at: parseExpiresAt(args)
59
+ });
60
+ console.log(`Name: ${key.name}`);
61
+ console.log(`ID: ${key.id}`);
62
+ console.log(`Scopes: ${key.scopes.join(', ')}`);
63
+ console.log(`Expires: ${key.expires_at || 'never'}`);
64
+ console.log(`Token: ${key.token}`);
65
+ }
@@ -0,0 +1,22 @@
1
+ import bcrypt from 'bcrypt';
2
+ import { BCRYPT_COST } from '../server/auth.mjs';
3
+
4
+ export default async function hashPassword(args) {
5
+ if (args.includes('--help') || args.includes('-h') || args.length === 0) {
6
+ console.log(`
7
+ total-recall hash-password "new dashboard password"
8
+
9
+ Prints a bcrypt hash for ~/.agent/config/security.yml dashboard.password_hash.
10
+ `);
11
+ return;
12
+ }
13
+
14
+ const password = args.join(' ');
15
+ if (password.length < 12) {
16
+ console.error('Password must be at least 12 characters.');
17
+ process.exit(1);
18
+ }
19
+
20
+ console.log(await bcrypt.hash(password, BCRYPT_COST));
21
+ }
22
+
@@ -0,0 +1,153 @@
1
+ /**
2
+ * total-recall help
3
+ *
4
+ * Interactive local offline help system.
5
+ * Queries local specifications, SSSS layout, and command reference files.
6
+ *
7
+ * Usage:
8
+ * npx total-recall help <command|topic>
9
+ */
10
+
11
+ import fs from 'node:fs';
12
+ import path from 'node:path';
13
+ import { fileURLToPath } from 'node:url';
14
+
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = path.dirname(__filename);
17
+ const ROOT = path.join(__dirname, '..', '..');
18
+
19
+ export default async function run(argv) {
20
+ const args = argv || [];
21
+ const topic = args[0] ? args[0].toLowerCase() : null;
22
+ const isJson = args.includes('--json') || args.includes('-j');
23
+
24
+ const cliRefPath = path.join(ROOT, 'docs', 'reference', 'cli-reference.md');
25
+ const ssssPath = path.join(ROOT, 'docs', 'SSSS.md');
26
+ const archPath = path.join(ROOT, 'docs', 'ARCHITECTURE.md');
27
+
28
+ if (!fs.existsSync(cliRefPath)) {
29
+ console.error(' ❌ Error: Total Recall CLI reference docs not found.');
30
+ process.exit(1);
31
+ }
32
+
33
+ const cliRefContent = fs.readFileSync(cliRefPath, 'utf8');
34
+
35
+ if (!topic) {
36
+ if (isJson) {
37
+ console.log(JSON.stringify({
38
+ description: "Total Recall Sovereign OS Help System",
39
+ command_documentation_path: cliRefPath,
40
+ available_sections: ["architecture", "ssss", "commands"]
41
+ }, null, 2));
42
+ return;
43
+ }
44
+ // Print general guide with gorgeous formatting
45
+ printGeneralHelp();
46
+ return;
47
+ }
48
+
49
+ // Handle Architecture or SSSS topics
50
+ if (topic === 'architecture' || topic === 'arch') {
51
+ if (fs.existsSync(archPath)) {
52
+ const archContent = fs.readFileSync(archPath, 'utf8');
53
+ if (isJson) {
54
+ console.log(JSON.stringify({ topic: 'architecture', content: archContent }, null, 2));
55
+ } else {
56
+ console.log(`\n\x1b[35m=== TOTAL RECALL ARCHITECTURE ===\x1b[0m\n`);
57
+ console.log(archContent.slice(0, 3500) + '\n... (truncated for length)');
58
+ }
59
+ return;
60
+ }
61
+ }
62
+
63
+ if (topic === 'ssss') {
64
+ if (fs.existsSync(ssssPath)) {
65
+ const ssssContent = fs.readFileSync(ssssPath, 'utf8');
66
+ if (isJson) {
67
+ console.log(JSON.stringify({ topic: 'ssss', content: ssssContent }, null, 2));
68
+ } else {
69
+ console.log(`\n\x1b[36m=== STRUCTURED SEMANTIC SYNTAX SYSTEM (SSSS) ===\x1b[0m\n`);
70
+ console.log(ssssContent.slice(0, 3500) + '\n... (truncated for length)');
71
+ }
72
+ return;
73
+ }
74
+ }
75
+
76
+ // Handle Config, Settings, or Environment topics
77
+ if (topic === 'config' || topic === 'settings' || topic === 'environment' || topic === 'env') {
78
+ const configSectionIdx = cliRefContent.indexOf('## Configuration & Environment Variables Reference');
79
+ if (configSectionIdx !== -1) {
80
+ const configContent = cliRefContent.slice(configSectionIdx);
81
+ if (isJson) {
82
+ console.log(JSON.stringify({ topic: 'config', content: configContent }, null, 2));
83
+ } else {
84
+ console.log(`\n\x1b[33m=== TOTAL RECALL CONFIGURATION & SETTINGS ===\x1b[0m\n`);
85
+ console.log(configContent.trim());
86
+ console.log('\n' + '─'.repeat(60) + '\n');
87
+ }
88
+ return;
89
+ }
90
+ }
91
+
92
+ // Parse command-specific help from cli-reference.md
93
+ // Header pattern: ### `command` or ### command
94
+ const sections = cliRefContent.split(/\n(?=### )/);
95
+ let matchedSection = null;
96
+
97
+ for (const section of sections) {
98
+ const lines = section.trim().split('\n');
99
+ const header = lines[0] || '';
100
+ // Extract command name from e.g. "### `connect`" or "### connect"
101
+ const cmdMatch = header.match(/###\s+`?([a-zA-Z0-9_-]+)`?/);
102
+ if (cmdMatch && cmdMatch[1].toLowerCase() === topic) {
103
+ matchedSection = section;
104
+ break;
105
+ }
106
+ }
107
+
108
+ if (matchedSection) {
109
+ if (isJson) {
110
+ console.log(JSON.stringify({
111
+ topic,
112
+ documentation: matchedSection
113
+ }, null, 2));
114
+ } else {
115
+ console.log(`\n\x1b[32m=== Help: total-recall ${topic} ===\x1b[0m\n`);
116
+ // Beautify header-less lines
117
+ const displayContent = matchedSection
118
+ .replace(/^###\s+.*$/m, '')
119
+ .trim();
120
+ console.log(displayContent);
121
+ console.log('\n' + '─'.repeat(60) + '\n');
122
+ }
123
+ } else {
124
+ console.error(` ❌ Error: No help section found for topic or command: "${topic}"`);
125
+ console.error(` Run 'npx total-recall help' to see the complete list of commands.`);
126
+ process.exit(1);
127
+ }
128
+ }
129
+
130
+ function printGeneralHelp() {
131
+ console.log(`
132
+ \x1b[1m\x1b[35m┌─────────────────────────────────────────────────────────┐\x1b[0m
133
+ \x1b[1m\x1b[35m│ Total Recall Interactive Help System │\x1b[0m
134
+ \x1b[1m\x1b[35m│ query local system documentation and architecture │\x1b[0m
135
+ \x1b[1m\x1b[35m└─────────────────────────────────────────────────────────┘\x1b[0m
136
+
137
+ \x1b[1mUsage:\x1b[0m
138
+ npx total-recall help <command> Get detailed help on a specific subcommand
139
+ npx total-recall help architecture View total-recall system & directory architecture
140
+ npx total-recall help ssss View SSSS formatting & semantics rules
141
+ npx total-recall help settings View comprehensive configuration & environment settings
142
+
143
+ \x1b[1mExamples:\x1b[0m
144
+ npx total-recall help connect
145
+ npx total-recall help settings
146
+ npx total-recall help architecture
147
+
148
+ \x1b[1mAll Commands Available:\x1b[0m
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
+ \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
152
+ `);
153
+ }