opencode-copilot-account-switcher 0.14.34 → 0.14.36

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,5 +1,5 @@
1
1
  import { bindOperator, readOperatorBinding, rebindOperator, resetOperatorBinding } from "./operator-store.js";
2
- import { loadOpenClawWeixinPublicHelpers } from "./compat/openclaw-public-helpers.js";
2
+ import { loadOpenClawWeixinBindHelpers } from "./compat/openclaw-bind-helpers.js";
3
3
  import type { CommonSettingsStore } from "../common-settings-store.js";
4
4
  type BindAction = "wechat-bind" | "wechat-rebind";
5
5
  type WechatBindFlowResult = {
@@ -12,7 +12,7 @@ type WechatBindFlowResult = {
12
12
  };
13
13
  type WechatBindFlowInput = {
14
14
  action: BindAction;
15
- loadPublicHelpers?: typeof loadOpenClawWeixinPublicHelpers;
15
+ loadPublicHelpers?: typeof loadOpenClawWeixinBindHelpers;
16
16
  bindOperator?: typeof bindOperator;
17
17
  rebindOperator?: typeof rebindOperator;
18
18
  readOperatorBinding?: typeof readOperatorBinding;
@@ -1,5 +1,5 @@
1
1
  import { bindOperator, readOperatorBinding, rebindOperator, resetOperatorBinding } from "./operator-store.js";
2
- import { loadOpenClawWeixinPublicHelpers } from "./compat/openclaw-public-helpers.js";
2
+ import { loadOpenClawWeixinBindHelpers } from "./compat/openclaw-bind-helpers.js";
3
3
  import { buildOpenClawMenuAccount } from "./openclaw-account-adapter.js";
4
4
  import { loadQrCodeTerminal } from "./compat/qrcode-terminal-loader.js";
5
5
  import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
@@ -50,7 +50,7 @@ async function renderQrTerminalDefault(input) {
50
50
  }
51
51
  export async function runWechatBindFlow(input) {
52
52
  const now = input.now ?? Date.now;
53
- const loadPublicHelpers = input.loadPublicHelpers ?? loadOpenClawWeixinPublicHelpers;
53
+ const loadPublicHelpers = input.loadPublicHelpers ?? loadOpenClawWeixinBindHelpers;
54
54
  const persistOperatorBinding = input.bindOperator ?? bindOperator;
55
55
  const persistOperatorRebinding = input.rebindOperator ?? rebindOperator;
56
56
  const loadOperatorBinding = input.readOperatorBinding ?? readOperatorBinding;
@@ -2,6 +2,8 @@ export type JitiLoader = (path: string) => unknown;
2
2
  type CreateJiti = (id: string | URL, options?: Record<string, unknown>) => JitiLoader;
3
3
  type JitiImport = (specifier: string) => Promise<unknown> | unknown;
4
4
  type JitiResolve = (specifier: string) => string;
5
+ type JitiRequire = (specifier: string) => unknown;
6
+ type ModuleImport = (specifier: string) => Promise<unknown>;
5
7
  type JitiNamespace = {
6
8
  createJiti?: unknown;
7
9
  default?: unknown;
@@ -9,8 +11,17 @@ type JitiNamespace = {
9
11
  };
10
12
  export declare function resolveCreateJiti(namespace: JitiNamespace): CreateJiti;
11
13
  export declare function resolveJitiEsmEntry(resolveImpl?: JitiResolve): string;
14
+ export declare function resolveJitiCjsEntry(resolveImpl?: JitiResolve): string;
15
+ export declare function hasBunRuntime(bunVersion?: string | undefined): boolean;
12
16
  export declare function wrapCreateJiti(createJiti: CreateJiti): CreateJiti;
13
- export declare function loadJiti(importImpl?: JitiImport, resolveImpl?: JitiResolve): Promise<{
17
+ export declare function loadJiti(importImpl?: JitiImport, resolveImpl?: JitiResolve, requireImpl?: JitiRequire): Promise<{
14
18
  createJiti: CreateJiti;
15
19
  }>;
20
+ export declare function loadModuleWithTsFallback(modulePath: string, options?: {
21
+ bunVersion?: string | undefined;
22
+ importImpl?: ModuleImport;
23
+ loadJitiImpl?: typeof loadJiti;
24
+ parentURL?: string | URL;
25
+ jitiOptions?: Record<string, unknown>;
26
+ }): Promise<unknown>;
16
27
  export {};
@@ -22,16 +22,40 @@ export function resolveCreateJiti(namespace) {
22
22
  isCreateJiti(namespace.default.createJiti)) {
23
23
  return namespace.default.createJiti;
24
24
  }
25
- throw new Error("[wechat-compat] createJiti export unavailable");
25
+ if (namespace.default &&
26
+ typeof namespace.default === "object" &&
27
+ isCreateJiti(namespace.default.default)) {
28
+ return namespace.default.default;
29
+ }
30
+ if (namespace.default &&
31
+ typeof namespace.default === "object" &&
32
+ isCreateJiti(namespace.default["module.exports"])) {
33
+ return namespace.default["module.exports"];
34
+ }
35
+ const topLevelKeys = namespace && typeof namespace === "object" ? Object.keys(namespace).join(",") : typeof namespace;
36
+ const defaultValue = namespace?.default;
37
+ const defaultKeys = defaultValue && typeof defaultValue === "object" ? Object.keys(defaultValue).join(",") : typeof defaultValue;
38
+ throw new Error(`[wechat-compat] createJiti export unavailable (keys=${topLevelKeys}; default=${defaultKeys})`);
26
39
  }
27
40
  export function resolveJitiEsmEntry(resolveImpl = createRequire(import.meta.url).resolve) {
28
41
  const packageJsonPath = resolveImpl("jiti/package.json");
29
- return pathToFileURL(path.join(path.dirname(packageJsonPath), "dist", "jiti.cjs")).href;
42
+ return pathToFileURL(path.join(path.dirname(packageJsonPath), "lib", "jiti.cjs")).href;
43
+ }
44
+ export function resolveJitiCjsEntry(resolveImpl = createRequire(import.meta.url).resolve) {
45
+ const packageJsonPath = resolveImpl("jiti/package.json");
46
+ return path.join(path.dirname(packageJsonPath), "lib", "jiti.cjs");
30
47
  }
31
48
  function onJitiError(error) {
32
49
  throw error;
33
50
  }
34
51
  const nativeImport = (id) => import(id);
52
+ const DEFAULT_JITI_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs", ".json"];
53
+ function isTypeScriptModulePath(modulePath) {
54
+ return /\.(ts|tsx|mts|cts)$/i.test(modulePath);
55
+ }
56
+ export function hasBunRuntime(bunVersion = process.versions?.bun) {
57
+ return typeof bunVersion === "string" && bunVersion.length > 0;
58
+ }
35
59
  export function wrapCreateJiti(createJiti) {
36
60
  const requireFromJiti = createRequire(resolveJitiEsmEntry());
37
61
  let transformImpl;
@@ -52,9 +76,43 @@ export function wrapCreateJiti(createJiti) {
52
76
  });
53
77
  };
54
78
  }
55
- export async function loadJiti(importImpl = (specifier) => import(specifier), resolveImpl = createRequire(import.meta.url).resolve) {
56
- const namespace = await Promise.resolve(importImpl(resolveJitiEsmEntry(resolveImpl)));
57
- return {
58
- createJiti: wrapCreateJiti(resolveCreateJiti(namespace)),
59
- };
79
+ export async function loadJiti(importImpl = (specifier) => import(specifier), resolveImpl = createRequire(import.meta.url).resolve, requireImpl = createRequire(import.meta.url)) {
80
+ try {
81
+ const required = requireImpl("jiti");
82
+ return {
83
+ createJiti: wrapCreateJiti(resolveCreateJiti(required)),
84
+ };
85
+ }
86
+ catch {
87
+ // Fall back to import() when require-based loading is unavailable.
88
+ }
89
+ try {
90
+ const namespace = await Promise.resolve(importImpl("jiti"));
91
+ return {
92
+ createJiti: wrapCreateJiti(resolveCreateJiti(namespace)),
93
+ };
94
+ }
95
+ catch {
96
+ const namespace = await Promise.resolve(importImpl(resolveJitiEsmEntry(resolveImpl)));
97
+ return {
98
+ createJiti: wrapCreateJiti(resolveCreateJiti(namespace)),
99
+ };
100
+ }
101
+ }
102
+ export async function loadModuleWithTsFallback(modulePath, options = {}) {
103
+ const moduleUrl = pathToFileURL(modulePath).href;
104
+ const importImpl = options.importImpl ?? nativeImport;
105
+ // Even under Bun, TS entrypoints inside node_modules can transitively hit ESM/CJS
106
+ // interop edges (for example openclaw -> json5 default import). Jiti keeps that
107
+ // path stable for the WeChat compat loader.
108
+ if (hasBunRuntime(options.bunVersion) && !isTypeScriptModulePath(modulePath)) {
109
+ return await importImpl(moduleUrl);
110
+ }
111
+ const { createJiti } = await (options.loadJitiImpl ?? loadJiti)();
112
+ const loader = createJiti(options.parentURL ?? import.meta.url, {
113
+ interopDefault: true,
114
+ extensions: DEFAULT_JITI_EXTENSIONS,
115
+ ...(options.jitiOptions ?? {}),
116
+ });
117
+ return loader(modulePath);
60
118
  }
@@ -1,17 +1,6 @@
1
1
  import { createRequire } from "node:module";
2
- import { loadJiti } from "./jiti-loader.js";
2
+ import { loadModuleWithTsFallback } from "./jiti-loader.js";
3
3
  const OPENCLAW_WEIXIN_ACCOUNTS_MODULE = "@tencent-weixin/openclaw-weixin/src/auth/accounts.ts";
4
- let accountJitiLoader = null;
5
- async function getAccountJiti() {
6
- if (accountJitiLoader) {
7
- return accountJitiLoader;
8
- }
9
- accountJitiLoader = (await loadJiti()).createJiti(import.meta.url, {
10
- interopDefault: true,
11
- extensions: [".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs", ".json"],
12
- });
13
- return accountJitiLoader;
14
- }
15
4
  function asObject(value) {
16
5
  return value && typeof value === "object" ? value : {};
17
6
  }
@@ -52,7 +41,7 @@ export function createOpenClawAccountHelpers(input) {
52
41
  export async function loadOpenClawAccountHelpers(options = {}) {
53
42
  const require = createRequire(import.meta.url);
54
43
  const accountsModulePath = require.resolve(options.accountsModulePath ?? OPENCLAW_WEIXIN_ACCOUNTS_MODULE);
55
- const accountsModule = (await getAccountJiti())(accountsModulePath);
44
+ const accountsModule = await loadModuleWithTsFallback(accountsModulePath, { parentURL: import.meta.url });
56
45
  if (typeof accountsModule.listIndexedWeixinAccountIds !== "function" || typeof accountsModule.loadWeixinAccount !== "function") {
57
46
  throw new Error("[wechat-compat] account source helper unavailable");
58
47
  }
@@ -0,0 +1,29 @@
1
+ type WeixinBindQrGateway = {
2
+ loginWithQrStart: (input?: unknown) => Promise<unknown>;
3
+ loginWithQrWait: (input?: unknown) => Promise<unknown>;
4
+ };
5
+ type WeixinBindAccountHelpers = {
6
+ listAccountIds: () => Promise<string[]>;
7
+ resolveAccount: (accountId: string) => Promise<{
8
+ accountId: string;
9
+ enabled: boolean;
10
+ configured: boolean;
11
+ name?: string;
12
+ userId?: string;
13
+ }>;
14
+ describeAccount: (accountIdOrInput: string | {
15
+ accountId: string;
16
+ }) => Promise<{
17
+ accountId: string;
18
+ enabled: boolean;
19
+ configured: boolean;
20
+ name?: string;
21
+ userId?: string;
22
+ }>;
23
+ };
24
+ export type OpenClawWeixinBindHelpers = {
25
+ qrGateway: WeixinBindQrGateway;
26
+ accountHelpers: WeixinBindAccountHelpers;
27
+ };
28
+ export declare function loadOpenClawWeixinBindHelpers(): Promise<OpenClawWeixinBindHelpers>;
29
+ export {};
@@ -0,0 +1,153 @@
1
+ import { randomUUID } from "node:crypto";
2
+ const DEFAULT_BASE_URL = "https://ilinkai.weixin.qq.com";
3
+ const DEFAULT_ILINK_BOT_TYPE = "3";
4
+ const ACTIVE_LOGIN_TTL_MS = 5 * 60_000;
5
+ const QR_LONG_POLL_TIMEOUT_MS = 35_000;
6
+ const activeLogins = new Map();
7
+ function asObject(value) {
8
+ return value && typeof value === "object" ? value : {};
9
+ }
10
+ function asNonEmptyString(value) {
11
+ return typeof value === "string" && value.trim().length > 0 ? value : undefined;
12
+ }
13
+ function asPositiveNumber(value) {
14
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
15
+ }
16
+ function isLoginFresh(login) {
17
+ return Date.now() - login.startedAt < ACTIVE_LOGIN_TTL_MS;
18
+ }
19
+ function purgeExpiredLogins() {
20
+ for (const [sessionKey, login] of activeLogins) {
21
+ if (!isLoginFresh(login)) {
22
+ activeLogins.delete(sessionKey);
23
+ }
24
+ }
25
+ }
26
+ async function fetchQrCode(apiBaseUrl, botType) {
27
+ const base = apiBaseUrl.endsWith("/") ? apiBaseUrl : `${apiBaseUrl}/`;
28
+ const url = new URL(`ilink/bot/get_bot_qrcode?bot_type=${encodeURIComponent(botType)}`, base);
29
+ const response = await fetch(url.toString());
30
+ if (!response.ok) {
31
+ throw new Error(`Failed to fetch QR code: ${response.status} ${response.statusText}`);
32
+ }
33
+ return await response.json();
34
+ }
35
+ async function pollQrStatus(apiBaseUrl, qrcode) {
36
+ const base = apiBaseUrl.endsWith("/") ? apiBaseUrl : `${apiBaseUrl}/`;
37
+ const url = new URL(`ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(qrcode)}`, base);
38
+ const controller = new AbortController();
39
+ const timer = setTimeout(() => controller.abort(), QR_LONG_POLL_TIMEOUT_MS);
40
+ try {
41
+ const response = await fetch(url.toString(), {
42
+ headers: { "iLink-App-ClientVersion": "1" },
43
+ signal: controller.signal,
44
+ });
45
+ clearTimeout(timer);
46
+ const rawText = await response.text();
47
+ if (!response.ok) {
48
+ throw new Error(`Failed to poll QR status: ${response.status} ${response.statusText}`);
49
+ }
50
+ const parsed = JSON.parse(rawText);
51
+ return parsed && typeof parsed === "object" ? parsed : {};
52
+ }
53
+ catch (error) {
54
+ clearTimeout(timer);
55
+ if (error instanceof Error && error.name === "AbortError") {
56
+ return { status: "wait" };
57
+ }
58
+ throw error;
59
+ }
60
+ }
61
+ function createAccountHelpers() {
62
+ async function describeAccount(accountId) {
63
+ return {
64
+ accountId,
65
+ enabled: true,
66
+ configured: false,
67
+ };
68
+ }
69
+ return {
70
+ async listAccountIds() {
71
+ return [];
72
+ },
73
+ resolveAccount: describeAccount,
74
+ async describeAccount(accountIdOrInput) {
75
+ const accountId = typeof accountIdOrInput === "string" ? accountIdOrInput : accountIdOrInput.accountId;
76
+ return await describeAccount(accountId);
77
+ },
78
+ };
79
+ }
80
+ export async function loadOpenClawWeixinBindHelpers() {
81
+ const accountHelpers = createAccountHelpers();
82
+ return {
83
+ qrGateway: {
84
+ async loginWithQrStart(input) {
85
+ const params = asObject(input);
86
+ const sessionKey = asNonEmptyString(params.accountId) ?? randomUUID();
87
+ const force = params.force === true;
88
+ purgeExpiredLogins();
89
+ const existing = activeLogins.get(sessionKey);
90
+ if (!force && existing && isLoginFresh(existing) && existing.qrcodeUrl) {
91
+ return {
92
+ qrcodeUrl: existing.qrcodeUrl,
93
+ message: "二维码已就绪,请使用微信扫描。",
94
+ sessionKey,
95
+ };
96
+ }
97
+ const qrResponse = await fetchQrCode(DEFAULT_BASE_URL, DEFAULT_ILINK_BOT_TYPE);
98
+ activeLogins.set(sessionKey, {
99
+ sessionKey,
100
+ qrcode: qrResponse.qrcode,
101
+ qrcodeUrl: qrResponse.qrcode_img_content,
102
+ startedAt: Date.now(),
103
+ });
104
+ return {
105
+ qrDataUrl: qrResponse.qrcode_img_content,
106
+ qrcodeUrl: qrResponse.qrcode_img_content,
107
+ message: "使用微信扫描以下二维码,以完成连接。",
108
+ sessionKey,
109
+ };
110
+ },
111
+ async loginWithQrWait(input) {
112
+ const params = asObject(input);
113
+ const sessionKey = asNonEmptyString(params.sessionKey);
114
+ if (!sessionKey) {
115
+ throw new Error("missing sessionKey from qr wait");
116
+ }
117
+ let activeLogin = activeLogins.get(sessionKey);
118
+ if (!activeLogin) {
119
+ return { connected: false, message: "当前没有进行中的登录,请先发起登录。" };
120
+ }
121
+ if (!isLoginFresh(activeLogin)) {
122
+ activeLogins.delete(sessionKey);
123
+ return { connected: false, message: "二维码已过期,请重新生成。" };
124
+ }
125
+ const timeoutMs = Math.max(asPositiveNumber(params.timeoutMs) ?? 480_000, 1000);
126
+ const deadline = Date.now() + timeoutMs;
127
+ while (Date.now() < deadline) {
128
+ const statusResponse = await pollQrStatus(DEFAULT_BASE_URL, activeLogin.qrcode);
129
+ const status = asNonEmptyString(statusResponse.status);
130
+ if (status === "confirmed") {
131
+ activeLogins.delete(sessionKey);
132
+ return {
133
+ connected: true,
134
+ accountId: asNonEmptyString(statusResponse.ilink_bot_id),
135
+ baseUrl: asNonEmptyString(statusResponse.baseurl),
136
+ userId: asNonEmptyString(statusResponse.ilink_user_id),
137
+ message: "✅ 与微信连接成功!",
138
+ };
139
+ }
140
+ if (status === "expired") {
141
+ activeLogins.delete(sessionKey);
142
+ return { connected: false, message: "二维码已过期,请重新生成。" };
143
+ }
144
+ await new Promise((resolve) => setTimeout(resolve, 1000));
145
+ activeLogin = activeLogins.get(sessionKey) ?? activeLogin;
146
+ }
147
+ activeLogins.delete(sessionKey);
148
+ return { connected: false, message: "登录超时,请重试。" };
149
+ },
150
+ },
151
+ accountHelpers,
152
+ };
153
+ }
@@ -1,23 +1,12 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { createRequire } from "node:module";
3
3
  import path from "node:path";
4
- import { loadJiti } from "./jiti-loader.js";
5
- let publicJitiLoader = null;
4
+ import { loadModuleWithTsFallback } from "./jiti-loader.js";
6
5
  function requireField(condition, message) {
7
6
  if (!condition) {
8
7
  throw new Error(`[wechat-compat] ${message}`);
9
8
  }
10
9
  }
11
- async function getPublicJiti() {
12
- if (publicJitiLoader) {
13
- return publicJitiLoader;
14
- }
15
- publicJitiLoader = (await loadJiti()).createJiti(import.meta.url, {
16
- interopDefault: true,
17
- extensions: [".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs", ".json"],
18
- });
19
- return publicJitiLoader;
20
- }
21
10
  export async function resolveOpenClawWeixinPublicEntry() {
22
11
  const require = createRequire(import.meta.url);
23
12
  const packageName = "@tencent-weixin/openclaw-weixin";
@@ -42,7 +31,7 @@ export async function resolveOpenClawWeixinPublicEntry() {
42
31
  }
43
32
  export async function loadOpenClawWeixinDefaultExport() {
44
33
  const entry = await resolveOpenClawWeixinPublicEntry();
45
- const moduleNamespace = (await getPublicJiti())(entry.entryAbsolutePath);
34
+ const moduleNamespace = await loadModuleWithTsFallback(entry.entryAbsolutePath, { parentURL: import.meta.url });
46
35
  const plugin = moduleNamespace.default;
47
36
  if (!plugin || typeof plugin !== "object" || typeof plugin.register !== "function") {
48
37
  throw new Error("[wechat-compat] @tencent-weixin/openclaw-weixin public entry default export is missing register(api)");
@@ -1,20 +1,9 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { createRequire } from "node:module";
3
3
  import path from "node:path";
4
- import { loadJiti } from "./jiti-loader.js";
4
+ import { loadModuleWithTsFallback } from "./jiti-loader.js";
5
5
  const OPENCLAW_SYNC_BUF_MODULE = "@tencent-weixin/openclaw-weixin/src/storage/sync-buf.ts";
6
6
  const OPENCLAW_STATE_DIR_MODULE = "@tencent-weixin/openclaw-weixin/src/storage/state-dir.ts";
7
- let syncBufJitiLoader = null;
8
- async function getSyncBufJiti() {
9
- if (syncBufJitiLoader) {
10
- return syncBufJitiLoader;
11
- }
12
- syncBufJitiLoader = (await loadJiti()).createJiti(import.meta.url, {
13
- interopDefault: true,
14
- extensions: [".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs", ".json"],
15
- });
16
- return syncBufJitiLoader;
17
- }
18
7
  export function createOpenClawSyncBufHelper(input) {
19
8
  return {
20
9
  async persistGetUpdatesBuf({ accountId, getUpdatesBuf }) {
@@ -29,7 +18,7 @@ export function createOpenClawSyncBufHelper(input) {
29
18
  export async function loadOpenClawSyncBufHelper(options = {}) {
30
19
  const require = createRequire(import.meta.url);
31
20
  const syncBufModulePath = require.resolve(options.syncBufModulePath ?? OPENCLAW_SYNC_BUF_MODULE);
32
- const syncBufModule = (await getSyncBufJiti())(syncBufModulePath);
21
+ const syncBufModule = await loadModuleWithTsFallback(syncBufModulePath, { parentURL: import.meta.url });
33
22
  if (typeof syncBufModule.getSyncBufFilePath !== "function" || typeof syncBufModule.saveGetUpdatesBuf !== "function") {
34
23
  throw new Error("[wechat-compat] sync-buf source helper unavailable");
35
24
  }
@@ -41,7 +30,7 @@ export async function loadOpenClawSyncBufHelper(options = {}) {
41
30
  export async function loadLatestWeixinAccountState(options = {}) {
42
31
  const require = createRequire(import.meta.url);
43
32
  const stateDirModulePath = require.resolve(options.stateDirModulePath ?? OPENCLAW_STATE_DIR_MODULE);
44
- const stateDirModule = (await getSyncBufJiti())(stateDirModulePath);
33
+ const stateDirModule = await loadModuleWithTsFallback(stateDirModulePath, { parentURL: import.meta.url });
45
34
  const stateDir = stateDirModule.resolveStateDir?.();
46
35
  if (!stateDir) {
47
36
  return null;
@@ -67,7 +56,7 @@ export async function loadLatestWeixinAccountState(options = {}) {
67
56
  const accountRaw = await readFile(accountFilePath, "utf8");
68
57
  const account = JSON.parse(accountRaw);
69
58
  const syncBufModulePath = require.resolve(options.syncBufModulePath ?? OPENCLAW_SYNC_BUF_MODULE);
70
- const syncBufModule = (await getSyncBufJiti())(syncBufModulePath);
59
+ const syncBufModule = await loadModuleWithTsFallback(syncBufModulePath, { parentURL: import.meta.url });
71
60
  if (typeof account.token !== "string" || account.token.trim().length === 0) {
72
61
  return null;
73
62
  }
@@ -1,18 +1,7 @@
1
1
  import { createRequire } from "node:module";
2
- import { loadJiti } from "./jiti-loader.js";
2
+ import { loadModuleWithTsFallback } from "./jiti-loader.js";
3
3
  const OPENCLAW_UPDATES_MODULE = "@tencent-weixin/openclaw-weixin/src/api/api.ts";
4
4
  const OPENCLAW_SEND_MODULE = "@tencent-weixin/openclaw-weixin/src/messaging/send.ts";
5
- let updatesSendJitiLoader = null;
6
- async function getUpdatesSendJiti() {
7
- if (updatesSendJitiLoader) {
8
- return updatesSendJitiLoader;
9
- }
10
- updatesSendJitiLoader = (await loadJiti()).createJiti(import.meta.url, {
11
- interopDefault: true,
12
- extensions: [".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs", ".json"],
13
- });
14
- return updatesSendJitiLoader;
15
- }
16
5
  function toObjectInput(input) {
17
6
  return input && typeof input === "object" ? input : {};
18
7
  }
@@ -34,9 +23,8 @@ export async function loadOpenClawUpdatesAndSendHelpers(options = {}) {
34
23
  const require = createRequire(import.meta.url);
35
24
  const getUpdatesModulePath = require.resolve(options.getUpdatesModulePath ?? OPENCLAW_UPDATES_MODULE);
36
25
  const sendModulePath = require.resolve(options.sendMessageWeixinModulePath ?? OPENCLAW_SEND_MODULE);
37
- const jiti = await getUpdatesSendJiti();
38
- const getUpdatesModule = jiti(getUpdatesModulePath);
39
- const sendModule = jiti(sendModulePath);
26
+ const getUpdatesModule = await loadModuleWithTsFallback(getUpdatesModulePath, { parentURL: import.meta.url });
27
+ const sendModule = await loadModuleWithTsFallback(sendModulePath, { parentURL: import.meta.url });
40
28
  if (typeof getUpdatesModule.getUpdates !== "function") {
41
29
  throw new Error("public getUpdates helper unavailable");
42
30
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-copilot-account-switcher",
3
- "version": "0.14.34",
3
+ "version": "0.14.36",
4
4
  "description": "GitHub Copilot account switcher plugin for OpenCode",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -49,6 +49,7 @@
49
49
  "wechat:smoke:self-test": "npm run build && node --input-type=module -e \"import('./dist/wechat/compat/openclaw-smoke.js').then(async (m) => { const results = await m.runOpenClawSmoke('self-test'); console.log(JSON.stringify(results, null, 2)); })\"",
50
50
  "wechat:smoke:real-account": "npm run build && node --input-type=module -e \"import('./dist/wechat/compat/openclaw-smoke.js').then(async (m) => { const dryRun = process.argv.includes('--dry-run'); const results = await m.runOpenClawSmoke('real-account', { dryRun }); console.log(JSON.stringify(results, null, 2)); })\" --",
51
51
  "wechat:smoke:guided": "npm run build && node dist/wechat/compat/openclaw-guided-smoke.js",
52
+ "test:wechat-real-host-gate": "npm run build && node --test test/wechat-opencode-real-host-gate.test.js",
52
53
  "test": "npm run build && node --test",
53
54
  "typecheck": "tsc --noEmit",
54
55
  "prepublishOnly": "npm run build"