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
@@ -7,96 +7,20 @@
7
7
  * - Zero hardcoded hostnames, IP addresses, or personal node topologies.
8
8
  * - Zero fabricated or simulated quota percentages: a figure is reported only when a real
9
9
  * provider API or local telemetry file supplies it; otherwise `unknown` is reported honestly.
10
- * - Filters candidates to harnesses actually installed on the target host unless `--include-uninstalled` is requested.
10
+ * - Candidates are the harnesses that can take work now; `resolvePool` reports why the others cannot.
11
11
  */
12
12
 
13
13
  import fs from 'node:fs';
14
14
  import path from 'node:path';
15
15
  import os from 'node:os';
16
16
  import { execFileSync } from 'node:child_process';
17
- import { ADAPTER_CATALOG, classifyTaskComplexity, selectOptimalHarness, computeEmpiricalScorecard } from '../capability/index.mjs';
18
- import { inspectAgents, getActiveAdapters } from './worker.mjs';
19
-
20
- // Generic Coding Benchmark Reference Data (SWE-bench Pro, Terminal-Bench 2.0, Artificial Analysis ELO)
21
- export const BENCHMARK_MATRIX = {
22
- agy: {
23
- sweBenchPro: 68.4,
24
- terminalBench2: 74.2,
25
- artificialAnalysisElo: 1380,
26
- costPer1kTokens: 0.003,
27
- provider: 'Google Antigravity'
28
- },
29
- claude: {
30
- sweBenchPro: 72.8,
31
- terminalBench2: 76.5,
32
- artificialAnalysisElo: 1410,
33
- costPer1kTokens: 0.008,
34
- provider: 'Anthropic'
35
- },
36
- codex: {
37
- sweBenchPro: 69.1,
38
- terminalBench2: 71.8,
39
- artificialAnalysisElo: 1375,
40
- costPer1kTokens: 0.006,
41
- provider: 'OpenAI'
42
- },
43
- grok: {
44
- sweBenchPro: 61.2,
45
- terminalBench2: 66.0,
46
- artificialAnalysisElo: 1320,
47
- costPer1kTokens: 0.0025,
48
- provider: 'xAI'
49
- },
50
- dsh: {
51
- sweBenchPro: 64.7,
52
- terminalBench2: 67.9,
53
- artificialAnalysisElo: 1335,
54
- costPer1kTokens: 0.0006,
55
- provider: 'DeepSeek / OpenRouter'
56
- },
57
- ollama: {
58
- sweBenchPro: 44.5,
59
- terminalBench2: 52.1,
60
- artificialAnalysisElo: 1210,
61
- costPer1kTokens: 0.0,
62
- provider: 'Local / Ollama'
63
- },
64
- hermes: {
65
- sweBenchPro: 56.8,
66
- terminalBench2: 60.4,
67
- artificialAnalysisElo: 1285,
68
- costPer1kTokens: 0.0002,
69
- provider: 'Local / Nous Research'
70
- },
71
- openhands: {
72
- sweBenchPro: 67.3,
73
- terminalBench2: 70.1,
74
- artificialAnalysisElo: 1360,
75
- costPer1kTokens: 0.005,
76
- provider: 'OpenHands Community'
77
- },
78
- aider: {
79
- sweBenchPro: 62.4,
80
- terminalBench2: 65.8,
81
- artificialAnalysisElo: 1310,
82
- costPer1kTokens: 0.002,
83
- provider: 'Aider AI'
84
- },
85
- goose: {
86
- sweBenchPro: 58.0,
87
- terminalBench2: 63.2,
88
- artificialAnalysisElo: 1295,
89
- costPer1kTokens: 0.002,
90
- provider: 'Block Goose'
91
- },
92
- cline: {
93
- sweBenchPro: 63.5,
94
- terminalBench2: 66.4,
95
- artificialAnalysisElo: 1315,
96
- costPer1kTokens: 0.003,
97
- provider: 'Cline AI'
98
- }
99
- };
17
+ import { classifyTaskComplexity, selectOptimalHarness, computeEmpiricalScorecard } from '../capability/index.mjs';
18
+ import { inspectAgents } from './worker.mjs';
19
+ import { inspectNode } from './executor.mjs';
20
+ import { getModelCatalog, joinHarnessModels } from './model-catalog.mjs';
21
+ import { readReceipts, activeQuotaWalls, activeCredentialBlocks } from './learner.mjs';
22
+ import { resolvePool, exclusionReason } from './pool.mjs';
23
+ import { readCodexRateLimits, measuredWalls } from './telemetry.mjs';
100
24
 
101
25
  /**
102
26
  * Helper to safely query host Total Recall CLI without assumptions
@@ -106,7 +30,7 @@ function runHostCli(args = []) {
106
30
  const totalRecallBin = process.env.TOTAL_RECALL_BIN || 'total-recall';
107
31
  const output = execFileSync(totalRecallBin, args, {
108
32
  stdio: ['pipe', 'pipe', 'pipe'],
109
- timeout: 8000,
33
+ timeout: 20000,
110
34
  encoding: 'utf8'
111
35
  });
112
36
  return output.trim();
@@ -115,18 +39,17 @@ function runHostCli(args = []) {
115
39
  }
116
40
  }
117
41
 
118
- /**
119
- * Read local empirical run ledger safely
120
- */
121
- export function readLocalRunLedger() {
122
- const home = process.env.HOME || process.env.USERPROFILE || os.homedir();
123
- const ledgerPath = path.join(home, '.agent', 'skills', 'total-recall', 'meta-harness-runs.json');
124
- if (!fs.existsSync(ledgerPath)) return [];
42
+ const gigabytes = bytes => (typeof bytes === 'number' ? +(bytes / 1024 ** 3).toFixed(2) : null);
43
+ function normalizeFleetRow(row) {
44
+ return { hostname: row.hostname, ip: row.ip, online: row.online !== false, self: Boolean(row.self), telemetry: row.state || null, cpuCores: row.cores ?? null, loadAvg1m: row.loadAvg?.[0] ?? null, freeMemGB: gigabytes(row.memory?.free), totalMemGB: gigabytes(row.memory?.total), memoryUtilizationPercent: row.memory?.usedPercent ?? null };
45
+ }
46
+ function fleetTelemetry(run = runHostCli) {
125
47
  try {
126
- const parsed = JSON.parse(fs.readFileSync(ledgerPath, 'utf8'));
127
- return Array.isArray(parsed) ? parsed : [];
128
- } catch {
129
- return [];
48
+ const parsed = JSON.parse(run(['system-monitor', 'fleet', '--json']) || 'null');
49
+ if (!parsed?.rows) return { ok: false, error: 'Fleet telemetry is unavailable', nodes: [] };
50
+ return { ok: true, machines: parsed.machines, answered: parsed.answered, nodes: parsed.rows.map(normalizeFleetRow) };
51
+ } catch (error) {
52
+ return { ok: false, error: String(error.message), nodes: [] };
130
53
  }
131
54
  }
132
55
 
@@ -137,279 +60,146 @@ export function readLocalRunLedger() {
137
60
  */
138
61
  export async function inspectQuotas(options = {}) {
139
62
  const quotas = {};
140
-
141
- // 1. Dynamic Host Hardware & RAM Telemetry (works on Android, Linux, macOS, Windows, or cloud VMs)
142
- let totalMemBytes = os.totalmem();
143
- let freeMemBytes = os.freemem();
144
- let hostname = os.hostname();
145
- let platform = os.platform();
146
- let arch = os.arch();
147
- let cpuCores = os.cpus()?.length || 1;
148
- let loadAvg1m = os.loadavg()?.[0] || 0;
149
-
150
- try {
151
- const sysJson = runHostCli(['system-monitor', 'status', '--json']);
152
- if (sysJson) {
153
- const sysData = JSON.parse(sysJson);
154
- if (sysData.memory?.total && sysData.memory?.free) {
155
- totalMemBytes = sysData.memory.total;
156
- freeMemBytes = sysData.memory.free;
157
- }
158
- if (sysData.hostname) hostname = sysData.hostname;
159
- if (sysData.platform) platform = sysData.platform;
160
- if (sysData.cores) cpuCores = sysData.cores;
161
- }
162
- } catch {}
163
-
164
- const freeMemGB = parseFloat((freeMemBytes / (1024 * 1024 * 1024)).toFixed(2));
165
- const totalMemGB = parseFloat((totalMemBytes / (1024 * 1024 * 1024)).toFixed(2));
166
- const memoryUtilizationPercent = Math.round(((totalMemBytes - freeMemBytes) / totalMemBytes) * 100);
167
-
168
- quotas.system = {
169
- hostname,
170
- platform,
171
- arch,
172
- cpuCores,
173
- loadAvg1m: parseFloat(loadAvg1m.toFixed(2)),
174
- totalMemGB,
175
- freeMemGB,
176
- memoryUtilizationPercent,
177
- node: options.node || 'local'
178
- };
179
-
180
- // 2. Discover actually installed harnesses and their real authentication state
181
- let installedState = {};
182
- try {
183
- const inspected = await inspectAgents({ env: process.env });
184
- for (const a of inspected.agents || []) {
185
- installedState[a.id] = a;
186
- }
187
- } catch {}
188
-
189
- // 3. Subscription & Frontier Runners (honest state: never invent percentages)
190
- for (const id of ['agy', 'claude', 'codex', 'grok']) {
191
- const agent = installedState[id];
192
- const installed = Boolean(agent?.installed);
193
- let status = installed ? 'ready' : 'not_installed';
194
- let quotaSource = 'unintegrated';
195
- let rolling5hRemainingPercent = null;
196
- let weeklyRemainingPercent = null;
197
- let usagePercent = null;
198
-
199
- // Check if local telemetry file provides actual rate-limit snapshots
200
- if (id === 'claude') {
201
- const telemetryFile = path.join(os.homedir(), '.claude', 'rate_limits.json');
202
- if (fs.existsSync(telemetryFile)) {
203
- try {
204
- const data = JSON.parse(fs.readFileSync(telemetryFile, 'utf8'));
205
- if (typeof data.five_hour?.used_percentage === 'number') {
206
- rolling5hRemainingPercent = Math.max(0, 100 - Math.round(data.five_hour.used_percentage));
207
- usagePercent = Math.round(data.five_hour.used_percentage);
208
- quotaSource = 'claude-telemetry';
209
- }
210
- if (typeof data.seven_day?.used_percentage === 'number') {
211
- weeklyRemainingPercent = Math.max(0, 100 - Math.round(data.seven_day.used_percentage));
212
- }
213
- } catch {}
214
- }
215
- }
216
-
217
- if (agent?.authenticated === false) {
218
- status = 'needs_auth';
219
- }
220
-
221
- quotas[id] = {
222
- installed,
223
- version: agent?.version || null,
224
- billingModel: 'subscription',
225
- rolling5hRemainingPercent,
226
- weeklyRemainingPercent,
227
- usagePercent,
228
- quotaNote: rolling5hRemainingPercent !== null ? 'measured' : (installed ? 'unknown — provider exposes no public quota endpoint' : 'not installed'),
229
- quotaSource,
230
- status
63
+ const remote = options.node && options.node !== 'local';
64
+ const fleet = (options.fleet || fleetTelemetry)();
65
+ const rowFor = node => fleet.nodes.find(row => [row.hostname, row.ip].includes(node) || String(row.hostname || '').split('.')[0] === node);
66
+
67
+ if (remote) {
68
+ const row = rowFor(options.node);
69
+ if (!row || row.freeMemGB === null) throw new Error(`No telemetry from mesh node ${options.node}${fleet.ok ? '' : `: ${fleet.error}`}`);
70
+ quotas.system = { ...row, node: options.node };
71
+ } else {
72
+ // os.freemem() on macOS excludes reclaimable memory, so the monitor's figure wins when it answered.
73
+ const totalMemBytes = os.totalmem(), freeMemBytes = os.freemem();
74
+ const self = fleet.nodes.find(row => row.self);
75
+ quotas.system = {
76
+ hostname: os.hostname(), platform: os.platform(), arch: os.arch(), cpuCores: os.cpus()?.length || 1,
77
+ loadAvg1m: parseFloat((os.loadavg()?.[0] || 0).toFixed(2)),
78
+ totalMemGB: parseFloat((totalMemBytes / 1024 ** 3).toFixed(2)), freeMemGB: parseFloat((freeMemBytes / 1024 ** 3).toFixed(2)),
79
+ memoryUtilizationPercent: Math.round(((totalMemBytes - freeMemBytes) / totalMemBytes) * 100), node: 'local',
80
+ ...(typeof self?.freeMemGB === 'number' ? { freeMemGB: self.freeMemGB, totalMemGB: self.totalMemGB, memoryUtilizationPercent: self.memoryUtilizationPercent } : {}),
231
81
  };
232
82
  }
233
83
 
234
- // 4. Generic Metered Balances (OpenRouter / API Credits if configured by user)
235
- let meteredQuota = {
236
- metered: true,
237
- billingModel: 'metered',
238
- creditRemainingUSD: null,
239
- usageUSD: null,
240
- usageDailyUSD: null,
241
- usageWeeklyUSD: null,
242
- usagePercent: null,
243
- quotaNote: 'unconfigured — set OPENROUTER_API_KEY in auth secret to track metered credits',
244
- status: 'unconfigured'
245
- };
84
+ // Harness state comes from the selected machine. Quota walls are this machine's receipts.
85
+ const inspected = remote ? await (options.inspectNodeFn || inspectNode)(options.node) : await (options.inspect || inspectAgents)({ env: process.env });
86
+ const codexLimits = remote ? null : readCodexRateLimits();
87
+ const walls = remote ? {} : { ...activeQuotaWalls(await readReceipts()), ...measuredWalls(codexLimits) };
88
+ const metered = new Set(['dsh', 'hermes', 'openclaw', 'pi', 'aider', 'goose', 'openhands', 'cline']);
89
+
90
+ const blocks = remote ? {} : activeCredentialBlocks(await readReceipts());
91
+ for (const agent of inspected.agents || []) {
92
+ const wall = walls[agent.id];
93
+ const block = blocks[agent.id];
94
+ const reason = exclusionReason(agent, wall, block);
95
+ let status = 'ready';
96
+ if (!agent.installed) status = 'not_installed';
97
+ else if (agent.authenticated === false || block) status = 'needs_auth';
98
+ else if (agent.blockedBy) status = 'blocked';
99
+ else if (wall) status = 'exhausted';
100
+ else if (agent.authenticated === 'unknown') status = 'unverified';
101
+ const quota = {
102
+ installed: Boolean(agent.installed), version: agent.version || null,
103
+ billingModel: agent.id === 'ollama' ? 'local' : metered.has(agent.id) ? 'metered' : 'subscription',
104
+ rolling5hUsedPercent: null, weeklyUsedPercent: null, usagePercent: null,
105
+ quotaSource: 'none', quotaNote: reason || 'No usage figure is available from this harness', status,
106
+ ...(wall ? { resetsAt: wall.until, wallMessage: wall.message } : {}),
107
+ };
108
+ if (agent.id === 'codex' && codexLimits) {
109
+ quota.rolling5hUsedPercent = codexLimits.primary?.used_percent ?? null;
110
+ quota.weeklyUsedPercent = codexLimits.secondary?.used_percent ?? null;
111
+ if (codexLimits.primary || codexLimits.secondary) quota.usagePercent = Math.max(quota.rolling5hUsedPercent ?? 0, quota.weeklyUsedPercent ?? 0);
112
+ quota.quotaSource = 'codex-session-log';
113
+ quota.observedAt = codexLimits.observedAt;
114
+ if (!reason) quota.quotaNote = `Measured in the Codex session log at ${codexLimits.observedAt}`;
115
+ }
116
+ quotas[agent.id] = quota;
117
+ }
246
118
 
119
+ // Metered balance, from the provider
120
+ let meteredQuota = { billingModel: 'metered', creditRemainingUSD: null, usageUSD: null, usageDailyUSD: null, usageWeeklyUSD: null, usagePercent: null, quotaNote: 'No OpenRouter key in the auth store', status: 'unconfigured' };
247
121
  try {
248
- const key = options.openRouterKey !== undefined
249
- ? options.openRouterKey
250
- : (runHostCli(['auth', 'secret', 'get', 'OPENROUTER_API_KEY']) || process.env.OPENROUTER_API_KEY);
251
- if (key && key.startsWith('sk-or-')) {
252
- const fetchFn = options.fetchImpl || fetch;
253
- const res = await fetchFn('https://openrouter.ai/api/v1/auth/key', {
254
- headers: { Authorization: `Bearer ${key}` },
255
- signal: AbortSignal.timeout(4000)
256
- });
257
- if (res.ok) {
258
- const json = await res.json();
259
- const data = json.data;
260
- if (data) {
261
- const limit = data.limit;
262
- const usage = typeof data.usage === 'number' ? parseFloat(data.usage.toFixed(4)) : 0;
263
- const limitRemaining = data.limit_remaining;
264
- meteredQuota = {
265
- metered: true,
266
- billingModel: 'metered',
267
- creditRemainingUSD: limitRemaining !== null && limitRemaining !== undefined
268
- ? parseFloat(Number(limitRemaining).toFixed(4))
269
- : (limit ? parseFloat(Math.max(0, limit - usage).toFixed(4)) : null),
270
- usageUSD: usage,
271
- usageDailyUSD: typeof data.usage_daily === 'number' ? parseFloat(data.usage_daily.toFixed(4)) : 0,
272
- usageWeeklyUSD: typeof data.usage_weekly === 'number' ? parseFloat(data.usage_weekly.toFixed(4)) : 0,
273
- usagePercent: limit ? Math.min(100, Math.round((usage / limit) * 100)) : 0,
274
- label: data.label || 'configured',
275
- quotaNote: limit ? `${Math.round((usage / limit) * 100)}% of limit used` : `Metered active ($${usage} total used, no hard cap)`,
276
- status: 'ready'
277
- };
278
- }
279
- }
122
+ const key = options.openRouterKey !== undefined ? options.openRouterKey : (runHostCli(['auth', 'secret', 'get', 'DEVELOPER_OPENROUTER_API_KEY']) || runHostCli(['auth', 'secret', 'get', 'OPENROUTER_API_KEY']));
123
+ if (key) {
124
+ const response = await (options.fetchImpl || fetch)('https://openrouter.ai/api/v1/auth/key', { headers: { Authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(6000) });
125
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
126
+ const data = (await response.json()).data || {};
127
+ const usage = typeof data.usage === 'number' ? +data.usage.toFixed(4) : null;
128
+ meteredQuota = {
129
+ billingModel: 'metered', creditRemainingUSD: typeof data.limit_remaining === 'number' ? +data.limit_remaining.toFixed(4) : null,
130
+ usageUSD: usage, usageDailyUSD: data.usage_daily ?? null, usageWeeklyUSD: data.usage_weekly ?? null,
131
+ usagePercent: data.limit && usage !== null ? Math.min(100, Math.round((usage / data.limit) * 100)) : null,
132
+ quotaNote: data.limit ? `Limit $${data.limit}` : 'No spending limit on this key', quotaSource: 'openrouter', status: 'ready',
133
+ };
280
134
  }
281
- } catch {
282
- meteredQuota.quotaNote = 'offline — unable to reach metered provider endpoint';
135
+ } catch (error) {
136
+ meteredQuota.quotaNote = `OpenRouter could not be reached: ${error.message}`;
137
+ meteredQuota.status = 'unavailable';
283
138
  }
284
139
  quotas.metered = meteredQuota;
285
140
 
286
- // 5. Zero-Cost Local Inference (Ollama / Hermes)
287
- // Evaluated against actual host RAM and binary installation
288
- for (const localId of ['ollama', 'hermes']) {
289
- const agent = installedState[localId];
290
- const installed = Boolean(agent?.installed);
291
- const hasRam = freeMemGB >= 2.0;
292
- quotas[localId] = {
293
- installed,
294
- version: agent?.version || null,
295
- metered: false,
296
- billingModel: 'local',
297
- costUSD: 0,
298
- usagePercent: 0,
299
- freeMemGB,
300
- quotaNote: !installed
301
- ? 'not installed'
302
- : (hasRam ? `Unlimited local inference (${freeMemGB} GB free RAM)` : `Low host memory (${freeMemGB} GB free RAM)`),
303
- status: !installed ? 'not_installed' : (hasRam ? 'ready' : 'low-ram')
304
- };
305
- }
141
+ return { ok: true, timestamp: new Date().toISOString(), node: options.node || 'local', fleet: { ok: fleet.ok, error: fleet.error, machines: fleet.machines, answered: fleet.answered, nodes: fleet.nodes }, quotas };
142
+ }
306
143
 
144
+ /** Models with sourced figures, the leaderboards they came from, and pass rates measured on this machine. */
145
+ export async function getBenchmarks(options = {}) {
146
+ const catalog = getModelCatalog();
147
+ const receipts = options.ledger || await readReceipts();
307
148
  return {
308
- ok: true,
309
- timestamp: new Date().toISOString(),
310
- quotas
149
+ ok: true, updatedAt: catalog.updatedAt, synced: Boolean(catalog.updatedAt),
150
+ note: catalog.updatedAt ? undefined : 'Run `total-recall meta-harness maintenance --models` to fetch real figures.',
151
+ sources: catalog.sources, models: joinHarnessModels(catalog), leaderboards: catalog.leaderboards,
152
+ local: computeEmpiricalScorecard(receipts),
311
153
  };
312
154
  }
313
155
 
314
- /**
315
- * Query Benchmarks Matrix and Local Empirical Pass Rates
316
- */
317
- export function getBenchmarks(options = {}) {
318
- const localLedger = options.ledger || readLocalRunLedger();
319
- const empirical = computeEmpiricalScorecard(localLedger);
320
- const customAdapters = getActiveAdapters().filter(a => a.custom);
321
-
322
- const combined = {};
323
- for (const [id, bm] of Object.entries(BENCHMARK_MATRIX)) {
324
- const stats = empirical[id] || { total: 0, passed: 0, passRate: null, avgDurationMs: 0 };
325
- combined[id] = {
326
- ...bm,
327
- localRuns: stats.total,
328
- localPassRatePercent: stats.total > 0 ? stats.passRate : null,
329
- avgDurationMs: stats.total > 0 ? stats.avgDurationMs : null
330
- };
331
- }
332
-
333
- // Include any custom user adapters so their empirical pass rates are tracked too
334
- for (const custom of customAdapters) {
335
- if (!combined[custom.id]) {
336
- const stats = empirical[custom.id] || { total: 0, passed: 0, passRate: null, avgDurationMs: 0 };
337
- combined[custom.id] = {
338
- sweBenchPro: null,
339
- terminalBench2: null,
340
- artificialAnalysisElo: null,
341
- costPer1kTokens: null,
342
- provider: `Custom (${custom.name})`,
343
- localRuns: stats.total,
344
- localPassRatePercent: stats.total > 0 ? stats.passRate : null,
345
- avgDurationMs: stats.total > 0 ? stats.avgDurationMs : null
346
- };
347
- }
348
- }
156
+ /** Ask the decision plugin to classify. Its failure is reported; the caller sees which classifier answered. */
157
+ export function classifyWithDecision(task, run = args => runHostCli(args)) {
158
+ const questions = { complexity: { type: 'choice', prompt: 'How demanding is this software engineering task for a coding agent?', options: ['local', 'budget', 'frontier'] } };
159
+ const output = run(['decision', 'run', '--state', JSON.stringify({ task: task.slice(0, 2000) }), '--questions', JSON.stringify(questions), '--json']);
160
+ if (!output) throw new Error('The decision plugin did not answer');
161
+ const parsed = JSON.parse(output);
162
+ const answer = parsed.answers?.complexity ?? parsed.decision?.answers?.complexity ?? parsed.result?.complexity;
163
+ const tier = typeof answer === 'string' ? answer : answer?.choice;
164
+ if (!['local', 'budget', 'frontier'].includes(tier)) throw new Error('The decision plugin returned no usable tier');
165
+ return { tier, confidence: answer?.confidence ?? null };
166
+ }
349
167
 
350
- return {
351
- ok: true,
352
- updatedAt: new Date().toISOString(),
353
- matrix: combined
354
- };
168
+ /** Local-tier work goes to the online machine with the most free memory that reported telemetry. */
169
+ export function placeLocalWork(fleet = {}) {
170
+ const nodes = (fleet.nodes || []).filter(node => node.online !== false && typeof node.freeMemGB === 'number');
171
+ if (!nodes.length) return null;
172
+ const best = nodes.reduce((a, b) => (b.freeMemGB > a.freeMemGB ? b : a));
173
+ return { node: best.hostname, freeMemGB: best.freeMemGB };
355
174
  }
356
175
 
357
- /**
358
- * Route a task dynamically based on complexity, installed harnesses, quotas, and empirical pass rates
359
- */
360
176
  export async function routeTask(taskDescription, options = {}) {
361
- const complexity = classifyTaskComplexity(taskDescription, options);
362
- const quotaReport = await inspectQuotas(options);
363
- const quotas = quotaReport.quotas;
364
- const empiricalScorecard = computeEmpiricalScorecard(readLocalRunLedger());
365
-
366
- // Discover actually installed harnesses on the host unless caller passes an explicit pool
367
- let available = options.availableHarnesses;
368
- let installedOnly = true;
369
- if (!Array.isArray(available) || available.length === 0) {
177
+ let complexity = classifyTaskComplexity(taskDescription, options);
178
+ let classifier = { source: 'heuristic' };
179
+ if (options.jev) {
370
180
  try {
371
- const inspected = await inspectAgents({ env: process.env });
372
- const installedIds = (inspected.agents || []).filter(a => a.installed).map(a => a.id);
373
- if (installedIds.length > 0 && !options.includeUninstalled) {
374
- available = installedIds;
375
- } else {
376
- available = getActiveAdapters().map(a => a.id);
377
- installedOnly = false;
378
- }
379
- } catch {
380
- available = Object.keys(ADAPTER_CATALOG);
381
- installedOnly = false;
181
+ const decided = classifyWithDecision(taskDescription, options.decisionRun);
182
+ complexity = { ...complexity, tier: decided.tier, isFrontierRecommended: decided.tier === 'frontier', isLocalRecommended: decided.tier === 'local' };
183
+ classifier = { source: 'decision', confidence: decided.confidence };
184
+ } catch (error) {
185
+ classifier = { source: 'heuristic', decisionError: String(error.message).slice(0, 300) };
382
186
  }
383
187
  }
384
-
385
- const routing = selectOptimalHarness(taskDescription, available, quotas, {
386
- ...options,
387
- empiricalScorecard
388
- });
389
-
188
+ const [quotaReport, pool, receipts] = await Promise.all([inspectQuotas(options), resolvePool(options), readReceipts()]);
189
+ const quotas = quotaReport.quotas;
190
+ const routing = selectOptimalHarness(taskDescription, pool.ready.map(h => h.id), quotas, { ...options, tierOverride: complexity.tier, empiricalScorecard: computeEmpiricalScorecard(receipts) });
390
191
  const selectedQuota = quotas[routing.selected] || {};
391
- const usage = selectedQuota.usagePercent ?? null;
392
192
  const warnings = [];
393
- if (typeof usage === 'number' && usage > 85) {
394
- warnings.push(`Selected harness '${routing.selected}' is at ${usage}% measured quota usage.`);
395
- }
396
- if (selectedQuota.status === 'needs_auth') {
397
- warnings.push(`Selected harness '${routing.selected}' is installed but requires authentication.`);
398
- }
399
-
193
+ if (typeof selectedQuota.usagePercent === 'number' && selectedQuota.usagePercent > 85) warnings.push(`${routing.selected} is at ${selectedQuota.usagePercent}% measured usage.`);
194
+ if (selectedQuota.status === 'unverified') warnings.push(`${routing.selected} has no login probe; only a completed run proves it works.`);
195
+ if (selectedQuota.billingModel === 'metered') warnings.push(`${routing.selected} bills per token.`);
196
+ if (!routing.selected) warnings.push('No harness can take this task right now.');
400
197
  return {
401
- ok: true,
402
- task: taskDescription,
403
- complexity,
404
- selected: routing.selected,
405
- tier: routing.complexity.tier,
406
- installedOnlyPool: installedOnly,
407
- candidates: routing.candidates,
408
- quotaSnapshot: {
409
- selectedHarnessStatus: selectedQuota.status || 'unknown',
410
- selectedHarnessUsage: usage,
411
- freeMemGB: quotas.system.freeMemGB
412
- },
413
- warnings
198
+ ok: Boolean(routing.selected), task: taskDescription, classifier, complexity,
199
+ selected: routing.selected, tier: complexity.tier, candidates: routing.candidates, excluded: pool.excluded,
200
+ placement: complexity.tier === 'local' ? placeLocalWork(quotaReport.fleet) : null,
201
+ scoring: 'Adapter quality and cost scores are configured priors, adjusted by pass rates measured on this machine.',
202
+ quotaSnapshot: { selectedHarnessStatus: selectedQuota.status || null, selectedHarnessUsage: selectedQuota.usagePercent ?? null, freeMemGB: quotas.system.freeMemGB ?? null },
203
+ warnings,
414
204
  };
415
205
  }
@@ -16,7 +16,7 @@ export async function manageRuntime(agent, args = [], { env = process.env, probe
16
16
  let result, code;
17
17
  try {
18
18
  console.log = (...parts) => lines.push(parts.join(' ')); console.error = (...parts) => errors.push(parts.join(' '));
19
- result = await run([process.execPath, 'cli-agents', 'dsh', ...args]);
19
+ result = await run([process.execPath, 'meta-harness', 'dsh', ...args]);
20
20
  code = process.exitCode || 0;
21
21
  } finally { console.log = log; console.error = error; process.exitCode = previous; }
22
22
  return { ok:code === 0, agent, exitCode:code, data:result?.data, output:lines.join('\n'), error:errors.join('\n') || undefined };
@@ -0,0 +1,20 @@
1
+ /** Bind only to the verified native Total Recall storage contract. */
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { pathToFileURL, fileURLToPath } from 'node:url';
5
+
6
+ function resolveStateStoreSource() {
7
+ const here = path.dirname(fileURLToPath(import.meta.url));
8
+ const candidates = [process.env.TR_PACKAGE_ROOT, path.resolve(here, '..', '..', 'total-recall'), path.resolve(process.cwd(), '..', 'total-recall'), process.cwd()].filter(Boolean);
9
+ for (const root of candidates) {
10
+ try {
11
+ if (JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')).name !== 'total-recall-brain') continue;
12
+ const file = path.join(root, 'src/core/plugin-state-store.mjs');
13
+ if (fs.existsSync(file)) return file;
14
+ } catch { /* try the next candidate */ }
15
+ }
16
+ return null;
17
+ }
18
+ const source = resolveStateStoreSource();
19
+ if (!source) throw new Error('Cannot bind the native Total Recall storage contract: no total-recall-brain host found. Run inside a Total Recall host or set TR_PACKAGE_ROOT.');
20
+ export const { PluginStateStore } = await import(pathToFileURL(source).href);
@@ -0,0 +1,43 @@
1
+ /** Usage figures the harnesses themselves recorded on this machine. */
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+
6
+ function recentSessionFiles(dir, depth = 3, limit = 5) {
7
+ let names;
8
+ try { names = fs.readdirSync(dir).sort().reverse(); } catch { return []; }
9
+ const files = [];
10
+ for (const name of names) {
11
+ const full = path.join(dir, name);
12
+ if (depth > 0) files.push(...recentSessionFiles(full, depth - 1, limit));
13
+ else if (name.endsWith('.jsonl')) files.push(full);
14
+ if (files.length >= limit) break;
15
+ }
16
+ return files;
17
+ }
18
+
19
+ /** Codex logs its real rate-limit windows. A window whose reset has passed no longer applies. */
20
+ export function readCodexRateLimits({ sessionsDir = path.join(process.env.CODEX_HOME || path.join(process.env.HOME || os.homedir(), '.codex'), 'sessions'), now = Date.now() } = {}) {
21
+ const live = window => (window && typeof window.used_percent === 'number' && window.resets_at * 1000 > now ? window : null);
22
+ for (const file of recentSessionFiles(sessionsDir)) {
23
+ const lines = fs.readFileSync(file, 'utf8').trim().split('\n').reverse();
24
+ for (const line of lines) {
25
+ if (!line.includes('"used_percent"')) continue;
26
+ try {
27
+ const event = JSON.parse(line);
28
+ const limits = event.payload?.rate_limits;
29
+ if (!limits?.primary && !limits?.secondary) continue;
30
+ return { observedAt: event.timestamp || null, primary: live(limits.primary), secondary: live(limits.secondary) };
31
+ } catch { /* a partial line */ }
32
+ }
33
+ }
34
+ return null;
35
+ }
36
+
37
+ /** Quota walls from measured usage: a live window at 100% blocks the harness until it resets. */
38
+ export function measuredWalls(limits = readCodexRateLimits()) {
39
+ const full = [limits?.primary, limits?.secondary].filter(window => window && window.used_percent >= 100);
40
+ if (!full.length) return {};
41
+ const until = Math.max(...full.map(window => window.resets_at)) * 1000;
42
+ return { codex: { until: new Date(until).toISOString(), resetReported: true, observedAt: limits.observedAt, message: 'Codex session log shows a rate-limit window at 100%.' } };
43
+ }