@inetafrica/open-claudia 2.14.5 → 2.14.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/core/actions.js +3 -19
- package/core/channel-wizard.js +32 -0
- package/core/handlers.js +2 -28
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v2.14.6
|
|
4
|
+
- **`/channel add kazee` started from the inline "Add Kazee" button now completes — owner-capture confirm lands on the operator's channel, not on Kazee.** The wizard's owner-confirm prompt (*"Is this you — the owner?"*) is meant to go back to the channel the operator ran `/channel` from, via `channel-wizard.sayToOrigin`, which needs `session.origin` — captured from the envelope passed to `start()`. The typed `/channel add kazee` path (`handlers.js`) passed the envelope; the button path (`actions.js` `chn:add:kazee`) did **not**, so `origin` was null and the prompt fell back to ambient `io.send` scope — which, while processing the operator's inbound Kazee trigger message, is the Kazee room. The Yes/No/Skip buttons then rendered on Kazee, where a tap can never resolve the session: it's keyed by the operator's canonical id, but a Kazee tap resolves to the owner's *unlinked* Kazee user id (the very thing owner-capture is establishing) → `handleAction` finds no session → *"That setup step expired."* `actions.js` now passes the envelope to `wizard.start`, exactly like the typed path.
|
|
5
|
+
- **`/channel remove` and the inline "Remove <id>" button now share one teardown, so they can't drift.** v2.14.5 made the typed `/channel remove` a complete teardown (adapter + `.env` + `people.unlinkAdapterHandles` + `identity.removeTransportIdentities`), but the button (`actions.js` `chn:rm:`) still ran the pre-v2.14.5 version that cleared only `.env` — so removing via the button left exactly the handle/identity residue v2.14.5 was built to clear. The full teardown is now a single `channel-wizard.removeChannel(id)` called by both entry points; callers only guard `telegram` and format `r.summary` / `r.error`. Net −10 lines.
|
|
6
|
+
- **Agent-space / OpenClaw:** no new deps, no new env, no schema change; Docker image builds identically. Both fixes close divergences between the button and typed entry points of the owner-driven `/channel` flow — inert for deployments that never add/remove a channel. Full `npm test` green.
|
|
7
|
+
|
|
3
8
|
## v2.14.5
|
|
4
9
|
- **`/channel remove <id>` is now a complete teardown — a re-add starts from a genuinely clean slate.** Removal used to clear only the `.env` channel config (`CHANNELS` + the `KAZEE_*` keys), but the wizard's v2.14.4 owner-capture also links the owner's Kazee handle onto their people record (`people.linkHandle`) and mirrors an identity mapping into `identities.json` (`setIdentityMapping`). Those were left behind, so a subsequent `/channel add kazee` stacked on stale handle + identity state. `/channel remove` now also drops every handle for that transport across all people records (new `people.unlinkAdapterHandles`) and removes its identity mappings — channel→canonical links and preferred-channel pointers (new `identity.removeTransportIdentities`) — and clears the previously-orphaned `KAZEE_BOT_USER_ID`.
|
|
5
10
|
- **The cleanup goes through the in-memory stores, so disk and the running process stay consistent.** `identities.json` is loaded once at boot into a shared in-memory object (`identity.js`), and `saveIdentities()` re-serializes that whole object on every write. Because `router.js` calls `autoLinkOwnerChannel` → `setIdentityMapping` → `saveIdentities` on each owner message, any entry lingering in memory is rewritten to disk continuously — so an out-of-band file edit can't stick, and a partial teardown leaves ghosts that reappear. Removing through the in-memory maps (then persisting) means the teardown holds. The `/channel remove` reply now reports what it cleared (e.g. `Removed channel: kazee — cleared 1 handle + identity links`).
|
package/core/actions.js
CHANGED
|
@@ -488,28 +488,12 @@ async function handleAction(envelope) {
|
|
|
488
488
|
if (d.startsWith("chn:")) {
|
|
489
489
|
if (!isChatOwner(envelope.channelId)) { await send("Owner only."); return; }
|
|
490
490
|
const wizard = require("./channel-wizard");
|
|
491
|
-
|
|
492
|
-
if (d === "chn:add:kazee") { await wizard.start(envelope.canonicalUserId, "kazee"); return; }
|
|
491
|
+
if (d === "chn:add:kazee") { await wizard.start(envelope.canonicalUserId, "kazee", envelope); return; }
|
|
493
492
|
if (d.startsWith("chn:rm:")) {
|
|
494
493
|
const id = d.slice("chn:rm:".length);
|
|
495
494
|
if (id === "telegram") { await send("Refusing to remove the Telegram adapter."); return; }
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
const { config, saveEnvKey } = require("./config");
|
|
499
|
-
const channels = (config.CHANNELS || "telegram").split(",").map((s) => s.trim()).filter(Boolean);
|
|
500
|
-
const kept = channels.filter((c) => c !== id && !c.startsWith(id + ":") && c !== id.split(":")[0]);
|
|
501
|
-
const next = kept.join(",") || "telegram";
|
|
502
|
-
saveEnvKey("CHANNELS", next);
|
|
503
|
-
config.CHANNELS = next;
|
|
504
|
-
if (id === "kazee") {
|
|
505
|
-
saveEnvKey("KAZEE_URL", "");
|
|
506
|
-
saveEnvKey("KAZEE_BOT_TOKEN", "");
|
|
507
|
-
saveEnvKey("KAZEE_OWNER_USER_ID", "");
|
|
508
|
-
config.KAZEE_URL = "";
|
|
509
|
-
config.KAZEE_BOT_TOKEN = "";
|
|
510
|
-
config.KAZEE_OWNER_USER_ID = "";
|
|
511
|
-
}
|
|
512
|
-
await send(`Removed channel: ${id}`);
|
|
495
|
+
const r = await wizard.removeChannel(id);
|
|
496
|
+
await send(r.ok ? r.summary : r.error);
|
|
513
497
|
return;
|
|
514
498
|
}
|
|
515
499
|
}
|
package/core/channel-wizard.js
CHANGED
|
@@ -325,6 +325,37 @@ async function finalizeOwner(canonicalUserId, session, ownerUserId) {
|
|
|
325
325
|
);
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
+
// Full teardown for a live channel, shared by the /channel remove command and
|
|
329
|
+
// the inline "Remove <id>" button so the two entry points can't drift. Removes
|
|
330
|
+
// the adapter, strips its keys from .env (so the change survives restart), and
|
|
331
|
+
// drops its handles + identity mappings through the in-memory stores — a stale
|
|
332
|
+
// handle/link otherwise survives in memory and gets rewritten on the next add,
|
|
333
|
+
// which is what made a re-add feel un-clean. Callers guard "telegram" (their
|
|
334
|
+
// own connection) and format r.summary / r.error for their channel.
|
|
335
|
+
async function removeChannel(id) {
|
|
336
|
+
const result = await registry.removeAdapter(id);
|
|
337
|
+
if (!result.ok) return { ok: false, error: result.error };
|
|
338
|
+
const transport = id.split(":")[0];
|
|
339
|
+
const channels = (config.CHANNELS || "telegram").split(",").map((s) => s.trim()).filter(Boolean);
|
|
340
|
+
const kept = channels.filter((c) => c !== id && !c.startsWith(id + ":") && c !== transport);
|
|
341
|
+
saveEnvKey("CHANNELS", kept.join(",") || "telegram");
|
|
342
|
+
config.CHANNELS = kept.join(",") || "telegram";
|
|
343
|
+
if (transport === "kazee") {
|
|
344
|
+
for (const k of ["KAZEE_URL", "KAZEE_BOT_TOKEN", "KAZEE_OWNER_USER_ID", "KAZEE_BOT_USER_ID"]) {
|
|
345
|
+
saveEnvKey(k, "");
|
|
346
|
+
config[k] = "";
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
let unlinked = 0;
|
|
350
|
+
try { unlinked = people.unlinkAdapterHandles(transport).length; } catch (e) {}
|
|
351
|
+
let idsCleared = false;
|
|
352
|
+
try { idsCleared = require("./identity").removeTransportIdentities(transport); } catch (e) {}
|
|
353
|
+
const extra = (unlinked || idsCleared)
|
|
354
|
+
? ` — cleared ${unlinked} handle${unlinked === 1 ? "" : "s"} + identity links`
|
|
355
|
+
: "";
|
|
356
|
+
return { ok: true, id, transport, unlinked, idsCleared, summary: `Removed channel: ${id}${extra}` };
|
|
357
|
+
}
|
|
358
|
+
|
|
328
359
|
module.exports = {
|
|
329
360
|
isAwaiting,
|
|
330
361
|
getSession,
|
|
@@ -334,5 +365,6 @@ module.exports = {
|
|
|
334
365
|
handleText,
|
|
335
366
|
handleAction,
|
|
336
367
|
tryCaptureOwner,
|
|
368
|
+
removeChannel,
|
|
337
369
|
validateKazee,
|
|
338
370
|
};
|
package/core/handlers.js
CHANGED
|
@@ -1672,34 +1672,8 @@ register({
|
|
|
1672
1672
|
if (removeMatch) {
|
|
1673
1673
|
const id = removeMatch[1];
|
|
1674
1674
|
if (id === "telegram") return send("Refusing to remove the Telegram adapter from a /channel command — that's your own connection.");
|
|
1675
|
-
const
|
|
1676
|
-
|
|
1677
|
-
const transport = id.split(":")[0];
|
|
1678
|
-
// Strip from .env so the change survives restart.
|
|
1679
|
-
const channels = (config.CHANNELS || "telegram").split(",").map((s) => s.trim()).filter(Boolean);
|
|
1680
|
-
const kept = channels.filter((c) => c !== id && !c.startsWith(id + ":") && c !== transport);
|
|
1681
|
-
const next = kept.join(",") || "telegram";
|
|
1682
|
-
saveEnvKey("CHANNELS", next);
|
|
1683
|
-
config.CHANNELS = next;
|
|
1684
|
-
if (transport === "kazee") {
|
|
1685
|
-
for (const k of ["KAZEE_URL", "KAZEE_BOT_TOKEN", "KAZEE_OWNER_USER_ID", "KAZEE_BOT_USER_ID"]) {
|
|
1686
|
-
saveEnvKey(k, "");
|
|
1687
|
-
config[k] = "";
|
|
1688
|
-
}
|
|
1689
|
-
}
|
|
1690
|
-
// Complete the teardown: drop this transport's handles from every person
|
|
1691
|
-
// record and its identity mappings. Both mutate through the in-memory
|
|
1692
|
-
// stores, so disk and the running process stay consistent — otherwise a
|
|
1693
|
-
// stale handle/link survives in memory and gets rewritten on the next
|
|
1694
|
-
// add, which is exactly what made a re-add feel un-clean.
|
|
1695
|
-
let unlinked = 0;
|
|
1696
|
-
try { unlinked = require("./people").unlinkAdapterHandles(transport).length; } catch (e) {}
|
|
1697
|
-
let idsCleared = false;
|
|
1698
|
-
try { idsCleared = require("./identity").removeTransportIdentities(transport); } catch (e) {}
|
|
1699
|
-
const extra = (unlinked || idsCleared)
|
|
1700
|
-
? ` — cleared ${unlinked} handle${unlinked === 1 ? "" : "s"} + identity links`
|
|
1701
|
-
: "";
|
|
1702
|
-
return send(`Removed channel: ${id}${extra}`);
|
|
1675
|
+
const r = await wizard.removeChannel(id);
|
|
1676
|
+
return send(r.ok ? r.summary : r.error);
|
|
1703
1677
|
}
|
|
1704
1678
|
|
|
1705
1679
|
send("Usage: /channel | /channel add kazee | /channel remove <id>");
|
package/package.json
CHANGED