@keychat-io/keychat-openclaw 0.1.8 → 0.1.9
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/README.md +11 -16
- package/docs/setup-guide.md +1 -1
- package/package.json +1 -1
- package/src/channel.ts +16 -6
- package/src/paths.ts +1 -1
- package/src/qrcode-types.d.ts +1 -0
- package/src/qrcode.ts +14 -0
package/README.md
CHANGED
|
@@ -13,11 +13,11 @@ Your agent becomes a full Keychat citizen: it can receive friend requests, estab
|
|
|
13
13
|
### Option A: OpenClaw plugin (recommended)
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
openclaw plugins install @keychat-io/keychat
|
|
16
|
+
openclaw plugins install @keychat-io/keychat-openclaw
|
|
17
17
|
openclaw gateway restart
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Supported platforms: macOS (ARM/x64), Linux (x64/ARM64).
|
|
21
21
|
|
|
22
22
|
### Option B: Shell script
|
|
23
23
|
|
|
@@ -40,31 +40,26 @@ Source code is fully open: [github.com/keychat-io/keychat-openclaw](https://gith
|
|
|
40
40
|
|
|
41
41
|
### Upgrade
|
|
42
42
|
|
|
43
|
+
If you installed via **Option A**:
|
|
44
|
+
|
|
43
45
|
```bash
|
|
44
|
-
|
|
45
|
-
openclaw plugins install @keychat-io/keychat@latest
|
|
46
|
+
openclaw plugins install @keychat-io/keychat-openclaw@latest
|
|
46
47
|
openclaw gateway restart
|
|
48
|
+
```
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
If you installed via **Option B**:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
49
53
|
curl -fsSL https://raw.githubusercontent.com/keychat-io/keychat-openclaw/main/scripts/install.sh | bash
|
|
50
54
|
```
|
|
51
55
|
|
|
52
56
|
### Connect
|
|
53
57
|
|
|
54
|
-
1. Run `openclaw status`
|
|
58
|
+
1. Run `openclaw status` — your agent's **npub** and **QR code** will be displayed
|
|
55
59
|
2. Open the [Keychat app](https://keychat.io) → tap **Add Contact** on the home page
|
|
56
|
-
3.
|
|
60
|
+
3. Scan the QR code, or paste the npub
|
|
57
61
|
4. The agent will automatically accept the friend request and establish an encrypted session
|
|
58
62
|
|
|
59
|
-
You can also scan the QR code instead of pasting the npub:
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
# View QR code in terminal
|
|
63
|
-
chafa ~/.openclaw/keychat/qr-default.png
|
|
64
|
-
# or generate from npub
|
|
65
|
-
qrencode -t ANSIUTF8 "https://www.keychat.io/u/?k=YOUR_NPUB"
|
|
66
|
-
```
|
|
67
|
-
|
|
68
63
|
## Configuration
|
|
69
64
|
|
|
70
65
|
All options go under `channels.keychat` in your OpenClaw config:
|
package/docs/setup-guide.md
CHANGED
|
@@ -11,7 +11,7 @@ Step-by-step instructions to get your OpenClaw agent communicating via Keychat.
|
|
|
11
11
|
## Step 1: Install the Plugin
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
openclaw plugins install @keychat-io/keychat
|
|
14
|
+
openclaw plugins install @keychat-io/keychat-openclaw
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
This auto-downloads the pre-compiled Rust sidecar binary for your platform. No Rust toolchain needed.
|
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -714,7 +714,7 @@ export const keychatPlugin: ChannelPlugin<ResolvedKeychatAccount> = {
|
|
|
714
714
|
ctx.log?.info(`[${account.accountId}] Bridge sidecar started`);
|
|
715
715
|
|
|
716
716
|
// 2. Initialize Signal Protocol DB
|
|
717
|
-
const dbPath = `~/.openclaw/keychat
|
|
717
|
+
const dbPath = `~/.openclaw/keychat-signal-${account.accountId}.db`;
|
|
718
718
|
await bridge.init(dbPath);
|
|
719
719
|
ctx.log?.info(`[${account.accountId}] Signal DB initialized`);
|
|
720
720
|
|
|
@@ -797,14 +797,19 @@ export const keychatPlugin: ChannelPlugin<ResolvedKeychatAccount> = {
|
|
|
797
797
|
const contactUrl = `https://www.keychat.io/u/?k=${info.pubkey_npub}`;
|
|
798
798
|
const qrPath = qrCodePath(account.accountId);
|
|
799
799
|
|
|
800
|
-
// Generate QR
|
|
801
|
-
let
|
|
800
|
+
// Generate QR codes (best-effort)
|
|
801
|
+
let qrTerminal = "";
|
|
802
|
+
try {
|
|
803
|
+
const { generateQRTerminal } = await import("./qrcode.js");
|
|
804
|
+
qrTerminal = await generateQRTerminal(contactUrl);
|
|
805
|
+
} catch { /* qrcode not installed, skip */ }
|
|
806
|
+
|
|
807
|
+
// Also save PNG for sharing (best-effort)
|
|
802
808
|
try {
|
|
803
809
|
mkdirSync(WORKSPACE_KEYCHAT_DIR, { recursive: true });
|
|
804
810
|
const QRCode = await import("qrcode");
|
|
805
811
|
await QRCode.toFile(qrPath, contactUrl, { width: 256 });
|
|
806
|
-
|
|
807
|
-
} catch { /* qrcode not installed, skip */ }
|
|
812
|
+
} catch { /* skip */ }
|
|
808
813
|
|
|
809
814
|
const cfg = runtime.config.loadConfig();
|
|
810
815
|
const displayName = resolveDisplayName(cfg, account.accountId, account.name);
|
|
@@ -817,7 +822,7 @@ export const keychatPlugin: ChannelPlugin<ResolvedKeychatAccount> = {
|
|
|
817
822
|
`\n` +
|
|
818
823
|
` 📱 Add contact (tap or scan):\n` +
|
|
819
824
|
` ${contactUrl}\n` +
|
|
820
|
-
(
|
|
825
|
+
(qrTerminal ? `\n${qrTerminal}\n` : ``) +
|
|
821
826
|
`═══════════════════════════════════════════════════\n`,
|
|
822
827
|
);
|
|
823
828
|
|
|
@@ -840,8 +845,10 @@ export const keychatPlugin: ChannelPlugin<ResolvedKeychatAccount> = {
|
|
|
840
845
|
activeBridges.set(account.accountId, bridge);
|
|
841
846
|
|
|
842
847
|
// 7. Restore peer sessions and receiving addresses from DB
|
|
848
|
+
console.log(`[keychat] [${account.accountId}] Step 7: restoring peer sessions...`);
|
|
843
849
|
try {
|
|
844
850
|
const { mappings } = await bridge.getPeerMappings();
|
|
851
|
+
console.log(`[keychat] [${account.accountId}] Step 7: getPeerMappings returned ${mappings.length} mapping(s)`);
|
|
845
852
|
if (mappings.length > 0) {
|
|
846
853
|
ctx.log?.info(`[${account.accountId}] Restored ${mappings.length} peer mapping(s) from DB`);
|
|
847
854
|
for (const m of mappings) {
|
|
@@ -871,7 +878,9 @@ export const keychatPlugin: ChannelPlugin<ResolvedKeychatAccount> = {
|
|
|
871
878
|
}
|
|
872
879
|
|
|
873
880
|
// Restore address-to-peer mappings from DB and populate peerSubscribedAddresses
|
|
881
|
+
console.log(`[keychat] [${account.accountId}] Step 7b: getting address mappings...`);
|
|
874
882
|
const { mappings: addrMappings } = await bridge.getAddressMappings();
|
|
883
|
+
console.log(`[keychat] [${account.accountId}] Step 7b: getAddressMappings returned ${addrMappings.length} mapping(s)`);
|
|
875
884
|
if (addrMappings.length > 0) {
|
|
876
885
|
for (const am of addrMappings) {
|
|
877
886
|
getAddressToPeer(account.accountId).set(am.address, am.peer_nostr_pubkey);
|
|
@@ -935,6 +944,7 @@ export const keychatPlugin: ChannelPlugin<ResolvedKeychatAccount> = {
|
|
|
935
944
|
}
|
|
936
945
|
} catch (err) {
|
|
937
946
|
ctx.log?.error(`[${account.accountId}] Failed to restore sessions from DB: ${err}`);
|
|
947
|
+
console.error(`[keychat] [${account.accountId}] Failed to restore sessions from DB:`, err);
|
|
938
948
|
}
|
|
939
949
|
|
|
940
950
|
// 8. Restore groups from DB
|
package/src/paths.ts
CHANGED
|
@@ -19,7 +19,7 @@ export const WORKSPACE_KEYCHAT_DIR = join(HOME, ".openclaw", "workspace", "keych
|
|
|
19
19
|
|
|
20
20
|
/** Signal DB path for a given account */
|
|
21
21
|
export function signalDbPath(accountId: string): string {
|
|
22
|
-
return join(
|
|
22
|
+
return join(HOME, ".openclaw", `keychat-signal-${accountId}.db`);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/** QR code image path for a given account */
|
package/src/qrcode-types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
declare module "qrcode" {
|
|
2
2
|
export function toDataURL(text: string, options?: Record<string, unknown>): Promise<string>;
|
|
3
3
|
export function toFile(path: string, text: string, options?: Record<string, unknown>): Promise<void>;
|
|
4
|
+
export function toString(text: string, options?: Record<string, unknown>): Promise<string>;
|
|
4
5
|
}
|
package/src/qrcode.ts
CHANGED
|
@@ -7,3 +7,17 @@ export async function generateQRDataUrl(npub: string): Promise<string> {
|
|
|
7
7
|
return ""; // QR code generation not available
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Generate a QR code as Unicode block characters for terminal display.
|
|
13
|
+
* Uses half-block characters (▀▄█ ) so each text row encodes 2 pixel rows.
|
|
14
|
+
* Can be scanned by phone camera directly from the screen.
|
|
15
|
+
*/
|
|
16
|
+
export async function generateQRTerminal(url: string): Promise<string> {
|
|
17
|
+
try {
|
|
18
|
+
const QRCode = await import("qrcode");
|
|
19
|
+
return await QRCode.toString(url, { type: "terminal", small: true });
|
|
20
|
+
} catch {
|
|
21
|
+
return ""; // qrcode not installed
|
|
22
|
+
}
|
|
23
|
+
}
|