@inetafrica/open-claudia 3.1.20 → 3.1.22
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 +16 -0
- package/channels/kazee/adapter.js +143 -4
- package/channels/kazee/state.js +42 -0
- package/core/access.js +8 -1
- package/core/people.js +10 -1
- package/core/relationship.js +26 -1
- package/core/router.js +1 -1
- package/package.json +2 -2
- package/test-provider-language.js +21 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v3.1.22 — Group silence is no longer context-blind: engaged turns catch up from the cursor
|
|
4
|
+
|
|
5
|
+
- Follow-through on the v3.1.21 group gate, per the owner's direction: the bot must not reply in a group unless tagged (owner included) — "but should get messages since its last cursor."
|
|
6
|
+
- The kazee adapter now implements the router's `buildThreadContext` hook (the same contract Spaces uses): an engaged group turn opens with a context block of every message since the bot's last engaged turn — exactly the messages the participation gate stayed silent through — with sender attribution ("You" for its own), `[type] caption` rendering for media, deleted messages dropped, bodies clipped at 280 chars, at most 40 messages.
|
|
7
|
+
- The cursor is a persisted per-chat watermark (`kazee-state.json`, atomic writes) holding the newest `createdAt` already folded into a turn. The delta is server-derived (`GET /messages/:chatId/:botUserId?since=`, oldest-first, server-capped at 500), so missed socket events and restarts self-heal. A chat's first-ever engage pulls a recent 15-message page instead of the whole backlog.
|
|
8
|
+
- Best-effort: a fetch failure returns no block, leaves the watermark alone, and never delays the reply.
|
|
9
|
+
- New release-chain test `test-kazee-group-context.js`: cold-start window, warm since-delta, You-attribution, media/deletion/clipping rendering, trigger exclusion, trigger-only watermark advance, failure semantics, DM no-op, on-disk persistence.
|
|
10
|
+
|
|
11
|
+
## v3.1.21 — Kazee public participation: owner seeding, group tag-gating, guarded external turns
|
|
12
|
+
|
|
13
|
+
- **Owner seeding for kazee-only pods.** A pod whose only owner signal is `KAZEE_OWNER_USER_ID` (empty `auth.json`) never got a people-store owner record, so every unknown inbound — group or DM — was refused with a false "no owner configured" (observed on network-mon, 2026-07-23). `seedOwnerFromLegacy` now falls back to the kazee env owner; legacy `auth.json` owners keep precedence and seeding stays idempotent.
|
|
14
|
+
- **Group chats engage only when addressed.** The kazee adapter fetches chat meta (5-min cache) and, in group chats, engages only on an @-mention of the bot or a reply to the bot's own message — matching chat-central's own `assistantAction` default `assistant_tagged_reply`. Chats set to `assistant_free_reply` engage on everything. Untagged group chatter is dropped silently (no roster prompts, no refusals — owner included). 1:1 chats are unchanged; a meta-fetch failure fails open to pre-gate behavior and is not cached.
|
|
15
|
+
- **Tagged externals get the guarded turn.** An engaged group message authorizes the turn via adapter-attested `envelope.engaged` (never derived from message content), but the speaker still classifies external: replies are vetted by the enforcer and escalate to the owner's approve-once / deny / make-a-rule card — the same pattern as Spaces. Slash commands stay closed to externals.
|
|
16
|
+
- **Escalation cards reach the kazee owner.** `ownerTarget` used to return env-seeded kazee owner handles as the raw user id, but kazee sends need a chat-document id, so approval cards would 404. User-id handles now resolve through `openDirectChat`, falling back to the configured owner target.
|
|
17
|
+
- New release-chain tests: `test-people-owner-seed.js` (env seed, legacy precedence, no-signal refusal) and `test-kazee-group-gate.js` (mention/reply engagement, free-reply, 1:1, meta failure, meta cache, engaged access pass-through).
|
|
18
|
+
|
|
3
19
|
## v3.1.17 — Call bridge joins through the caller's room-setup race (fixes "Call declined")
|
|
4
20
|
|
|
5
21
|
- Answering a Kazee web call could fail deterministically fast: the caller creates the Janus videoroom during its own dial-time setup, and the bot answers quicker than any human — its `join` hit Janus before the room existed, got 426 "No such room", and the whole call was rejected as `connection_failed` (surfacing as "Call declined" in the web UI).
|
|
@@ -14,6 +14,14 @@ const { inlineKeyboardToPortable } = require("../types");
|
|
|
14
14
|
const { createKazeeSocket } = require("./socket");
|
|
15
15
|
const { normalize } = require("./format");
|
|
16
16
|
const { KazeeCallManager } = require("./call/manager");
|
|
17
|
+
const kazeeState = require("./state");
|
|
18
|
+
|
|
19
|
+
// Group catch-up context sizing: how many messages an engaged turn may carry,
|
|
20
|
+
// how long each rendered body may be, and how far back a chat's very first
|
|
21
|
+
// engage looks (no watermark yet — recent window instead of the whole backlog).
|
|
22
|
+
const CONTEXT_MAX_MESSAGES = 40;
|
|
23
|
+
const CONTEXT_BODY_LIMIT = 280;
|
|
24
|
+
const COLD_START_WINDOW = 15;
|
|
17
25
|
|
|
18
26
|
class KazeeAdapter {
|
|
19
27
|
constructor({ id = "kazee", url, token, ownerUserId, botUserId }) {
|
|
@@ -28,9 +36,34 @@ class KazeeAdapter {
|
|
|
28
36
|
this.botUserId = botUserId || null;
|
|
29
37
|
this._listeners = { message: new Set(), action: new Set() };
|
|
30
38
|
this._socket = null;
|
|
39
|
+
this._chatMetaCache = new Map();
|
|
31
40
|
this._callManager = new KazeeCallManager({ adapter: this });
|
|
32
41
|
}
|
|
33
42
|
|
|
43
|
+
// chat-central's chat doc carries the group flag and the per-chat assistant
|
|
44
|
+
// policy (assistant_tagged_reply is the platform default for groups). Cached
|
|
45
|
+
// briefly so the participation gate costs one REST fetch per chat, not per
|
|
46
|
+
// message. Failures are NOT cached: a transient error must not stick a chat
|
|
47
|
+
// open or closed.
|
|
48
|
+
async _chatMeta(chatId) {
|
|
49
|
+
const cached = this._chatMetaCache.get(chatId);
|
|
50
|
+
if (cached && Date.now() - cached.at < 5 * 60 * 1000) return cached.meta;
|
|
51
|
+
try {
|
|
52
|
+
const res = await this._request("GET", `/chats/${encodeURIComponent(chatId)}`);
|
|
53
|
+
const chat = res?.chat || res || {};
|
|
54
|
+
if (chat.error) throw new Error(String(chat.error));
|
|
55
|
+
const meta = {
|
|
56
|
+
isGroupChat: !!chat.isGroupChat,
|
|
57
|
+
assistantAction: String(chat.assistantAction || ""),
|
|
58
|
+
};
|
|
59
|
+
this._chatMetaCache.set(chatId, { meta, at: Date.now() });
|
|
60
|
+
return meta;
|
|
61
|
+
} catch (e) {
|
|
62
|
+
console.error(`Kazee chat meta fetch failed (${chatId}):`, e.message);
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
34
67
|
on(event, fn) {
|
|
35
68
|
if (!this._listeners[event]) return () => {};
|
|
36
69
|
this._listeners[event].add(fn);
|
|
@@ -190,12 +223,18 @@ class KazeeAdapter {
|
|
|
190
223
|
}
|
|
191
224
|
}
|
|
192
225
|
|
|
193
|
-
// Reply-to context:
|
|
194
|
-
//
|
|
226
|
+
// Reply-to context: the socket payload may carry the full replied-to doc
|
|
227
|
+
// (chat-central V2) or just its id — resolve either into the same shape
|
|
228
|
+
// Telegram provides. Best-effort — failure is silent.
|
|
195
229
|
if (msg.replyTo) {
|
|
196
230
|
try {
|
|
197
|
-
|
|
198
|
-
|
|
231
|
+
let m = null;
|
|
232
|
+
if (typeof msg.replyTo === "object") {
|
|
233
|
+
m = msg.replyTo;
|
|
234
|
+
} else {
|
|
235
|
+
const data = await this._request("GET", `/message/${encodeURIComponent(String(msg.replyTo))}`);
|
|
236
|
+
m = data?.message || data;
|
|
237
|
+
}
|
|
199
238
|
if (m && (m._id || m.id)) {
|
|
200
239
|
envelope.reply = {
|
|
201
240
|
text: m.content || "",
|
|
@@ -210,9 +249,109 @@ class KazeeAdapter {
|
|
|
210
249
|
} catch (e) { /* best-effort — envelope is still valid without reply context */ }
|
|
211
250
|
}
|
|
212
251
|
|
|
252
|
+
// Group participation gate: in a group chat the bot engages only when
|
|
253
|
+
// addressed — an @-mention of the bot user or a reply to one of its own
|
|
254
|
+
// messages — unless the chat's assistantAction opts into free replies.
|
|
255
|
+
// Everyone is gated, owner included: a bot answering every group message
|
|
256
|
+
// drowns the room. 1:1 chats are never gated. Engaged messages are marked
|
|
257
|
+
// so the router can authorize the turn for non-owner speakers, who then
|
|
258
|
+
// run guarded (mandate/guardrail vetting + owner escalation).
|
|
259
|
+
if (this.botUserId) {
|
|
260
|
+
const meta = await this._chatMeta(channelId);
|
|
261
|
+
if (meta && meta.isGroupChat) {
|
|
262
|
+
const botId = String(this.botUserId);
|
|
263
|
+
const mentions = (Array.isArray(msg.mentions) ? msg.mentions : [])
|
|
264
|
+
.map((m) => String(m?._id || m?.id || m));
|
|
265
|
+
const mentioned = mentions.includes(botId);
|
|
266
|
+
const replyToBot = String(envelope.reply?.from?.id || "") === botId;
|
|
267
|
+
const freeReply = meta.assistantAction === "assistant_free_reply";
|
|
268
|
+
if (!mentioned && !replyToBot && !freeReply) {
|
|
269
|
+
console.log(`Kazee group gate: silent (chat=${channelId} from=${userId})`);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
envelope.engaged = true;
|
|
273
|
+
envelope.surface = "group";
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
213
277
|
this._emit("message", envelope);
|
|
214
278
|
}
|
|
215
279
|
|
|
280
|
+
// Channel-agnostic thread-context provider (ChannelAdapter contract, same
|
|
281
|
+
// hook Spaces implements). The router calls this at the start of an engaged
|
|
282
|
+
// group turn and prepends the returned contextBlock to the prompt, so the
|
|
283
|
+
// bot arrives knowing everything said in the room since it last spoke — the
|
|
284
|
+
// messages the participation gate stayed silent through are caught up here,
|
|
285
|
+
// exactly once, via a persisted per-chat watermark. The delta is
|
|
286
|
+
// server-derived (GET /messages?since=), so a missed socket event or a
|
|
287
|
+
// restart self-heals: the next engage still pulls the true set. Best-effort:
|
|
288
|
+
// any failure returns null, leaves the watermark alone, and never blocks the
|
|
289
|
+
// reply.
|
|
290
|
+
async buildThreadContext(envelope) {
|
|
291
|
+
if (!envelope || envelope.surface !== "group" || !this.botUserId) return null;
|
|
292
|
+
const chatId = String(envelope.channelId || "");
|
|
293
|
+
if (!chatId) return null;
|
|
294
|
+
try {
|
|
295
|
+
const since = kazeeState.getContextWatermark(chatId);
|
|
296
|
+
const msgs = await this._messagesSince(chatId, since);
|
|
297
|
+
if (!msgs.length) return null;
|
|
298
|
+
const newest = msgs[msgs.length - 1]?.createdAt;
|
|
299
|
+
if (newest) kazeeState.setContextWatermark(chatId, newest);
|
|
300
|
+
const triggerId = String(envelope.messageId || "");
|
|
301
|
+
const botId = String(this.botUserId);
|
|
302
|
+
const rendered = msgs
|
|
303
|
+
.filter((m) => !m.isDeleted && String(m._id || m.id || "") !== triggerId)
|
|
304
|
+
.map((m) => {
|
|
305
|
+
const senderId = String(m.sender?._id || m.sender?.id || "");
|
|
306
|
+
const who = senderId === botId ? "You" : (m.sender?.name || "Someone");
|
|
307
|
+
let body = (typeof m.content === "string" ? m.content : "").trim();
|
|
308
|
+
if (m.type && m.type !== "text" && m.type !== "interactive") {
|
|
309
|
+
body = `[${m.type}]${body ? " " + body : ""}`;
|
|
310
|
+
}
|
|
311
|
+
if (body.length > CONTEXT_BODY_LIMIT) body = body.slice(0, CONTEXT_BODY_LIMIT).trimEnd() + " …";
|
|
312
|
+
return { who, body, ago: this._ago(m.createdAt) };
|
|
313
|
+
})
|
|
314
|
+
.filter((m) => m.body);
|
|
315
|
+
if (!rendered.length) return null;
|
|
316
|
+
const lines = ["[Kazee group chat context]"];
|
|
317
|
+
lines.push(since
|
|
318
|
+
? "Messages in this group since your last engaged turn (oldest→newest):"
|
|
319
|
+
: "Recent messages in this group (oldest→newest):");
|
|
320
|
+
for (const m of rendered.slice(-CONTEXT_MAX_MESSAGES)) lines.push(` [${m.ago}] ${m.who}: ${m.body}`);
|
|
321
|
+
return { contextBlock: lines.join("\n") };
|
|
322
|
+
} catch (e) {
|
|
323
|
+
console.error("kazee buildThreadContext:", e.message);
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Message delta for a chat. With a watermark: chat-central's since-sync
|
|
329
|
+
// (oldest-first, server-capped at 500). Without one — the chat's first-ever
|
|
330
|
+
// engage — one recent page, which the server already returns in
|
|
331
|
+
// chronological order.
|
|
332
|
+
async _messagesSince(chatId, sinceIso) {
|
|
333
|
+
const base = `/messages/${encodeURIComponent(chatId)}/${encodeURIComponent(String(this.botUserId))}`;
|
|
334
|
+
const query = sinceIso
|
|
335
|
+
? `?since=${encodeURIComponent(sinceIso)}`
|
|
336
|
+
: `?page=1&messageCount=${COLD_START_WINDOW}`;
|
|
337
|
+
const res = await this._request("GET", base + query);
|
|
338
|
+
const data = res?.data || res || {};
|
|
339
|
+
if (data.error) throw new Error(String(data.error));
|
|
340
|
+
return Array.isArray(data.messages) ? data.messages : [];
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
_ago(iso) {
|
|
344
|
+
const t = Date.parse(iso || 0);
|
|
345
|
+
if (!t) return "?";
|
|
346
|
+
const s = Math.max(0, Math.floor((Date.now() - t) / 1000));
|
|
347
|
+
if (s < 60) return `${s}s ago`;
|
|
348
|
+
const m = Math.floor(s / 60);
|
|
349
|
+
if (m < 60) return `${m}m ago`;
|
|
350
|
+
const h = Math.floor(m / 60);
|
|
351
|
+
if (h < 24) return `${h}h ago`;
|
|
352
|
+
return `${Math.floor(h / 24)}d ago`;
|
|
353
|
+
}
|
|
354
|
+
|
|
216
355
|
_normalizeKeyboard(keyboard) {
|
|
217
356
|
if (!keyboard) return null;
|
|
218
357
|
if (keyboard.buttons) return keyboard.buttons;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Persistent per-chat context watermark for the Kazee group participation
|
|
2
|
+
// model: the createdAt (ISO) of the newest message already folded into an
|
|
3
|
+
// engaged turn's context block. buildThreadContext reads it to compute the
|
|
4
|
+
// "messages since I last engaged" delta and advances it on every engage, so
|
|
5
|
+
// group chatter the gate stayed silent through is caught up exactly once.
|
|
6
|
+
// Parent-process only; small, atomic writes.
|
|
7
|
+
|
|
8
|
+
const path = require("path");
|
|
9
|
+
const { CONFIG_DIR } = require("../../core/config");
|
|
10
|
+
const { atomicWriteFileSync, readJsonWithFallback } = require("../../core/fsutil");
|
|
11
|
+
|
|
12
|
+
const STATE_FILE = path.join(CONFIG_DIR, "kazee-state.json");
|
|
13
|
+
|
|
14
|
+
let store = null;
|
|
15
|
+
|
|
16
|
+
function load() {
|
|
17
|
+
if (store) return store;
|
|
18
|
+
const raw = readJsonWithFallback(STATE_FILE, null) || {};
|
|
19
|
+
store = { chats: raw.chats && typeof raw.chats === "object" ? raw.chats : {} };
|
|
20
|
+
return store;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function save() {
|
|
24
|
+
try { atomicWriteFileSync(STATE_FILE, JSON.stringify(store, null, 2)); }
|
|
25
|
+
catch (e) { console.error("kazee state save:", e.message); }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function setContextWatermark(chatId, iso) {
|
|
29
|
+
const id = String(chatId || "");
|
|
30
|
+
if (!id || !iso) return;
|
|
31
|
+
const s = load();
|
|
32
|
+
s.chats[id] = { ...(s.chats[id] || {}), contextAt: String(iso) };
|
|
33
|
+
save();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getContextWatermark(chatId) {
|
|
37
|
+
const s = load();
|
|
38
|
+
const c = s.chats[String(chatId || "")];
|
|
39
|
+
return (c && c.contextAt) || null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = { setContextWatermark, getContextWatermark, STATE_FILE };
|
package/core/access.js
CHANGED
|
@@ -48,10 +48,17 @@ function saveAuth(auth) {
|
|
|
48
48
|
fs.writeFileSync(AUTH_FILE, JSON.stringify(auth, null, 2));
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
function isChatAuthorized(chatId) {
|
|
51
|
+
function isChatAuthorized(chatId, envelope) {
|
|
52
52
|
if (matchesTransportOwner()) return true;
|
|
53
53
|
const id = String(chatId || "");
|
|
54
54
|
if (!id) return false;
|
|
55
|
+
// Adapter-attested engagement (e.g. a kazee group @-mention of the bot):
|
|
56
|
+
// the platform semantics invited the bot into this exchange, so the turn
|
|
57
|
+
// proceeds — the speaker still classifies external and runs fully guarded
|
|
58
|
+
// (reply vetting, action enforcement, owner escalation), same as the Spaces
|
|
59
|
+
// participation rule below. The flag is set only by adapter code, never
|
|
60
|
+
// derived from message content.
|
|
61
|
+
if (envelope && envelope.engaged === true) return true;
|
|
55
62
|
// Spaces task threads authorize by participation: the bot only receives a
|
|
56
63
|
// Spaces notification for a task it follows/was mentioned on, so the inbound
|
|
57
64
|
// itself is the authorization signal. Effective only while the conversational
|
package/core/people.js
CHANGED
|
@@ -255,7 +255,16 @@ function seedOwnerFromLegacy() {
|
|
|
255
255
|
const auth = JSON.parse(fs.readFileSync(AUTH_FILE, "utf-8"));
|
|
256
256
|
legacyOwner = (auth.authorized || []).find((a) => a.isOwner === true) || null;
|
|
257
257
|
} catch (e) {}
|
|
258
|
-
if (!legacyOwner)
|
|
258
|
+
if (!legacyOwner) {
|
|
259
|
+
// Pods configured with only KAZEE_OWNER_USER_ID (empty auth.json) DO have
|
|
260
|
+
// an owner — without a person record here, every unknown inbound was
|
|
261
|
+
// refused with a false "no owner configured" message.
|
|
262
|
+
const kazeeOnlyOwner = (config && config.KAZEE_OWNER_USER_ID) || "";
|
|
263
|
+
if (!kazeeOnlyOwner) return null;
|
|
264
|
+
const person = add({ name: "Owner", isOwner: true, bio: "Seeded from KAZEE_OWNER_USER_ID" });
|
|
265
|
+
try { linkHandle(person.id, { adapter: "kazee", channelId: String(kazeeOnlyOwner), approvedBy: "bootstrap" }); } catch (e) {}
|
|
266
|
+
return person;
|
|
267
|
+
}
|
|
259
268
|
|
|
260
269
|
const adapter = "telegram";
|
|
261
270
|
const channelId = String(legacyOwner.chatId);
|
package/core/relationship.js
CHANGED
|
@@ -161,10 +161,35 @@ async function ownerTarget() {
|
|
|
161
161
|
String(h.channelId) === String(owner.primaryChannel.channelId))
|
|
162
162
|
: null;
|
|
163
163
|
const handle = primary || handles[0];
|
|
164
|
-
if (handle)
|
|
164
|
+
if (handle) {
|
|
165
|
+
const resolved = await resolveHandleSendTarget(handle);
|
|
166
|
+
if (resolved) return { ...resolved, person: owner };
|
|
167
|
+
}
|
|
165
168
|
}
|
|
166
169
|
} catch (e) { /* fall through to the env fallback */ }
|
|
167
170
|
return configuredOwnerTarget();
|
|
168
171
|
}
|
|
169
172
|
|
|
173
|
+
// Env/legacy-seeded kazee owner handles store the owner's USER id, but kazee
|
|
174
|
+
// sends address a chat-document id — posting buttons to the raw user id 404s
|
|
175
|
+
// and escalation silently dies. Resolve those handles to the 1:1 DM the same
|
|
176
|
+
// way configuredOwnerTarget does; every other handle is already a send target.
|
|
177
|
+
async function resolveHandleSendTarget(handle) {
|
|
178
|
+
const adapter = String(handle.adapter || "");
|
|
179
|
+
const channelId = String(handle.channelId || "");
|
|
180
|
+
if (adapter !== "kazee") return { adapter, channelId };
|
|
181
|
+
let kzOwner = "";
|
|
182
|
+
try { const cfg = require("./config"); kzOwner = String((cfg.config && cfg.config.KAZEE_OWNER_USER_ID) || ""); } catch (e) {}
|
|
183
|
+
if (!kzOwner || channelId !== kzOwner) return { adapter, channelId };
|
|
184
|
+
try {
|
|
185
|
+
const registry = require("./adapter-registry");
|
|
186
|
+
const kazee = (registry.getAdapters() || []).find((a) => a.type === "kazee");
|
|
187
|
+
if (kazee && typeof kazee.openDirectChat === "function") {
|
|
188
|
+
const chatId = await kazee.openDirectChat(channelId);
|
|
189
|
+
if (chatId) return { adapter, channelId: String(chatId) };
|
|
190
|
+
}
|
|
191
|
+
} catch (e) { /* outreach unavailable → let the env fallback decide */ }
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
|
|
170
195
|
module.exports = { speakerFor, currentSpeaker, guardActive, isCurrentSpeakerGuarded, ownerTarget, configuredOwnerTarget };
|
package/core/router.js
CHANGED
|
@@ -140,7 +140,7 @@ async function onMessage(envelope) {
|
|
|
140
140
|
return;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
if (!isChatAuthorized(envelope.channelId)) {
|
|
143
|
+
if (!isChatAuthorized(envelope.channelId, envelope)) {
|
|
144
144
|
if (envelope.type === "text") {
|
|
145
145
|
if (isDuplicate(envelope)) return;
|
|
146
146
|
await introFlow.handleInbound(envelope, (text) => send(text));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inetafrica/open-claudia",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.22",
|
|
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-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-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
|
-
"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-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 && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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"
|
|
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-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-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"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"bot.js",
|
|
@@ -251,7 +251,27 @@ assert.match(pkg.description, /provider-agnostic coding-agent harness/i);
|
|
|
251
251
|
// stop being estimates — plus the Janus keepalive ack fix (Janus answers
|
|
252
252
|
// keepalive with ONLY an ack; acks now settle keepalive requests alone,
|
|
253
253
|
// ending the bogus per-interval "keepalive timed out" log noise).
|
|
254
|
-
|
|
254
|
+
// 3.1.21 approved by Sumeet 2026-07-23 ("Proceed as you see fit and fix in a
|
|
255
|
+
// production ready way work through till it's fully fixed you have my approval
|
|
256
|
+
// unless you need confirmation"): kazee public participation — pods whose only
|
|
257
|
+
// owner signal is KAZEE_OWNER_USER_ID now seed an owner person record (an
|
|
258
|
+
// empty auth.json used to turn every unknown inbound into a false "no owner
|
|
259
|
+
// configured" refusal — network-mon, 2026-07-23); kazee group chats honor
|
|
260
|
+
// chat-central's assistantAction (default tagged-reply: the bot engages only
|
|
261
|
+
// on @-mention or a reply to its own message; free-reply engages everything);
|
|
262
|
+
// engaged externals run the guarded external turn with the owner
|
|
263
|
+
// approve/deny/make-a-rule escalation, same pattern as Spaces; and
|
|
264
|
+
// ownerTarget resolves kazee user-id owner handles to a DM chat id via
|
|
265
|
+
// openDirectChat so escalation cards actually deliver.
|
|
266
|
+
// 3.1.22 approved by Sumeet 2026-07-23 ("It should not reply to owner messages
|
|
267
|
+
// also on a group unless tagged but should get messages since it's last
|
|
268
|
+
// cursor"): group catch-up context — an engaged kazee group turn now opens
|
|
269
|
+
// with every message since the bot's last engaged turn (persisted per-chat
|
|
270
|
+
// watermark; server-derived GET /messages?since= delta; a chat's first engage
|
|
271
|
+
// uses a recent-page window), rendered Spaces-style with sender attribution,
|
|
272
|
+
// so the chatter the gate stayed silent through is caught up exactly once:
|
|
273
|
+
// the gate keeps the bot reply-silent, never context-blind.
|
|
274
|
+
assert.strictEqual(pkg.version, "3.1.22", "release version must remain unchanged without explicit approval");
|
|
255
275
|
for (const keyword of ["claude", "codex", "coding-agent", "provider-agnostic"]) {
|
|
256
276
|
assert.ok(pkg.keywords.includes(keyword), `package keyword missing: ${keyword}`);
|
|
257
277
|
}
|