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.
- package/bin/total-recall.mjs +10 -6
- package/docs/reference/cli-reference.md +18 -0
- package/frontend/dist/assets/index-4tGQfTa2.js +5605 -0
- package/frontend/dist/assets/index-DtwsDyFM.css +1 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/package.json +11 -0
- package/frontend/src/App.tsx +47 -122
- package/frontend/src/components/plugins/plugin-frame.ts +1 -0
- package/frontend/src/index.css +152 -86
- package/frontend/src/pages/HelpPage.tsx +13 -10
- package/frontend/src/pages/MemoryPage.tsx +28 -30
- package/frontend/src/pages/NetworkPage.tsx +3 -3
- package/frontend/src/pages/PluginsPage.tsx +6 -5
- package/frontend/src/pages/RulesPage.tsx +16 -12
- package/package.json +4 -3
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +3114 -36
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +4 -1
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +3114 -36
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +4 -1
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +3121 -33
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +4 -1
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +3122 -34
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +4 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +3127 -49
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +5 -2
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +136 -7
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +135 -26
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +3121 -33
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +5 -2
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +228 -9
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +24 -30
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +29 -16
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +73 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +182 -365
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +33 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +40 -14
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/agy.mjs +187 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/claude.mjs +275 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cline.mjs +132 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/codex.mjs +187 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cursor.mjs +158 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/devin.mjs +157 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/dsh.mjs +183 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/grok.mjs +132 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/hermes.mjs +173 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/index.mjs +87 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/openclaw.mjs +173 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/pi.mjs +129 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate.mjs +12 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/json-reply.mjs +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +72 -70
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/model-catalog.mjs +195 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/paths.mjs +11 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/pool.mjs +36 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/review.mjs +169 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +136 -346
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/ssss-store.mjs +20 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/telemetry.mjs +43 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/threads.mjs +156 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +117 -35
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worktree.mjs +51 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +398 -57
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +304 -46
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +367 -41
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +5 -2
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +33 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/config.mjs +2 -2
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/generate.mjs +159 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/graph.mjs +197 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/lint.mjs +153 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/mesh-vaults.mjs +261 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +151 -4
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/search.mjs +114 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/token.mjs +96 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +899 -662
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/openwiki.mjs +8987 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/mermaid-diagrams/SKILL.md +44 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/write-connector/SKILL.md +56 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +3097 -81
- package/scaffold/.agent/skills/total-recall/plugins/security/package.json +4 -1
- package/src/cli/agent.mjs +12 -1
- package/src/cli/compact.mjs +108 -0
- package/src/cli/connect.mjs +56 -1
- package/src/cli/context.mjs +55 -23
- package/src/cli/doctor.mjs +5 -2
- package/src/cli/forget.mjs +2 -0
- package/src/cli/harness.mjs +62 -50
- package/src/cli/memory-entry.mjs +2 -2
- package/src/cli/preflight.mjs +152 -16
- package/src/cli/release.mjs +386 -0
- package/src/cli/remember.mjs +19 -1
- package/src/cli/rules.mjs +54 -12
- package/src/cli/startup.mjs +1 -1
- package/src/cli/status.mjs +12 -2
- package/src/core/claude-hooks.mjs +41 -3
- package/src/core/cli-commands.mjs +2 -0
- package/src/core/cli-semantic-index.mjs +3 -2
- package/src/core/conflict-detector.mjs +23 -12
- package/src/core/context-compactor.mjs +145 -0
- package/src/core/context-policy.mjs +20 -0
- package/src/core/duplicate-guard.mjs +350 -0
- package/src/core/meta-harness.mjs +31 -11
- package/src/core/preflight-gate.mjs +2 -2
- package/src/core/preflight-receipt.mjs +29 -1
- package/src/core/scaffold-plugins.mjs +7 -0
- package/src/core/stdio-flush.mjs +23 -0
- package/src/core/surface.mjs +33 -10
- package/src/server/invoke-durability.mjs +39 -0
- package/src/server/invoke-write-child.mjs +25 -0
- package/src/server/routes/invoke.mjs +7 -0
- package/src/server/routes/plugins.mjs +2 -2
- package/frontend/dist/assets/index-BIQmqDKP.css +0 -1
- package/frontend/dist/assets/index-CRzjQLu7.js +0 -5631
- package/frontend/src/components/DaemonLogsTab.tsx +0 -54
- package/frontend/src/components/ResearchAgendaTab.tsx +0 -712
- package/frontend/src/components/TaskQueueTab.tsx +0 -193
- package/frontend/src/components/VoiceInput.tsx +0 -112
- package/frontend/src/pages/ChatPage.tsx +0 -1059
- package/frontend/src/pages/CollabPage.tsx +0 -470
- package/frontend/src/pages/DesignDocsPage.tsx +0 -621
- package/frontend/src/pages/FilesPage.tsx +0 -393
- package/frontend/src/pages/HealthPage.tsx +0 -359
- package/frontend/src/pages/InboxPage.tsx +0 -83
- package/frontend/src/pages/InstructionsPage.tsx +0 -583
- package/frontend/src/pages/IntegrationsPage.tsx +0 -761
- package/frontend/src/pages/MeshPage.css +0 -58
- package/frontend/src/pages/MeshPage.tsx +0 -1219
- package/frontend/src/pages/OkfPage.tsx +0 -535
- package/frontend/src/pages/SandboxPage.tsx +0 -113
- package/frontend/src/pages/SkillsPage.tsx +0 -1994
- package/frontend/src/pages/TasksPage.tsx +0 -427
- package/frontend/src/pages/UsagePage.tsx +0 -702
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/README.md +0 -65
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/cli.mjs +0 -76
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/package.json +0 -19
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/plugin.json +0 -266
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/adapters/dsh.mjs +0 -446
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/documentation.mjs +0 -152
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/executor.mjs +0 -71
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/runtime.mjs +0 -36
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/setup.mjs +0 -35
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/worker.mjs +0 -175
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/DESIGN.md +0 -32
- 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
|
-
* -
|
|
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 {
|
|
18
|
-
import { inspectAgents
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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:
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
//
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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 =
|
|
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
|
-
|
|
287
|
-
|
|
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
|
-
|
|
310
|
-
|
|
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
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
const
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
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
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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
|
|
386
|
-
|
|
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
|
|
394
|
-
|
|
395
|
-
}
|
|
396
|
-
if (
|
|
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:
|
|
402
|
-
|
|
403
|
-
complexity,
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
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, '
|
|
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
|
+
}
|