@inetafrica/open-claudia 2.2.1 → 2.2.3

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,8 @@
1
1
  # Changelog
2
2
 
3
+ ## v2.2.3
4
+ - Queue drain now batches: when multiple messages are received while a task is running, they're delivered as one combined follow-up turn instead of N isolated turns. The model sees them together (numbered, with HH:MM:SS queue timestamps), in context of what it just finished, so it can plan across them. A single queued message still delivers as before — no behavior change for the common case.
5
+
3
6
  ## v2.0.1
4
7
  - Kazee owner detection: `envelope.channelId` is the chat-document id, but `KAZEE_OWNER_USER_ID` is the Kazee user id. `isChatOwner`/`isChatAuthorized` now also short-circuit when the inbound user id matches the configured transport owner, so the owner running `/auth` (or anything else) on a fresh Kazee install is recognized immediately instead of being queued as a non-owner request.
5
8
  - `chatContext` now carries `userId` and `transport` in addition to `chatId`; new `currentUserId()` / `currentTransport()` exports.
package/core/actions.js CHANGED
@@ -113,6 +113,7 @@ async function handleAction(envelope) {
113
113
  state.pendingVaultUnlock = false;
114
114
  state.pendingVaultAction = null;
115
115
  state.pendingVaultUnlockAt = 0;
116
+ state.pendingVaultUnlockAttempts = 0;
116
117
  return send("Cancelled.");
117
118
  }
118
119
  if (action === "create") {
@@ -120,6 +121,7 @@ async function handleAction(envelope) {
120
121
  if (vault.exists()) return send("Vault already exists.");
121
122
  state.pendingVaultUnlock = true;
122
123
  state.pendingVaultUnlockAt = Date.now();
124
+ state.pendingVaultUnlockAttempts = 3;
123
125
  state.pendingVaultAction = { type: "create" };
124
126
  return send("Pick a vault password and send it next.\n(Message will be deleted. Send /vault cancel to abort.)", {
125
127
  keyboard: { inline_keyboard: [[{ text: "Cancel", callback_data: "vault:cancel" }]] },
package/core/handlers.js CHANGED
@@ -883,6 +883,7 @@ const PASSWORD_PROMPT_KB = { inline_keyboard: [[{ text: "Cancel", callback_data:
883
883
  function armVaultPrompt(state, action) {
884
884
  state.pendingVaultUnlock = true;
885
885
  state.pendingVaultUnlockAt = Date.now();
886
+ state.pendingVaultUnlockAttempts = 3;
886
887
  state.pendingVaultAction = action;
887
888
  }
888
889
 
@@ -925,6 +926,7 @@ register({
925
926
  state.pendingVaultUnlock = false;
926
927
  state.pendingVaultAction = null;
927
928
  state.pendingVaultUnlockAt = 0;
929
+ state.pendingVaultUnlockAttempts = 0;
928
930
  return send("Cancelled.");
929
931
  }
930
932
 
package/core/router.js CHANGED
@@ -246,17 +246,19 @@ async function handleText(envelope) {
246
246
  state.pendingVaultUnlock = false;
247
247
  state.pendingVaultAction = null;
248
248
  state.pendingVaultUnlockAt = 0;
249
+ state.pendingVaultUnlockAttempts = 0;
249
250
  await send("Vault prompt timed out. Re-run the command.");
250
251
  return;
251
252
  }
252
253
  const password = envelope.text;
253
254
  await deleteMessage(envelope.messageId);
254
255
  const action = state.pendingVaultAction;
255
- state.pendingVaultUnlock = false;
256
- state.pendingVaultAction = null;
257
- state.pendingVaultUnlockAt = 0;
258
256
 
259
257
  if (action && action.type === "create") {
258
+ state.pendingVaultUnlock = false;
259
+ state.pendingVaultAction = null;
260
+ state.pendingVaultUnlockAt = 0;
261
+ state.pendingVaultUnlockAttempts = 0;
260
262
  if (vault.exists()) { await send("Vault was created in another flow — re-run /vault."); return; }
261
263
  vault.create(password);
262
264
  await send("Vault created and unlocked.\n\nUse /vault set <name> <value>");
@@ -265,9 +267,27 @@ async function handleText(envelope) {
265
267
 
266
268
  const ok = vault.unlock(password);
267
269
  if (!ok) {
268
- await send("Wrong password.");
270
+ const left = (state.pendingVaultUnlockAttempts || 1) - 1;
271
+ if (left > 0) {
272
+ state.pendingVaultUnlockAttempts = left;
273
+ state.pendingVaultUnlockAt = Date.now();
274
+ await send(`Wrong password. ${left} attempt${left === 1 ? "" : "s"} left.\nSend the password again or /vault cancel.`, {
275
+ keyboard: { inline_keyboard: [[{ text: "Cancel", callback_data: "vault:cancel" }]] },
276
+ });
277
+ return;
278
+ }
279
+ state.pendingVaultUnlock = false;
280
+ state.pendingVaultAction = null;
281
+ state.pendingVaultUnlockAt = 0;
282
+ state.pendingVaultUnlockAttempts = 0;
283
+ await send("Too many wrong attempts. Re-run /vault to try again.");
269
284
  return;
270
285
  }
286
+
287
+ state.pendingVaultUnlock = false;
288
+ state.pendingVaultAction = null;
289
+ state.pendingVaultUnlockAt = 0;
290
+ state.pendingVaultUnlockAttempts = 0;
271
291
  if (action.type === "list") {
272
292
  const entries = vault.list();
273
293
  const keys = Object.keys(entries);
package/core/runner.js CHANGED
@@ -390,7 +390,7 @@ async function runClaude(prompt, cwd, replyToMsgId, opts = {}) {
390
390
  const { settings } = state;
391
391
 
392
392
  if (state.runningProcess) {
393
- state.messageQueue.push({ prompt, replyToMsgId, opts });
393
+ state.messageQueue.push({ prompt, replyToMsgId, opts, queuedAt: Date.now() });
394
394
  await send(state.isCompacting ? "Compacting context, will pick this up next…" : "Queued.", { replyTo: replyToMsgId });
395
395
  return;
396
396
  }
@@ -676,8 +676,27 @@ async function runClaude(prompt, cwd, replyToMsgId, opts = {}) {
676
676
  }
677
677
 
678
678
  if (state.messageQueue.length > 0 && state.currentSession) {
679
- const next = state.messageQueue.shift();
680
- await runClaude(next.prompt, state.currentSession.dir, next.replyToMsgId, next.opts);
679
+ const drained = state.messageQueue.splice(0);
680
+ if (drained.length === 1) {
681
+ const only = drained[0];
682
+ await runClaude(only.prompt, state.currentSession.dir, only.replyToMsgId, only.opts);
683
+ } else {
684
+ const fmtTime = (ts) => {
685
+ const d = new Date(ts);
686
+ const hh = String(d.getHours()).padStart(2, "0");
687
+ const mm = String(d.getMinutes()).padStart(2, "0");
688
+ const ss = String(d.getSeconds()).padStart(2, "0");
689
+ return `${hh}:${mm}:${ss}`;
690
+ };
691
+ const numbered = drained.map((m, i) => `[${i + 1}] (${fmtTime(m.queuedAt || Date.now())}) ${m.prompt}`).join("\n\n");
692
+ const batched =
693
+ `While you were working the user sent these ${drained.length} follow-up messages (oldest first):\n\n` +
694
+ `${numbered}\n\n` +
695
+ `Treat each as a distinct follow-up request. Add them to your plan and handle them; ` +
696
+ `if any contradicts an earlier one, prefer the newer one and call out the conflict.`;
697
+ const last = drained[drained.length - 1];
698
+ await runClaude(batched, state.currentSession.dir, last.replyToMsgId, last.opts);
699
+ }
681
700
  }
682
701
  }));
683
702
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inetafrica/open-claudia",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "description": "Your always-on AI coding assistant — Claude Code, Cursor Agent, and OpenAI Codex via Telegram or Kazee Chat",
5
5
  "main": "bot.js",
6
6
  "bin": {