olvid-channel 0.0.0-a0
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/SKILL.md +4 -0
- package/index.ts +177 -0
- package/openclaw.plugin.json +29 -0
- package/package.json +36 -0
- package/pub/SKILL.md +4 -0
- package/pub/index.ts +177 -0
- package/pub/openclaw.plugin.json +29 -0
- package/pub/package.json +36 -0
- package/pub/src/accounts.ts +111 -0
- package/pub/src/config-schema.ts +14 -0
- package/pub/src/monitor.ts +196 -0
- package/pub/src/normalize.ts +44 -0
- package/pub/src/onboarding.ts +181 -0
- package/pub/src/runtime.ts +14 -0
- package/pub/src/send.ts +54 -0
- package/pub/src/tools.ts +22 -0
- package/pub/src/types.ts +54 -0
- package/src/accounts.ts +111 -0
- package/src/config-schema.ts +14 -0
- package/src/monitor.ts +196 -0
- package/src/normalize.ts +44 -0
- package/src/onboarding.ts +181 -0
- package/src/runtime.ts +14 -0
- package/src/send.ts +54 -0
- package/src/tools.ts +22 -0
- package/src/types.ts +54 -0
- package/tsconfig.json +20 -0
package/SKILL.md
ADDED
package/index.ts
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type OpenClawPluginApi,
|
|
3
|
+
buildChannelConfigSchema,
|
|
4
|
+
type ChannelPlugin,
|
|
5
|
+
setAccountEnabledInConfigSection, deleteAccountFromConfigSection, DEFAULT_ACCOUNT_ID, ChannelAccountSnapshot,
|
|
6
|
+
emptyPluginConfigSchema
|
|
7
|
+
} from "openclaw/plugin-sdk";
|
|
8
|
+
import {
|
|
9
|
+
listOlvidAccountIds,
|
|
10
|
+
resolveDefaultOlvidAccountId,
|
|
11
|
+
ResolvedOlvidAccount,
|
|
12
|
+
resolveOlvidAccount
|
|
13
|
+
} from "./src/accounts";
|
|
14
|
+
import {OlvidConfigSchema} from "./src/config-schema";
|
|
15
|
+
import {CoreConfig} from "./src/types";
|
|
16
|
+
import {getOlvidRuntime, setOlvidRuntime} from "./src/runtime";
|
|
17
|
+
import {sendMessageOlvid} from "./src/send";
|
|
18
|
+
import {monitorOlvidProvider} from "./src/monitor";
|
|
19
|
+
import {olvidOnboardingAdapter} from "./src/onboarding";
|
|
20
|
+
|
|
21
|
+
let olvidPlugin: ChannelPlugin<ResolvedOlvidAccount> = {
|
|
22
|
+
id: "olvid",
|
|
23
|
+
meta: {
|
|
24
|
+
id: "olvid",
|
|
25
|
+
label: "Olvid",
|
|
26
|
+
selectionLabel: "Olvid (Daemon)",
|
|
27
|
+
docsPath: "/channels/olvid",
|
|
28
|
+
docsLabel: "olvid",
|
|
29
|
+
blurb: "Securely exchange with your bot with authenticated e2e encryption",
|
|
30
|
+
order: 65,
|
|
31
|
+
quickstartAllowFrom: true,
|
|
32
|
+
},
|
|
33
|
+
capabilities: {
|
|
34
|
+
chatTypes: ["direct", "group"],
|
|
35
|
+
media: true,
|
|
36
|
+
reactions: true,
|
|
37
|
+
threads: false,
|
|
38
|
+
reply: true,
|
|
39
|
+
nativeCommands: false,
|
|
40
|
+
blockStreaming: true
|
|
41
|
+
},
|
|
42
|
+
reload: { configPrefixes: ["channels.olvid"] },
|
|
43
|
+
configSchema: buildChannelConfigSchema(OlvidConfigSchema),
|
|
44
|
+
onboarding: olvidOnboardingAdapter,
|
|
45
|
+
config: {
|
|
46
|
+
listAccountIds: (cfg) => listOlvidAccountIds(cfg as CoreConfig),
|
|
47
|
+
resolveAccount: (cfg, accountId) => resolveOlvidAccount({ cfg: cfg as CoreConfig, accountId }),
|
|
48
|
+
defaultAccountId: (cfg) => resolveDefaultOlvidAccountId(cfg as CoreConfig),
|
|
49
|
+
setAccountEnabled: ({ cfg, accountId, enabled }) =>
|
|
50
|
+
setAccountEnabledInConfigSection({
|
|
51
|
+
cfg,
|
|
52
|
+
sectionKey: "olvid",
|
|
53
|
+
accountId,
|
|
54
|
+
enabled,
|
|
55
|
+
allowTopLevel: true,
|
|
56
|
+
}),
|
|
57
|
+
deleteAccount: ({ cfg, accountId }) =>
|
|
58
|
+
deleteAccountFromConfigSection({
|
|
59
|
+
cfg,
|
|
60
|
+
sectionKey: "olvid",
|
|
61
|
+
accountId,
|
|
62
|
+
clearBaseFields: ["clientKey", "daemonUrl", "name"],
|
|
63
|
+
}),
|
|
64
|
+
isConfigured: (account) => Boolean(account.clientKey && account.daemonUrl),
|
|
65
|
+
describeAccount: (account) => ({
|
|
66
|
+
accountId: account.accountId,
|
|
67
|
+
name: account.name,
|
|
68
|
+
enabled: account.enabled,
|
|
69
|
+
configured: Boolean(account.clientKey && account.daemonUrl),
|
|
70
|
+
clientKeySource: account.clientKeySource,
|
|
71
|
+
daemonUrl: account.daemonUrl,
|
|
72
|
+
}),
|
|
73
|
+
},
|
|
74
|
+
outbound: {
|
|
75
|
+
deliveryMode: "direct",
|
|
76
|
+
chunker: (text: string, limit: number): string[] => {
|
|
77
|
+
return getOlvidRuntime().channel.text.chunkMarkdownText(text, limit);
|
|
78
|
+
},
|
|
79
|
+
chunkerMode: "markdown",
|
|
80
|
+
textChunkLimit: 4000,
|
|
81
|
+
sendText: async ({ to, text, accountId, replyToId }) => {
|
|
82
|
+
const result = await sendMessageOlvid(to, text, {
|
|
83
|
+
accountId: accountId ?? undefined,
|
|
84
|
+
replyTo: replyToId ?? undefined,
|
|
85
|
+
});
|
|
86
|
+
return { channel: "olvid", ...result };
|
|
87
|
+
},
|
|
88
|
+
sendMedia: async ({ to, text, mediaUrl, accountId, replyToId }) => {
|
|
89
|
+
const result = await sendMessageOlvid(to, text, {
|
|
90
|
+
accountId: accountId ?? undefined,
|
|
91
|
+
replyTo: replyToId ?? undefined,
|
|
92
|
+
mediaUrls: mediaUrl ? [mediaUrl] : undefined,
|
|
93
|
+
});
|
|
94
|
+
return { channel: "olvid", ...result };
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
status: {
|
|
98
|
+
defaultRuntime: {
|
|
99
|
+
accountId: DEFAULT_ACCOUNT_ID,
|
|
100
|
+
running: false,
|
|
101
|
+
connected: false,
|
|
102
|
+
lastConnectedAt: null,
|
|
103
|
+
lastDisconnect: null,
|
|
104
|
+
lastStartAt: null,
|
|
105
|
+
lastStopAt: null,
|
|
106
|
+
lastError: null,
|
|
107
|
+
},
|
|
108
|
+
buildChannelSummary: ({ snapshot }) => ({
|
|
109
|
+
configured: snapshot.configured ?? false,
|
|
110
|
+
running: snapshot.running ?? false,
|
|
111
|
+
connected: snapshot.connected ?? false,
|
|
112
|
+
lastStartAt: snapshot.lastStartAt ?? null,
|
|
113
|
+
lastStopAt: snapshot.lastStopAt ?? null,
|
|
114
|
+
lastError: snapshot.lastError ?? null,
|
|
115
|
+
baseUrl: snapshot.baseUrl ?? null,
|
|
116
|
+
probe: snapshot.probe,
|
|
117
|
+
lastProbeAt: snapshot.lastProbeAt ?? null,
|
|
118
|
+
}),
|
|
119
|
+
buildAccountSnapshot: ({ account, runtime }) => {
|
|
120
|
+
return {
|
|
121
|
+
accountId: account.accountId,
|
|
122
|
+
name: account.name,
|
|
123
|
+
enabled: account.enabled,
|
|
124
|
+
configured: Boolean(account.clientKey && account.daemonUrl),
|
|
125
|
+
clientKeySource: account.clientKeySource,
|
|
126
|
+
baseUrl: account.daemonUrl,
|
|
127
|
+
connected: runtime?.connected ?? false,
|
|
128
|
+
lastConnectedAt: runtime?.lastConnectedAt ?? null,
|
|
129
|
+
lastDisconnect: runtime?.lastDisconnect ?? null,
|
|
130
|
+
lastStartAt: runtime?.lastStartAt ?? null,
|
|
131
|
+
lastStopAt: runtime?.lastStopAt ?? null,
|
|
132
|
+
lastError: runtime?.lastError ?? null,
|
|
133
|
+
lastInboundAt: runtime?.lastInboundAt ?? null,
|
|
134
|
+
lastOutboundAt: runtime?.lastOutboundAt ?? null,
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
gateway: {
|
|
139
|
+
startAccount: async (ctx) => {
|
|
140
|
+
const account = ctx.account;
|
|
141
|
+
if (!account.daemonUrl || !account.clientKey) {
|
|
142
|
+
throw new Error(`Olvid not configuration is invalid`);
|
|
143
|
+
}
|
|
144
|
+
ctx.setStatus({
|
|
145
|
+
accountId: account.accountId,
|
|
146
|
+
baseUrl: account.daemonUrl,
|
|
147
|
+
botTokenSource: account.clientKeySource,
|
|
148
|
+
lastStartAt: Date.now(),
|
|
149
|
+
});
|
|
150
|
+
ctx.log?.info(`[${account.accountId}] starting channel`);
|
|
151
|
+
return monitorOlvidProvider({
|
|
152
|
+
accountId: account.accountId,
|
|
153
|
+
config: ctx.cfg as CoreConfig,
|
|
154
|
+
runtime: ctx.runtime,
|
|
155
|
+
abortSignal: ctx.abortSignal,
|
|
156
|
+
statusSink: (patch: Partial<ChannelAccountSnapshot>) =>
|
|
157
|
+
ctx.setStatus({ accountId: ctx.accountId, ...patch }),
|
|
158
|
+
});
|
|
159
|
+
},
|
|
160
|
+
stopAccount: async (ctx) => {
|
|
161
|
+
ctx.setStatus({ accountId: ctx.accountId, lastStopAt: Date.now() });
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const plugin: {id: string, name: string, description: string, configSchema: unknown, register: (api: OpenClawPluginApi) => void} = {
|
|
167
|
+
id: "olvid",
|
|
168
|
+
name: "Olvid",
|
|
169
|
+
description: "Olvid channel plugin",
|
|
170
|
+
configSchema: emptyPluginConfigSchema(),
|
|
171
|
+
register(api: OpenClawPluginApi) {
|
|
172
|
+
setOlvidRuntime(api.runtime);
|
|
173
|
+
api.registerChannel(olvidPlugin);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export default plugin;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "olvid-channel",
|
|
3
|
+
"channels": ["olvid"],
|
|
4
|
+
"name": "Olvid Channel",
|
|
5
|
+
"openclaw": {
|
|
6
|
+
"extensions": ["./index.ts"],
|
|
7
|
+
"channel": {
|
|
8
|
+
"id": "olvid",
|
|
9
|
+
"label": "olvid",
|
|
10
|
+
"selectionLabel": "Olvid (Daemon)",
|
|
11
|
+
"docsPath": "/channels/olvid",
|
|
12
|
+
"docsLabel": "olvid",
|
|
13
|
+
"blurb": "Trust your agent with authenticated e2e encryption.",
|
|
14
|
+
"order": 35
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"configSchema": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"additionalProperties": false,
|
|
20
|
+
"properties": {
|
|
21
|
+
"daemonUrl": { "type": "string", "default": "http://localhost:50051" },
|
|
22
|
+
"clientKey": { "type": "string" }
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"uiHints": {
|
|
26
|
+
"daemonUrl": { "label": "Daemon Url", "placeholder": "http://localhost:50051" },
|
|
27
|
+
"clientKey": { "label": "Client Key", "sensitive": true }
|
|
28
|
+
}
|
|
29
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "olvid-channel",
|
|
3
|
+
"version": "0.0.0a0",
|
|
4
|
+
"description": "Olvid native channel for OpenClaw.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@olvid/bot-node": "^1.5.0",
|
|
8
|
+
"zod": "^4.3.6"
|
|
9
|
+
},
|
|
10
|
+
"peerDependencies": {
|
|
11
|
+
"openclaw": "^2026.2.1"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"openclaw",
|
|
15
|
+
"channel",
|
|
16
|
+
"olvid"
|
|
17
|
+
],
|
|
18
|
+
"author": "bot@olvid.io",
|
|
19
|
+
"openclaw": {
|
|
20
|
+
"extensions": ["./index.ts"],
|
|
21
|
+
"channel": {
|
|
22
|
+
"id": "olvid",
|
|
23
|
+
"label": "olvid",
|
|
24
|
+
"selectionLabel": "Olvid (Daemon)",
|
|
25
|
+
"docsPath": "/channels/olvid",
|
|
26
|
+
"docsLabel": "olvid",
|
|
27
|
+
"blurb": "Trust your agent with authenticated e2e encryption.",
|
|
28
|
+
"order": 35
|
|
29
|
+
},
|
|
30
|
+
"install": {
|
|
31
|
+
"npmSpec": "olvid-channel",
|
|
32
|
+
"localPath": "extensions/olvid",
|
|
33
|
+
"defaultChoice": "npm"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
package/pub/SKILL.md
ADDED
package/pub/index.ts
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type OpenClawPluginApi,
|
|
3
|
+
buildChannelConfigSchema,
|
|
4
|
+
type ChannelPlugin,
|
|
5
|
+
setAccountEnabledInConfigSection, deleteAccountFromConfigSection, DEFAULT_ACCOUNT_ID, ChannelAccountSnapshot,
|
|
6
|
+
emptyPluginConfigSchema
|
|
7
|
+
} from "openclaw/plugin-sdk";
|
|
8
|
+
import {
|
|
9
|
+
listOlvidAccountIds,
|
|
10
|
+
resolveDefaultOlvidAccountId,
|
|
11
|
+
ResolvedOlvidAccount,
|
|
12
|
+
resolveOlvidAccount
|
|
13
|
+
} from "./src/accounts";
|
|
14
|
+
import {OlvidConfigSchema} from "./src/config-schema";
|
|
15
|
+
import {CoreConfig} from "./src/types";
|
|
16
|
+
import {getOlvidRuntime, setOlvidRuntime} from "./src/runtime";
|
|
17
|
+
import {sendMessageOlvid} from "./src/send";
|
|
18
|
+
import {monitorOlvidProvider} from "./src/monitor";
|
|
19
|
+
import {olvidOnboardingAdapter} from "./src/onboarding";
|
|
20
|
+
|
|
21
|
+
let olvidPlugin: ChannelPlugin<ResolvedOlvidAccount> = {
|
|
22
|
+
id: "olvid",
|
|
23
|
+
meta: {
|
|
24
|
+
id: "olvid",
|
|
25
|
+
label: "Olvid",
|
|
26
|
+
selectionLabel: "Olvid (Daemon)",
|
|
27
|
+
docsPath: "/channels/olvid",
|
|
28
|
+
docsLabel: "olvid",
|
|
29
|
+
blurb: "Securely exchange with your bot with authenticated e2e encryption",
|
|
30
|
+
order: 65,
|
|
31
|
+
quickstartAllowFrom: true,
|
|
32
|
+
},
|
|
33
|
+
capabilities: {
|
|
34
|
+
chatTypes: ["direct", "group"],
|
|
35
|
+
media: true,
|
|
36
|
+
reactions: true,
|
|
37
|
+
threads: false,
|
|
38
|
+
reply: true,
|
|
39
|
+
nativeCommands: false,
|
|
40
|
+
blockStreaming: true
|
|
41
|
+
},
|
|
42
|
+
reload: { configPrefixes: ["channels.olvid"] },
|
|
43
|
+
configSchema: buildChannelConfigSchema(OlvidConfigSchema),
|
|
44
|
+
onboarding: olvidOnboardingAdapter,
|
|
45
|
+
config: {
|
|
46
|
+
listAccountIds: (cfg) => listOlvidAccountIds(cfg as CoreConfig),
|
|
47
|
+
resolveAccount: (cfg, accountId) => resolveOlvidAccount({ cfg: cfg as CoreConfig, accountId }),
|
|
48
|
+
defaultAccountId: (cfg) => resolveDefaultOlvidAccountId(cfg as CoreConfig),
|
|
49
|
+
setAccountEnabled: ({ cfg, accountId, enabled }) =>
|
|
50
|
+
setAccountEnabledInConfigSection({
|
|
51
|
+
cfg,
|
|
52
|
+
sectionKey: "olvid",
|
|
53
|
+
accountId,
|
|
54
|
+
enabled,
|
|
55
|
+
allowTopLevel: true,
|
|
56
|
+
}),
|
|
57
|
+
deleteAccount: ({ cfg, accountId }) =>
|
|
58
|
+
deleteAccountFromConfigSection({
|
|
59
|
+
cfg,
|
|
60
|
+
sectionKey: "olvid",
|
|
61
|
+
accountId,
|
|
62
|
+
clearBaseFields: ["clientKey", "daemonUrl", "name"],
|
|
63
|
+
}),
|
|
64
|
+
isConfigured: (account) => Boolean(account.clientKey && account.daemonUrl),
|
|
65
|
+
describeAccount: (account) => ({
|
|
66
|
+
accountId: account.accountId,
|
|
67
|
+
name: account.name,
|
|
68
|
+
enabled: account.enabled,
|
|
69
|
+
configured: Boolean(account.clientKey && account.daemonUrl),
|
|
70
|
+
clientKeySource: account.clientKeySource,
|
|
71
|
+
daemonUrl: account.daemonUrl,
|
|
72
|
+
}),
|
|
73
|
+
},
|
|
74
|
+
outbound: {
|
|
75
|
+
deliveryMode: "direct",
|
|
76
|
+
chunker: (text: string, limit: number): string[] => {
|
|
77
|
+
return getOlvidRuntime().channel.text.chunkMarkdownText(text, limit);
|
|
78
|
+
},
|
|
79
|
+
chunkerMode: "markdown",
|
|
80
|
+
textChunkLimit: 4000,
|
|
81
|
+
sendText: async ({ to, text, accountId, replyToId }) => {
|
|
82
|
+
const result = await sendMessageOlvid(to, text, {
|
|
83
|
+
accountId: accountId ?? undefined,
|
|
84
|
+
replyTo: replyToId ?? undefined,
|
|
85
|
+
});
|
|
86
|
+
return { channel: "olvid", ...result };
|
|
87
|
+
},
|
|
88
|
+
sendMedia: async ({ to, text, mediaUrl, accountId, replyToId }) => {
|
|
89
|
+
const result = await sendMessageOlvid(to, text, {
|
|
90
|
+
accountId: accountId ?? undefined,
|
|
91
|
+
replyTo: replyToId ?? undefined,
|
|
92
|
+
mediaUrls: mediaUrl ? [mediaUrl] : undefined,
|
|
93
|
+
});
|
|
94
|
+
return { channel: "olvid", ...result };
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
status: {
|
|
98
|
+
defaultRuntime: {
|
|
99
|
+
accountId: DEFAULT_ACCOUNT_ID,
|
|
100
|
+
running: false,
|
|
101
|
+
connected: false,
|
|
102
|
+
lastConnectedAt: null,
|
|
103
|
+
lastDisconnect: null,
|
|
104
|
+
lastStartAt: null,
|
|
105
|
+
lastStopAt: null,
|
|
106
|
+
lastError: null,
|
|
107
|
+
},
|
|
108
|
+
buildChannelSummary: ({ snapshot }) => ({
|
|
109
|
+
configured: snapshot.configured ?? false,
|
|
110
|
+
running: snapshot.running ?? false,
|
|
111
|
+
connected: snapshot.connected ?? false,
|
|
112
|
+
lastStartAt: snapshot.lastStartAt ?? null,
|
|
113
|
+
lastStopAt: snapshot.lastStopAt ?? null,
|
|
114
|
+
lastError: snapshot.lastError ?? null,
|
|
115
|
+
baseUrl: snapshot.baseUrl ?? null,
|
|
116
|
+
probe: snapshot.probe,
|
|
117
|
+
lastProbeAt: snapshot.lastProbeAt ?? null,
|
|
118
|
+
}),
|
|
119
|
+
buildAccountSnapshot: ({ account, runtime }) => {
|
|
120
|
+
return {
|
|
121
|
+
accountId: account.accountId,
|
|
122
|
+
name: account.name,
|
|
123
|
+
enabled: account.enabled,
|
|
124
|
+
configured: Boolean(account.clientKey && account.daemonUrl),
|
|
125
|
+
clientKeySource: account.clientKeySource,
|
|
126
|
+
baseUrl: account.daemonUrl,
|
|
127
|
+
connected: runtime?.connected ?? false,
|
|
128
|
+
lastConnectedAt: runtime?.lastConnectedAt ?? null,
|
|
129
|
+
lastDisconnect: runtime?.lastDisconnect ?? null,
|
|
130
|
+
lastStartAt: runtime?.lastStartAt ?? null,
|
|
131
|
+
lastStopAt: runtime?.lastStopAt ?? null,
|
|
132
|
+
lastError: runtime?.lastError ?? null,
|
|
133
|
+
lastInboundAt: runtime?.lastInboundAt ?? null,
|
|
134
|
+
lastOutboundAt: runtime?.lastOutboundAt ?? null,
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
gateway: {
|
|
139
|
+
startAccount: async (ctx) => {
|
|
140
|
+
const account = ctx.account;
|
|
141
|
+
if (!account.daemonUrl || !account.clientKey) {
|
|
142
|
+
throw new Error(`Olvid not configuration is invalid`);
|
|
143
|
+
}
|
|
144
|
+
ctx.setStatus({
|
|
145
|
+
accountId: account.accountId,
|
|
146
|
+
baseUrl: account.daemonUrl,
|
|
147
|
+
botTokenSource: account.clientKeySource,
|
|
148
|
+
lastStartAt: Date.now(),
|
|
149
|
+
});
|
|
150
|
+
ctx.log?.info(`[${account.accountId}] starting channel`);
|
|
151
|
+
return monitorOlvidProvider({
|
|
152
|
+
accountId: account.accountId,
|
|
153
|
+
config: ctx.cfg as CoreConfig,
|
|
154
|
+
runtime: ctx.runtime,
|
|
155
|
+
abortSignal: ctx.abortSignal,
|
|
156
|
+
statusSink: (patch: Partial<ChannelAccountSnapshot>) =>
|
|
157
|
+
ctx.setStatus({ accountId: ctx.accountId, ...patch }),
|
|
158
|
+
});
|
|
159
|
+
},
|
|
160
|
+
stopAccount: async (ctx) => {
|
|
161
|
+
ctx.setStatus({ accountId: ctx.accountId, lastStopAt: Date.now() });
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const plugin: {id: string, name: string, description: string, configSchema: unknown, register: (api: OpenClawPluginApi) => void} = {
|
|
167
|
+
id: "olvid",
|
|
168
|
+
name: "Olvid",
|
|
169
|
+
description: "Olvid channel plugin",
|
|
170
|
+
configSchema: emptyPluginConfigSchema(),
|
|
171
|
+
register(api: OpenClawPluginApi) {
|
|
172
|
+
setOlvidRuntime(api.runtime);
|
|
173
|
+
api.registerChannel(olvidPlugin);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export default plugin;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "olvid",
|
|
3
|
+
"channels": ["olvid"],
|
|
4
|
+
"name": "Olvid Channel",
|
|
5
|
+
"openclaw": {
|
|
6
|
+
"extensions": ["./index.ts"],
|
|
7
|
+
"channel": {
|
|
8
|
+
"id": "olvid",
|
|
9
|
+
"label": "olvid",
|
|
10
|
+
"selectionLabel": "Olvid (Daemon)",
|
|
11
|
+
"docsPath": "/channels/olvid",
|
|
12
|
+
"docsLabel": "olvid",
|
|
13
|
+
"blurb": "Trust your agent with authenticated e2e encryption.",
|
|
14
|
+
"order": 35
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"configSchema": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"additionalProperties": false,
|
|
20
|
+
"properties": {
|
|
21
|
+
"daemonUrl": { "type": "string", "default": "http://localhost:50051" },
|
|
22
|
+
"clientKey": { "type": "string" }
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"uiHints": {
|
|
26
|
+
"daemonUrl": { "label": "Daemon Url", "placeholder": "http://localhost:50051" },
|
|
27
|
+
"clientKey": { "label": "Client Key", "sensitive": true }
|
|
28
|
+
}
|
|
29
|
+
}
|
package/pub/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "openclaw-channel-olvid",
|
|
3
|
+
"version": "0.0.6",
|
|
4
|
+
"description": "Olvid native channel for OpenClaw.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@olvid/bot-node": "^1.5.0",
|
|
8
|
+
"zod": "^4.3.6"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"openclaw": "==2026.2.1"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"openclaw",
|
|
15
|
+
"channel",
|
|
16
|
+
"olvid"
|
|
17
|
+
],
|
|
18
|
+
"author": "bot@olvid.io",
|
|
19
|
+
"openclaw": {
|
|
20
|
+
"extensions": ["./index.ts"],
|
|
21
|
+
"channel": {
|
|
22
|
+
"id": "olvid",
|
|
23
|
+
"label": "olvid",
|
|
24
|
+
"selectionLabel": "Olvid (Daemon)",
|
|
25
|
+
"docsPath": "/channels/olvid",
|
|
26
|
+
"docsLabel": "olvid",
|
|
27
|
+
"blurb": "Trust your agent with authenticated e2e encryption.",
|
|
28
|
+
"order": 35
|
|
29
|
+
},
|
|
30
|
+
"install": {
|
|
31
|
+
"npmSpec": "openclaw-channel-olvid",
|
|
32
|
+
"localPath": "extensions/olvid",
|
|
33
|
+
"defaultChoice": "npm"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk";
|
|
2
|
+
import type { CoreConfig, OlvidAccountConfig } from "./types.js";
|
|
3
|
+
|
|
4
|
+
export type OlvidClientKeySource = "env" | "config" | "none";
|
|
5
|
+
export type OlvidDaemonUrlSource = "env" | "config" | "none";
|
|
6
|
+
|
|
7
|
+
export type ResolvedOlvidAccount = {
|
|
8
|
+
accountId: string;
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
name?: string;
|
|
11
|
+
clientKey?: string;
|
|
12
|
+
daemonUrl?: string;
|
|
13
|
+
clientKeySource: OlvidClientKeySource;
|
|
14
|
+
daemonUrlSource: OlvidDaemonUrlSource;
|
|
15
|
+
config: OlvidAccountConfig;
|
|
16
|
+
oncharPrefixes?: string[];
|
|
17
|
+
requireMention?: boolean;
|
|
18
|
+
textChunkLimit?: number;
|
|
19
|
+
blockStreaming?: boolean;
|
|
20
|
+
blockStreamingCoalesce?: OlvidAccountConfig["blockStreamingCoalesce"];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function listConfiguredAccountIds(cfg: CoreConfig): string[] {
|
|
24
|
+
const accounts = cfg.channels?.olvid?.accounts;
|
|
25
|
+
if (!accounts || typeof accounts !== "object") {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
return Object.keys(accounts).filter(Boolean);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function listOlvidAccountIds(cfg: CoreConfig): string[] {
|
|
32
|
+
const ids = listConfiguredAccountIds(cfg);
|
|
33
|
+
if (ids.length === 0) {
|
|
34
|
+
return [DEFAULT_ACCOUNT_ID];
|
|
35
|
+
}
|
|
36
|
+
return ids.sort((a, b) => a.localeCompare(b));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function resolveDefaultOlvidAccountId(cfg: CoreConfig): string {
|
|
40
|
+
const ids = listOlvidAccountIds(cfg);
|
|
41
|
+
if (ids.includes(DEFAULT_ACCOUNT_ID)) {
|
|
42
|
+
return DEFAULT_ACCOUNT_ID;
|
|
43
|
+
}
|
|
44
|
+
return ids[0] ?? DEFAULT_ACCOUNT_ID;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function resolveAccountConfig(cfg: CoreConfig, accountId: string): OlvidAccountConfig | undefined {
|
|
48
|
+
const accounts = cfg.channels?.olvid?.accounts;
|
|
49
|
+
if (!accounts || typeof accounts !== "object") {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
return accounts[accountId] as ResolvedOlvidAccount | undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function mergeOlvidAccountConfig(cfg: CoreConfig, accountId: string): OlvidAccountConfig {
|
|
56
|
+
const { accounts: _ignored, ...base } = (cfg.channels?.olvid ?? {}) as OlvidAccountConfig & {
|
|
57
|
+
accounts?: unknown;
|
|
58
|
+
};
|
|
59
|
+
const account = resolveAccountConfig(cfg, accountId) ?? {};
|
|
60
|
+
return { ...base, ...account };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function resolveOlvidAccount(params: {
|
|
64
|
+
cfg: CoreConfig;
|
|
65
|
+
accountId?: string | null;
|
|
66
|
+
}): ResolvedOlvidAccount {
|
|
67
|
+
const accountId = normalizeAccountId(params.accountId);
|
|
68
|
+
const baseEnabled = params.cfg.channels?.olvid?.enabled !== false;
|
|
69
|
+
const merged = mergeOlvidAccountConfig(params.cfg, accountId);
|
|
70
|
+
const accountEnabled = merged.enabled !== false;
|
|
71
|
+
const enabled = baseEnabled && accountEnabled;
|
|
72
|
+
|
|
73
|
+
const allowEnv = accountId === DEFAULT_ACCOUNT_ID;
|
|
74
|
+
const envClientKey = allowEnv ? process.env.OLVID_CLIENT_KEY?.trim() : undefined;
|
|
75
|
+
const envDaemonUrl = allowEnv ? process.env.OLVID_DAEMON_TARGET?.trim() : undefined;
|
|
76
|
+
const configClientKey = merged.clientKey?.trim();
|
|
77
|
+
const configDaemonUrl = merged.daemonUrl?.trim();
|
|
78
|
+
const clientKey = configClientKey || envClientKey;
|
|
79
|
+
const daemonUrl = configDaemonUrl || envDaemonUrl;
|
|
80
|
+
|
|
81
|
+
const clientKeySource: OlvidClientKeySource = configClientKey
|
|
82
|
+
? "config"
|
|
83
|
+
: envClientKey
|
|
84
|
+
? "env"
|
|
85
|
+
: "none";
|
|
86
|
+
const daemonUrlSource: OlvidDaemonUrlSource = configDaemonUrl
|
|
87
|
+
? "config"
|
|
88
|
+
: envDaemonUrl
|
|
89
|
+
? "env"
|
|
90
|
+
: "none";
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
accountId,
|
|
94
|
+
enabled,
|
|
95
|
+
name: merged.name?.trim() || undefined,
|
|
96
|
+
clientKey,
|
|
97
|
+
daemonUrl,
|
|
98
|
+
clientKeySource: clientKeySource,
|
|
99
|
+
daemonUrlSource: daemonUrlSource,
|
|
100
|
+
config: merged,
|
|
101
|
+
textChunkLimit: merged.textChunkLimit,
|
|
102
|
+
blockStreaming: merged.blockStreaming,
|
|
103
|
+
blockStreamingCoalesce: merged.blockStreamingCoalesce,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function listEnabledOlvidAccounts(cfg: CoreConfig): ResolvedOlvidAccount[] {
|
|
108
|
+
return listOlvidAccountIds(cfg)
|
|
109
|
+
.map((accountId) => resolveOlvidAccount({ cfg, accountId }))
|
|
110
|
+
.filter((account) => account.enabled);
|
|
111
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const OlvidAccountSchema = z
|
|
4
|
+
.object({
|
|
5
|
+
name: z.string().optional(),
|
|
6
|
+
enabled: z.boolean().optional(),
|
|
7
|
+
daemonUrl: z.string().optional(),
|
|
8
|
+
clientKey: z.string().optional(),
|
|
9
|
+
})
|
|
10
|
+
.strict();
|
|
11
|
+
|
|
12
|
+
export const OlvidConfigSchema = OlvidAccountSchema.extend({
|
|
13
|
+
accounts: z.record(z.string(), OlvidAccountSchema.optional()).optional(),
|
|
14
|
+
});
|