@inetafrica/open-claudia 3.5.61 → 3.5.63
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/CHANGELOG.md +19 -0
- package/channels/kazee/adapter.js +9 -3
- package/core/cost-report.js +86 -13
- package/core/model-prices.js +123 -0
- package/core/passive-replies.js +3 -1
- package/core/recall/discoverer.js +21 -1
- package/core/recall/warm-walker.js +11 -1
- package/core/usage-log.js +53 -0
- package/core/utility-agent.js +28 -1
- package/package.json +2 -2
- package/test-provider-language.js +7 -1
- package/web.js +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.5.63
|
|
4
|
+
|
|
5
|
+
3.5.62 plus a passive-group fix (APP-29; Sumeet, 14 Oct: "my chat with Judith Brenda and books bot ... doesn't seem to be auto waking yet it's definitely relevant"). Canary first.
|
|
6
|
+
|
|
7
|
+
- **A captioned screenshot or file is judged in a "reply when they can help" group.** The group gate only handed plain text to the passive check, so every message with an attachment was skipped, captioned or not. In Kazee Books update, Judith's three screenshots ("Add 'Transaction' under banking", the exchange rate, "Editing of Journal Entry missing") each logged `Kazee group gate: silent` and the books bot only answered when tagged. A photo or file with a caption now goes to the check, shown as `[photo] <caption>`, and if the bot replies the attachment rides along to the turn. Voice notes, words-less media, commands, cards and other bots' messages are still skipped.
|
|
8
|
+
|
|
9
|
+
Tests: `test-passive-replies.js` (captioned photo and file judged; a words-less voice note still skipped; the check's prompt reads `[photo] <caption>`).
|
|
10
|
+
|
|
11
|
+
## 3.5.62
|
|
12
|
+
|
|
13
|
+
3.5.61 plus spend split by part (APP-28; Sumeet, 14 Oct: "how much is used for memory? How much is used for work? How much is used for the dream?"). Canary first.
|
|
14
|
+
|
|
15
|
+
- **Every background call is logged with what it was for.** The recall finder, note reviewer, dream, reply guard, passive replies, thread titles, dedup and sub-agents run as background Claude calls with no saved session, so their spend left no trace. Each now writes a usage-history row: `usageScope: "utility"`, `purpose`, its tokens, `costUsd` priced from those tokens, `priced`, `ok`, `durationMs`. Codex calls are logged unpriced. A ledger failure never fails the call.
|
|
16
|
+
- **Prices come from tokens, not Claude Code's figure.** New `core/model-prices.js` (Anthropic list prices). Claude Code 2.1.280 does not know claude-haiku-5-5 and bills it at Opus 5.5 rates, so the recall finder's logged cost (recall metrics, the dream's "recall spend") was 20-40x too high. The warm walker now prices each walk from that message's own usage.
|
|
17
|
+
- **The dream's weekly cost line is priced from tokens and split by part.** It summed the ledger's costUsd, which is a running total per conversation (14 Oct: 8,862 USD shown for a week that cost about 2,400 priced call by call). It now prices each turn from its tokens (rows without a model as Opus 5.5), skips cumulative snapshots, and adds a "By part" line: chats and checks, summaries (compactions), and each background purpose.
|
|
18
|
+
- The dashboard's usage charts leave background rows out of their turn counts.
|
|
19
|
+
|
|
20
|
+
Tests: `test-cost-by-part.js` (new); `test-cost-report.js` moved to token pricing. The oc-usage tool's new `parts` verb reads these rows per day or week.
|
|
21
|
+
|
|
3
22
|
## 3.5.61
|
|
4
23
|
|
|
5
24
|
3.5.60 plus a chat turn that survives Claude Code's sign-in refresh race (home pi, 14 Oct 06:48 EAT: "Claude Code run failed: Failed to refresh OAuth token: another Claude Code process is refreshing it or exited mid-refresh"; Sumeet: "handle it internally and do like a back off"). Canary first.
|
|
@@ -47,6 +47,9 @@ const CATCHUP_FETCH_TIMEOUT_MS = 15000;
|
|
|
47
47
|
const CONTEXT_MAX_MESSAGES = 40;
|
|
48
48
|
const CONTEXT_BODY_LIMIT = 280;
|
|
49
49
|
const COLD_START_WINDOW = 40;
|
|
50
|
+
// What a passive group's check reads (router types): text, and photos or
|
|
51
|
+
// files when they carry a caption. Voice notes have no words until heard.
|
|
52
|
+
const PASSIVE_JUDGED_TYPES = new Set(["text", "photo", "document"]);
|
|
50
53
|
|
|
51
54
|
// Chat threads ("reply in thread"). Button presses carry no thread, so the
|
|
52
55
|
// adapter remembers which thread each message it posted went into (and that
|
|
@@ -1091,10 +1094,13 @@ class KazeeAdapter {
|
|
|
1091
1094
|
}
|
|
1092
1095
|
|
|
1093
1096
|
// Whether an unaddressed message in a passive group is the bot's to judge:
|
|
1094
|
-
//
|
|
1095
|
-
//
|
|
1097
|
+
// words a person wrote, as plain text or as the caption on a photo or file
|
|
1098
|
+
// (14 Oct: Judith's Books screenshots captioned "Editing of Journal Entry
|
|
1099
|
+
// missing" never reached the check). Never another bot (no bot-to-bot
|
|
1100
|
+
// chatter), never a command, system notice, card, voice note or media
|
|
1101
|
+
// without words.
|
|
1096
1102
|
_passiveCandidate(msg, envelope, meta, senderId) {
|
|
1097
|
-
if (envelope.type
|
|
1103
|
+
if (!PASSIVE_JUDGED_TYPES.has(envelope.type) || !String(envelope.text || "").trim()) return false;
|
|
1098
1104
|
if (msg.type === "system" || msg.type === "interactive" || msg.card) return false;
|
|
1099
1105
|
if ((meta.botIds || []).includes(String(senderId))) return false;
|
|
1100
1106
|
return true;
|
package/core/cost-report.js
CHANGED
|
@@ -8,6 +8,21 @@
|
|
|
8
8
|
// surface, nothing recorded at turn time beyond what already exists.
|
|
9
9
|
|
|
10
10
|
const usageLog = require("./usage-log");
|
|
11
|
+
const { priceRecord } = require("./model-prices");
|
|
12
|
+
|
|
13
|
+
// Plain names for background-call purposes in the by-part line.
|
|
14
|
+
const PART_NAMES = {
|
|
15
|
+
recall: "recall finder",
|
|
16
|
+
review: "note reviewer",
|
|
17
|
+
dream: "dream",
|
|
18
|
+
learn: "learn",
|
|
19
|
+
enforcer: "reply guard",
|
|
20
|
+
"passive-reply": "passive replies",
|
|
21
|
+
"thread-title": "thread titles",
|
|
22
|
+
dedup: "dedup",
|
|
23
|
+
"side-chat": "side chats",
|
|
24
|
+
subagent: "sub-agents",
|
|
25
|
+
};
|
|
11
26
|
|
|
12
27
|
const WINDOW_DAYS = 7;
|
|
13
28
|
// Heuristic thresholds (exported for tests): concentration of spend in one
|
|
@@ -31,28 +46,55 @@ function inWindow(ts, from, to) {
|
|
|
31
46
|
return Number.isFinite(t) && t >= from && t < to;
|
|
32
47
|
}
|
|
33
48
|
|
|
49
|
+
// Spend is priced from each row's own tokens (core/model-prices.js). The
|
|
50
|
+
// ledger's costUsd is the CLI's running total for a conversation, so summing
|
|
51
|
+
// it overstated a week roughly fourfold (14 Oct: 8,862 USD shown vs about
|
|
52
|
+
// 2,400 priced call by call). Background-call rows (usageScope "utility")
|
|
53
|
+
// carry a cost already priced from their tokens.
|
|
34
54
|
function aggregate(records) {
|
|
35
55
|
const agg = {
|
|
36
56
|
turns: 0, costUsd: 0, inputTokens: 0, outputTokens: 0,
|
|
37
57
|
cacheReadTokens: 0, contextTokenSum: 0, contextTurns: 0,
|
|
58
|
+
unpricedTurns: 0,
|
|
59
|
+
compactions: 0, compactionUsd: 0,
|
|
60
|
+
utilityCalls: 0, utilityUsd: 0, unpricedUtility: 0,
|
|
61
|
+
byPurpose: new Map(),
|
|
38
62
|
byProject: new Map(),
|
|
39
63
|
};
|
|
40
64
|
for (const r of records) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
65
|
+
if (r.kind === "compaction") {
|
|
66
|
+
// A compaction is not a turn; price it from compactionUsage's tokens.
|
|
67
|
+
agg.compactions += 1;
|
|
68
|
+
const priced = r.compactionUsage ? priceRecord({ ...r.compactionUsage, model: r.model }) : null;
|
|
69
|
+
agg.compactionUsd += priced ? priced.costUsd : 0;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (r.usageScope === "utility") {
|
|
73
|
+
agg.utilityCalls += 1;
|
|
74
|
+
const cost = Number(r.costUsd);
|
|
75
|
+
if (r.priced === false || !Number.isFinite(cost)) agg.unpricedUtility += 1;
|
|
76
|
+
const usd = Number.isFinite(cost) ? cost : 0;
|
|
77
|
+
agg.utilityUsd += usd;
|
|
78
|
+
const key = String(r.purpose || "unknown");
|
|
79
|
+
const p = agg.byPurpose.get(key) || { costUsd: 0, calls: 0 };
|
|
80
|
+
p.costUsd += usd;
|
|
81
|
+
p.calls += 1;
|
|
82
|
+
agg.byPurpose.set(key, p);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
// session_total records carry cumulative token snapshots: pricing them
|
|
86
|
+
// would double-bill the turns they sum up.
|
|
87
|
+
if (r.usageScope === "session_total") continue;
|
|
44
88
|
agg.turns += 1;
|
|
45
|
-
const
|
|
89
|
+
const priced = r.provider === "codex" || r.backend === "codex" ? null : priceRecord(r);
|
|
90
|
+
if (!priced) agg.unpricedTurns += 1;
|
|
91
|
+
const cost = priced ? priced.costUsd : 0;
|
|
46
92
|
agg.costUsd += cost;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
agg.cacheReadTokens += Number(r.cacheReadTokens) || 0;
|
|
53
|
-
const ctx = Number(r.billedContextTokens ?? r.contextTokens) || 0;
|
|
54
|
-
if (ctx > 0) { agg.contextTokenSum += ctx; agg.contextTurns += 1; }
|
|
55
|
-
}
|
|
93
|
+
agg.inputTokens += Number(r.inputTokens) || 0;
|
|
94
|
+
agg.outputTokens += Number(r.outputTokens) || 0;
|
|
95
|
+
agg.cacheReadTokens += Number(r.cacheReadTokens) || 0;
|
|
96
|
+
const ctx = Number(r.billedContextTokens ?? r.contextTokens) || 0;
|
|
97
|
+
if (ctx > 0) { agg.contextTokenSum += ctx; agg.contextTurns += 1; }
|
|
56
98
|
const key = String(r.project || "(no project)");
|
|
57
99
|
const p = agg.byProject.get(key) || { costUsd: 0, turns: 0 };
|
|
58
100
|
p.costUsd += cost;
|
|
@@ -108,6 +150,27 @@ function weeklyReport({ now = Date.now(), days = WINDOW_DAYS, history } = {}) {
|
|
|
108
150
|
deltaPct: previous.costUsd > 0 ? Math.round(((current.costUsd - previous.costUsd) / previous.costUsd) * 100) : null,
|
|
109
151
|
topBurns: burns,
|
|
110
152
|
suggestedCut: suggestCut(current, burns),
|
|
153
|
+
unpricedTurns: current.unpricedTurns,
|
|
154
|
+
parts: byPart(current),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Spend by part for the window: chats and scheduled checks (turns),
|
|
159
|
+
// conversation summaries (compactions), then each background purpose.
|
|
160
|
+
function byPart(agg) {
|
|
161
|
+
const round = (n) => Math.round(n * 100) / 100;
|
|
162
|
+
const parts = [
|
|
163
|
+
{ key: "turns", name: "chats and checks", costUsd: round(agg.costUsd), count: agg.turns },
|
|
164
|
+
{ key: "compactions", name: "summaries", costUsd: round(agg.compactionUsd), count: agg.compactions },
|
|
165
|
+
];
|
|
166
|
+
const background = [...agg.byPurpose.entries()]
|
|
167
|
+
.map(([purpose, v]) => ({ key: purpose, name: PART_NAMES[purpose] || purpose, costUsd: round(v.costUsd), count: v.calls }))
|
|
168
|
+
.sort((a, b) => b.costUsd - a.costUsd);
|
|
169
|
+
return {
|
|
170
|
+
total: round(agg.costUsd + agg.compactionUsd + agg.utilityUsd),
|
|
171
|
+
items: parts.concat(background),
|
|
172
|
+
backgroundLogged: agg.utilityCalls > 0,
|
|
173
|
+
unpricedBackground: agg.unpricedUtility,
|
|
111
174
|
};
|
|
112
175
|
}
|
|
113
176
|
|
|
@@ -124,6 +187,14 @@ function reportLines(opts = {}) {
|
|
|
124
187
|
const lines = [
|
|
125
188
|
`💸 Cost, last ${r.days}d: $${r.costUsd.toFixed(2)} · ${r.turns} turn${r.turns === 1 ? "" : "s"} · ${fmtTokens(r.inputTokens)} in / ${fmtTokens(r.outputTokens)} out${cacheTxt}${deltaTxt}.${burnsTxt}`,
|
|
126
189
|
];
|
|
190
|
+
const parts = r.parts;
|
|
191
|
+
if (parts) {
|
|
192
|
+
const shown = parts.items.filter((p) => p.count > 0);
|
|
193
|
+
const tail = parts.backgroundLogged ? "" : " · background calls not logged yet";
|
|
194
|
+
if (shown.length) {
|
|
195
|
+
lines.push(`🧾 By part, last ${r.days}d: ${shown.map((p) => `${p.name} $${p.costUsd.toFixed(2)}`).join(" · ")}${tail} (priced from tokens at list rates).`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
127
198
|
if (r.suggestedCut) lines.push(`💡 Cut: ${r.suggestedCut}`);
|
|
128
199
|
return { report: r, lines };
|
|
129
200
|
}
|
|
@@ -135,7 +206,9 @@ module.exports = {
|
|
|
135
206
|
CACHE_RATIO_FLOOR,
|
|
136
207
|
CACHE_MIN_INPUT_TOKENS,
|
|
137
208
|
CONTEXT_AVG_CEILING,
|
|
209
|
+
PART_NAMES,
|
|
138
210
|
aggregate,
|
|
211
|
+
byPart,
|
|
139
212
|
topBurns,
|
|
140
213
|
suggestCut,
|
|
141
214
|
weeklyReport,
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// Anthropic list prices, USD per million tokens:
|
|
4
|
+
// [input, output, cache read, 5-minute cache write, 1-hour cache write].
|
|
5
|
+
//
|
|
6
|
+
// Accounting prices calls from their own tokens instead of trusting the CLI's
|
|
7
|
+
// total_cost_usd: Claude Code 2.1.280 does not know claude-haiku-5-5
|
|
8
|
+
// ("unrecognized_model", costBasis "unknown") and bills it at Opus 5.5 rates,
|
|
9
|
+
// 20-40x too high (probe, 14 Oct 2026: 10,418 cache reads + 2 in + 4 out =
|
|
10
|
+
// 0.0021716 USD, exactly 4/20/0.20 per million). Sources: the Anthropic
|
|
11
|
+
// pricing page (9 Oct 2026) for the 5.5 family, the claude-api model table for
|
|
12
|
+
// the rest. Same table as the oc-usage tool.
|
|
13
|
+
const PRICES = {
|
|
14
|
+
"claude-opus-5-5": [4, 20, 0.2, 5, 8],
|
|
15
|
+
"claude-opus-5": [5, 25, 0.5, 6.25, 10],
|
|
16
|
+
"claude-opus-4-8": [5, 25, 0.5, 6.25, 10],
|
|
17
|
+
"claude-opus-4-7": [5, 25, 0.5, 6.25, 10],
|
|
18
|
+
"claude-opus-4-6": [5, 25, 0.5, 6.25, 10],
|
|
19
|
+
"claude-fable-5-1": [10, 50, 0.25, 12.5, 20],
|
|
20
|
+
"claude-fable-5": [10, 50, 1, 12.5, 20],
|
|
21
|
+
"claude-sonnet-5-5": [2, 10, 0.1, 2.5, 4],
|
|
22
|
+
"claude-sonnet-5": [2, 10, 0.2, 2.5, 4],
|
|
23
|
+
"claude-sonnet-4-6": [3, 15, 0.3, 3.75, 6],
|
|
24
|
+
"claude-haiku-4-5": [1, 5, 0.1, 1.25, 2],
|
|
25
|
+
// Haiku 5.5 is priced by prompt length: this up to 100,000 prompt tokens
|
|
26
|
+
// (input + cache reads + cache writes), HAIKU_5_5_LONG above.
|
|
27
|
+
"claude-haiku-5-5": [0.1, 0.5, 0.01, 0.125, 0.2],
|
|
28
|
+
};
|
|
29
|
+
const HAIKU_5_5_LONG = [0.5, 2.5, 0.05, 0.625, 1];
|
|
30
|
+
const HAIKU_5_5_LONG_FROM = 100000;
|
|
31
|
+
|
|
32
|
+
// Rows written before a turn's model was known (the room used the provider
|
|
33
|
+
// default) are priced as this model. Every bot runs Opus 5.5 by default.
|
|
34
|
+
const DEFAULT_PRICED_MODEL = "claude-opus-5-5";
|
|
35
|
+
|
|
36
|
+
function priceOf(model) {
|
|
37
|
+
const m = String(model || "").trim().replace(/\[.*\]$/, "").replace(/-\d{8}$/, "");
|
|
38
|
+
if (!m) return null;
|
|
39
|
+
if (PRICES[m]) return PRICES[m];
|
|
40
|
+
const key = Object.keys(PRICES).sort((a, b) => b.length - a.length).find((p) => m.startsWith(p));
|
|
41
|
+
return key ? PRICES[key] : null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function num(value) {
|
|
45
|
+
const n = Number(value);
|
|
46
|
+
return Number.isFinite(n) && n > 0 ? n : 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function round6(n) {
|
|
50
|
+
return Math.round(n * 1e6) / 1e6;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Price token counts: { input, output, cacheRead, cacheWrite5m, cacheWrite1h,
|
|
54
|
+
// cacheCreation } where cacheCreation is an unsplit write total, priced at
|
|
55
|
+
// the 1-hour rate (Open Claudia caches for an hour). Returns
|
|
56
|
+
// { costUsd, parts } or null when the model has no price (Codex, unknown).
|
|
57
|
+
function priceTokens(tokens = {}, model, options = {}) {
|
|
58
|
+
let p = priceOf(model);
|
|
59
|
+
if (!p) return null;
|
|
60
|
+
const input = num(tokens.input);
|
|
61
|
+
const output = num(tokens.output);
|
|
62
|
+
const cacheRead = num(tokens.cacheRead);
|
|
63
|
+
const split = tokens.cacheWrite5m != null || tokens.cacheWrite1h != null;
|
|
64
|
+
const w5 = split ? num(tokens.cacheWrite5m) : 0;
|
|
65
|
+
const w1 = split ? num(tokens.cacheWrite1h) : num(tokens.cacheCreation);
|
|
66
|
+
if (p === PRICES["claude-haiku-5-5"] && input + cacheRead + w5 + w1 > HAIKU_5_5_LONG_FROM) p = HAIKU_5_5_LONG;
|
|
67
|
+
const k = (options.fast ? 2 : 1) / 1e6;
|
|
68
|
+
const parts = {
|
|
69
|
+
input: round6(input * p[0] * k),
|
|
70
|
+
output: round6(output * p[1] * k),
|
|
71
|
+
reads: round6(cacheRead * p[2] * k),
|
|
72
|
+
writes5m: round6(w5 * p[3] * k),
|
|
73
|
+
writes1h: round6(w1 * p[4] * k),
|
|
74
|
+
};
|
|
75
|
+
const costUsd = round6(parts.input + parts.output + parts.reads + parts.writes5m + parts.writes1h);
|
|
76
|
+
return { costUsd, parts };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Token counts from one Anthropic usage block (a result or message `usage`).
|
|
80
|
+
function tokensFromUsage(usage = {}) {
|
|
81
|
+
const cc = usage.cache_creation || {};
|
|
82
|
+
const split = cc.ephemeral_5m_input_tokens != null || cc.ephemeral_1h_input_tokens != null;
|
|
83
|
+
return {
|
|
84
|
+
input: num(usage.input_tokens),
|
|
85
|
+
output: num(usage.output_tokens),
|
|
86
|
+
cacheRead: num(usage.cache_read_input_tokens),
|
|
87
|
+
cacheCreation: num(usage.cache_creation_input_tokens),
|
|
88
|
+
...(split ? { cacheWrite5m: num(cc.ephemeral_5m_input_tokens), cacheWrite1h: num(cc.ephemeral_1h_input_tokens) } : {}),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function priceUsage(usage, model) {
|
|
93
|
+
if (!usage || typeof usage !== "object") return null;
|
|
94
|
+
return priceTokens(tokensFromUsage(usage), model, { fast: usage.speed === "fast" });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Price one usage-history row from its own token fields. The ledger's costUsd
|
|
98
|
+
// is the CLI's running total for the conversation, so summing it overstates
|
|
99
|
+
// spend (8 Oct: 49.7k USD summed vs 12.4k priced call by call).
|
|
100
|
+
function priceRecord(record = {}, options = {}) {
|
|
101
|
+
const model = record.model || options.defaultModel || DEFAULT_PRICED_MODEL;
|
|
102
|
+
return priceTokens({
|
|
103
|
+
input: record.inputTokens,
|
|
104
|
+
output: record.outputTokens,
|
|
105
|
+
cacheRead: record.cacheReadTokens,
|
|
106
|
+
cacheCreation: record.cacheCreationTokens,
|
|
107
|
+
...(record.cacheWrite5mTokens != null || record.cacheWrite1hTokens != null
|
|
108
|
+
? { cacheWrite5m: record.cacheWrite5mTokens, cacheWrite1h: record.cacheWrite1hTokens }
|
|
109
|
+
: {}),
|
|
110
|
+
}, model);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = {
|
|
114
|
+
PRICES,
|
|
115
|
+
HAIKU_5_5_LONG,
|
|
116
|
+
HAIKU_5_5_LONG_FROM,
|
|
117
|
+
DEFAULT_PRICED_MODEL,
|
|
118
|
+
priceOf,
|
|
119
|
+
priceTokens,
|
|
120
|
+
priceUsage,
|
|
121
|
+
priceRecord,
|
|
122
|
+
tokensFromUsage,
|
|
123
|
+
};
|
package/core/passive-replies.js
CHANGED
|
@@ -196,7 +196,9 @@ function createPassiveGate(dependencies = {}) {
|
|
|
196
196
|
for (const item of batch) {
|
|
197
197
|
const id = String(item.envelope.messageId || "");
|
|
198
198
|
if (id && !seen.has(id)) {
|
|
199
|
-
|
|
199
|
+
// A captioned photo or file reads the way the room's history shows it.
|
|
200
|
+
const kind = item.envelope.media?.length ? `[${item.envelope.type}] ` : "";
|
|
201
|
+
list.push({ id, who: item.envelope.from?.name || "Someone", text: kind + (item.envelope.text || ""), ago: "just now" });
|
|
200
202
|
seen.add(id);
|
|
201
203
|
}
|
|
202
204
|
}
|
|
@@ -346,9 +346,26 @@ async function runWalker(prompt, options = {}) {
|
|
|
346
346
|
systemPrompt,
|
|
347
347
|
timeoutMs: WALKER_TIMEOUT_MS,
|
|
348
348
|
};
|
|
349
|
+
const recordUsage = options.recordUsage || require("../usage-log").recordUtilityUsage;
|
|
349
350
|
if (warm.isEnabled(selection.provider)) {
|
|
350
351
|
try {
|
|
352
|
+
const startedAt = Date.now();
|
|
351
353
|
const result = await warm.walkWarm(prompt, opts);
|
|
354
|
+
// The warm walker bypasses spawnUtilityAgent, so it logs its own
|
|
355
|
+
// priced ledger row (a cold walk is logged by spawnUtilityAgent).
|
|
356
|
+
try {
|
|
357
|
+
if (result.usage) {
|
|
358
|
+
recordUsage({
|
|
359
|
+
usage: result.usage,
|
|
360
|
+
provider: selection.providerId,
|
|
361
|
+
model: result.model || selection.model || null,
|
|
362
|
+
purpose: "recall",
|
|
363
|
+
source: "warm",
|
|
364
|
+
ok: true,
|
|
365
|
+
durationMs: Date.now() - startedAt,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
} catch (_) { /* accounting is best effort */ }
|
|
352
369
|
return {
|
|
353
370
|
text: result.text,
|
|
354
371
|
costUsd: result.costUsd,
|
|
@@ -377,9 +394,12 @@ async function runWalker(prompt, options = {}) {
|
|
|
377
394
|
timeoutMs: WALKER_TIMEOUT_MS,
|
|
378
395
|
cwd: options.cwd || process.cwd(),
|
|
379
396
|
});
|
|
397
|
+
const coldPriced = result.usage?.usage
|
|
398
|
+
? require("../model-prices").priceUsage(result.usage.usage, result.model || selection.model)
|
|
399
|
+
: null;
|
|
380
400
|
return {
|
|
381
401
|
text: result.text,
|
|
382
|
-
costUsd: null,
|
|
402
|
+
costUsd: coldPriced ? coldPriced.costUsd : null,
|
|
383
403
|
source: "cold",
|
|
384
404
|
provider: result.provider || selection.providerId,
|
|
385
405
|
model: result.model || selection.model,
|
|
@@ -9,6 +9,7 @@ const { spawn } = require("child_process");
|
|
|
9
9
|
const { StringDecoder } = require("string_decoder");
|
|
10
10
|
const { killProcessTree } = require("../process-tree");
|
|
11
11
|
const { redactSensitive } = require("../redact");
|
|
12
|
+
const { priceUsage } = require("../model-prices");
|
|
12
13
|
|
|
13
14
|
const MAX_MSGS = Number(process.env.RECALL_WARM_WALKER_MAX_MSGS || 12);
|
|
14
15
|
const MAX_CHARS = Number(process.env.RECALL_WARM_WALKER_MAX_CHARS || 24000);
|
|
@@ -23,6 +24,7 @@ let chain = Promise.resolve();
|
|
|
23
24
|
let msgCount = 0;
|
|
24
25
|
let charCount = 0;
|
|
25
26
|
let costTotal = 0;
|
|
27
|
+
let childModel = null;
|
|
26
28
|
let stopPromise = null;
|
|
27
29
|
|
|
28
30
|
function isEnabled(provider) {
|
|
@@ -102,6 +104,7 @@ function spawnChild(cfg) {
|
|
|
102
104
|
});
|
|
103
105
|
child = proc;
|
|
104
106
|
childProviderId = cfg.provider.id;
|
|
107
|
+
try { childModel = cfg.model || cfg.provider.tierModel("low") || null; } catch (_) { childModel = null; }
|
|
105
108
|
msgCount = 0;
|
|
106
109
|
charCount = 0;
|
|
107
110
|
costTotal = 0;
|
|
@@ -135,7 +138,14 @@ function spawnChild(cfg) {
|
|
|
135
138
|
costUsd = Math.max(0, event.total_cost_usd - costTotal);
|
|
136
139
|
costTotal = event.total_cost_usd;
|
|
137
140
|
}
|
|
138
|
-
|
|
141
|
+
// Price the walk from its own tokens: each result's usage is that
|
|
142
|
+
// message only, while Claude Code's running total prices models it
|
|
143
|
+
// does not know (claude-haiku-5-5) at Opus rates (APP-28).
|
|
144
|
+
const usage = event.usage && typeof event.usage === "object" ? event.usage : null;
|
|
145
|
+
const model = (event.modelUsage && Object.keys(event.modelUsage)[0]) || childModel;
|
|
146
|
+
const priced = usage ? priceUsage(usage, model) : null;
|
|
147
|
+
if (priced) costUsd = priced.costUsd;
|
|
148
|
+
if (text && !event.is_error) settle("resolve", { text: redactSensitive(String(text).trim()), costUsd, usage, model });
|
|
139
149
|
else settle("reject", new Error("warm walker returned an empty or error result"));
|
|
140
150
|
}
|
|
141
151
|
}
|
package/core/usage-log.js
CHANGED
|
@@ -28,6 +28,58 @@ function appendUsageRecord(record, options = {}) {
|
|
|
28
28
|
return true;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
let packageVersion;
|
|
32
|
+
function ocVersion() {
|
|
33
|
+
if (packageVersion === undefined) {
|
|
34
|
+
try { packageVersion = require("../package.json").version || null; } catch (_) { packageVersion = null; }
|
|
35
|
+
}
|
|
36
|
+
return packageVersion;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// One row per background call (recall finder, note reviewer, dream, guard,
|
|
40
|
+
// thread titles...), so spend can be split by what it was for. Background
|
|
41
|
+
// calls run without a saved session, so this row is their only trace. The
|
|
42
|
+
// cost is priced from the call's own tokens (core/model-prices.js); a model
|
|
43
|
+
// with no price (Codex) is logged with costUsd null and priced: false.
|
|
44
|
+
function recordUtilityUsage(entry = {}, options = {}) {
|
|
45
|
+
const raw = entry.usage && typeof entry.usage === "object" ? entry.usage : null;
|
|
46
|
+
if (!raw) return false;
|
|
47
|
+
const provider = entry.provider || null;
|
|
48
|
+
const prices = require("./model-prices");
|
|
49
|
+
const tokens = prices.tokensFromUsage(raw);
|
|
50
|
+
if (provider === "codex") {
|
|
51
|
+
const cached = Number(raw.cached_input_tokens) || 0;
|
|
52
|
+
tokens.cacheRead = cached;
|
|
53
|
+
tokens.input = Math.max(0, (Number(raw.input_tokens) || 0) - cached);
|
|
54
|
+
}
|
|
55
|
+
const model = entry.model || null;
|
|
56
|
+
const priced = provider === "codex" ? null : prices.priceTokens(tokens, model, { fast: raw.speed === "fast" });
|
|
57
|
+
const record = {
|
|
58
|
+
ts: new Date(entry.now || Date.now()).toISOString(),
|
|
59
|
+
version: ocVersion(),
|
|
60
|
+
provider,
|
|
61
|
+
model,
|
|
62
|
+
usageScope: "utility",
|
|
63
|
+
purpose: entry.purpose || "unknown",
|
|
64
|
+
source: entry.source || null,
|
|
65
|
+
ok: entry.ok !== false,
|
|
66
|
+
inputTokens: tokens.input,
|
|
67
|
+
outputTokens: tokens.output,
|
|
68
|
+
cacheReadTokens: tokens.cacheRead,
|
|
69
|
+
cacheCreationTokens: tokens.cacheCreation || (tokens.cacheWrite5m || 0) + (tokens.cacheWrite1h || 0),
|
|
70
|
+
costUsd: priced ? priced.costUsd : null,
|
|
71
|
+
priced: !!priced,
|
|
72
|
+
};
|
|
73
|
+
if (tokens.cacheWrite5m != null || tokens.cacheWrite1h != null) {
|
|
74
|
+
record.cacheWrite5mTokens = tokens.cacheWrite5m || 0;
|
|
75
|
+
record.cacheWrite1hTokens = tokens.cacheWrite1h || 0;
|
|
76
|
+
}
|
|
77
|
+
if (entry.usageScope) record.callScope = entry.usageScope;
|
|
78
|
+
if (entry.effort) record.effort = entry.effort;
|
|
79
|
+
if (Number.isFinite(entry.durationMs)) record.durationMs = entry.durationMs;
|
|
80
|
+
return appendUsageRecord(record, options);
|
|
81
|
+
}
|
|
82
|
+
|
|
31
83
|
function loadUsageHistory() {
|
|
32
84
|
let raw;
|
|
33
85
|
try { raw = fs.readFileSync(USAGE_HISTORY_FILE, "utf-8"); } catch (e) { return []; }
|
|
@@ -126,6 +178,7 @@ function evaluateUsageAlert(previousRecords, record, policy = usageAlertPolicy()
|
|
|
126
178
|
module.exports = {
|
|
127
179
|
normalizeUsageRecord,
|
|
128
180
|
appendUsageRecord,
|
|
181
|
+
recordUtilityUsage,
|
|
129
182
|
loadUsageHistory,
|
|
130
183
|
usageAlertPolicy,
|
|
131
184
|
usageTrend,
|
package/core/utility-agent.js
CHANGED
|
@@ -478,6 +478,7 @@ function createUtilityAgentService(options = {}) {
|
|
|
478
478
|
// The limit record (core/usage-limits.js): a used-up provider is not
|
|
479
479
|
// started; a limit hit is recorded; a call that worked clears it.
|
|
480
480
|
const limitsLib = options.limits || require("./usage-limits");
|
|
481
|
+
const recordUsage = options.recordUsage || require("./usage-log").recordUtilityUsage;
|
|
481
482
|
const transientRetryMs = Number.isFinite(Number(options.transientRetryMs)) && Number(options.transientRetryMs) >= 0
|
|
482
483
|
? Number(options.transientRetryMs)
|
|
483
484
|
: DEFAULT_TRANSIENT_RETRY_MS;
|
|
@@ -547,6 +548,26 @@ function createUtilityAgentService(options = {}) {
|
|
|
547
548
|
} catch (_) { /* the record is best effort */ }
|
|
548
549
|
}
|
|
549
550
|
|
|
551
|
+
// Every background call leaves a priced row in the usage ledger, tagged
|
|
552
|
+
// with its purpose, so spend can be split by part (APP-28).
|
|
553
|
+
function noteUsage(result, meta) {
|
|
554
|
+
try {
|
|
555
|
+
const usage = result?.usage?.usage;
|
|
556
|
+
if (!usage) return;
|
|
557
|
+
recordUsage({
|
|
558
|
+
usage,
|
|
559
|
+
usageScope: result.usage.scope || null,
|
|
560
|
+
provider: meta.providerId,
|
|
561
|
+
model: meta.model || null,
|
|
562
|
+
purpose: meta.purpose,
|
|
563
|
+
effort: meta.effort || null,
|
|
564
|
+
ok: !!result.ok,
|
|
565
|
+
durationMs: meta.durationMs,
|
|
566
|
+
source: "utility",
|
|
567
|
+
});
|
|
568
|
+
} catch (_) { /* accounting is best effort */ }
|
|
569
|
+
}
|
|
570
|
+
|
|
550
571
|
function stats() {
|
|
551
572
|
return {
|
|
552
573
|
activeGlobal,
|
|
@@ -685,7 +706,13 @@ function createUtilityAgentService(options = {}) {
|
|
|
685
706
|
throw new UtilityAgentError(result.error.code, result.error.message, result);
|
|
686
707
|
}
|
|
687
708
|
|
|
688
|
-
const execute = (built) =>
|
|
709
|
+
const execute = async (built) => {
|
|
710
|
+
const startedAt = Date.now();
|
|
711
|
+
const out = await runInvocation(built);
|
|
712
|
+
noteUsage(out, { providerId: selection.providerId, model: selection.model, purpose, effort, durationMs: Date.now() - startedAt });
|
|
713
|
+
return out;
|
|
714
|
+
};
|
|
715
|
+
const runInvocation = (built) => context.run({ depth: depth + 1, purpose }, () => executeUtilityInvocation({
|
|
689
716
|
provider,
|
|
690
717
|
invocation: built,
|
|
691
718
|
cwd: request.cwd || process.cwd(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inetafrica/open-claudia",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.63",
|
|
4
4
|
"description": "An always-on, provider-agnostic coding-agent harness for Claude Code and OpenAI Codex via chat",
|
|
5
5
|
"main": "bot.js",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"setup": "node setup.js",
|
|
12
12
|
"start": "node bot.js",
|
|
13
13
|
"pretest": "node test-provider-fixture.js && node test-provider-core-prompt.js && node test-turn-observer.js && node test-provider-prompt-parity.js && node test-provider-env-isolation.js && node test-provider-resume-parity.js && node test-provider-bootstrap.js && node test-provider-registry.js && node test-provider-stream-decoder.js && node test-provider-events.js && node test-provider-claude.js && node test-provider-codex.js && node test-codex-output-schema.js && node test-codex-device-login.js && node test-provider-runner.js && node test-provider-refusal-recovery.js && node test-provider-run-lifecycle.js && node test-provider-gateway.js && node test-provider-side-chat.js && node test-single-runtime.js && node test-provider-migration-backup.js && node test-provider-state-migration.js && node test-provider-session-history.js && node test-provider-session-commands.js && node test-provider-compaction.js && node test-provider-scheduler.js && node test-credential-capture.js && node test-cursor-removal.js && node test-utility-provider-policy.js && node test-provider-subagent.js && node test-provider-recall.js && node test-provider-pack-review.js && node test-memory-mutation-queue.js && node test-provider-dream.js && node test-provider-enforcer.js && node test-provider-tool-hooks.js && node test-provider-boot-matrix.js && node test-provider-capabilities.js && node test-provider-language.js && node test-upgrade-path.js && node test-provider-coupling-audit.js && node test-provider-parity-e2e.js && node test-kazee-channel-health.js && node test-kazee-media-caption.js && node test-kazee-context-media.js && node test-kazee-typing-join.js && node test-kazee-inbound-dedup.js && node test-typing-phase-push.js && node test-socket-reconnect.js && node test-speech-loopback.js && node test-prompt-budget.js && node test-agency-ledger.js && node test-agency-deliberate.js && node test-guardrail.js && node test-group-status-notes.js && node test-spaces-comment-content.js && node test-boot-health.js && node test-lexical-floor.js && node test-safe-mode.js && node test-logout.js && node test-kazee-call-audio.js && node test-kazee-call-janus.js && node test-kazee-call-webrtc.js && node test-kazee-call-speech.js && node test-kazee-call-manager.js && node test-call-speech.js && node test-kazee-call-session.js",
|
|
14
|
-
"test": "OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node -e \"require('./vault'); console.log('OK')\" && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-runner-watchdog-static.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-usage-accounting.js && node test-codex-rollout.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-engine.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-graph.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-discoverer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-query.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-walker-score.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-score-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-cokept-warming.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-project-transcripts-smoke.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-transcript-room-scope.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-abilities.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-extraction.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-couse.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-transfer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-tiers.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-merge-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-learning-e2e.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-pack-nesting.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-pack-search.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-extractive-injection.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-journal-dedupe.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-read-signal.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tools.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-graph.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-read-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tooling-mode.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-manifest.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-evolution.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-approval-async.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-unified-identity.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-persona-packs.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-speaker-persona.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-persona-pipeline.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-relationship-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-relationship.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-enforcer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-mandate-hygiene.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-external-rule-scopes.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-owner-cards-dm.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-approval-cards.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-identity-prune.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-message-id.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-group-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-group-context.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-threads.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-people-owner-seed.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-delivery-contract.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-run-lock.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-thread-lanes.js && node test-thread-titles.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-thread-stop.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-stop-queue.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-typing-heartbeat.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-web-sessions.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-poll-recovery.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-409-grace.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-conflict-heal-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-single-instance.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-streaming-split.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-stream-preview-purpose.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-quiet-defaults.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-spaces-autoenable.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-say-loopback.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-loopback-threads.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-transcript-threads.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-journal-union.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-subst-score.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-section-budgets.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-dedup-adjudicator.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-prospective.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-regressions.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-cost-report.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-speaker-context.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-approval-mining.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-certification.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-apprenticeship.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-speaker-attest.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-run-attest.js && node test-sandbox-probe.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-bot-endpoint.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-cli-owner-gates.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-verify-contact.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-loopback-owner-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-watch-check-env.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-intro-adoption.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-grants.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-room-provider-settings.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-store-durability.js && node test-kazee-cards.js && node test-decision-upkeep.js && node test-passive-replies.js && node test-kazee-bot-loops.js && node test-kazee-bot-handoffs.js && node test-placeholder-reply.js && node test-media-speech.js && node test-speech-voices.js && node test-tts-voice.js && node test-passive-replies-router.js && node test-loopback-cards.js && node test-task-injection.js && node test-speaker-extras.js && node test-token-diet.js && node test-dream-tasks.js && node test-task-archive.js && node test-cron-tolerance.js && node test-dream-schedule.js && node test-job-failures.js && node test-scheduled-placeholder.js && node test-lessons-since.js && node test-pack-reinject.js && node test-turn-journal.js && node test-kazee-catchup.js && node test-usage-limits.js && node test-limit-waits.js && node test-signin-race-retry.js && node test-limit-pickup.js && node test-browser-view.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-browser-view.js && node test-browser-address.js && node test-browser-control.js && node test-browser-drive.js && node test-browser-teach.js && node test-kazee-bot-apps.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-browser-app.js && node test-safe-filename.js && node test-media-filename-paths.js && node test-router-document-guard.js && OPEN_CLAUDIA_TEST=1 node test-web-dashboard-escape.js && OPEN_CLAUDIA_TEST=1 node test-web-bad-requests.js && OPEN_CLAUDIA_TEST=1 node test-kazee-download-limit.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-auth-routes.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-otp-link-preview.js && node test-call-quick-voice.js && node test-call-run-stop.js && node test-call-stopped-transcript.js && node test-call-greeting-context.js && node test-call-camera.js && node test-switchboard-calls.js && node test-switchboard-supervisor.js"
|
|
14
|
+
"test": "OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node -e \"require('./vault'); console.log('OK')\" && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-runner-watchdog-static.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-usage-accounting.js && node test-codex-rollout.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-engine.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-graph.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-discoverer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-query.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-walker-score.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-score-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-cokept-warming.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-project-transcripts-smoke.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-transcript-room-scope.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-abilities.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-extraction.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-couse.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-transfer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-tiers.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-merge-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-learning-e2e.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-pack-nesting.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-pack-search.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-extractive-injection.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-journal-dedupe.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-read-signal.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tools.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-graph.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-read-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tooling-mode.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-manifest.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-evolution.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-approval-async.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-unified-identity.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-persona-packs.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-speaker-persona.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-persona-pipeline.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-relationship-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-relationship.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-enforcer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-mandate-hygiene.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-external-rule-scopes.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-owner-cards-dm.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-approval-cards.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-identity-prune.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-message-id.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-group-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-group-context.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-threads.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-people-owner-seed.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-delivery-contract.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-run-lock.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-thread-lanes.js && node test-thread-titles.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-thread-stop.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-stop-queue.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-typing-heartbeat.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-web-sessions.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-poll-recovery.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-409-grace.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-conflict-heal-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-single-instance.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-streaming-split.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-stream-preview-purpose.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-quiet-defaults.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-spaces-autoenable.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-say-loopback.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-loopback-threads.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-transcript-threads.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-journal-union.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-subst-score.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-section-budgets.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-dedup-adjudicator.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-prospective.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-regressions.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-cost-report.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-cost-by-part.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-speaker-context.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-approval-mining.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-certification.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-apprenticeship.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-speaker-attest.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-run-attest.js && node test-sandbox-probe.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-bot-endpoint.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-cli-owner-gates.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-verify-contact.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-loopback-owner-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-watch-check-env.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-intro-adoption.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-grants.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-room-provider-settings.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-store-durability.js && node test-kazee-cards.js && node test-decision-upkeep.js && node test-passive-replies.js && node test-kazee-bot-loops.js && node test-kazee-bot-handoffs.js && node test-placeholder-reply.js && node test-media-speech.js && node test-speech-voices.js && node test-tts-voice.js && node test-passive-replies-router.js && node test-loopback-cards.js && node test-task-injection.js && node test-speaker-extras.js && node test-token-diet.js && node test-dream-tasks.js && node test-task-archive.js && node test-cron-tolerance.js && node test-dream-schedule.js && node test-job-failures.js && node test-scheduled-placeholder.js && node test-lessons-since.js && node test-pack-reinject.js && node test-turn-journal.js && node test-kazee-catchup.js && node test-usage-limits.js && node test-limit-waits.js && node test-signin-race-retry.js && node test-limit-pickup.js && node test-browser-view.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-browser-view.js && node test-browser-address.js && node test-browser-control.js && node test-browser-drive.js && node test-browser-teach.js && node test-kazee-bot-apps.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-browser-app.js && node test-safe-filename.js && node test-media-filename-paths.js && node test-router-document-guard.js && OPEN_CLAUDIA_TEST=1 node test-web-dashboard-escape.js && OPEN_CLAUDIA_TEST=1 node test-web-bad-requests.js && OPEN_CLAUDIA_TEST=1 node test-kazee-download-limit.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-auth-routes.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-otp-link-preview.js && node test-call-quick-voice.js && node test-call-run-stop.js && node test-call-stopped-transcript.js && node test-call-greeting-context.js && node test-call-camera.js && node test-switchboard-calls.js && node test-switchboard-supervisor.js"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"bot.js",
|
|
@@ -633,7 +633,13 @@ assert.match(pkg.description, /provider-agnostic coding-agent harness/i);
|
|
|
633
633
|
// 3.5.61 = 3.5.60 + a turn that waits and tries again on Claude Code's sign-in refresh race,
|
|
634
634
|
// under Sumeet's 2026-10-14 06:50 EAT "Bug fix ... handle it internally and do like a back off"
|
|
635
635
|
// (home pi's screenshot): canary first.
|
|
636
|
-
|
|
636
|
+
// 3.5.62 = 3.5.61 + every background call logged by purpose and priced from its tokens, the
|
|
637
|
+
// dream's cost line priced from tokens and split by part, under Sumeet's 2026-10-14 11:10 EAT
|
|
638
|
+
// "yes go ahead as you see fit" (to: shall I build the cost-by-part tracking?): canary first.
|
|
639
|
+
// 3.5.63 = 3.5.62 + passive groups judge captioned photos and files (APP-29), a proven bug
|
|
640
|
+
// (books bot logs, 14 Oct: Judith's captioned screenshots "group gate: silent") under
|
|
641
|
+
// Sumeet's standing clear-cut bug-fix rule (5 Oct 2026 12:08 EAT): canary first.
|
|
642
|
+
assert.strictEqual(pkg.version, "3.5.63", "release version must remain unchanged without explicit approval");
|
|
637
643
|
for (const keyword of ["claude", "codex", "coding-agent", "provider-agnostic"]) {
|
|
638
644
|
assert.ok(pkg.keywords.includes(keyword), `package keyword missing: ${keyword}`);
|
|
639
645
|
}
|
package/web.js
CHANGED
|
@@ -733,7 +733,8 @@ async function handleAPI(req, res, body, dependencies = {}) {
|
|
|
733
733
|
// Token usage history (for the Usage dashboard)
|
|
734
734
|
if (url === "/api/usage") {
|
|
735
735
|
// Turn records only: compaction records (kind "compaction") carry no turn.
|
|
736
|
-
|
|
736
|
+
// Background-call rows (usageScope "utility") are not turns either.
|
|
737
|
+
const records = loadUsageHistory().filter((r) => r.kind !== "compaction" && r.usageScope !== "utility");
|
|
737
738
|
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf-8"));
|
|
738
739
|
const env = loadEnv();
|
|
739
740
|
const alertPolicy = usageAlertPolicy(env);
|