@zbruceli/openclaw-dchat 0.3.0 → 0.4.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.
- package/index.ts +2 -2
- package/package.json +1 -1
- package/src/channel.ts +18 -16
- package/src/config-schema.ts +1 -1
- package/src/onboarding.ts +116 -135
- package/src/runtime.ts +1 -1
package/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
|
-
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
1
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
|
2
|
+
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
|
3
3
|
import { dchatPlugin } from "./src/channel.js";
|
|
4
4
|
import { setDchatRuntime } from "./src/runtime.js";
|
|
5
5
|
|
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
applyAccountNameToChannelSection,
|
|
3
|
-
buildBaseAccountStatusSnapshot,
|
|
4
|
-
buildBaseChannelStatusSummary,
|
|
5
3
|
buildChannelConfigSchema,
|
|
6
|
-
collectStatusIssuesFromLastError,
|
|
7
|
-
createDefaultChannelRuntimeState,
|
|
8
4
|
DEFAULT_ACCOUNT_ID,
|
|
9
5
|
deleteAccountFromConfigSection,
|
|
10
6
|
normalizeAccountId,
|
|
11
|
-
resolveOutboundMediaUrls,
|
|
12
|
-
resolveSenderCommandAuthorization,
|
|
13
7
|
setAccountEnabledInConfigSection,
|
|
14
8
|
type ChannelPlugin,
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
type PluginRuntime,
|
|
10
|
+
} from "openclaw/plugin-sdk/core";
|
|
11
|
+
import {
|
|
12
|
+
buildBaseAccountStatusSnapshot,
|
|
13
|
+
buildBaseChannelStatusSummary,
|
|
14
|
+
collectStatusIssuesFromLastError,
|
|
15
|
+
createDefaultChannelRuntimeState,
|
|
16
|
+
} from "openclaw/plugin-sdk/status-helpers";
|
|
17
|
+
import { resolveOutboundMediaUrls } from "openclaw/plugin-sdk/reply-payload";
|
|
18
|
+
import { resolveSenderCommandAuthorization } from "openclaw/plugin-sdk/command-auth";
|
|
17
19
|
|
|
18
20
|
/* ── Inline helpers that may not exist in older OpenClaw versions ── */
|
|
19
21
|
|
|
@@ -30,7 +32,7 @@ function createScopedPairingAccess(params: {
|
|
|
30
32
|
channel: params.channel,
|
|
31
33
|
accountId: resolvedAccountId,
|
|
32
34
|
}),
|
|
33
|
-
upsertPairingRequest: (input: { id: string; meta?: Record<string,
|
|
35
|
+
upsertPairingRequest: (input: { id: string; meta?: Record<string, string | null | undefined> }) =>
|
|
34
36
|
params.core.channel.pairing.upsertPairingRequest({
|
|
35
37
|
channel: params.channel,
|
|
36
38
|
accountId: resolvedAccountId,
|
|
@@ -51,7 +53,7 @@ import {
|
|
|
51
53
|
resolveDefaultDchatAccountId,
|
|
52
54
|
} from "./config-schema.js";
|
|
53
55
|
import { NknBus } from "./nkn-bus.js";
|
|
54
|
-
import {
|
|
56
|
+
import { dchatSetupWizard } from "./onboarding.js";
|
|
55
57
|
import { getDchatRuntime } from "./runtime.js";
|
|
56
58
|
import { SeenTracker } from "./seen-tracker.js";
|
|
57
59
|
import type { ResolvedDchatAccount } from "./types.js";
|
|
@@ -92,7 +94,7 @@ function getBusForAccount(accountId: string): NknBus | undefined {
|
|
|
92
94
|
export const dchatPlugin: ChannelPlugin<ResolvedDchatAccount> = {
|
|
93
95
|
id: "dchat",
|
|
94
96
|
meta,
|
|
95
|
-
|
|
97
|
+
setupWizard: dchatSetupWizard,
|
|
96
98
|
capabilities: {
|
|
97
99
|
chatTypes: ["direct", "group"],
|
|
98
100
|
media: true,
|
|
@@ -138,7 +140,7 @@ export const dchatPlugin: ChannelPlugin<ResolvedDchatAccount> = {
|
|
|
138
140
|
name: account.name,
|
|
139
141
|
enabled: account.enabled,
|
|
140
142
|
configured: account.configured,
|
|
141
|
-
|
|
143
|
+
publicKey: account.nknAddress ?? null,
|
|
142
144
|
}),
|
|
143
145
|
resolveAllowFrom: ({ cfg, accountId }) => {
|
|
144
146
|
const dchatConfig = resolveDchatAccountConfig({ cfg: cfg as CoreConfig, accountId });
|
|
@@ -407,15 +409,15 @@ export const dchatPlugin: ChannelPlugin<ResolvedDchatAccount> = {
|
|
|
407
409
|
},
|
|
408
410
|
buildChannelSummary: ({ snapshot }) => ({
|
|
409
411
|
...buildBaseChannelStatusSummary(snapshot),
|
|
410
|
-
|
|
412
|
+
publicKey: snapshot.publicKey ?? null,
|
|
411
413
|
connected: snapshot.connected ?? false,
|
|
412
414
|
lastConnectedAt: snapshot.lastConnectedAt ?? null,
|
|
413
415
|
}),
|
|
414
416
|
buildAccountSnapshot: ({ account, runtime }) => ({
|
|
415
417
|
...buildBaseAccountStatusSnapshot({ account, runtime }),
|
|
416
|
-
|
|
417
|
-
connected: (runtime
|
|
418
|
-
lastConnectedAt:
|
|
418
|
+
publicKey: account.nknAddress ?? null,
|
|
419
|
+
connected: Boolean(runtime?.connected),
|
|
420
|
+
lastConnectedAt: runtime?.lastConnectedAt ?? null,
|
|
419
421
|
}),
|
|
420
422
|
collectStatusIssues: (accounts) => collectStatusIssuesFromLastError("dchat", accounts),
|
|
421
423
|
},
|
package/src/config-schema.ts
CHANGED
package/src/onboarding.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import type { DmPolicy } from "openclaw/plugin-sdk";
|
|
1
|
+
import type { DmPolicy } from "openclaw/plugin-sdk/setup";
|
|
2
2
|
import {
|
|
3
3
|
addWildcardAllowFrom,
|
|
4
4
|
mergeAllowFromEntries,
|
|
5
5
|
formatDocsLink,
|
|
6
|
-
type
|
|
7
|
-
type ChannelOnboardingDmPolicy,
|
|
6
|
+
type ChannelSetupDmPolicy,
|
|
8
7
|
type WizardPrompter,
|
|
9
|
-
} from "openclaw/plugin-sdk";
|
|
10
|
-
import {
|
|
8
|
+
} from "openclaw/plugin-sdk/setup";
|
|
9
|
+
import type { ChannelSetupWizard } from "openclaw/plugin-sdk/setup";
|
|
10
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
|
|
11
|
+
import { listDchatAccountIds, resolveDchatAccount, resolveDchatAccountConfig, type CoreConfig } from "./config-schema.js";
|
|
11
12
|
|
|
12
13
|
const channel = "dchat" as const;
|
|
13
14
|
|
|
@@ -30,154 +31,134 @@ function setDchatDmPolicy(cfg: CoreConfig, policy: DmPolicy) {
|
|
|
30
31
|
};
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
cfg: CoreConfig;
|
|
35
|
-
prompter: WizardPrompter;
|
|
36
|
-
}): Promise<CoreConfig> {
|
|
37
|
-
const { cfg, prompter } = params;
|
|
38
|
-
const existingAllowFrom = cfg.channels?.dchat?.allowFrom ?? [];
|
|
39
|
-
|
|
40
|
-
const entry = await prompter.text({
|
|
41
|
-
message: "NKN address to allow (full public key hex)",
|
|
42
|
-
placeholder: "abc123...def456 (64-char hex NKN address)",
|
|
43
|
-
initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : undefined,
|
|
44
|
-
validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
const parts = String(entry)
|
|
48
|
-
.split(/[\n,;]+/g)
|
|
49
|
-
.map((e) => e.trim())
|
|
50
|
-
.filter(Boolean);
|
|
51
|
-
|
|
52
|
-
const unique = mergeAllowFromEntries(existingAllowFrom, parts);
|
|
53
|
-
return {
|
|
54
|
-
...cfg,
|
|
55
|
-
channels: {
|
|
56
|
-
...cfg.channels,
|
|
57
|
-
dchat: {
|
|
58
|
-
...cfg.channels?.dchat,
|
|
59
|
-
enabled: true,
|
|
60
|
-
dmPolicy: "allowlist",
|
|
61
|
-
allowFrom: unique,
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const dmPolicy: ChannelOnboardingDmPolicy = {
|
|
34
|
+
const dmPolicy: ChannelSetupDmPolicy = {
|
|
68
35
|
label: "D-Chat",
|
|
69
36
|
channel,
|
|
70
37
|
policyKey: "channels.dchat.dmPolicy",
|
|
71
38
|
allowFromKey: "channels.dchat.allowFrom",
|
|
72
39
|
getCurrent: (cfg) => ((cfg as CoreConfig).channels?.dchat?.dmPolicy as DmPolicy) ?? "pairing",
|
|
73
40
|
setPolicy: (cfg, policy) => setDchatDmPolicy(cfg as CoreConfig, policy),
|
|
74
|
-
promptAllowFrom:
|
|
75
|
-
|
|
41
|
+
promptAllowFrom: async (params) => {
|
|
42
|
+
const cfg = params.cfg as CoreConfig;
|
|
43
|
+
const { prompter } = params;
|
|
44
|
+
const existingAllowFrom = cfg.channels?.dchat?.allowFrom ?? [];
|
|
76
45
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
)
|
|
46
|
+
const entry = await prompter.text({
|
|
47
|
+
message: "NKN address to allow (full public key hex)",
|
|
48
|
+
placeholder: "abc123...def456 (64-char hex NKN address)",
|
|
49
|
+
initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : undefined,
|
|
50
|
+
validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const parts = String(entry)
|
|
54
|
+
.split(/[\n,;]+/g)
|
|
55
|
+
.map((e) => e.trim())
|
|
56
|
+
.filter(Boolean);
|
|
57
|
+
|
|
58
|
+
const unique = mergeAllowFromEntries(existingAllowFrom, parts);
|
|
85
59
|
return {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
60
|
+
...cfg,
|
|
61
|
+
channels: {
|
|
62
|
+
...cfg.channels,
|
|
63
|
+
dchat: {
|
|
64
|
+
...cfg.channels?.dchat,
|
|
65
|
+
enabled: true,
|
|
66
|
+
dmPolicy: "allowlist",
|
|
67
|
+
allowFrom: unique,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
90
70
|
};
|
|
91
71
|
},
|
|
92
|
-
|
|
93
|
-
let next = cfg as CoreConfig;
|
|
94
|
-
const existing = next.channels?.dchat ?? {};
|
|
95
|
-
const account = resolveDchatAccount({ cfg: next });
|
|
72
|
+
};
|
|
96
73
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
74
|
+
export const dchatSetupWizard: ChannelSetupWizard = {
|
|
75
|
+
channel,
|
|
76
|
+
status: {
|
|
77
|
+
configuredLabel: "configured",
|
|
78
|
+
unconfiguredLabel: "needs wallet seed",
|
|
79
|
+
resolveConfigured: ({ cfg }) => {
|
|
80
|
+
const typedCfg = cfg as CoreConfig;
|
|
81
|
+
const accountIds = listDchatAccountIds(typedCfg);
|
|
82
|
+
return accountIds.some(
|
|
83
|
+
(id) => resolveDchatAccount({ cfg: typedCfg, accountId: id }).configured,
|
|
106
84
|
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
85
|
+
},
|
|
86
|
+
resolveStatusLines: ({ cfg, configured }) => [
|
|
87
|
+
`D-Chat: ${configured ? "configured" : "needs wallet seed"}`,
|
|
88
|
+
],
|
|
89
|
+
resolveSelectionHint: ({ configured }) =>
|
|
90
|
+
configured ? "configured" : "needs seed",
|
|
91
|
+
},
|
|
92
|
+
introNote: {
|
|
93
|
+
title: "D-Chat setup",
|
|
94
|
+
lines: [
|
|
95
|
+
"D-Chat uses the NKN relay network for decentralized E2E encrypted messaging.",
|
|
96
|
+
"You need a wallet seed (64-character hex string) to connect.",
|
|
97
|
+
"Generate one with nkn-sdk or use an existing seed from D-Chat/nMobile.",
|
|
98
|
+
`Docs: ${formatDocsLink("/channels/dchat", "channels/dchat")}`,
|
|
99
|
+
],
|
|
100
|
+
shouldShow: ({ cfg }) => {
|
|
101
|
+
const account = resolveDchatAccount({ cfg: cfg as CoreConfig });
|
|
102
|
+
return !account.configured;
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
envShortcut: {
|
|
106
|
+
prompt: "NKN seed env var detected. Use env value?",
|
|
107
|
+
preferredEnvVar: "DCHAT_SEED",
|
|
108
|
+
isAvailable: ({ cfg }) => {
|
|
109
|
+
const envSeed = process.env.DCHAT_SEED?.trim() || process.env.NKN_SEED?.trim();
|
|
110
|
+
const existing = (cfg as CoreConfig).channels?.dchat?.seed;
|
|
111
|
+
return Boolean(envSeed && /^[0-9a-f]{64}$/i.test(envSeed) && !existing);
|
|
112
|
+
},
|
|
113
|
+
apply: ({ cfg, accountId }) => {
|
|
114
|
+
const envSeed = (process.env.DCHAT_SEED?.trim() || process.env.NKN_SEED?.trim())!;
|
|
115
|
+
return {
|
|
116
|
+
...cfg,
|
|
117
|
+
channels: {
|
|
118
|
+
...(cfg as CoreConfig).channels,
|
|
119
|
+
dchat: {
|
|
120
|
+
...(cfg as CoreConfig).channels?.dchat,
|
|
121
|
+
enabled: true,
|
|
122
|
+
seed: envSeed,
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
} as OpenClawConfig;
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
credentials: [
|
|
129
|
+
{
|
|
130
|
+
inputKey: "accessToken",
|
|
131
|
+
providerHint: "NKN",
|
|
132
|
+
credentialLabel: "wallet seed",
|
|
133
|
+
preferredEnvVar: "DCHAT_SEED",
|
|
134
|
+
envPrompt: "NKN seed env var detected. Use env value?",
|
|
135
|
+
keepPrompt: "Wallet seed already configured. Keep it?",
|
|
136
|
+
inputPrompt: "NKN wallet seed (64-char hex)",
|
|
137
|
+
inspect: ({ cfg, accountId }) => {
|
|
138
|
+
const acctCfg = resolveDchatAccountConfig({ cfg: cfg as CoreConfig, accountId });
|
|
139
|
+
const seed = acctCfg.seed?.trim();
|
|
140
|
+
return {
|
|
141
|
+
accountConfigured: Boolean(seed),
|
|
142
|
+
hasConfiguredValue: Boolean(seed),
|
|
143
|
+
resolvedValue: seed,
|
|
144
|
+
};
|
|
145
|
+
},
|
|
146
|
+
applySet: ({ cfg, accountId, resolvedValue }) => {
|
|
147
|
+
const seed = resolvedValue.trim();
|
|
148
|
+
return {
|
|
149
|
+
...cfg,
|
|
119
150
|
channels: {
|
|
120
|
-
...
|
|
151
|
+
...(cfg as CoreConfig).channels,
|
|
121
152
|
dchat: {
|
|
122
|
-
...
|
|
153
|
+
...(cfg as CoreConfig).channels?.dchat,
|
|
123
154
|
enabled: true,
|
|
124
|
-
seed
|
|
155
|
+
seed,
|
|
125
156
|
},
|
|
126
157
|
},
|
|
127
|
-
};
|
|
128
|
-
if (forceAllowFrom) {
|
|
129
|
-
next = await promptDchatAllowFrom({ cfg: next, prompter });
|
|
130
|
-
}
|
|
131
|
-
return { cfg: next };
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Prompt for seed
|
|
136
|
-
let seed = existing.seed ?? "";
|
|
137
|
-
if (seed) {
|
|
138
|
-
const keep = await prompter.confirm({
|
|
139
|
-
message: "Wallet seed already configured. Keep it?",
|
|
140
|
-
initialValue: true,
|
|
141
|
-
});
|
|
142
|
-
if (!keep) {
|
|
143
|
-
seed = "";
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (!seed) {
|
|
148
|
-
seed = String(
|
|
149
|
-
await prompter.text({
|
|
150
|
-
message: "NKN wallet seed (64-char hex)",
|
|
151
|
-
validate: (value) => {
|
|
152
|
-
const raw = String(value ?? "").trim();
|
|
153
|
-
if (!raw) return "Required";
|
|
154
|
-
if (!/^[0-9a-f]{64}$/i.test(raw)) {
|
|
155
|
-
return "Must be a 64-character hex string";
|
|
156
|
-
}
|
|
157
|
-
return undefined;
|
|
158
|
-
},
|
|
159
|
-
}),
|
|
160
|
-
).trim();
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
next = {
|
|
164
|
-
...next,
|
|
165
|
-
channels: {
|
|
166
|
-
...next.channels,
|
|
167
|
-
dchat: {
|
|
168
|
-
...next.channels?.dchat,
|
|
169
|
-
enabled: true,
|
|
170
|
-
seed,
|
|
171
|
-
},
|
|
158
|
+
} as OpenClawConfig;
|
|
172
159
|
},
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (forceAllowFrom) {
|
|
176
|
-
next = await promptDchatAllowFrom({ cfg: next, prompter });
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return { cfg: next };
|
|
180
|
-
},
|
|
160
|
+
},
|
|
161
|
+
],
|
|
181
162
|
dmPolicy,
|
|
182
163
|
disable: (cfg) => ({
|
|
183
164
|
...(cfg as CoreConfig),
|
package/src/runtime.ts
CHANGED