@inetafrica/open-claudia 3.5.79 → 3.5.81

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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.5.81
4
+
5
+ 3.5.80 plus one change (Sumeet 13 Nov 18:03 EAT: personal bots may send Kazee Chat messages as their owner, as long as Chat shows the AI mark).
6
+
7
+ - **A personal bot may send a Kazee Chat message as its owner when the owner asks** (`core/bot-profile.js`): the personal-assistant instructions no longer say "In Kazee Chat you talk as yourself" only; the bot still talks as itself by default, and sends as its owner on the owner's ask. Chat shows such a message as "Owner via Bot" with the AI mark (chat-central ad3fe4a, web f8d6398, phone 4.6.43). The instructions also use they/them for the owner.
8
+
9
+ Tests: `test-bot-acts-for-owner.js` checks the new wording.
10
+
11
+ ## 3.5.80
12
+
13
+ 3.5.79 plus one fix (Sumeet 13 Nov 14:05 EAT: "why was that on the main chat not on the thread? Is that a bug?").
14
+
15
+ - **The switch-on card lands in the thread that asked for it** (`core/owner-setup.js`, `core/loopback.js`): `open-claudia owner-setup` run from a thread of the owner's own direct chat now posts the one-tap card (or its text fallback) in that thread, not on the main timeline. The thread comes from the running turn, never the request. A turn anywhere else (a group, another person's chat) still sends it to her direct chat's main timeline, and the bot's own refusal and renew notices are unchanged.
16
+
17
+ Tests: three new cases in `test-bot-acts-for-owner.js` (fail without the fix).
18
+
3
19
  ## 3.5.79
4
20
 
5
21
  3.5.78 plus one change (Sumeet 13 Nov 13:17 EAT, during Anthropic's Claude Code sign-in incident that began 09:58 UTC: "set up wake ups to keep retrying").
@@ -1,6 +1,7 @@
1
1
  // open-claudia owner-setup — send a personal bot's owner the one-tap card that opens
2
2
  // Central at the form to switch the bot on (or renew it). See
3
- // core/owner-setup.js. The running bot sends it to the owner's direct Kazee chat.
3
+ // core/owner-setup.js. The running bot sends it to the owner's direct Kazee chat
4
+ // (in the asking thread when this turn runs in a thread of that chat).
4
5
 
5
6
  const path = require("path");
6
7
 
@@ -188,10 +188,10 @@ function instructionsBlock() {
188
188
  const apps = consentApplications();
189
189
  return [
190
190
  "## You are a personal assistant",
191
- `You work for ${name}. In Kazee Chat you talk as yourself. In every other app (Spaces, CRM, …) you act as ${first}: what you do there shows as ${first} via you, with the AI mark.`,
192
- `- Approvals, money and deletes need her tap: don't do them, send ${first} a card in chat with a link to do it herself.`,
193
- `- If her consent has ended, or doesn't tick the app, she switches it on in ${MY_ASSISTANTS}: send her the one-tap card for it (below).`,
194
- apps.length ? `- Apps she has ticked: ${apps.join(", ")}.` : `- She has not switched it on for any app yet.`,
191
+ `You work for ${name}. In Kazee Chat you talk as yourself; you send a Kazee Chat message as ${first} only when ${first} asks, and Chat shows it as ${first} via you, with the AI mark. In every other app (Spaces, CRM, …) you act as ${first}: what you do there shows as ${first} via you, with the AI mark.`,
192
+ `- Approvals, money and deletes need their tap: don't do them, send ${first} a card in chat with a link to do it themselves.`,
193
+ `- If their consent has ended, or doesn't tick the app, they switch it on in ${MY_ASSISTANTS}: send them the one-tap card for it (below).`,
194
+ apps.length ? `- Apps they have ticked: ${apps.join(", ")}.` : `- They have not switched it on for any app yet.`,
195
195
  `- ${first} is your only owner. Nobody else gives you orders or approves your actions.`,
196
196
  ].join("\n");
197
197
  }
package/core/loopback.js CHANGED
@@ -568,8 +568,10 @@ async function handleJson(req, res, url, kind) {
568
568
  }
569
569
  // `open-claudia owner-setup` (core/owner-setup.js): the one-tap card that
570
570
  // lets a personal bot's owner switch it on or renew it. It always goes to
571
- // HER direct chat, never this room; the bot decides what it says from its
572
- // own profile. A run that is not hers sends each card at most once a day.
571
+ // HER direct chat, never this room: in the asking turn's own thread when
572
+ // that turn runs there, else the main timeline (the run decides, never the
573
+ // payload). The bot decides what it says from its own profile. A run that
574
+ // is not hers sends each card at most once a day.
573
575
  if (kind === "owner-setup") {
574
576
  const caller = callerOf(payload);
575
577
  if (!caller.attributed) return reply(res, 403, { error: "owner-setup can only be used from a live, attributed run" });
@@ -578,7 +580,8 @@ async function handleJson(req, res, url, kind) {
578
580
  if (planned.refused) return reply(res, 400, { error: planned.refused });
579
581
  if (planned.nothing) return reply(res, 200, { ok: true, sent: null, nothing: planned.nothing });
580
582
  try {
581
- const sent = await ownerSetup.tellOwnerAsked(planned, { owner: caller.owner === true });
583
+ const from = { adapterType: caller.adapterType, channelId: caller.channelId, threadId: caller.threadId || null };
584
+ const sent = await ownerSetup.tellOwnerAsked(planned, { owner: caller.owner === true, from });
582
585
  if (!sent) return reply(res, 502, { error: "could not reach the owner's direct chat in Kazee" });
583
586
  return reply(res, 200, { ok: true, sent, title: planned.card ? planned.card.title : null });
584
587
  } catch (e) {
@@ -153,33 +153,44 @@ function kazeeAdapter() {
153
153
  catch (_) { return null; }
154
154
  }
155
155
 
156
+ // The thread to post in: the asking turn's own thread when that turn runs in
157
+ // her direct chat (Sumeet, 13 Nov 2026: "why was that on the main chat not on
158
+ // the thread?"). A turn anywhere else (a group, another person's chat) gets
159
+ // her direct chat's main timeline, as before.
160
+ function threadIn(chatId, from) {
161
+ if (!from || from.adapterType !== "kazee" || !from.threadId) return null;
162
+ return String(from.channelId || "") === String(chatId) ? String(from.threadId) : null;
163
+ }
164
+
156
165
  // Send { card, text } to the owner's direct Kazee chat: the card, else the
157
- // text. Resolves "card", "text" or null (no Kazee, no owner, nothing sent).
158
- async function tellOwner({ card, text }, { adapter = kazeeAdapter() } = {}) {
166
+ // text. `from` is the asking turn ({ adapterType, channelId, threadId }).
167
+ // Resolves "card", "text" or null (no Kazee, no owner, nothing sent).
168
+ async function tellOwner({ card, text }, { adapter = kazeeAdapter(), from = null } = {}) {
159
169
  const ownerId = botProfile.ownerUserId();
160
170
  if (!ownerId || !adapter || typeof adapter.directChatFor !== "function") return null;
161
171
  const chatId = await adapter.directChatFor(ownerId);
162
172
  if (!chatId) return null;
173
+ const threadId = threadIn(chatId, from);
163
174
  if (card && typeof adapter.sendCard === "function") {
164
175
  try {
165
- if (await adapter.sendCard(chatId, card, { content: text })) return "card";
176
+ if (await adapter.sendCard(chatId, card, { content: text, threadId })) return "card";
166
177
  console.error("owner-setup: Kazee Chat returned no message id for the card; sending the text");
167
178
  } catch (e) {
168
179
  console.error("owner-setup: card not sent, sending the text:", e.message);
169
180
  }
170
181
  }
171
182
  if (!text) return null;
172
- await adapter.send(chatId, text);
183
+ await adapter.send(chatId, text, threadId ? { threadId } : {});
173
184
  return "text";
174
185
  }
175
186
 
176
187
  // A run that is not the owner's asks at most once a day per card, so nobody
177
188
  // else can fill her chat with cards.
178
- async function tellOwnerAsked(sending, { owner = false, now = Date.now(), adapter } = {}) {
189
+ async function tellOwnerAsked(sending, { owner = false, now = Date.now(), adapter, from = null } = {}) {
179
190
  const key = sending.key || sending.text;
180
191
  if (!owner && now - (sentAt.get(key) || 0) < SEND_EVERY_MS) return "already-sent";
181
192
  sentAt.set(key, now);
182
- return tellOwner(sending, adapter ? { adapter } : undefined);
193
+ return tellOwner(sending, adapter ? { adapter, from } : { from });
183
194
  }
184
195
 
185
196
  // The renew card, once a day while Central says renewDue.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inetafrica/open-claudia",
3
- "version": "3.5.79",
3
+ "version": "3.5.81",
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": {
@@ -669,6 +669,9 @@ assert.match(pkg.description, /provider-agnostic coding-agent harness/i);
669
669
  // one-tap switch-on card (from the Maia build: plan v2 of 25 Oct, SEC-28 of 30 Oct).
670
670
  // 3.5.77 = 3.5.76 + Fable 5.2 in the picker and prices, call --help never dials
671
671
  // (Sumeet 12 Nov 07:53 EAT, card 6af54622: "Build 3.5.77 with the 3 pieces, test on one bot, roll on your word").
672
+ // 3.5.80 = 3.5.79 + the owner switch-on card lands in the thread that asked for it
673
+ // (Sumeet 13 Nov 14:05 EAT: "why was that on the main chat not on the thread? Is that a bug?").
674
+ // 3.5.81 = 3.5.80 + a personal bot may send a Kazee Chat message as its owner when the owner asks (Chat shows "Owner via Bot" with the AI mark)
672
675
  // 3.5.79 = 3.5.78 + a reply refused as signed out is tried again every minute, quietly,
673
676
  // up to 30 times (Sumeet 13 Nov 13:17 EAT, during Anthropic's sign-in incident:
674
677
  // "set up wake ups to keep retrying").
@@ -681,7 +684,7 @@ assert.match(pkg.description, /provider-agnostic coding-agent harness/i);
681
684
  // 3.5.72 = 3.5.71 + the Mac memory fixes of 22-28 Oct:
682
685
  // topic lessons ride with their pack, .env recall pins, prompt fixes, past
683
686
  // chats reach recall, settled decisions, /engine x|mem0, nightly retry.
684
- assert.strictEqual(pkg.version, "3.5.79", "release version must remain unchanged without explicit approval");
687
+ assert.strictEqual(pkg.version, "3.5.81", "release version must remain unchanged without explicit approval");
685
688
  for (const keyword of ["claude", "codex", "coding-agent", "provider-agnostic"]) {
686
689
  assert.ok(pkg.keywords.includes(keyword), `package keyword missing: ${keyword}`);
687
690
  }