reticulum-openclaw 0.1.0

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.
@@ -0,0 +1,3 @@
1
+ import type { ChannelPlugin } from "./types.js";
2
+ export declare function createReticulumChannel(): ChannelPlugin;
3
+ //# sourceMappingURL=channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,aAAa,EAOd,MAAM,YAAY,CAAC;AAOpB,wBAAgB,sBAAsB,IAAI,aAAa,CAoNtD"}
@@ -0,0 +1,194 @@
1
+ import { GatewayClient } from "./runtime.js";
2
+ import { toGatewayConfig } from "./types.js";
3
+ function resolveConfig(cfg) {
4
+ return toGatewayConfig(cfg.channels?.reticulum ?? {});
5
+ }
6
+ export function createReticulumChannel() {
7
+ let client = null;
8
+ return {
9
+ id: "reticulum",
10
+ meta: {
11
+ id: "reticulum",
12
+ label: "Reticulum / LXMF",
13
+ selectionLabel: "Reticulum (mesh network)",
14
+ docsPath: "channels/reticulum",
15
+ blurb: "Send and receive messages over the Reticulum mesh network via LXMF (MeshChat, Sideband, NomadNet compatible)",
16
+ aliases: ["lxmf"],
17
+ },
18
+ capabilities: {
19
+ chatTypes: ["direct"],
20
+ // LXMF is store-and-forward — streaming is not supported
21
+ blockStreaming: true,
22
+ },
23
+ pairing: {
24
+ idLabel: "LXMF Address",
25
+ },
26
+ config: {
27
+ listAccountIds: () => ["default"],
28
+ resolveAccount: (cfg) => resolveConfig(cfg),
29
+ isConfigured: () => true,
30
+ },
31
+ status: {
32
+ buildAccountSnapshot: ({ runtime }) => {
33
+ const snap = {
34
+ accountId: runtime?.accountId ?? "default",
35
+ configured: true,
36
+ };
37
+ if (runtime?.enabled !== undefined)
38
+ snap.enabled = runtime.enabled;
39
+ if (runtime?.running !== undefined)
40
+ snap.running = runtime.running;
41
+ if (runtime?.connected !== undefined)
42
+ snap.connected = runtime.connected;
43
+ if (runtime?.lastInboundAt !== undefined)
44
+ snap.lastInboundAt = runtime.lastInboundAt;
45
+ if (runtime?.lastError !== undefined)
46
+ snap.lastError = runtime.lastError;
47
+ if (runtime?.address !== undefined)
48
+ snap.address = runtime.address;
49
+ return snap;
50
+ },
51
+ },
52
+ gateway: {
53
+ startAccount: (ctx) => {
54
+ client = new GatewayClient(ctx.account);
55
+ ctx.setStatus({ ...ctx.getStatus(), connected: true });
56
+ ctx.abortSignal.addEventListener("abort", () => {
57
+ client?.stop();
58
+ client = null;
59
+ });
60
+ const dispatchInbound = async (event) => {
61
+ ctx.setStatus({ ...ctx.getStatus(), lastInboundAt: Date.now() });
62
+ ctx.log?.info(`[${ctx.accountId}] inbound message from ${event.from.slice(0, 8)}…`);
63
+ if (!ctx.channelRuntime) {
64
+ ctx.log?.warn?.("channelRuntime not available — cannot dispatch inbound message");
65
+ return;
66
+ }
67
+ const senderName = event.display_name || event.from.slice(0, 8);
68
+ const messageBody = event.content || event.title;
69
+ try {
70
+ const dmPolicy = ctx.cfg.channels?.reticulum?.dm_policy ?? "pairing";
71
+ if (dmPolicy === "disabled") {
72
+ ctx.log?.info(`[${ctx.accountId}] blocked sender ${event.from.slice(0, 8)}… (policy: disabled)`);
73
+ return;
74
+ }
75
+ if (dmPolicy !== "open") {
76
+ if (!ctx.channelRuntime.pairing) {
77
+ ctx.log?.warn?.(`[${ctx.accountId}] dm_policy=${dmPolicy} but pairing runtime is unavailable — allowing message`);
78
+ }
79
+ else {
80
+ const allowFrom = await ctx.channelRuntime.pairing.readAllowFromStore({
81
+ channel: "reticulum",
82
+ accountId: ctx.accountId,
83
+ });
84
+ if (!allowFrom.includes(event.from)) {
85
+ if (dmPolicy === "pairing") {
86
+ const { code } = await ctx.channelRuntime.pairing.upsertPairingRequest({
87
+ channel: "reticulum",
88
+ accountId: ctx.accountId,
89
+ id: event.from,
90
+ meta: { display_name: senderName },
91
+ });
92
+ const replyText = ctx.channelRuntime.pairing.buildPairingReply({
93
+ channel: "reticulum",
94
+ idLine: event.from,
95
+ code,
96
+ });
97
+ if (client) {
98
+ await client.send(event.from, replyText);
99
+ }
100
+ ctx.log?.info(`[${ctx.accountId}] pairing challenge issued for ${event.from.slice(0, 8)}…`);
101
+ }
102
+ else {
103
+ // "allowlist" — block silently
104
+ ctx.log?.info(`[${ctx.accountId}] blocked sender ${event.from.slice(0, 8)}… (not in allowlist)`);
105
+ }
106
+ return;
107
+ }
108
+ }
109
+ }
110
+ const route = ctx.channelRuntime.routing.resolveAgentRoute({
111
+ cfg: ctx.cfg,
112
+ channel: "reticulum",
113
+ accountId: ctx.accountId,
114
+ peer: { kind: "direct", id: event.from },
115
+ });
116
+ ctx.log?.info(`[${ctx.accountId}] route: agentId=${route.agentId} sessionKey=${route.sessionKey}`);
117
+ const storePath = ctx.channelRuntime.session.resolveStorePath(ctx.cfg.session?.store, { agentId: route.agentId });
118
+ const msgCtx = {
119
+ Body: messageBody,
120
+ BodyForAgent: messageBody,
121
+ From: event.from,
122
+ To: event.from,
123
+ AccountId: ctx.accountId,
124
+ SessionKey: route.sessionKey,
125
+ ChatType: "direct",
126
+ SenderName: senderName,
127
+ SenderId: event.from,
128
+ Provider: "reticulum",
129
+ Surface: "reticulum",
130
+ MessageSid: `${event.from}:${String(event.timestamp)}`,
131
+ Timestamp: event.timestamp * 1000,
132
+ ConversationLabel: messageBody,
133
+ OriginatingChannel: "reticulum",
134
+ OriginatingTo: event.from,
135
+ };
136
+ await ctx.channelRuntime.session.recordInboundSession({
137
+ storePath,
138
+ sessionKey: route.sessionKey,
139
+ ctx: msgCtx,
140
+ createIfMissing: true,
141
+ updateLastRoute: {
142
+ sessionKey: route.mainSessionKey,
143
+ channel: "reticulum",
144
+ to: event.from,
145
+ accountId: ctx.accountId,
146
+ },
147
+ onRecordError: (err) => ctx.log?.error?.(`[${ctx.accountId}] session record error: ${String(err)}`),
148
+ });
149
+ ctx.log?.info(`[${ctx.accountId}] session recorded, dispatching to agent`);
150
+ const dispatchResult = (await ctx.channelRuntime.reply.dispatchReplyWithBufferedBlockDispatcher({
151
+ ctx: msgCtx,
152
+ cfg: ctx.cfg,
153
+ dispatcherOptions: {
154
+ deliver: async (payload) => {
155
+ ctx.log?.info(`[${ctx.accountId}] deliver: text=${String(!!payload.text)} reasoning=${String(!!payload.isReasoning)} client=${String(!!client)}`);
156
+ if (payload.text && !payload.isReasoning && client) {
157
+ const reply = await client.send(event.from, payload.text);
158
+ ctx.log?.info(`[${ctx.accountId}] send result: ${reply.status}`);
159
+ }
160
+ },
161
+ },
162
+ }));
163
+ ctx.log?.info(`[${ctx.accountId}] dispatch complete: queuedFinal=${String(dispatchResult.queuedFinal)}`);
164
+ }
165
+ catch (err) {
166
+ ctx.log?.error?.(`[${ctx.accountId}] dispatchInbound error: ${String(err)}`);
167
+ }
168
+ };
169
+ return client.start((event) => dispatchInbound(event), (connected, address) => {
170
+ ctx.setStatus({ ...ctx.getStatus(), connected, ...(address ? { address } : {}) });
171
+ ctx.log?.info(`[${ctx.accountId}] gateway ${connected ? "reconnected" : "disconnected"}`);
172
+ });
173
+ },
174
+ stopAccount: (ctx) => {
175
+ ctx.log?.info(`[${ctx.accountId}] stopping`);
176
+ ctx.setStatus({ ...ctx.getStatus(), connected: false });
177
+ client?.stop();
178
+ client = null;
179
+ return Promise.resolve();
180
+ },
181
+ },
182
+ outbound: {
183
+ deliveryMode: "direct",
184
+ sendText: async ({ to, text }) => {
185
+ if (!client) {
186
+ return { ok: false };
187
+ }
188
+ const reply = await client.send(to, text);
189
+ return { ok: reply.status === "queued" };
190
+ },
191
+ },
192
+ };
193
+ }
194
+ //# sourceMappingURL=channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { OpenClawPluginApi } from "./types.js";
2
+ declare const _default: {
3
+ id: string;
4
+ name: string;
5
+ description: string;
6
+ configSchema: {
7
+ type: string;
8
+ additionalProperties: boolean;
9
+ properties: {};
10
+ };
11
+ register(api: OpenClawPluginApi): void;
12
+ };
13
+ export default _default;
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;;;;;;;;;;kBAYpC,iBAAiB,GAAG,IAAI;;AAVxC,wBAaE"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ import { createReticulumChannel } from "./channel.js";
2
+ export default {
3
+ id: "reticulum",
4
+ name: "Reticulum / LXMF",
5
+ description: "Send and receive messages over the Reticulum mesh network via LXMF",
6
+ configSchema: {
7
+ type: "object",
8
+ additionalProperties: false,
9
+ properties: {},
10
+ },
11
+ register(api) {
12
+ api.registerChannel({ plugin: createReticulumChannel() });
13
+ },
14
+ };
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAGtD,eAAe;IACb,EAAE,EAAE,WAAW;IACf,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,oEAAoE;IACjF,YAAY,EAAE;QACZ,IAAI,EAAE,QAAQ;QACd,oBAAoB,EAAE,KAAK;QAC3B,UAAU,EAAE,EAAE;KACf;IAED,QAAQ,CAAC,GAAsB;QAC7B,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,sBAAsB,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC;CACF,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { GatewayConfig, GatewayReply, LxmfEvent } from "./types.js";
2
+ export type EventCallback = (event: LxmfEvent) => void | Promise<void>;
3
+ export type StatusCallback = (connected: boolean, address?: string) => void;
4
+ export declare class GatewayClient {
5
+ private readonly config;
6
+ private sub;
7
+ private req;
8
+ private running;
9
+ private heartbeatTimer;
10
+ constructor(config: GatewayConfig);
11
+ start(onEvent: EventCallback, onStatusChange?: StatusCallback): Promise<void>;
12
+ send(to: string, content: string, title?: string): Promise<GatewayReply>;
13
+ stop(): void;
14
+ }
15
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAe,MAAM,YAAY,CAAC;AAEtF,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AACvE,MAAM,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAE5E,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,GAAG,CAAc;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAA+C;gBAEzD,MAAM,EAAE,aAAa;IAM3B,KAAK,CAAC,OAAO,EAAE,aAAa,EAAE,cAAc,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA0D7E,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,YAAY,CAAC;IAS1E,IAAI,IAAI,IAAI;CASb"}
@@ -0,0 +1,103 @@
1
+ import * as zmq from "zeromq";
2
+ export class GatewayClient {
3
+ config;
4
+ sub;
5
+ req;
6
+ running = false;
7
+ heartbeatTimer = null;
8
+ constructor(config) {
9
+ this.config = config;
10
+ this.sub = new zmq.Subscriber();
11
+ this.req = new zmq.Request({ sendTimeout: config.send_timeout_ms, receiveTimeout: config.send_timeout_ms });
12
+ }
13
+ async start(onEvent, onStatusChange) {
14
+ this.sub.connect(this.config.events_socket);
15
+ this.sub.subscribe("");
16
+ this.req.connect(this.config.command_socket);
17
+ this.running = true;
18
+ // Track liveness via heartbeat frames published by the gateway.
19
+ // The timeout is 2.5× the heartbeat interval to tolerate one missed beat.
20
+ let lastPulseAt = Date.now();
21
+ let lastKnownAddress;
22
+ let reportedConnected = true;
23
+ const timeoutMs = this.config.heartbeat_interval_ms * 2.5;
24
+ this.heartbeatTimer = setInterval(() => {
25
+ const connected = Date.now() - lastPulseAt < timeoutMs;
26
+ if (connected !== reportedConnected) {
27
+ reportedConnected = connected;
28
+ onStatusChange?.(connected);
29
+ }
30
+ }, this.config.heartbeat_interval_ms);
31
+ for await (const [msg] of this.sub) {
32
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
33
+ if (!this.running)
34
+ break; // stop() may be called externally between iterations
35
+ const raw = msg?.toString();
36
+ if (!raw)
37
+ continue;
38
+ let event;
39
+ try {
40
+ event = JSON.parse(raw);
41
+ }
42
+ catch {
43
+ continue;
44
+ }
45
+ // Any parseable frame counts as a pulse (heartbeat or message).
46
+ lastPulseAt = Date.now();
47
+ const address = isHeartbeat(event) ? event.address : undefined;
48
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
49
+ if (!reportedConnected) {
50
+ // Reconnected after a gap — always notify (with address if available).
51
+ reportedConnected = true;
52
+ lastKnownAddress = address;
53
+ onStatusChange?.(true, address);
54
+ }
55
+ else if (address !== undefined && address !== lastKnownAddress) {
56
+ // Address changed (e.g. gateway restarted with a new identity) — notify once.
57
+ lastKnownAddress = address;
58
+ onStatusChange?.(true, address);
59
+ }
60
+ if (!isLxmfEvent(event))
61
+ continue; // silently drops heartbeats and unknown frames
62
+ const { allowed_senders, max_message_length } = this.config;
63
+ if (allowed_senders.length > 0 && !allowed_senders.includes(event.from))
64
+ continue;
65
+ void onEvent({ ...event, content: event.content.slice(0, max_message_length) });
66
+ }
67
+ }
68
+ async send(to, content, title = "") {
69
+ const cmd = { cmd: "send", id: crypto.randomUUID(), to, content, title };
70
+ await this.req.send(JSON.stringify(cmd));
71
+ const [raw] = await this.req.receive();
72
+ // REP socket always delivers exactly one frame; non-null is safe here
73
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
74
+ return JSON.parse(raw.toString());
75
+ }
76
+ stop() {
77
+ this.running = false;
78
+ if (this.heartbeatTimer !== null) {
79
+ clearInterval(this.heartbeatTimer);
80
+ this.heartbeatTimer = null;
81
+ }
82
+ this.sub.close();
83
+ this.req.close();
84
+ }
85
+ }
86
+ function isHeartbeat(value) {
87
+ if (typeof value !== "object" || value === null)
88
+ return false;
89
+ const v = value;
90
+ return v.type === "heartbeat" && typeof v.address === "string";
91
+ }
92
+ function isLxmfEvent(value) {
93
+ if (typeof value !== "object" || value === null)
94
+ return false;
95
+ const v = value;
96
+ return (v.type === "message" &&
97
+ typeof v.from === "string" &&
98
+ typeof v.display_name === "string" &&
99
+ typeof v.content === "string" &&
100
+ typeof v.title === "string" &&
101
+ typeof v.timestamp === "number");
102
+ }
103
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,223 @@
1
+ export interface LxmfEvent {
2
+ type: "message";
3
+ from: string;
4
+ display_name: string;
5
+ content: string;
6
+ title: string;
7
+ timestamp: number;
8
+ }
9
+ export interface SendCommand {
10
+ cmd: "send";
11
+ id: string;
12
+ to: string;
13
+ content: string;
14
+ title: string;
15
+ }
16
+ export interface GatewayReply {
17
+ status: "queued" | "error";
18
+ id: string;
19
+ reason?: string;
20
+ }
21
+ /** Full internal config passed to GatewayClient — all fields required. */
22
+ export interface GatewayConfig {
23
+ events_socket: string;
24
+ command_socket: string;
25
+ allowed_senders: string[];
26
+ max_message_length: number;
27
+ send_timeout_ms: number;
28
+ heartbeat_interval_ms: number;
29
+ }
30
+ export interface PluginConfig {
31
+ events_socket?: string;
32
+ command_socket?: string;
33
+ allowed_senders?: string[];
34
+ max_message_length?: number;
35
+ send_timeout_ms?: number;
36
+ heartbeat_interval_ms?: number;
37
+ dm_policy?: "open" | "pairing" | "allowlist" | "disabled";
38
+ }
39
+ export declare function toGatewayConfig(raw: PluginConfig): GatewayConfig;
40
+ export interface OpenClawConfig extends Record<string, unknown> {
41
+ channels?: {
42
+ reticulum?: PluginConfig;
43
+ } & Record<string, unknown>;
44
+ }
45
+ export interface ChannelMeta {
46
+ id: string;
47
+ label: string;
48
+ selectionLabel: string;
49
+ docsPath: string;
50
+ blurb: string;
51
+ aliases?: string[];
52
+ }
53
+ export interface ChannelCapabilities {
54
+ chatTypes: string[];
55
+ blockStreaming?: boolean;
56
+ media?: boolean;
57
+ }
58
+ export interface ChannelConfigAdapter<T> {
59
+ listAccountIds: (cfg: OpenClawConfig) => string[];
60
+ resolveAccount: (cfg: OpenClawConfig, accountId?: string | null) => T;
61
+ isConfigured?: (account: T, cfg: OpenClawConfig) => boolean | Promise<boolean>;
62
+ }
63
+ /** Subset of MsgContext used to describe an inbound LXMF message. */
64
+ export interface MsgContext {
65
+ Body?: string;
66
+ BodyForAgent?: string;
67
+ From?: string;
68
+ To?: string;
69
+ AccountId?: string;
70
+ SessionKey?: string;
71
+ ChatType?: string;
72
+ SenderName?: string;
73
+ SenderId?: string;
74
+ Provider?: string;
75
+ Surface?: string;
76
+ MessageSid?: string;
77
+ Timestamp?: number;
78
+ ConversationLabel?: string;
79
+ OriginatingChannel?: string;
80
+ OriginatingTo?: string;
81
+ }
82
+ /** AI-generated reply payload passed to the deliver callback. */
83
+ export interface ReplyPayload {
84
+ text?: string;
85
+ isReasoning?: boolean;
86
+ }
87
+ export interface AgentRoute {
88
+ agentId: string;
89
+ sessionKey: string;
90
+ mainSessionKey: string;
91
+ accountId: string;
92
+ }
93
+ export interface ChannelRuntime {
94
+ routing: {
95
+ resolveAgentRoute: (params: {
96
+ cfg: OpenClawConfig;
97
+ channel: string;
98
+ accountId?: string | null;
99
+ peer?: {
100
+ kind: string;
101
+ id: string;
102
+ } | null;
103
+ }) => AgentRoute;
104
+ };
105
+ pairing?: {
106
+ /** channel and accountId are required on the real PluginRuntime["channel"].pairing API. */
107
+ readAllowFromStore: (params: {
108
+ channel: string;
109
+ accountId: string;
110
+ }) => Promise<string[]>;
111
+ upsertPairingRequest: (input: {
112
+ channel: string;
113
+ id: string;
114
+ accountId: string;
115
+ meta?: Record<string, string | undefined>;
116
+ }) => Promise<{
117
+ code: string;
118
+ created: boolean;
119
+ }>;
120
+ buildPairingReply: (params: {
121
+ channel: string;
122
+ idLine: string;
123
+ code: string;
124
+ }) => string;
125
+ };
126
+ session: {
127
+ resolveStorePath: (store: string | undefined, opts: {
128
+ agentId: string;
129
+ }) => string;
130
+ recordInboundSession: (params: {
131
+ storePath: string;
132
+ sessionKey: string;
133
+ ctx: MsgContext;
134
+ createIfMissing?: boolean;
135
+ updateLastRoute?: {
136
+ sessionKey: string;
137
+ channel: string;
138
+ to: string;
139
+ accountId?: string | null;
140
+ };
141
+ onRecordError: (err: unknown) => void;
142
+ }) => Promise<void>;
143
+ };
144
+ reply: {
145
+ dispatchReplyWithBufferedBlockDispatcher: (params: {
146
+ ctx: MsgContext;
147
+ cfg: OpenClawConfig;
148
+ dispatcherOptions: {
149
+ deliver: (payload: ReplyPayload, info: {
150
+ kind: string;
151
+ }) => Promise<void>;
152
+ };
153
+ }) => Promise<unknown>;
154
+ };
155
+ }
156
+ export interface ChannelGatewayContext<TAccount = unknown> {
157
+ cfg: OpenClawConfig;
158
+ accountId: string;
159
+ account: TAccount;
160
+ abortSignal: AbortSignal;
161
+ log?: {
162
+ info: (msg: string) => void;
163
+ warn?: (msg: string) => void;
164
+ error?: (msg: string) => void;
165
+ };
166
+ channelRuntime?: ChannelRuntime;
167
+ getStatus: () => ChannelAccountSnapshot;
168
+ setStatus: (next: ChannelAccountSnapshot) => void;
169
+ }
170
+ export interface ChannelOutboundContext {
171
+ cfg: OpenClawConfig;
172
+ to: string;
173
+ text: string;
174
+ accountId?: string | null;
175
+ }
176
+ export interface ChannelStatusAdapter<TAccount> {
177
+ buildAccountSnapshot?: (params: {
178
+ account: TAccount;
179
+ cfg: OpenClawConfig;
180
+ runtime?: ChannelAccountSnapshot;
181
+ }) => ChannelAccountSnapshot | Promise<ChannelAccountSnapshot>;
182
+ }
183
+ export interface ChannelAccountSnapshot {
184
+ accountId: string;
185
+ name?: string;
186
+ enabled?: boolean;
187
+ configured?: boolean;
188
+ running?: boolean;
189
+ connected?: boolean;
190
+ lastInboundAt?: number | null;
191
+ lastError?: string | null;
192
+ address?: string | null;
193
+ }
194
+ export interface ChannelPairingAdapter {
195
+ /** Label shown to the user for the sender identifier (e.g. "LXMF Address"). */
196
+ idLabel: string;
197
+ normalizeAllowEntry?: (entry: string) => string;
198
+ }
199
+ export interface ChannelPlugin<TAccount = GatewayConfig> {
200
+ id: string;
201
+ meta: ChannelMeta;
202
+ capabilities: ChannelCapabilities;
203
+ config: ChannelConfigAdapter<TAccount>;
204
+ pairing?: ChannelPairingAdapter;
205
+ status?: ChannelStatusAdapter<TAccount>;
206
+ gateway?: {
207
+ startAccount?: (ctx: ChannelGatewayContext<TAccount>) => Promise<unknown>;
208
+ stopAccount?: (ctx: ChannelGatewayContext<TAccount>) => Promise<void>;
209
+ };
210
+ outbound?: {
211
+ deliveryMode: "direct" | "gateway" | "hybrid";
212
+ sendText?: (ctx: ChannelOutboundContext) => Promise<{
213
+ ok: boolean;
214
+ }>;
215
+ };
216
+ }
217
+ export interface OpenClawPluginApi {
218
+ runtime: unknown;
219
+ registerChannel: (registration: {
220
+ plugin: ChannelPlugin;
221
+ }) => void;
222
+ }
223
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,14 @@
1
+ // ---------------------------------------------------------------------------
2
+ // ZMQ wire types (gateway ↔ plugin IPC)
3
+ // ---------------------------------------------------------------------------
4
+ export function toGatewayConfig(raw) {
5
+ return {
6
+ events_socket: raw.events_socket ?? "tcp://localhost:2600",
7
+ command_socket: raw.command_socket ?? "tcp://localhost:2601",
8
+ allowed_senders: raw.allowed_senders ?? [],
9
+ max_message_length: raw.max_message_length ?? 4096,
10
+ send_timeout_ms: raw.send_timeout_ms ?? 5000,
11
+ heartbeat_interval_ms: raw.heartbeat_interval_ms ?? 30_000,
12
+ };
13
+ }
14
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,wCAAwC;AACxC,8EAA8E;AAiD9E,MAAM,UAAU,eAAe,CAAC,GAAiB;IAC/C,OAAO;QACL,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,sBAAsB;QAC1D,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,sBAAsB;QAC5D,eAAe,EAAE,GAAG,CAAC,eAAe,IAAI,EAAE;QAC1C,kBAAkB,EAAE,GAAG,CAAC,kBAAkB,IAAI,IAAI;QAClD,eAAe,EAAE,GAAG,CAAC,eAAe,IAAI,IAAI;QAC5C,qBAAqB,EAAE,GAAG,CAAC,qBAAqB,IAAI,MAAM;KAC3D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ {
2
+ "id": "reticulum",
3
+ "name": "Reticulum / LXMF",
4
+ "description": "Connect to Reticulum mesh networks via LXMF messaging (MeshChat, Sideband, NomadNet compatible)",
5
+ "version": "0.1.0",
6
+ "channels": ["reticulum"],
7
+ "configSchema": {
8
+ "type": "object",
9
+ "additionalProperties": false,
10
+ "properties": {}
11
+ }
12
+ }
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "reticulum-openclaw",
3
+ "version": "0.1.0",
4
+ "description": "OpenClaw channel plugin for Reticulum / LXMF mesh networking",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "files": ["dist", "openclaw.plugin.json"],
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "test": "vitest run",
11
+ "test:coverage": "vitest run --coverage",
12
+ "test:watch": "vitest",
13
+ "typecheck": "tsc --noEmit",
14
+ "lint": "eslint src",
15
+ "lint:fix": "eslint src --fix",
16
+ "format": "prettier --write src",
17
+ "format:check": "prettier --check src"
18
+ },
19
+ "openclaw": {
20
+ "extensions": ["./dist/index.js"]
21
+ },
22
+ "peerDependencies": {
23
+ "openclaw": "*"
24
+ },
25
+ "dependencies": {
26
+ "zeromq": "6.5.0"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "25.3.3",
30
+ "@typescript-eslint/eslint-plugin": "8.56.1",
31
+ "@typescript-eslint/parser": "8.56.1",
32
+ "eslint": "10.0.2",
33
+ "prettier": "3.8.1",
34
+ "typescript": "5.9.3",
35
+ "@vitest/coverage-v8": "4.0.18",
36
+ "vitest": "4.0.18"
37
+ }
38
+ }