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,181 @@
1
+ /**
2
+ * API Key Lifecycle Manager
3
+ *
4
+ * Manages Personal Access Tokens (PATs) in `.agent/config/keys.jsonl`.
5
+ * Each line is a JSON object representing a single API key with metadata.
6
+ *
7
+ * Schema:
8
+ * { id, name, token_hash, token_prefix, scopes, expires_at, created_at, last_used_at, hit_count, revoked }
9
+ */
10
+
11
+ import fs from 'node:fs';
12
+ import path from 'node:path';
13
+ import crypto from 'node:crypto';
14
+ import { brainDir } from '../core/config.mjs';
15
+
16
+ const BRAIN_DIR = brainDir;
17
+ const KEYS_FILE = path.join(BRAIN_DIR, 'config', 'keys.jsonl');
18
+
19
+ export const ALL_SCOPES = '*';
20
+
21
+ export const KNOWN_SCOPES = [
22
+ ALL_SCOPES,
23
+ 'chat:read',
24
+ 'chat:write',
25
+ 'models:read',
26
+ 'instructions:read',
27
+ 'ssss:read',
28
+ 'memory:read',
29
+ 'memory:write',
30
+ 'memory:recompile',
31
+ 'sandbox:run',
32
+ 'tts:use',
33
+ 'tasks:read',
34
+ 'tasks:write',
35
+ 'files:read',
36
+ 'config:read',
37
+ 'config:write',
38
+ 'keys:read',
39
+ 'keys:write',
40
+ 'health:read'
41
+ ];
42
+
43
+ function hashToken(token) {
44
+ return crypto.createHash('sha256').update(token, 'utf8').digest('hex');
45
+ }
46
+
47
+ function safeEqualHex(a, b) {
48
+ if (typeof a !== 'string' || typeof b !== 'string') return false;
49
+ if (!/^[a-f0-9]{64}$/i.test(a) || !/^[a-f0-9]{64}$/i.test(b)) return false;
50
+ return crypto.timingSafeEqual(Buffer.from(a, 'hex'), Buffer.from(b, 'hex'));
51
+ }
52
+
53
+ function normalizeKey(raw) {
54
+ const key = { ...raw };
55
+ if (key.token && typeof key.token === 'string') {
56
+ if (key.token === 'local') {
57
+ key.revoked = true;
58
+ key.token_prefix = 'local';
59
+ key.token_hash = hashToken(key.token);
60
+ } else if (!key.token_hash) {
61
+ key.token_hash = hashToken(key.token);
62
+ key.token_prefix = key.token.slice(0, 8);
63
+ }
64
+ delete key.token;
65
+ }
66
+ key.scopes = normalizeScopes(key.scopes);
67
+ key.expires_at = key.expires_at || null;
68
+ key.hit_count = key.hit_count || 0;
69
+ key.revoked = !!key.revoked;
70
+ return key;
71
+ }
72
+
73
+ export function normalizeScopes(scopes) {
74
+ if (!Array.isArray(scopes) || scopes.length === 0) return [ALL_SCOPES];
75
+ const normalized = scopes
76
+ .map(scope => String(scope || '').trim())
77
+ .filter(Boolean)
78
+ .filter(scope => scope === ALL_SCOPES || /^[a-z][a-z0-9-]*:(\*|[a-z][a-z0-9-]*)$/.test(scope));
79
+ return [...new Set(normalized)].length ? [...new Set(normalized)] : [ALL_SCOPES];
80
+ }
81
+
82
+ export function isExpiredKey(key, now = new Date()) {
83
+ if (!key?.expires_at) return false;
84
+ const expires = new Date(key.expires_at);
85
+ if (Number.isNaN(expires.getTime())) return true;
86
+ return expires.getTime() <= now.getTime();
87
+ }
88
+
89
+ export function keyHasScope(key, requiredScope) {
90
+ if (!requiredScope) return true;
91
+ const scopes = normalizeScopes(key?.scopes);
92
+ if (scopes.includes(ALL_SCOPES)) return true;
93
+ if (scopes.includes(requiredScope)) return true;
94
+ const [namespace] = String(requiredScope).split(':');
95
+ return scopes.includes(`${namespace}:*`);
96
+ }
97
+
98
+ export function keyHasAnyScope(key, requiredScopes = []) {
99
+ if (!requiredScopes.length) return true;
100
+ return requiredScopes.some(scope => keyHasScope(key, scope));
101
+ }
102
+
103
+ function ensureKeysFile() {
104
+ const dir = path.dirname(KEYS_FILE);
105
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
106
+ if (!fs.existsSync(KEYS_FILE)) fs.writeFileSync(KEYS_FILE, '', { encoding: 'utf8', mode: 0o600 });
107
+ try {
108
+ fs.chmodSync(KEYS_FILE, 0o600);
109
+ } catch {
110
+ // Best effort: chmod can fail on non-POSIX filesystems.
111
+ }
112
+ }
113
+
114
+ export function loadKeys() {
115
+ ensureKeysFile();
116
+ const raw = fs.readFileSync(KEYS_FILE, 'utf8').trim();
117
+ if (!raw) return [];
118
+ const parsed = raw.split('\n').map(line => normalizeKey(JSON.parse(line)));
119
+ if (raw.includes('"token"')) saveKeys(parsed);
120
+ return parsed;
121
+ }
122
+
123
+ function saveKeys(keys) {
124
+ ensureKeysFile();
125
+ const sanitized = keys.map((key) => {
126
+ const { token, ...rest } = normalizeKey(key);
127
+ return rest;
128
+ });
129
+ fs.writeFileSync(KEYS_FILE, sanitized.map(k => JSON.stringify(k)).join('\n') + (sanitized.length ? '\n' : ''), { encoding: 'utf8', mode: 0o600 });
130
+ }
131
+
132
+ export function issueKey(name, options = {}) {
133
+ const keys = loadKeys();
134
+ const token = `tr_${crypto.randomBytes(32).toString('base64url')}`;
135
+ const key = {
136
+ id: crypto.randomUUID(),
137
+ name: name || 'Unnamed Key',
138
+ token_hash: hashToken(token),
139
+ token_prefix: token.slice(0, 8),
140
+ scopes: normalizeScopes(options.scopes),
141
+ expires_at: options.expires_at || options.expiresAt || null,
142
+ created_at: new Date().toISOString(),
143
+ last_used_at: null,
144
+ hit_count: 0,
145
+ revoked: false,
146
+ };
147
+ keys.push(key);
148
+ saveKeys(keys);
149
+ return { ...key, token };
150
+ }
151
+
152
+ export function revokeKey(id) {
153
+ const keys = loadKeys();
154
+ const key = keys.find(k => k.id === id);
155
+ if (!key) return null;
156
+ key.revoked = true;
157
+ saveKeys(keys);
158
+ return key;
159
+ }
160
+
161
+ export function recordKeyUsage(token) {
162
+ const keys = loadKeys();
163
+ const tokenHash = hashToken(token);
164
+ const key = keys.find(k => safeEqualHex(k.token_hash, tokenHash) && !k.revoked && !isExpiredKey(k));
165
+ if (!key) return false;
166
+ key.hit_count = (key.hit_count || 0) + 1;
167
+ key.last_used_at = new Date().toISOString();
168
+ saveKeys(keys);
169
+ return true;
170
+ }
171
+
172
+ export function isValidToken(token) {
173
+ return !!findValidKeyByToken(token);
174
+ }
175
+
176
+ export function findValidKeyByToken(token) {
177
+ if (!token || token === 'local') return null;
178
+ const tokenHash = hashToken(token);
179
+ const keys = loadKeys();
180
+ return keys.find(k => safeEqualHex(k.token_hash, tokenHash) && !k.revoked && !isExpiredKey(k)) || null;
181
+ }