@inetafrica/open-claudia 3.0.4 → 3.0.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/CHANGELOG.md +12 -0
- package/channels/telegram/adapter.js +9 -1
- package/core/runner.js +15 -0
- package/package.json +2 -2
- package/test-provider-language.js +5 -5
- package/test-provider-migration-backup.js +3 -1
- package/test-usage-accounting.js +13 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v3.0.6 — cache-bust burn is now a one-line query
|
|
4
|
+
|
|
5
|
+
- **Usage records carry a `coldStart` flag.** The restart→cache-bust burn (each bot restart re-bills the whole accumulated window as cache *writes* instead of ~13×-cheaper cache *reads*) was invisible to every token-count analysis — same token counts, different price class — and took a forensic reconstruction of the 22-day usage history to quantify (~8% of all spend, ~$12/day at its worst). Now the first usage record a process writes for each session is tagged `coldStart: true`: a cold start mid-conversation is the restart fingerprint, so the burn is one jq filter away instead of a modelling exercise. Records already carried `cacheReadTokens`/`cacheCreationTokens`; this adds the missing "was the cache necessarily cold?" dimension.
|
|
6
|
+
- **Agent-space / OpenClaw:** no new deps, no new env, no schema change (additive JSONL field); Docker image builds identically. `usageSessionColdStart` covered by new assertions in `test-usage-accounting.js`.
|
|
7
|
+
|
|
8
|
+
## v3.0.5 — the conflict handler owns the poll
|
|
9
|
+
|
|
10
|
+
- **Hiccup heals no longer fight the 409 backoff.** During a 409 conflict streak the conflict handler pauses polling and retries on its own schedule — but a network hiccup (`ECONNRESET`) arriving mid-streak would schedule its own heal, which called `startPolling` straight back into the conflict and reset the streak clock. This was the live v2.15 burn mechanism: its own ghost long-poll after an ECONNRESET heal raised a 409, the old code exited on any 409, launchd respawned it (~1/hr, 208 lifetime startups), and every restart busted the prompt cache so the next turn re-billed the whole accumulated window uncached. Hiccup handling is now a no-op while a conflict streak is active — the conflict handler owns the poll lifecycle.
|
|
11
|
+
- **The 10-minute wedge backstop stands down during a conflict.** A conflict streak looks exactly like a wedge (no updates flowing), so the backstop could `exit(1)` mid-streak — the one remaining path where a token fight still killed the lock-holding bot (2 wedge-exits observed in the field). The backstop now skips while a conflict is active; a genuine >10-min wedge with no conflict still exits for a clean restart.
|
|
12
|
+
- **Investigated and cleared:** the v3 "token doubling" report was fully root-caused. Per-turn recall injection measured at parity (~4k tokens, 3 packs) across v2.15-classic, v2.15-discoverer, and v3-discoverer; the 160k→347k warning was the v3.0.0 cumulative-vs-peak display bug already fixed in v3.0.2; real spend was flat across the upgrade. The discoverer walker is identical in v2 and v3 (same haiku model via tier "low", same ~$0.015/turn) and stays on by default.
|
|
13
|
+
- **Agent-space / OpenClaw:** no new deps, no new env, no schema change; Docker image builds identically. New hermetic test `test-telegram-conflict-heal-guard.js` (wired into `npm test`) proves all four paths: hiccup no-op during conflict, hiccup still heals without conflict, backstop skipped during conflict, genuine wedge still exits.
|
|
14
|
+
|
|
3
15
|
## v3.0.4 — surviving the second mount, keeping the crons
|
|
4
16
|
|
|
5
17
|
- **A Kubernetes PVC remount no longer crashloops the bot.** The migration snapshot validator demanded exact owner-only modes (`0700` dirs, `0600` files). But kubelet's fsGroup ownership pass ORs group `rwX` + setgid onto every file and directory each time the volume is mounted — so the first v3 boot passed (snapshot created after the mount), and the **second pod recreation** hit `INVALID_MIGRATION_SNAPSHOT: migration snapshot has unsafe permissions` at boot and went CrashLoopBackOff. Every v3 pod on an fsGroup-mounted PVC was one recreation away from this (euvy hit it live on 2026-07-12 and needed a manual chmod rescue). Validation now rejects only world-access bits — group access is the pod's own supplemental group, not an exposure — while snapshots are still *created* `0700`/`0600`.
|
|
@@ -99,6 +99,11 @@ class TelegramAdapter {
|
|
|
99
99
|
// old exit-for-relaunch *was* the restart the bot kept doing on every idle
|
|
100
100
|
// timeout (a sleep/wake burst could exhaust all 6 attempts in seconds).
|
|
101
101
|
_onPollingHiccup(msg) {
|
|
102
|
+
// During a 409 streak the conflict handler owns the poll lifecycle; a heal
|
|
103
|
+
// here would startPolling straight back into the conflict and its errors
|
|
104
|
+
// would keep _wedgedSince pinned until the 10-min backstop killed us (the
|
|
105
|
+
// two wedge-exits of 2026-07-12 during the v3 upgrade handoff).
|
|
106
|
+
if (this._conflictTimer || this._conflictSince) return;
|
|
102
107
|
const now = Date.now();
|
|
103
108
|
if (!this._wedgedSince) this._wedgedSince = now;
|
|
104
109
|
if (now - this._lastHiccupLog > 60000) {
|
|
@@ -117,7 +122,10 @@ class TelegramAdapter {
|
|
|
117
122
|
// restart-in-place won't fix it — exit for a clean launchd relaunch. On a
|
|
118
123
|
// healthy network this never fires (heals recover in seconds); it replaces
|
|
119
124
|
// the old hair-trigger ~90s exit that caused the restart storm.
|
|
120
|
-
if (this._wedgedSince && Date.now() - this._wedgedSince > 600000) {
|
|
125
|
+
if (this._wedgedSince && !this._conflictSince && Date.now() - this._wedgedSince > 600000) {
|
|
126
|
+
// Never fires during a 409 streak: that's a token fight, not a network
|
|
127
|
+
// wedge, and exiting busts the prompt cache (full uncached re-bill of the
|
|
128
|
+
// conversation window on the next turn).
|
|
121
129
|
console.error("Polling wedged >10min — exiting for a clean restart.");
|
|
122
130
|
process.exit(1);
|
|
123
131
|
}
|
package/core/runner.js
CHANGED
|
@@ -183,6 +183,7 @@ function logTurnUsage(state, usage, costUsd, announce, opts = {}) {
|
|
|
183
183
|
billedContextTokens: parts.context,
|
|
184
184
|
costUsd: typeof costUsd === "number" ? costUsd : 0,
|
|
185
185
|
};
|
|
186
|
+
if (typeof opts.coldStart === "boolean") record.coldStart = opts.coldStart;
|
|
186
187
|
if (opts.rawUsage && opts.rawUsage !== usage) {
|
|
187
188
|
const raw = usageParts(opts.rawUsage, backend);
|
|
188
189
|
record.rawInputTokens = raw.input;
|
|
@@ -1425,6 +1426,18 @@ async function persistForegroundTranscript(result, runContext, state = currentSt
|
|
|
1425
1426
|
);
|
|
1426
1427
|
}
|
|
1427
1428
|
|
|
1429
|
+
// Sessions this PROCESS has already recorded usage for. The first record per
|
|
1430
|
+
// session since boot is a cold start: the prompt cache is necessarily cold, so
|
|
1431
|
+
// the whole accumulated window re-bills as cache writes (~13x the read rate).
|
|
1432
|
+
// Restart burn is therefore one query away: coldStart=true mid-conversation.
|
|
1433
|
+
const warmUsageSessions = new Set();
|
|
1434
|
+
function usageSessionColdStart(sessionId, warmSet = warmUsageSessions) {
|
|
1435
|
+
if (!sessionId) return true;
|
|
1436
|
+
if (warmSet.has(sessionId)) return false;
|
|
1437
|
+
warmSet.add(sessionId);
|
|
1438
|
+
return true;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1428
1441
|
async function persistForegroundUsage(result, runContext, state = currentState(), store = chatContext.getStore()) {
|
|
1429
1442
|
if (!result.usage) return;
|
|
1430
1443
|
const previousUsageBySession = structuredClone(state.usageBySession || {});
|
|
@@ -1468,6 +1481,7 @@ async function persistForegroundUsage(result, runContext, state = currentState()
|
|
|
1468
1481
|
usageScope,
|
|
1469
1482
|
liveContextTokens,
|
|
1470
1483
|
rawUsage,
|
|
1484
|
+
coldStart: usageSessionColdStart(usageSessionId),
|
|
1471
1485
|
strict: true,
|
|
1472
1486
|
},
|
|
1473
1487
|
);
|
|
@@ -2056,6 +2070,7 @@ module.exports = {
|
|
|
2056
2070
|
effectiveCompactThreshold,
|
|
2057
2071
|
usageParts,
|
|
2058
2072
|
peakContextTokens,
|
|
2073
|
+
usageSessionColdStart,
|
|
2059
2074
|
clampUsageDelta,
|
|
2060
2075
|
normalizeCodexUsage,
|
|
2061
2076
|
applyUsageToState,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inetafrica/open-claudia",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.6",
|
|
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": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"setup": "node setup.js",
|
|
11
11
|
"start": "node bot.js",
|
|
12
12
|
"pretest": "node test-provider-fixture.js && node test-provider-core-prompt.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-provider-runner.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-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-provider-coupling-audit.js && node test-provider-parity-e2e.js",
|
|
13
|
-
"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 && 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-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-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-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-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-queue-routing.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-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-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-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-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"
|
|
13
|
+
"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 && 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-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-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-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-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-queue-routing.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-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-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-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"
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
16
|
"bot.js",
|
|
@@ -32,11 +32,11 @@ assert.doesNotMatch(setup, /Your Claude Code bot is connected|Description=Claude
|
|
|
32
32
|
|
|
33
33
|
const pkg = JSON.parse(read("package.json"));
|
|
34
34
|
assert.match(pkg.description, /provider-agnostic coding-agent harness/i);
|
|
35
|
-
// 3.0.
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
assert.strictEqual(pkg.version, "3.0.
|
|
35
|
+
// 3.0.6 approved by Sumeet 2026-07-12 ("Yeh you can do that too" — coldStart
|
|
36
|
+
// flag on usage records so restart cache-bust burn, measured at ~8% of all
|
|
37
|
+
// spend from the 22-day history, is a one-line query instead of a forensic
|
|
38
|
+
// reconstruction).
|
|
39
|
+
assert.strictEqual(pkg.version, "3.0.6", "release version must remain unchanged without explicit approval");
|
|
40
40
|
for (const keyword of ["claude", "codex", "coding-agent", "provider-agnostic"]) {
|
|
41
41
|
assert.ok(pkg.keywords.includes(keyword), `package keyword missing: ${keyword}`);
|
|
42
42
|
}
|
|
@@ -398,7 +398,9 @@ function fsGroupToleranceProbe() {
|
|
|
398
398
|
}
|
|
399
399
|
};
|
|
400
400
|
applyFsGroup(snapshot.snapshotDir);
|
|
401
|
-
|
|
401
|
+
// chmod may silently drop setgid for non-members of the dir group, so
|
|
402
|
+
// assert only the group bits — the part every fsGroup mount guarantees.
|
|
403
|
+
assert.strictEqual(fs.statSync(snapshot.snapshotDir).mode & 0o770, 0o770);
|
|
402
404
|
|
|
403
405
|
const validated = validateMigrationSnapshot(snapshot.snapshotDir, { sources: opts.sources, verifySources: true });
|
|
404
406
|
assert.strictEqual(validated.ok, true, "group bits from a k8s fsGroup mount must not invalidate the snapshot");
|
package/test-usage-accounting.js
CHANGED
|
@@ -10,6 +10,7 @@ const {
|
|
|
10
10
|
applyUsageToState,
|
|
11
11
|
shouldAutoCompact,
|
|
12
12
|
peakContextTokens,
|
|
13
|
+
usageSessionColdStart,
|
|
13
14
|
} = require("./core/runner");
|
|
14
15
|
const stateApi = require("./core/state");
|
|
15
16
|
const { normalizeUsageRecord, loadUsageHistory, USAGE_HISTORY_FILE } = require("./core/usage-log");
|
|
@@ -176,5 +177,17 @@ assert.strictEqual(peakContextTokens([
|
|
|
176
177
|
{ type: "usage", scope: "provider_call", usage: { input_tokens: 70, cached_input_tokens: 30, output_tokens: 5 } },
|
|
177
178
|
], "codex"), 70, "codex context counts input only, matching usageParts");
|
|
178
179
|
|
|
180
|
+
// usageSessionColdStart: the first usage record per session since process boot
|
|
181
|
+
// is a cold start (prompt cache empty — the restart-burn fingerprint); every
|
|
182
|
+
// later record for that session in the same process is warm.
|
|
183
|
+
{
|
|
184
|
+
const warm = new Set();
|
|
185
|
+
assert.strictEqual(usageSessionColdStart("sess-a", warm), true, "first record for a session is cold");
|
|
186
|
+
assert.strictEqual(usageSessionColdStart("sess-a", warm), false, "second record for the same session is warm");
|
|
187
|
+
assert.strictEqual(usageSessionColdStart("sess-b", warm), true, "a different session is cold on its first record");
|
|
188
|
+
assert.strictEqual(usageSessionColdStart(null, warm), true, "no session id → always treated cold");
|
|
189
|
+
assert.strictEqual(usageSessionColdStart(null, warm), true, "null never warms");
|
|
190
|
+
}
|
|
191
|
+
|
|
179
192
|
fs.rmSync(configDir, { recursive: true, force: true });
|
|
180
193
|
console.log("usage accounting OK");
|