@inetafrica/open-claudia 3.4.0 → 3.4.2
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/kazee/adapter.js +75 -3
- package/core/providers/claude.js +3 -0
- package/package.json +2 -2
- package/test-provider-claude.js +1 -0
- package/test-provider-language.js +20 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v3.4.2 — The bot was typing into a room it had never joined
|
|
4
|
+
|
|
5
|
+
- **The typing and thinking indicators had been dead since 2026-08-23, and nothing said so.** chat-central `7aa9276` ("authorize typing") made `handleTypingStart` return early unless the sending socket had joined that chat's Socket.IO room — a correct fix, since `socket.to(chatId)` addresses a room by name and would otherwise let any authenticated user inject an indicator into any chat whose id they knew. But the Kazee adapter only ever joined the bot's own user room, which is how `message:new` reaches it. So messages kept flowing while every `typing:start` was discarded server-side, which is exactly why this read as a rendering bug in the web client.
|
|
6
|
+
- **The adapter now joins the chat room, and waits for the ack before signalling.** The ordering is the fix, not an optimisation: `chat:join` awaits a participant lookup while `typing:start` is handled synchronously, so emitting both back-to-back loses the race and the indicator is dropped anyway. Membership is cached so a per-second heartbeat does not re-join on every tick, concurrent ticks share one in-flight join, and the cache is cleared on connect *and* disconnect because server-side room membership dies with the socket. A refused join now emits nothing rather than something silently discarded, and `typingStop` never joins a room merely to leave it.
|
|
7
|
+
- Regression coverage in `test-kazee-typing-join.js`, wired into `pretest`: join-before-emit ordering, the `thinking` state surviving, one join per chat rather than per tick, shared in-flight joins, no indicator after a refusal, re-join after reconnect, and stop-only-for-joined-rooms. The reconnect case earned its place immediately by catching a real defect in the first cut of the fix — a synchronous ack settled the join promise before it was registered, stranding a resolved entry that would have suppressed the re-join.
|
|
8
|
+
|
|
9
|
+
## v3.4.1 — Fable 5.1, and the CLI floor it quietly needs
|
|
10
|
+
|
|
11
|
+
- **`claude-fable-5-1` joins the Claude model picker.** The identifier is dash-form; `claude-fable-5.1` does not exist and fails as an unknown model.
|
|
12
|
+
- **It carries a CLI floor: Claude Code >= 2.1.251.** An older CLI does not degrade gracefully — it returns an API 400 naming the required version. The local install was taken 2.1.150 -> 2.1.258 before the model was listed, and the picker offering a button the local binary cannot serve is the failure mode to avoid. Pod images install Claude Code unpinned, so a rebuild clears the floor by itself, but pods still on older images will 400 on this model until they are rolled.
|
|
13
|
+
- Verified by building the real main invocation through the provider and spawning it, rather than by a hand-written CLI probe: the API reported `claude-fable-5-1` as the serving model, and `claude-opus-4-8` was re-run through the same harness to prove the incumbent path was untouched. Full suite 135/135.
|
|
14
|
+
|
|
3
15
|
## v3.4.0 — Who you are, where you are, and what you may do there are three different questions
|
|
4
16
|
|
|
5
17
|
- **The bug that started it: a wakeup scheduled in a Codex room kept running on Claude.** `getActiveProvider` resolves the room's overlay from `state.roomKey`, but that key was stamped from `currentConversationKey()` — and a scheduled job resumes its own saved thread, whose conversation key is the job's *project name*, not a room. The overlay never resolved, so every job silently fell back to the creator's personal default. The thread and the room are now separate values (`roomKey`, defaulting to the conversation key so every inbound path is unchanged); the scheduler passes the room the job was created in. The same fusion is why a group answered as Codex to one person and Claude to another. Relatedly, a run that reverts to the provider it was scheduled under because the room's current choice is not runnable now **says so** — in the prompt and in a ⚠️ line on the advisory — instead of leaving a Codex room reporting a Claude quota error with nothing to explain where Claude came from.
|
|
@@ -19,6 +19,11 @@ const kazeeState = require("./state");
|
|
|
19
19
|
// Group catch-up context sizing: how many messages an engaged turn may carry,
|
|
20
20
|
// how long each rendered body may be, and how far back a chat's very first
|
|
21
21
|
// engage looks (no watermark yet — recent window instead of the whole backlog).
|
|
22
|
+
// How long to wait for chat-central's chat:join ack before giving up on the
|
|
23
|
+
// typing indicator for this tick. Short on purpose: an indicator that arrives
|
|
24
|
+
// late is worth less than the next heartbeat tick, which retries the join.
|
|
25
|
+
const KAZEE_JOIN_ACK_TIMEOUT_MS = 5000;
|
|
26
|
+
|
|
22
27
|
const CONTEXT_MAX_MESSAGES = 40;
|
|
23
28
|
const CONTEXT_BODY_LIMIT = 280;
|
|
24
29
|
const COLD_START_WINDOW = 15;
|
|
@@ -59,6 +64,13 @@ class KazeeAdapter {
|
|
|
59
64
|
this._listeners = { message: new Set(), action: new Set() };
|
|
60
65
|
this._socket = null;
|
|
61
66
|
this._chatMetaCache = new Map();
|
|
67
|
+
// Socket.IO rooms this socket has joined. chat-central only broadcasts a
|
|
68
|
+
// typing indicator from a socket that has joined the chat's room, so this
|
|
69
|
+
// tracks what we have joined to avoid re-joining on every keystroke tick.
|
|
70
|
+
// Server-side room membership dies with the connection, so it is cleared
|
|
71
|
+
// on every (re)connect.
|
|
72
|
+
this._joinedRooms = new Set();
|
|
73
|
+
this._joinPending = new Map();
|
|
62
74
|
this._callManager = new KazeeCallManager({ adapter: this });
|
|
63
75
|
}
|
|
64
76
|
|
|
@@ -119,13 +131,21 @@ class KazeeAdapter {
|
|
|
119
131
|
userId: this.botUserId,
|
|
120
132
|
onConnect: (s) => {
|
|
121
133
|
console.log(`Kazee socket connected (${this.url})`);
|
|
134
|
+
// A reconnect is a NEW socket server-side with an empty joinedRooms,
|
|
135
|
+
// so anything we believed we had joined is stale.
|
|
136
|
+
this._joinedRooms.clear();
|
|
137
|
+
this._joinPending.clear();
|
|
122
138
|
if (this.botUserId) {
|
|
123
139
|
// Join the bot's personal room so the server can fan out
|
|
124
140
|
// message:action presses directly to us.
|
|
125
141
|
s.emit("user:join", { userId: this.botUserId });
|
|
126
142
|
}
|
|
127
143
|
},
|
|
128
|
-
onDisconnect: (reason) =>
|
|
144
|
+
onDisconnect: (reason) => {
|
|
145
|
+
console.log(`Kazee socket disconnected: ${reason}`);
|
|
146
|
+
this._joinedRooms.clear();
|
|
147
|
+
this._joinPending.clear();
|
|
148
|
+
},
|
|
129
149
|
onError: (err) => console.error("Kazee socket error:", err.message),
|
|
130
150
|
});
|
|
131
151
|
this._wireSocket(this._socket);
|
|
@@ -610,9 +630,57 @@ class KazeeAdapter {
|
|
|
610
630
|
// `state` is an optional richer indicator: "thinking" (the bot is reasoning
|
|
611
631
|
// pre-first-token) vs the default "typing". Kazee clients render "thinking"
|
|
612
632
|
// distinctly; older clients ignore the field and fall back to "typing".
|
|
633
|
+
// chat-central authorizes typing by room membership (handleTypingStart
|
|
634
|
+
// returns early unless socket.data.joinedRooms has the chat), and the bot
|
|
635
|
+
// only ever joined its OWN user room — so every indicator was being dropped
|
|
636
|
+
// server-side. Joining is acknowledged and must complete BEFORE the typing
|
|
637
|
+
// emit: chat:join awaits a participant lookup while typing:start is handled
|
|
638
|
+
// synchronously, so emitting both back-to-back loses the race.
|
|
639
|
+
async _ensureJoinedRoom(chatId) {
|
|
640
|
+
if (this._joinedRooms.has(chatId)) return true;
|
|
641
|
+
const socket = this._socket;
|
|
642
|
+
if (!socket?.emit) return false;
|
|
643
|
+
const inFlight = this._joinPending.get(chatId);
|
|
644
|
+
if (inFlight) return inFlight;
|
|
645
|
+
|
|
646
|
+
let settled = false;
|
|
647
|
+
const attempt = new Promise((resolve) => {
|
|
648
|
+
const finish = (ok) => {
|
|
649
|
+
if (settled) return;
|
|
650
|
+
settled = true;
|
|
651
|
+
if (ok) this._joinedRooms.add(chatId);
|
|
652
|
+
this._joinPending.delete(chatId);
|
|
653
|
+
resolve(ok);
|
|
654
|
+
};
|
|
655
|
+
// The ack is called with an ErrorPayload on refusal and no argument on
|
|
656
|
+
// success. A silent server (or a dropped connection) must not strand the
|
|
657
|
+
// entry in _joinPending, hence the timeout.
|
|
658
|
+
const timer = setTimeout(() => finish(false), KAZEE_JOIN_ACK_TIMEOUT_MS);
|
|
659
|
+
try {
|
|
660
|
+
socket.emit("chat:join", { chatId }, (err) => {
|
|
661
|
+
clearTimeout(timer);
|
|
662
|
+
if (err) console.error(`Kazee chat:join refused (${chatId}):`, err.message || err.code || err);
|
|
663
|
+
finish(!err);
|
|
664
|
+
});
|
|
665
|
+
} catch (e) {
|
|
666
|
+
clearTimeout(timer);
|
|
667
|
+
finish(false);
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
// An ack that fires synchronously settles `attempt` before we reach this
|
|
671
|
+
// line, and its own cleanup ran against an entry that did not exist yet.
|
|
672
|
+
// Registering it now would strand a permanently-resolved promise that
|
|
673
|
+
// outlives the membership it recorded — so a later reconnect would read a
|
|
674
|
+
// cached "already joined" and never re-join.
|
|
675
|
+
if (!settled) this._joinPending.set(chatId, attempt);
|
|
676
|
+
return attempt;
|
|
677
|
+
}
|
|
678
|
+
|
|
613
679
|
async typing(channelId, state) {
|
|
614
680
|
try {
|
|
615
|
-
const
|
|
681
|
+
const chatId = String(channelId);
|
|
682
|
+
if (!(await this._ensureJoinedRoom(chatId))) return;
|
|
683
|
+
const payload = { chatId };
|
|
616
684
|
if (state) payload.state = state;
|
|
617
685
|
this._socket?.emit?.("typing:start", payload);
|
|
618
686
|
} catch (e) {}
|
|
@@ -622,7 +690,11 @@ class KazeeAdapter {
|
|
|
622
690
|
// has no equivalent (its chat action self-expires), so this is Kazee-only and
|
|
623
691
|
// called via optional chaining from the core typing heartbeat cleanup.
|
|
624
692
|
async typingStop(channelId) {
|
|
625
|
-
|
|
693
|
+
const chatId = String(channelId);
|
|
694
|
+
// Never join just to stop: a stop from a socket that never started is a
|
|
695
|
+
// no-op server-side anyway, and joining here would race the teardown.
|
|
696
|
+
if (!this._joinedRooms.has(chatId)) return;
|
|
697
|
+
try { this._socket?.emit?.("typing:stop", { chatId }); } catch (e) {}
|
|
626
698
|
}
|
|
627
699
|
|
|
628
700
|
async downloadMedia(media) {
|
package/core/providers/claude.js
CHANGED
|
@@ -6,7 +6,10 @@ const { createJsonlDecoder } = require("./events");
|
|
|
6
6
|
const { createClaudeParserState, normalizeClaudeEvent } = require("./claude-events");
|
|
7
7
|
const { createClaudeHookTransport } = require("./claude-hook");
|
|
8
8
|
|
|
9
|
+
// claude-fable-5-1 requires Claude Code >= 2.1.251; older CLIs reject it with an
|
|
10
|
+
// API 400 rather than falling back, so a pod on a stale image will error on it.
|
|
9
11
|
const CLAUDE_MODELS = Object.freeze([
|
|
12
|
+
"claude-fable-5-1",
|
|
10
13
|
"claude-fable-5",
|
|
11
14
|
"claude-opus-5",
|
|
12
15
|
"claude-opus-4-8",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inetafrica/open-claudia",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.2",
|
|
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
|
"test:kazee-call": "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-kazee-call-session.js",
|
|
11
11
|
"setup": "node setup.js",
|
|
12
12
|
"start": "node bot.js",
|
|
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-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-provider-coupling-audit.js && node test-provider-parity-e2e.js && node test-kazee-channel-health.js && node test-kazee-media-caption.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-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-kazee-call-session.js",
|
|
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-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-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-typing-join.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-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-kazee-call-session.js",
|
|
14
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 && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-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-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-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-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-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-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-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-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-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-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-store-durability.js"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
package/test-provider-claude.js
CHANGED
|
@@ -45,6 +45,7 @@ assert.strictEqual(provider.label, "Claude Code");
|
|
|
45
45
|
assert.strictEqual(provider.isAvailable(), true);
|
|
46
46
|
assert.strictEqual(provider.executable(), "/fixture/claude");
|
|
47
47
|
assert.strictEqual(provider.defaultModel(), "claude-default-fixture");
|
|
48
|
+
assert.ok(provider.modelChoices().includes("claude-fable-5-1"));
|
|
48
49
|
assert.ok(provider.modelChoices().includes("claude-fable-5"));
|
|
49
50
|
assert.ok(provider.modelChoices().includes("claude-sonnet-4-6"));
|
|
50
51
|
assert.deepStrictEqual(provider.compatibilityStatus(), {
|
|
@@ -404,7 +404,26 @@ assert.match(pkg.description, /provider-agnostic coding-agent harness/i);
|
|
|
404
404
|
// anything), and the people/auth stores got atomic backed-up writes plus
|
|
405
405
|
// cross-process locking, with hasOwner() failing CLOSED so a corrupt
|
|
406
406
|
// auth.json can no longer read as an unclaimed pod.
|
|
407
|
-
|
|
407
|
+
// 3.4.1 approved by Sumeet 2026-09-02 ("yes, but you tested it works?"):
|
|
408
|
+
// add claude-fable-5-1 to the Claude model picker. The ID is dash-form
|
|
409
|
+
// (claude-fable-5.1 does not exist) and it requires Claude Code >= 2.1.251 —
|
|
410
|
+
// an older CLI returns an API 400 rather than degrading, so the local CLI was
|
|
411
|
+
// taken 2.1.150 -> 2.1.258 first and the pod images (which install Claude Code
|
|
412
|
+
// unpinned) need a rebuild before the button is safe to tap there. Verified by
|
|
413
|
+
// building the real main invocation through the provider and spawning it: the
|
|
414
|
+
// API reported claude-fable-5-1 as the serving model, with claude-opus-4-8
|
|
415
|
+
// re-run through the same harness as a regression.
|
|
416
|
+
// 3.4.2 approved by Sumeet 2026-09-02 ("yeh", answering "Want me to cut
|
|
417
|
+
// v3.4.2 with this?") after he reported the typing/thinking indicator dead and
|
|
418
|
+
// asked whether Open Claudia or Kazee had changed: it was Kazee. chat-central
|
|
419
|
+
// 7aa9276 (2026-08-23, "authorize typing") made handleTypingStart return early
|
|
420
|
+
// unless the sending socket had JOINED the chat's room — and the bot only ever
|
|
421
|
+
// joined its own user room, so every indicator was dropped in silence for ten
|
|
422
|
+
// days while messages, which arrive by the personal-room fan-out, kept working.
|
|
423
|
+
// The adapter now joins the room and waits for the ACK before emitting:
|
|
424
|
+
// chat:join does an async participant lookup while typing:start is handled
|
|
425
|
+
// synchronously, so emitting both back-to-back loses the race.
|
|
426
|
+
assert.strictEqual(pkg.version, "3.4.2", "release version must remain unchanged without explicit approval");
|
|
408
427
|
for (const keyword of ["claude", "codex", "coding-agent", "provider-agnostic"]) {
|
|
409
428
|
assert.ok(pkg.keywords.includes(keyword), `package keyword missing: ${keyword}`);
|
|
410
429
|
}
|