@workclaw/openclaw-workchat 1.0.0 → 1.0.4

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.
@@ -1,70 +1,52 @@
1
- import { logger } from "../util/logger.js";
2
-
3
- /**
4
- * Persist the (userId, agentId) -> account binding into
5
- * channels.openclaw-workchat.accounts of openclaw.json so inbound
6
- * AGENT_MESSAGE frames route to the right account and outbound sends find
7
- * the agent.
8
- *
9
- * Weixin-style model: no dedicated sub-agent, no explicit binding — the
10
- * account routes to the main agent via the channel's default binding the
11
- * desktop configSync maintains (and the gateway's default-agent fallback).
12
- * Credentials are never written here; they arrive via
13
- * WORKCHAT_API_KEY / WORKCHAT_APP_SECRET env injection.
14
- *
15
- * Shared by the binding listener (login-qr wait path) and the monitor's
16
- * INIT_AGENT / AGENT_CREATED handling (process-message).
17
- */
18
- export async function bindAgentToAccount(
19
- accountId: string,
20
- agentId: string,
21
- userId?: string,
22
- ): Promise<void> {
23
- const { loadConfig, writeConfigFile } = await import("openclaw/plugin-sdk/config-runtime");
24
- const raw = loadConfig() as Record<string, any>;
25
- const channels = (raw.channels ?? {}) as Record<string, any>;
26
- const section = (channels["openclaw-workchat"] ?? {}) as Record<string, any>;
27
- const accounts = { ...(section.accounts ?? {}) };
28
-
29
- accounts[accountId] = {
30
- ...(accounts[accountId] ?? {}),
31
- enabled: true,
32
- agentId,
33
- ...(userId ? { userId } : {}),
34
- };
35
-
36
- const updated = {
37
- ...raw,
38
- channels: {
39
- ...channels,
40
- "openclaw-workchat": {
41
- ...section,
42
- accounts,
43
- ...(userId && !section.userId ? { userId } : {}),
44
- channelConfigUpdatedAt: new Date().toISOString(),
45
- },
46
- },
47
- } as Record<string, any>;
48
-
49
- await writeConfigFile(updated as import("openclaw/plugin-sdk").OpenClawConfig);
50
-
51
- // Persist the binding user in the framework allowFrom store so command
52
- // authorization has an explicit source of truth (the inbound path also
53
- // falls back to the account's userId, but writing it keeps parity with the
54
- // zhixiaotu reference plugin).
55
- if (userId) {
56
- try {
57
- const { registerUserInFrameworkStore } = await import("./pairing.js");
58
- await registerUserInFrameworkStore({ accountId, userId });
59
- } catch (err) {
60
- logger.warn(`bindAgentToAccount: allowFrom registration failed: ${String(err)}`);
61
- }
62
- }
63
-
64
- logger.info(
65
- `bindAgentToAccount: accountId=${accountId} agentId=${agentId} userId=${userId || "(none)"} (apiKey NOT written — env-injected)`,
66
- );
67
- }
68
-
69
- /** Alias used by the binding listener path. */
70
- export const bindAgentToAccountFromBinding = bindAgentToAccount;
1
+ import { logger } from "../util/logger.js";
2
+
3
+ /**
4
+ * Complete the binding on the plugin side.
5
+ *
6
+ * The account payload (agentId/userId) lives exclusively in the plugin's
7
+ * private state dir (`state/openclaw-workchat/accounts/`) — weixin-style. The
8
+ * caller (binding listener / monitor INIT_AGENT handling) persists it via
9
+ * saveWorkChatAccount + registerWorkChatAccountId before calling this.
10
+ *
11
+ * This function only bumps `channelConfigUpdatedAt` in openclaw.json so the
12
+ * gateway reloads config from disk and restarts the channel with the fresh
13
+ * private-dir account data. Writing account entries into
14
+ * channels.openclaw-workchat.accounts here would race the desktop configSync
15
+ * (which rebuilds that field) and orphan the credentials/
16
+ * <account>-allowFrom.json files — the gateway's startup migration treats
17
+ * those as a fatal unresolved state.
18
+ */
19
+ export async function bindAgentToAccount(
20
+ accountId: string,
21
+ agentId: string,
22
+ userId?: string,
23
+ ): Promise<void> {
24
+ // Persist the binding user in the framework allowFrom store so command
25
+ // authorization has an explicit source of truth (the inbound path also
26
+ // falls back to the account's userId, but writing it keeps parity with the
27
+ // zhixiaotu reference plugin).
28
+ if (userId) {
29
+ try {
30
+ const { registerUserInFrameworkStore } = await import("./pairing.js");
31
+ await registerUserInFrameworkStore({ accountId, userId });
32
+ } catch (err) {
33
+ logger.warn(`bindAgentToAccount: allowFrom registration failed: ${String(err)}`);
34
+ }
35
+ }
36
+
37
+ // Trigger the channel hot reload; account data itself stays in the private
38
+ // state dir (already persisted by the caller before this runs).
39
+ try {
40
+ const { triggerWorkChatChannelReload } = await import("./accounts.js");
41
+ await triggerWorkChatChannelReload();
42
+ } catch (err) {
43
+ logger.warn(`bindAgentToAccount: channel reload trigger failed: ${String(err)}`);
44
+ }
45
+
46
+ logger.info(
47
+ `bindAgentToAccount: accountId=${accountId} agentId=${agentId} userId=${userId || "(none)"} (private-dir only; apiKey NOT written — env-injected)`,
48
+ );
49
+ }
50
+
51
+ /** Alias used by the binding listener path. */
52
+ export const bindAgentToAccountFromBinding = bindAgentToAccount;
@@ -1,16 +1,16 @@
1
- /**
2
- * Terminal QR display for the CLI `openclaw channels login` flow.
3
- * Mirrors the weixin plugin's displayQRCode: render with qrcode-terminal when
4
- * available, always fall back to printing the raw link.
5
- */
6
- export async function displayQRCode(qrcodeUrl: string): Promise<void> {
7
- try {
8
- const qrterm = await import("qrcode-terminal");
9
- qrterm.default.generate(qrcodeUrl, { small: true });
10
- process.stdout.write(`若二维码未能显示或无法使用,你可以访问以下链接以继续:\n`);
11
- process.stdout.write(`${qrcodeUrl}\n`);
12
- } catch {
13
- process.stdout.write(`若二维码未能显示或无法使用,你可以访问以下链接以继续:\n`);
14
- process.stdout.write(`${qrcodeUrl}\n`);
15
- }
16
- }
1
+ /**
2
+ * Terminal QR display for the CLI `openclaw channels login` flow.
3
+ * Mirrors the weixin plugin's displayQRCode: render with qrcode-terminal when
4
+ * available, always fall back to printing the raw link.
5
+ */
6
+ export async function displayQRCode(qrcodeUrl: string): Promise<void> {
7
+ try {
8
+ const qrterm = await import("qrcode-terminal");
9
+ qrterm.default.generate(qrcodeUrl, { small: true });
10
+ process.stdout.write(`若二维码未能显示或无法使用,你可以访问以下链接以继续:\n`);
11
+ process.stdout.write(`${qrcodeUrl}\n`);
12
+ } catch {
13
+ process.stdout.write(`若二维码未能显示或无法使用,你可以访问以下链接以继续:\n`);
14
+ process.stdout.write(`${qrcodeUrl}\n`);
15
+ }
16
+ }