@workclaw/openclaw-workchat 1.0.3 → 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.
package/index.js CHANGED
@@ -373,23 +373,9 @@ async function removeWorkChatAccountBinding(accountId) {
373
373
  logger.warn(`removeWorkChatAccountBinding: allowFrom cleanup failed: ${String(err)}`);
374
374
  }
375
375
  try {
376
- const { loadConfig, writeConfigFile } = await import("openclaw/plugin-sdk/config-runtime");
377
- const cfg = loadConfig();
378
- const channels = cfg.channels ?? {};
379
- const section = channels["openclaw-workchat"];
380
- if (section?.accounts?.[accountId] !== void 0) {
381
- const accounts = { ...section.accounts ?? {} };
382
- delete accounts[accountId];
383
- await writeConfigFile({
384
- ...cfg,
385
- channels: {
386
- ...channels,
387
- "openclaw-workchat": { ...section, accounts }
388
- }
389
- });
390
- }
376
+ await triggerWorkChatChannelReload();
391
377
  } catch (err) {
392
- logger.warn(`removeWorkChatAccountBinding: config cleanup failed: ${String(err)}`);
378
+ logger.warn(`removeWorkChatAccountBinding: channel reload trigger failed: ${String(err)}`);
393
379
  }
394
380
  }
395
381
  async function pruneStaleWorkChatAccounts(keepAgentId) {
@@ -26883,30 +26869,6 @@ __export(bind_agent_exports, {
26883
26869
  bindAgentToAccountFromBinding: () => bindAgentToAccountFromBinding
26884
26870
  });
26885
26871
  async function bindAgentToAccount(accountId, agentId, userId) {
26886
- const { loadConfig, writeConfigFile } = await import("openclaw/plugin-sdk/config-runtime");
26887
- const raw = loadConfig();
26888
- const channels = raw.channels ?? {};
26889
- const section = channels["openclaw-workchat"] ?? {};
26890
- const accounts = { ...section.accounts ?? {} };
26891
- accounts[accountId] = {
26892
- ...accounts[accountId] ?? {},
26893
- enabled: true,
26894
- agentId,
26895
- ...userId ? { userId } : {}
26896
- };
26897
- const updated = {
26898
- ...raw,
26899
- channels: {
26900
- ...channels,
26901
- "openclaw-workchat": {
26902
- ...section,
26903
- accounts,
26904
- ...userId && !section.userId ? { userId } : {},
26905
- channelConfigUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
26906
- }
26907
- }
26908
- };
26909
- await writeConfigFile(updated);
26910
26872
  if (userId) {
26911
26873
  try {
26912
26874
  const { registerUserInFrameworkStore: registerUserInFrameworkStore2 } = await Promise.resolve().then(() => (init_pairing(), pairing_exports));
@@ -26915,8 +26877,14 @@ async function bindAgentToAccount(accountId, agentId, userId) {
26915
26877
  logger.warn(`bindAgentToAccount: allowFrom registration failed: ${String(err)}`);
26916
26878
  }
26917
26879
  }
26880
+ try {
26881
+ const { triggerWorkChatChannelReload: triggerWorkChatChannelReload2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
26882
+ await triggerWorkChatChannelReload2();
26883
+ } catch (err) {
26884
+ logger.warn(`bindAgentToAccount: channel reload trigger failed: ${String(err)}`);
26885
+ }
26918
26886
  logger.info(
26919
- `bindAgentToAccount: accountId=${accountId} agentId=${agentId} userId=${userId || "(none)"} (apiKey NOT written \u2014 env-injected)`
26887
+ `bindAgentToAccount: accountId=${accountId} agentId=${agentId} userId=${userId || "(none)"} (private-dir only; apiKey NOT written \u2014 env-injected)`
26920
26888
  );
26921
26889
  }
26922
26890
  var bindAgentToAccountFromBinding;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workclaw/openclaw-workchat",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "type": "module",
5
5
  "description": "OpenClaw WorkChat channel plugin: QR binding + WebSocket messaging with the WorkChat open platform",
6
6
  "license": "MIT",
@@ -141,24 +141,13 @@ export async function removeWorkChatAccountBinding(accountId: string): Promise<v
141
141
  logger.warn(`removeWorkChatAccountBinding: allowFrom cleanup failed: ${String(err)}`);
142
142
  }
143
143
 
144
+ // Account entries no longer live in openclaw.json (weixin-style private-dir
145
+ // ownership), so there is no shared config to clean up here — the channel
146
+ // reload bump below lets the gateway drop the removed account.
144
147
  try {
145
- const { loadConfig, writeConfigFile } = await import("openclaw/plugin-sdk/config-runtime");
146
- const cfg = loadConfig();
147
- const channels = (cfg.channels ?? {}) as Record<string, any>;
148
- const section = channels["openclaw-workchat"];
149
- if (section?.accounts?.[accountId] !== undefined) {
150
- const accounts = { ...(section.accounts ?? {}) };
151
- delete accounts[accountId];
152
- await writeConfigFile({
153
- ...cfg,
154
- channels: {
155
- ...channels,
156
- "openclaw-workchat": { ...section, accounts },
157
- },
158
- } as import("openclaw/plugin-sdk").OpenClawConfig);
159
- }
148
+ await triggerWorkChatChannelReload();
160
149
  } catch (err) {
161
- logger.warn(`removeWorkChatAccountBinding: config cleanup failed: ${String(err)}`);
150
+ logger.warn(`removeWorkChatAccountBinding: channel reload trigger failed: ${String(err)}`);
162
151
  }
163
152
  }
164
153
 
@@ -1,53 +1,26 @@
1
1
  import { logger } from "../util/logger.js";
2
2
 
3
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.
4
+ * Complete the binding on the plugin side.
8
5
  *
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.
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.
14
10
  *
15
- * Shared by the binding listener (login-qr wait path) and the monitor's
16
- * INIT_AGENT / AGENT_CREATED handling (process-message).
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.
17
18
  */
18
19
  export async function bindAgentToAccount(
19
20
  accountId: string,
20
21
  agentId: string,
21
22
  userId?: string,
22
23
  ): 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
24
  // Persist the binding user in the framework allowFrom store so command
52
25
  // authorization has an explicit source of truth (the inbound path also
53
26
  // falls back to the account's userId, but writing it keeps parity with the
@@ -61,8 +34,17 @@ export async function bindAgentToAccount(
61
34
  }
62
35
  }
63
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
+
64
46
  logger.info(
65
- `bindAgentToAccount: accountId=${accountId} agentId=${agentId} userId=${userId || "(none)"} (apiKey NOT written — env-injected)`,
47
+ `bindAgentToAccount: accountId=${accountId} agentId=${agentId} userId=${userId || "(none)"} (private-dir only; apiKey NOT written — env-injected)`,
66
48
  );
67
49
  }
68
50
 
@@ -427,7 +427,9 @@ async function handleListenerFrame(sessionKey: string, data: string, ws: WebSock
427
427
  ...(userId ? { userId } : {}),
428
428
  });
429
429
  registerWorkChatAccountId(accountId);
430
- // Bind agent into openclaw.json accounts (routing) — no apiKey ever written.
430
+ // Complete the binding: account data is already in the private state
431
+ // dir; this call registers the allowFrom user and triggers the channel
432
+ // hot reload.
431
433
  const { bindAgentToAccountFromBinding } = await import("./bind-agent.js");
432
434
  await bindAgentToAccountFromBinding(accountId, agentId, userId);
433
435
  logger.info(`binding listener: account=${accountId} agent=${agentId} persisted`);