@xopcai/xopc 0.0.27 → 0.0.29
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/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/adapters/onboard-cli.d.ts +7 -0
- package/dist/extensions/weixin/src/adapters/onboard-cli.js +61 -0
- package/dist/extensions/weixin/src/adapters/onboard-cli.js.map +1 -0
- package/dist/extensions/weixin/src/cli/qr-login.d.ts +5 -0
- package/dist/extensions/weixin/src/cli/qr-login.js +1 -1
- package/dist/extensions/weixin/src/cli/qr-login.js.map +1 -1
- package/dist/extensions/weixin/src/index.js +1 -1
- package/dist/extensions/weixin/src/plugin.d.ts +1 -0
- package/dist/extensions/weixin/src/plugin.js +2 -0
- package/dist/extensions/weixin/src/plugin.js.map +1 -1
- package/dist/gateway/static/root/assets/agents-CkgFSiCY.js +216 -0
- package/dist/gateway/static/root/assets/agents-CkgFSiCY.js.map +1 -0
- package/dist/gateway/static/root/assets/{apps-page-CBBh_Ww8.js → apps-page-Bmq19MS-.js} +2 -2
- package/dist/gateway/static/root/assets/{apps-page-CBBh_Ww8.js.map → apps-page-Bmq19MS-.js.map} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-CE7jrdkO.js +9 -0
- package/dist/gateway/static/root/assets/channels-settings-CE7jrdkO.js.map +1 -0
- package/dist/gateway/static/root/assets/cron-page-BpPPcykJ.js +2 -0
- package/dist/gateway/static/root/assets/cron-page-BpPPcykJ.js.map +1 -0
- package/dist/gateway/static/root/assets/{cron-utils-08gdQfl9.js → cron-utils-N1PqD2DB.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-utils-08gdQfl9.js.map → cron-utils-N1PqD2DB.js.map} +1 -1
- package/dist/gateway/static/root/assets/{dist-C1MrygQH.js → dist--p2HQ2QF.js} +2 -2
- package/dist/gateway/static/root/assets/{dist-C1MrygQH.js.map → dist--p2HQ2QF.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DN3HKUGS.js → extension-debug-page-DwHCB_6T.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-debug-page-DN3HKUGS.js.map → extension-debug-page-DwHCB_6T.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CoFDHZtZ.js → extension-page-BsYwQIex.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-page-CoFDHZtZ.js.map → extension-page-BsYwQIex.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-BcPCu_Go.js → extension-settings-page-nsisEgjB.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-settings-page-BcPCu_Go.js.map → extension-settings-page-nsisEgjB.js.map} +1 -1
- package/dist/gateway/static/root/assets/index-CR8zUHGR.js +4734 -0
- package/dist/gateway/static/root/assets/{index-PfkB8N37.js.map → index-CR8zUHGR.js.map} +1 -1
- package/dist/gateway/static/root/assets/index-Dnfha4O2.css +1 -0
- package/dist/gateway/static/root/assets/logs-page-CQwdV_Xw.js +2 -0
- package/dist/gateway/static/root/assets/logs-page-CQwdV_Xw.js.map +1 -0
- package/dist/gateway/static/root/assets/sessions-page-Be5kIGl_.js +2 -0
- package/dist/gateway/static/root/assets/sessions-page-Be5kIGl_.js.map +1 -0
- package/dist/gateway/static/root/assets/settings-page-PodSlNwr.js +2 -0
- package/dist/gateway/static/root/assets/settings-page-PodSlNwr.js.map +1 -0
- package/dist/gateway/static/root/assets/skills-page-Clg8deH0.js +3 -0
- package/dist/gateway/static/root/assets/{skills-page-BmBDCEbY.js.map → skills-page-Clg8deH0.js.map} +1 -1
- package/dist/gateway/static/root/index.html +2 -2
- package/dist/package.js +1 -1
- package/dist/src/agent/lifecycle/hook-handler.d.ts +2 -0
- package/dist/src/agent/lifecycle/hook-handler.js +24 -0
- package/dist/src/agent/lifecycle/hook-handler.js.map +1 -1
- package/dist/src/agent/messaging/command-handler.js +10 -2
- package/dist/src/agent/messaging/command-handler.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.js +77 -20
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service.d.ts +15 -0
- package/dist/src/agent/service.js +21 -1
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/channels/weixin/index.js +1 -1
- package/dist/src/cli/agent-chat-log-level-preset.d.ts +8 -0
- package/dist/src/cli/agent-chat-log-level-preset.js +25 -0
- package/dist/src/cli/agent-chat-log-level-preset.js.map +1 -0
- package/dist/src/cli/commands/agent/interactive.js +4 -2
- package/dist/src/cli/commands/agent/interactive.js.map +1 -1
- package/dist/src/cli/commands/agent/stream-renderer.d.ts +14 -0
- package/dist/src/cli/commands/agent/stream-renderer.js +99 -0
- package/dist/src/cli/commands/agent/stream-renderer.js.map +1 -0
- package/dist/src/cli/commands/agent.js +2 -2
- package/dist/src/cli/commands/agent.js.map +1 -1
- package/dist/src/cli/commands/onboard.js +77 -93
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/commands/tui.d.ts +1 -0
- package/dist/src/cli/commands/tui.js +40 -0
- package/dist/src/cli/commands/tui.js.map +1 -0
- package/dist/src/cli/index.d.ts +2 -0
- package/dist/src/cli/index.js +7 -3
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/config/schema.d.ts +6 -0
- package/dist/src/config/schema.js +11 -3
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/extensions/hooks.js +5 -1
- package/dist/src/extensions/hooks.js.map +1 -1
- package/dist/src/extensions/loader.d.ts +1 -0
- package/dist/src/extensions/loader.js +3 -1
- package/dist/src/extensions/loader.js.map +1 -1
- package/dist/src/extensions/sdk/index.d.ts +1 -1
- package/dist/src/extensions/sdk/index.js.map +1 -1
- package/dist/src/extensions/types/core.d.ts +8 -0
- package/dist/src/extensions/types/hooks.d.ts +16 -1
- package/dist/src/extensions/types/hooks.js +1 -0
- package/dist/src/extensions/types/hooks.js.map +1 -1
- package/dist/src/gateway/agents-admin.d.ts +19 -1
- package/dist/src/gateway/agents-admin.js +164 -3
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/auth.d.ts +17 -3
- package/dist/src/gateway/auth.js +35 -16
- package/dist/src/gateway/auth.js.map +1 -1
- package/dist/src/gateway/hono/app.js +31 -1
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -1
- package/dist/src/gateway/hono/middleware/auth.js +4 -3
- package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
- package/dist/src/gateway/hono/middleware/scopes.d.ts +15 -0
- package/dist/src/gateway/hono/middleware/scopes.js +41 -0
- package/dist/src/gateway/hono/middleware/scopes.js.map +1 -0
- package/dist/src/gateway/hono/routes/agents.js +59 -5
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/config.js +2 -2
- package/dist/src/gateway/hono/routes/config.js.map +1 -1
- package/dist/src/gateway/hono/routes/public-gateway.js +1 -0
- package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +17 -0
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/security/audit.d.ts +18 -0
- package/dist/src/gateway/security/audit.js +68 -0
- package/dist/src/gateway/security/audit.js.map +1 -0
- package/dist/src/gateway/security/csp.d.ts +19 -0
- package/dist/src/gateway/security/csp.js +52 -0
- package/dist/src/gateway/security/csp.js.map +1 -0
- package/dist/src/gateway/security/dangerous-tools.d.ts +20 -0
- package/dist/src/gateway/security/dangerous-tools.js +46 -0
- package/dist/src/gateway/security/dangerous-tools.js.map +1 -0
- package/dist/src/gateway/security/flood-guard.d.ts +28 -0
- package/dist/src/gateway/security/flood-guard.js +42 -0
- package/dist/src/gateway/security/flood-guard.js.map +1 -0
- package/dist/src/gateway/security/index.d.ts +9 -0
- package/dist/src/gateway/security/index.js +10 -0
- package/dist/src/gateway/security/known-weak-secrets.d.ts +10 -0
- package/dist/src/gateway/security/known-weak-secrets.js +36 -0
- package/dist/src/gateway/security/known-weak-secrets.js.map +1 -0
- package/dist/src/gateway/security/operator-scopes.d.ts +37 -0
- package/dist/src/gateway/security/operator-scopes.js +137 -0
- package/dist/src/gateway/security/operator-scopes.js.map +1 -0
- package/dist/src/gateway/security/origin-check.d.ts +21 -0
- package/dist/src/gateway/security/origin-check.js +56 -0
- package/dist/src/gateway/security/origin-check.js.map +1 -0
- package/dist/src/gateway/security/preauth-connection-budget.d.ts +17 -0
- package/dist/src/gateway/security/preauth-connection-budget.js +49 -0
- package/dist/src/gateway/security/preauth-connection-budget.js.map +1 -0
- package/dist/src/gateway/security/secret-equal.d.ts +8 -0
- package/dist/src/gateway/security/secret-equal.js +30 -0
- package/dist/src/gateway/security/secret-equal.js.map +1 -0
- package/dist/src/gateway/service.d.ts +3 -1
- package/dist/src/gateway/service.js +40 -4
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/session/client-history.d.ts +21 -0
- package/dist/src/session/client-history.js +89 -0
- package/dist/src/session/client-history.js.map +1 -0
- package/dist/src/session/index.d.ts +1 -0
- package/dist/src/session/index.js +2 -1
- package/dist/src/session/manager.d.ts +2 -0
- package/dist/src/session/manager.js +5 -0
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/thinking-resolve.js +1 -1
- package/dist/src/session/thinking-resolve.js.map +1 -1
- package/dist/src/tui/backends/embedded-backend.d.ts +42 -0
- package/dist/src/tui/backends/embedded-backend.js +173 -0
- package/dist/src/tui/backends/embedded-backend.js.map +1 -0
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +53 -0
- package/dist/src/tui/backends/gateway-sse-backend.js +256 -0
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -0
- package/dist/src/tui/chat-history.d.ts +4 -0
- package/dist/src/tui/chat-history.js +29 -0
- package/dist/src/tui/chat-history.js.map +1 -0
- package/dist/src/tui/components/assistant-message.d.ts +6 -0
- package/dist/src/tui/components/assistant-message.js +19 -0
- package/dist/src/tui/components/assistant-message.js.map +1 -0
- package/dist/src/tui/components/chat-log.d.ts +21 -0
- package/dist/src/tui/components/chat-log.js +113 -0
- package/dist/src/tui/components/chat-log.js.map +1 -0
- package/dist/src/tui/components/custom-editor.d.ts +14 -0
- package/dist/src/tui/components/custom-editor.js +50 -0
- package/dist/src/tui/components/custom-editor.js.map +1 -0
- package/dist/src/tui/components/fuzzy-filter.d.ts +17 -0
- package/dist/src/tui/components/fuzzy-filter.js +85 -0
- package/dist/src/tui/components/fuzzy-filter.js.map +1 -0
- package/dist/src/tui/components/searchable-select-list.d.ts +39 -0
- package/dist/src/tui/components/searchable-select-list.js +257 -0
- package/dist/src/tui/components/searchable-select-list.js.map +1 -0
- package/dist/src/tui/components/tool-execution.d.ts +16 -0
- package/dist/src/tui/components/tool-execution.js +76 -0
- package/dist/src/tui/components/tool-execution.js.map +1 -0
- package/dist/src/tui/components/user-message.d.ts +6 -0
- package/dist/src/tui/components/user-message.js +22 -0
- package/dist/src/tui/components/user-message.js.map +1 -0
- package/dist/src/tui/sse-consumer.d.ts +15 -0
- package/dist/src/tui/sse-consumer.js +75 -0
- package/dist/src/tui/sse-consumer.js.map +1 -0
- package/dist/src/tui/stream-assembler.d.ts +22 -0
- package/dist/src/tui/stream-assembler.js +63 -0
- package/dist/src/tui/stream-assembler.js.map +1 -0
- package/dist/src/tui/theme.d.ts +73 -0
- package/dist/src/tui/theme.js +157 -0
- package/dist/src/tui/theme.js.map +1 -0
- package/dist/src/tui/tui-agent-events.d.ts +7 -0
- package/dist/src/tui/tui-agent-events.js +103 -0
- package/dist/src/tui/tui-agent-events.js.map +1 -0
- package/dist/src/tui/tui-backend.d.ts +80 -0
- package/dist/src/tui/tui-backend.js +1 -0
- package/dist/src/tui/tui-commands.d.ts +23 -0
- package/dist/src/tui/tui-commands.js +165 -0
- package/dist/src/tui/tui-commands.js.map +1 -0
- package/dist/src/tui/tui-lifecycle.d.ts +26 -0
- package/dist/src/tui/tui-lifecycle.js +57 -0
- package/dist/src/tui/tui-lifecycle.js.map +1 -0
- package/dist/src/tui/tui-local-shell.d.ts +28 -0
- package/dist/src/tui/tui-local-shell.js +147 -0
- package/dist/src/tui/tui-local-shell.js.map +1 -0
- package/dist/src/tui/tui-overlays.d.ts +8 -0
- package/dist/src/tui/tui-overlays.js +22 -0
- package/dist/src/tui/tui-overlays.js.map +1 -0
- package/dist/src/tui/tui-picker-overlay.d.ts +26 -0
- package/dist/src/tui/tui-picker-overlay.js +69 -0
- package/dist/src/tui/tui-picker-overlay.js.map +1 -0
- package/dist/src/tui/tui-stdio-filter.d.ts +17 -0
- package/dist/src/tui/tui-stdio-filter.js +96 -0
- package/dist/src/tui/tui-stdio-filter.js.map +1 -0
- package/dist/src/tui/tui-submit.d.ts +25 -0
- package/dist/src/tui/tui-submit.js +102 -0
- package/dist/src/tui/tui-submit.js.map +1 -0
- package/dist/src/tui/tui-suspend.d.ts +10 -0
- package/dist/src/tui/tui-suspend.js +18 -0
- package/dist/src/tui/tui-suspend.js.map +1 -0
- package/dist/src/tui/tui-types.d.ts +86 -0
- package/dist/src/tui/tui-types.js +21 -0
- package/dist/src/tui/tui-types.js.map +1 -0
- package/dist/src/tui/tui.d.ts +5 -0
- package/dist/src/tui/tui.js +389 -0
- package/dist/src/tui/tui.js.map +1 -0
- package/package.json +5 -3
- package/dist/gateway/static/root/assets/agents-w8_jzuiX.js +0 -216
- package/dist/gateway/static/root/assets/agents-w8_jzuiX.js.map +0 -1
- package/dist/gateway/static/root/assets/channels-settings-DUKRPC7C.js +0 -9
- package/dist/gateway/static/root/assets/channels-settings-DUKRPC7C.js.map +0 -1
- package/dist/gateway/static/root/assets/cron-page-S18t1yG-.js +0 -2
- package/dist/gateway/static/root/assets/cron-page-S18t1yG-.js.map +0 -1
- package/dist/gateway/static/root/assets/index-OT4cGzon.css +0 -1
- package/dist/gateway/static/root/assets/index-PfkB8N37.js +0 -4734
- package/dist/gateway/static/root/assets/logs-page-DoWe1GWy.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-DoWe1GWy.js.map +0 -1
- package/dist/gateway/static/root/assets/sessions-page-2uOYwEwd.js +0 -2
- package/dist/gateway/static/root/assets/sessions-page-2uOYwEwd.js.map +0 -1
- package/dist/gateway/static/root/assets/settings-page-fQWswCuq.js +0 -2
- package/dist/gateway/static/root/assets/settings-page-fQWswCuq.js.map +0 -1
- package/dist/gateway/static/root/assets/skills-page-BmBDCEbY.js +0 -3
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "telegram",
|
|
3
3
|
"name": "Telegram Channel",
|
|
4
4
|
"description": "Bundled Telegram Bot channel (private workspace sources; ships inside @xopcai/xopc dist/)",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.29",
|
|
6
6
|
"kind": "channel",
|
|
7
7
|
"main": "src/index.ts",
|
|
8
8
|
"channels": ["telegram"],
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weixin interactive onboarding — {@link ChannelOnboardAdapter} (QR scan).
|
|
3
|
+
*/
|
|
4
|
+
import type { Config } from '@xopcai/xopc/config/schema.js';
|
|
5
|
+
import type { ChannelOnboardAdapter } from '@xopcai/xopc/channels/plugins/types.adapters.js';
|
|
6
|
+
export declare function isWeixinOnboardConfigured(config: Config): boolean;
|
|
7
|
+
export declare const weixinOnboardAdapter: ChannelOnboardAdapter;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { init_paths, resolveConfigPath } from "../../../../src/config/paths.js";
|
|
2
|
+
import { listWeixinAccountIds, resolveWeixinAccount } from "../auth/accounts.js";
|
|
3
|
+
import { mergeWeixinConfigAfterLogin, runWeixinQrLoginCli } from "../cli/qr-login.js";
|
|
4
|
+
import { confirm } from "@inquirer/prompts";
|
|
5
|
+
//#region extensions/weixin/src/adapters/onboard-cli.ts
|
|
6
|
+
/**
|
|
7
|
+
* Weixin interactive onboarding — {@link ChannelOnboardAdapter} (QR scan).
|
|
8
|
+
*/
|
|
9
|
+
init_paths();
|
|
10
|
+
function isWeixinOnboardConfigured(config) {
|
|
11
|
+
const ids = listWeixinAccountIds(config);
|
|
12
|
+
for (const id of ids) try {
|
|
13
|
+
if (resolveWeixinAccount(config, id).configured) return true;
|
|
14
|
+
} catch {}
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
function resolveCliConfigPath() {
|
|
18
|
+
return process.env.XOPC_CONFIG_PATH?.trim() || process.env.XOPC_CONFIG?.trim() || resolveConfigPath();
|
|
19
|
+
}
|
|
20
|
+
async function configureWeixin(config) {
|
|
21
|
+
console.log(`\n${"=".repeat(50)}`);
|
|
22
|
+
console.log("💬 Weixin (WeChat ilink)");
|
|
23
|
+
console.log(`${"=".repeat(50)}\n`);
|
|
24
|
+
if (isWeixinOnboardConfigured(config)) {
|
|
25
|
+
if (!await confirm({
|
|
26
|
+
message: "Weixin appears configured. Scan QR again to replace login?",
|
|
27
|
+
default: false
|
|
28
|
+
})) {
|
|
29
|
+
console.log("ℹ️ Weixin onboarding skipped.");
|
|
30
|
+
return config;
|
|
31
|
+
}
|
|
32
|
+
} else if (!await confirm({
|
|
33
|
+
message: "Log in with WeChat using a QR scan?",
|
|
34
|
+
default: true
|
|
35
|
+
})) {
|
|
36
|
+
console.log("ℹ️ Weixin onboarding skipped.");
|
|
37
|
+
console.log(" Configure later with: xopc channels login --channel weixin\n");
|
|
38
|
+
return config;
|
|
39
|
+
}
|
|
40
|
+
const result = await runWeixinQrLoginCli({
|
|
41
|
+
configPath: resolveCliConfigPath(),
|
|
42
|
+
writeConfig: true,
|
|
43
|
+
existingConfig: config
|
|
44
|
+
});
|
|
45
|
+
if (!result.ok || !result.accountId) {
|
|
46
|
+
console.log(`\n⚠️ ${result.message || "Weixin login did not complete."}`);
|
|
47
|
+
console.log(" You can retry from channel setup or run: xopc channels login --channel weixin\n");
|
|
48
|
+
return config;
|
|
49
|
+
}
|
|
50
|
+
const merged = mergeWeixinConfigAfterLogin(config, result.accountId);
|
|
51
|
+
console.log("\n✅ Weixin onboarding complete\n");
|
|
52
|
+
return merged;
|
|
53
|
+
}
|
|
54
|
+
const weixinOnboardAdapter = {
|
|
55
|
+
isConfigured: isWeixinOnboardConfigured,
|
|
56
|
+
configure: configureWeixin
|
|
57
|
+
};
|
|
58
|
+
//#endregion
|
|
59
|
+
export { isWeixinOnboardConfigured, weixinOnboardAdapter };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=onboard-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onboard-cli.js","names":[],"sources":["../../../../../extensions/weixin/src/adapters/onboard-cli.ts"],"sourcesContent":["/**\n * Weixin interactive onboarding — {@link ChannelOnboardAdapter} (QR scan).\n */\n\nimport { confirm } from '@inquirer/prompts';\n\nimport type { Config } from '@xopcai/xopc/config/schema.js';\nimport type { ChannelOnboardAdapter } from '@xopcai/xopc/channels/plugins/types.adapters.js';\nimport { resolveConfigPath } from '@xopcai/xopc/config/paths.js';\n\nimport { resolveWeixinAccount, listWeixinAccountIds } from '../auth/accounts.js';\nimport { mergeWeixinConfigAfterLogin, runWeixinQrLoginCli } from '../cli/qr-login.js';\n\nexport function isWeixinOnboardConfigured(config: Config): boolean {\n const ids = listWeixinAccountIds(config);\n for (const id of ids) {\n try {\n if (resolveWeixinAccount(config, id).configured) return true;\n } catch {\n // Skip invalid ids\n }\n }\n return false;\n}\n\nfunction resolveCliConfigPath(): string {\n return (\n process.env.XOPC_CONFIG_PATH?.trim() ||\n process.env.XOPC_CONFIG?.trim() ||\n resolveConfigPath()\n );\n}\n\nasync function configureWeixin(config: Config): Promise<Config> {\n console.log(`\\n${'='.repeat(50)}`);\n console.log('💬 Weixin (WeChat ilink)');\n console.log(`${'='.repeat(50)}\\n`);\n\n if (isWeixinOnboardConfigured(config)) {\n const rescan = await confirm({\n message: 'Weixin appears configured. Scan QR again to replace login?',\n default: false,\n });\n if (!rescan) {\n console.log('ℹ️ Weixin onboarding skipped.');\n return config;\n }\n } else {\n const proceed = await confirm({\n message: 'Log in with WeChat using a QR scan?',\n default: true,\n });\n if (!proceed) {\n console.log('ℹ️ Weixin onboarding skipped.');\n console.log(' Configure later with: xopc channels login --channel weixin\\n');\n return config;\n }\n }\n\n const configPath = resolveCliConfigPath();\n const result = await runWeixinQrLoginCli({\n configPath,\n writeConfig: true,\n existingConfig: config,\n });\n\n if (!result.ok || !result.accountId) {\n console.log(`\\n⚠️ ${result.message || 'Weixin login did not complete.'}`);\n console.log(' You can retry from channel setup or run: xopc channels login --channel weixin\\n');\n return config;\n }\n\n const merged = mergeWeixinConfigAfterLogin(config, result.accountId);\n console.log('\\n✅ Weixin onboarding complete\\n');\n return merged;\n}\n\nexport const weixinOnboardAdapter: ChannelOnboardAdapter = {\n isConfigured: isWeixinOnboardConfigured,\n configure: configureWeixin,\n};\n"],"mappings":";;;;;;;;YAQiE;AAKjE,SAAgB,0BAA0B,QAAyB;CACjE,MAAM,MAAM,qBAAqB,OAAO;AACxC,MAAK,MAAM,MAAM,IACf,KAAI;AACF,MAAI,qBAAqB,QAAQ,GAAG,CAAC,WAAY,QAAO;SAClD;AAIV,QAAO;;AAGT,SAAS,uBAA+B;AACtC,QACE,QAAQ,IAAI,kBAAkB,MAAM,IACpC,QAAQ,IAAI,aAAa,MAAM,IAC/B,mBAAmB;;AAIvB,eAAe,gBAAgB,QAAiC;AAC9D,SAAQ,IAAI,KAAK,IAAI,OAAO,GAAG,GAAG;AAClC,SAAQ,IAAI,2BAA2B;AACvC,SAAQ,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,IAAI;AAElC,KAAI,0BAA0B,OAAO;MAK/B,CAAC,MAJgB,QAAQ;GAC3B,SAAS;GACT,SAAS;GACV,CAAC,EACW;AACX,WAAQ,IAAI,iCAAiC;AAC7C,UAAO;;YAOL,CAAC,MAJiB,QAAQ;EAC5B,SAAS;EACT,SAAS;EACV,CAAC,EACY;AACZ,UAAQ,IAAI,iCAAiC;AAC7C,UAAQ,IAAI,kEAAkE;AAC9E,SAAO;;CAKX,MAAM,SAAS,MAAM,oBAAoB;EACvC,YAFiB,sBAEP;EACV,aAAa;EACb,gBAAgB;EACjB,CAAC;AAEF,KAAI,CAAC,OAAO,MAAM,CAAC,OAAO,WAAW;AACnC,UAAQ,IAAI,SAAS,OAAO,WAAW,mCAAmC;AAC1E,UAAQ,IAAI,qFAAqF;AACjG,SAAO;;CAGT,MAAM,SAAS,4BAA4B,QAAQ,OAAO,UAAU;AACpE,SAAQ,IAAI,mCAAmC;AAC/C,QAAO;;AAGT,MAAa,uBAA8C;CACzD,cAAc;CACd,WAAW;CACZ"}
|
|
@@ -12,6 +12,11 @@ export type WeixinQrLoginCliOptions = {
|
|
|
12
12
|
account?: string;
|
|
13
13
|
/** When true, merge `channels.weixin.enabled` and accounts entry after success. */
|
|
14
14
|
writeConfig?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* When set (e.g. interactive onboard), merges Weixin after login into this in-memory snapshot
|
|
17
|
+
* instead of reloading from disk so prior unsaved onboarding edits are preserved when saving.
|
|
18
|
+
*/
|
|
19
|
+
existingConfig?: Config;
|
|
15
20
|
};
|
|
16
21
|
export declare function getWeixinLoginApiContext(cfg: Config, accountHint?: string): {
|
|
17
22
|
baseUrl: string;
|
|
@@ -50,7 +50,7 @@ function mergeWeixinConfigAfterLogin(cfg, normalizedAccountId) {
|
|
|
50
50
|
*/
|
|
51
51
|
async function runWeixinQrLoginCli(opts) {
|
|
52
52
|
const configPath = opts.configPath ?? process.env.XOPC_CONFIG_PATH;
|
|
53
|
-
const cfg = loadConfig(configPath);
|
|
53
|
+
const cfg = opts.existingConfig ?? loadConfig(configPath);
|
|
54
54
|
const { baseUrl, routeTag } = getWeixinLoginApiContext(cfg, opts.account);
|
|
55
55
|
const timeoutMs = opts.timeoutMs ?? 48e4;
|
|
56
56
|
const verbose = Boolean(opts.verbose);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qr-login.js","names":[],"sources":["../../../../../extensions/weixin/src/cli/qr-login.ts"],"sourcesContent":["/**\n * CLI: Weixin QR login — start poll, show terminal QR, persist token + optional config merge.\n */\n\nimport type { Config } from '@xopcai/xopc/config/schema.js';\nimport { ConfigSchema } from '@xopcai/xopc/config/schema.js';\nimport { loadConfig, saveConfig } from '@xopcai/xopc/config/loader.js';\n\nimport {\n clearStaleAccountsForUserId,\n normalizeWeixinAccountId,\n registerWeixinAccountId,\n resolveWeixinAccount,\n saveWeixinAccount,\n DEFAULT_BASE_URL,\n} from '../auth/accounts.js';\nimport { clearContextTokensForAccount } from '../messaging/inbound.js';\nimport {\n DEFAULT_ILINK_BOT_TYPE,\n startWeixinLoginWithQr,\n waitForWeixinLogin,\n} from '../auth/login-qr.js';\nimport { logger } from '../util/logger.js';\n\nexport type WeixinQrLoginCliOptions = {\n /** Config file path (same as CLI --config / XOPC_CONFIG). */\n configPath?: string;\n verbose?: boolean;\n /** Client wait for scan (ms). */\n timeoutMs?: number;\n /** Existing account id to re-login, or omit for a new account session. */\n account?: string;\n /** When true, merge `channels.weixin.enabled` and accounts entry after success. */\n writeConfig?: boolean;\n};\n\nexport function getWeixinLoginApiContext(cfg: Config, accountHint?: string): { baseUrl: string; routeTag?: string } {\n const section = cfg.channels?.weixin as { routeTag?: string | number } | undefined;\n const routeTagRaw = section?.routeTag;\n const sectionRouteTag =\n typeof routeTagRaw === 'number'\n ? String(routeTagRaw)\n : typeof routeTagRaw === 'string' && routeTagRaw.trim()\n ? routeTagRaw.trim()\n : undefined;\n\n if (accountHint?.trim()) {\n try {\n const r = resolveWeixinAccount(cfg, accountHint);\n return { baseUrl: r.baseUrl, routeTag: r.routeTag ?? sectionRouteTag };\n } catch {\n // ignore\n }\n }\n return { baseUrl: DEFAULT_BASE_URL, routeTag: sectionRouteTag };\n}\n\nexport function mergeWeixinConfigAfterLogin(cfg: Config, normalizedAccountId: string): Config {\n const prev = cfg.channels?.weixin as Record<string, unknown> | undefined;\n const prevAccounts = (prev?.accounts as Record<string, Record<string, unknown>> | undefined) ?? {};\n const merged = {\n ...cfg,\n channels: {\n ...cfg.channels,\n weixin: {\n ...(prev ?? {}),\n enabled: true,\n accounts: {\n ...prevAccounts,\n [normalizedAccountId]: {\n ...(prevAccounts[normalizedAccountId] ?? {}),\n enabled: true,\n },\n },\n },\n },\n };\n return ConfigSchema.parse(merged);\n}\n\n/**\n * Run interactive Weixin QR login (terminal QR + long-poll until confirmed or timeout).\n */\nexport async function runWeixinQrLoginCli(opts: WeixinQrLoginCliOptions): Promise<{\n ok: boolean;\n accountId?: string;\n message: string;\n}> {\n const configPath = opts.configPath ?? process.env.XOPC_CONFIG_PATH;\n const cfg = loadConfig(configPath);\n const { baseUrl, routeTag } = getWeixinLoginApiContext(cfg, opts.account);\n const timeoutMs = opts.timeoutMs ?? 480_000;\n const verbose = Boolean(opts.verbose);\n\n console.log('\\n🔐 Weixin QR login');\n console.log(` API base: ${baseUrl}\\n`);\n\n const startResult = await startWeixinLoginWithQr({\n accountId: opts.account?.trim() || undefined,\n botType: DEFAULT_ILINK_BOT_TYPE,\n routeTag,\n verbose,\n });\n\n if (!startResult.qrcodeUrl) {\n return { ok: false, message: startResult.message || 'Failed to get QR code' };\n }\n\n console.log('Scan this QR code with WeChat:\\n');\n try {\n const qrcodeTerminal = await import(/* @vite-ignore */ 'qrcode-terminal');\n await new Promise<void>((resolve) => {\n qrcodeTerminal.default.generate(startResult.qrcodeUrl!, { small: true }, (qr: string) => {\n console.log(qr);\n resolve();\n });\n });\n } catch {\n console.log('Open this URL in a browser to scan:\\n');\n console.log(startResult.qrcodeUrl);\n }\n console.log('\\nWaiting for confirmation...\\n');\n\n const waitResult = await waitForWeixinLogin({\n sessionKey: startResult.sessionKey,\n timeoutMs,\n verbose,\n routeTag,\n botType: DEFAULT_ILINK_BOT_TYPE,\n });\n\n if (!waitResult.connected || !waitResult.botToken || !waitResult.accountId) {\n return {\n ok: false,\n message: waitResult.message || 'Login did not complete',\n };\n }\n\n const normalizedId = normalizeWeixinAccountId(waitResult.accountId);\n\n try {\n saveWeixinAccount(normalizedId, {\n token: waitResult.botToken,\n baseUrl: waitResult.baseUrl?.trim() || baseUrl,\n userId: waitResult.userId,\n });\n registerWeixinAccountId(normalizedId);\n if (waitResult.userId) {\n clearStaleAccountsForUserId(normalizedId, waitResult.userId, clearContextTokensForAccount);\n }\n } catch (err) {\n logger.error(`Failed to save Weixin account: ${String(err)}`);\n return { ok: false, message: `Saved login failed: ${String(err)}` };\n }\n\n if (opts.writeConfig !== false) {\n try {\n const next = mergeWeixinConfigAfterLogin(cfg, normalizedId);\n await saveConfig(next, configPath);\n } catch (err) {\n logger.warn(`Config merge failed (credentials saved on disk): ${String(err)}`);\n }\n }\n\n console.log(`\\n✅ Weixin connected as account \"${normalizedId}\".`);\n console.log(' Restart the gateway if it is already running.\\n');\n\n return { ok: true, accountId: normalizedId, message: 'OK' };\n}\n"],"mappings":";;;;;;;;aAK6D;aACU;
|
|
1
|
+
{"version":3,"file":"qr-login.js","names":[],"sources":["../../../../../extensions/weixin/src/cli/qr-login.ts"],"sourcesContent":["/**\n * CLI: Weixin QR login — start poll, show terminal QR, persist token + optional config merge.\n */\n\nimport type { Config } from '@xopcai/xopc/config/schema.js';\nimport { ConfigSchema } from '@xopcai/xopc/config/schema.js';\nimport { loadConfig, saveConfig } from '@xopcai/xopc/config/loader.js';\n\nimport {\n clearStaleAccountsForUserId,\n normalizeWeixinAccountId,\n registerWeixinAccountId,\n resolveWeixinAccount,\n saveWeixinAccount,\n DEFAULT_BASE_URL,\n} from '../auth/accounts.js';\nimport { clearContextTokensForAccount } from '../messaging/inbound.js';\nimport {\n DEFAULT_ILINK_BOT_TYPE,\n startWeixinLoginWithQr,\n waitForWeixinLogin,\n} from '../auth/login-qr.js';\nimport { logger } from '../util/logger.js';\n\nexport type WeixinQrLoginCliOptions = {\n /** Config file path (same as CLI --config / XOPC_CONFIG). */\n configPath?: string;\n verbose?: boolean;\n /** Client wait for scan (ms). */\n timeoutMs?: number;\n /** Existing account id to re-login, or omit for a new account session. */\n account?: string;\n /** When true, merge `channels.weixin.enabled` and accounts entry after success. */\n writeConfig?: boolean;\n /**\n * When set (e.g. interactive onboard), merges Weixin after login into this in-memory snapshot\n * instead of reloading from disk so prior unsaved onboarding edits are preserved when saving.\n */\n existingConfig?: Config;\n};\n\nexport function getWeixinLoginApiContext(cfg: Config, accountHint?: string): { baseUrl: string; routeTag?: string } {\n const section = cfg.channels?.weixin as { routeTag?: string | number } | undefined;\n const routeTagRaw = section?.routeTag;\n const sectionRouteTag =\n typeof routeTagRaw === 'number'\n ? String(routeTagRaw)\n : typeof routeTagRaw === 'string' && routeTagRaw.trim()\n ? routeTagRaw.trim()\n : undefined;\n\n if (accountHint?.trim()) {\n try {\n const r = resolveWeixinAccount(cfg, accountHint);\n return { baseUrl: r.baseUrl, routeTag: r.routeTag ?? sectionRouteTag };\n } catch {\n // ignore\n }\n }\n return { baseUrl: DEFAULT_BASE_URL, routeTag: sectionRouteTag };\n}\n\nexport function mergeWeixinConfigAfterLogin(cfg: Config, normalizedAccountId: string): Config {\n const prev = cfg.channels?.weixin as Record<string, unknown> | undefined;\n const prevAccounts = (prev?.accounts as Record<string, Record<string, unknown>> | undefined) ?? {};\n const merged = {\n ...cfg,\n channels: {\n ...cfg.channels,\n weixin: {\n ...(prev ?? {}),\n enabled: true,\n accounts: {\n ...prevAccounts,\n [normalizedAccountId]: {\n ...(prevAccounts[normalizedAccountId] ?? {}),\n enabled: true,\n },\n },\n },\n },\n };\n return ConfigSchema.parse(merged);\n}\n\n/**\n * Run interactive Weixin QR login (terminal QR + long-poll until confirmed or timeout).\n */\nexport async function runWeixinQrLoginCli(opts: WeixinQrLoginCliOptions): Promise<{\n ok: boolean;\n accountId?: string;\n message: string;\n}> {\n const configPath = opts.configPath ?? process.env.XOPC_CONFIG_PATH;\n const cfg = opts.existingConfig ?? loadConfig(configPath);\n const { baseUrl, routeTag } = getWeixinLoginApiContext(cfg, opts.account);\n const timeoutMs = opts.timeoutMs ?? 480_000;\n const verbose = Boolean(opts.verbose);\n\n console.log('\\n🔐 Weixin QR login');\n console.log(` API base: ${baseUrl}\\n`);\n\n const startResult = await startWeixinLoginWithQr({\n accountId: opts.account?.trim() || undefined,\n botType: DEFAULT_ILINK_BOT_TYPE,\n routeTag,\n verbose,\n });\n\n if (!startResult.qrcodeUrl) {\n return { ok: false, message: startResult.message || 'Failed to get QR code' };\n }\n\n console.log('Scan this QR code with WeChat:\\n');\n try {\n const qrcodeTerminal = await import(/* @vite-ignore */ 'qrcode-terminal');\n await new Promise<void>((resolve) => {\n qrcodeTerminal.default.generate(startResult.qrcodeUrl!, { small: true }, (qr: string) => {\n console.log(qr);\n resolve();\n });\n });\n } catch {\n console.log('Open this URL in a browser to scan:\\n');\n console.log(startResult.qrcodeUrl);\n }\n console.log('\\nWaiting for confirmation...\\n');\n\n const waitResult = await waitForWeixinLogin({\n sessionKey: startResult.sessionKey,\n timeoutMs,\n verbose,\n routeTag,\n botType: DEFAULT_ILINK_BOT_TYPE,\n });\n\n if (!waitResult.connected || !waitResult.botToken || !waitResult.accountId) {\n return {\n ok: false,\n message: waitResult.message || 'Login did not complete',\n };\n }\n\n const normalizedId = normalizeWeixinAccountId(waitResult.accountId);\n\n try {\n saveWeixinAccount(normalizedId, {\n token: waitResult.botToken,\n baseUrl: waitResult.baseUrl?.trim() || baseUrl,\n userId: waitResult.userId,\n });\n registerWeixinAccountId(normalizedId);\n if (waitResult.userId) {\n clearStaleAccountsForUserId(normalizedId, waitResult.userId, clearContextTokensForAccount);\n }\n } catch (err) {\n logger.error(`Failed to save Weixin account: ${String(err)}`);\n return { ok: false, message: `Saved login failed: ${String(err)}` };\n }\n\n if (opts.writeConfig !== false) {\n try {\n const next = mergeWeixinConfigAfterLogin(cfg, normalizedId);\n await saveConfig(next, configPath);\n } catch (err) {\n logger.warn(`Config merge failed (credentials saved on disk): ${String(err)}`);\n }\n }\n\n console.log(`\\n✅ Weixin connected as account \"${normalizedId}\".`);\n console.log(' Restart the gateway if it is already running.\\n');\n\n return { ok: true, accountId: normalizedId, message: 'OK' };\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { normalizeWeixinCronDeliveryTo, normalizeWeixinCronDeliveryToResolved, resolveWeixinAccountIdFromSessions } from "./delivery-to.js";
|
|
2
|
-
import { WeixinChannelPlugin, weixinPlugin } from "./plugin.js";
|
|
3
2
|
import { runWeixinQrLoginCli } from "./cli/qr-login.js";
|
|
3
|
+
import { WeixinChannelPlugin, weixinPlugin } from "./plugin.js";
|
|
4
4
|
import { getWeixinGatewayQrLoginStatus, startWeixinGatewayQrLogin } from "./cli/gateway-qr-login.js";
|
|
5
5
|
export { WeixinChannelPlugin, getWeixinGatewayQrLoginStatus, normalizeWeixinCronDeliveryTo, normalizeWeixinCronDeliveryToResolved, resolveWeixinAccountIdFromSessions, runWeixinQrLoginCli, startWeixinGatewayQrLogin, weixinPlugin };
|
|
@@ -30,6 +30,7 @@ export declare class WeixinChannelPlugin implements ChannelPlugin<ResolvedWeixin
|
|
|
30
30
|
};
|
|
31
31
|
};
|
|
32
32
|
readonly cronDelivery: ChannelCronDeliveryAdapter;
|
|
33
|
+
readonly onboard: import("@xopcai/xopc/channels/plugins/types.adapters.js").ChannelOnboardAdapter;
|
|
33
34
|
readonly cliLogin: ChannelCliLoginAdapter;
|
|
34
35
|
readonly configSurface: import("@xopcai/xopc/channels/plugins/types.adapters.js").ChannelConfigSurfaceAdapter;
|
|
35
36
|
readonly defaults: ChannelPluginDefaults;
|
|
@@ -9,6 +9,7 @@ import { monitorWeixinProvider } from "./monitor/monitor.js";
|
|
|
9
9
|
import { createWeixinOutboundHandlers, weixinTextChunker } from "./outbound-send.js";
|
|
10
10
|
import { normalizeWeixinCronDeliveryToResolved } from "./delivery-to.js";
|
|
11
11
|
import { weixinConfigSurface } from "./config-surface.js";
|
|
12
|
+
import { weixinOnboardAdapter } from "./adapters/onboard-cli.js";
|
|
12
13
|
import { isDeepStrictEqual } from "node:util";
|
|
13
14
|
//#region extensions/weixin/src/plugin.ts
|
|
14
15
|
/**
|
|
@@ -54,6 +55,7 @@ var WeixinChannelPlugin = class {
|
|
|
54
55
|
accountId
|
|
55
56
|
};
|
|
56
57
|
} };
|
|
58
|
+
onboard = weixinOnboardAdapter;
|
|
57
59
|
cliLogin = { async runLogin(params) {
|
|
58
60
|
const { runWeixinQrLoginCli } = await import("./cli/qr-login.js");
|
|
59
61
|
return runWeixinQrLoginCli({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","names":[],"sources":["../../../../extensions/weixin/src/plugin.ts"],"sourcesContent":["/**\n * Weixin (WeChat ilink) channel — long-poll getUpdates, QR login, direct messages only.\n */\n\nimport { isDeepStrictEqual } from 'node:util';\n\nimport type { Config } from '@xopcai/xopc/config/schema.js';\nimport type { MessageBus } from '@xopcai/xopc/infra/bus/index.js';\nimport type {\n ChannelCapabilities,\n ChannelPlugin,\n ChannelPluginDefaults,\n ChannelPluginInitOptions,\n ChannelPluginReloadMeta,\n ChannelPluginStartOptions,\n ChannelSecurityContext,\n ChannelStreamingAdapter,\n ChatType,\n} from '@xopcai/xopc/channels/plugin-types.js';\nimport { evaluateAccess, resolveDmPolicy } from '@xopcai/xopc/channels/security.js';\nimport { createLogger } from '@xopcai/xopc/utils/logger.js';\n\nimport { restoreContextTokens } from './messaging/inbound.js';\nimport { monitorWeixinProvider } from './monitor/monitor.js';\nimport type { ChannelCliLoginAdapter, ChannelCronDeliveryAdapter } from '@xopcai/xopc/channels/plugins/types.adapters.js';\nimport {\n listWeixinAccountIds,\n resolveWeixinAccount,\n type ResolvedWeixinAccount,\n} from './auth/accounts.js';\nimport { readFrameworkAllowFromList } from './auth/pairing.js';\nimport { createWeixinOutboundHandlers, weixinTextChunker } from './outbound-send.js';\nimport { normalizeWeixinCronDeliveryToResolved } from './delivery-to.js';\nimport { weixinConfigSurface } from './config-surface.js';\nimport { WeixinConfigSchema } from './config-schema.js';\n\nconst log = createLogger('WeixinPlugin');\n\nexport class WeixinChannelPlugin implements ChannelPlugin<ResolvedWeixinAccount> {\n readonly id = 'weixin' as const;\n\n readonly reload: ChannelPluginReloadMeta = {\n configPrefixes: ['channels.weixin'],\n };\n\n readonly meta = {\n id: 'weixin',\n label: 'Weixin',\n selectionLabel: 'Weixin (ilink)',\n docsPath: '/channels/weixin',\n blurb: 'WeChat via Tencent ilink bot API (QR login, direct chat).',\n order: 3,\n } as const;\n\n readonly capabilities: ChannelCapabilities = {\n chatTypes: ['direct'] as ChatType[],\n reactions: false,\n threads: false,\n media: true,\n polls: false,\n nativeCommands: false,\n blockStreaming: true,\n };\n\n readonly configSchema = {\n schema: {},\n validate: (raw: unknown) => {\n const r = WeixinConfigSchema.safeParse(raw);\n return r.success ? { ok: true as const } : { ok: false as const, errors: [r.error.message] };\n },\n };\n\n readonly cronDelivery: ChannelCronDeliveryAdapter = {\n async normalizeDeliveryTarget(to, sessionStore) {\n const { chatId, accountId } = await normalizeWeixinCronDeliveryToResolved(to, sessionStore);\n return { chatId, accountId };\n },\n };\n\n readonly cliLogin: ChannelCliLoginAdapter = {\n async runLogin(params) {\n const { runWeixinQrLoginCli } = await import('./cli/qr-login.js');\n return runWeixinQrLoginCli({\n configPath: params.configPath,\n verbose: params.verbose,\n timeoutMs: params.timeoutMs,\n account: params.accountId,\n writeConfig: params.writeConfig,\n });\n },\n };\n\n readonly configSurface = weixinConfigSurface;\n\n readonly defaults: ChannelPluginDefaults = {\n queue: { debounceMs: 0 },\n outbound: { textChunkLimit: 4000 },\n streaming: {\n blockStreamingCoalesce: {\n minChars: 200,\n idleMs: 3000,\n },\n },\n };\n\n private bus!: ChannelPluginInitOptions['bus'];\n private cfg!: Config;\n private abortControllers = new Map<string, AbortController>();\n\n config = {\n listAccountIds: (cfg: Config) => listWeixinAccountIds(cfg),\n resolveAccount: (cfg: Config, accountId?: string | null) => resolveWeixinAccount(cfg, accountId),\n isConfigured: async (account: ResolvedWeixinAccount) => account.configured,\n describeAccount: (account: ResolvedWeixinAccount, _cfg: Config) => ({\n accountId: account.accountId,\n channelId: 'weixin',\n name: account.name,\n enabled: account.enabled,\n configured: account.configured,\n status: undefined,\n }),\n };\n\n security = {\n resolveDmPolicy: ({ account }: { account: ResolvedWeixinAccount }) =>\n resolveDmPolicy(account.dmPolicy, 'pairing'),\n checkAccess: (ctx: ChannelSecurityContext, account: ResolvedWeixinAccount, _cfg: Config) => {\n const allowFrom = [...(account.allowFrom ?? []), ...readFrameworkAllowFromList(account.accountId)];\n return evaluateAccess({\n context: {\n channel: 'weixin',\n accountId: account.accountId,\n chatId: ctx.chatId,\n senderId: ctx.senderId,\n senderName: ctx.senderName,\n isGroup: false,\n isDm: true,\n },\n dmPolicy: account.dmPolicy,\n allowFrom,\n });\n },\n };\n\n outbound = {\n deliveryMode: 'direct' as const,\n chunker: weixinTextChunker,\n chunkerMode: 'text' as const,\n textChunkLimit: 4000,\n ...createWeixinOutboundHandlers(),\n };\n\n streaming: ChannelStreamingAdapter = {\n startStream: () => null,\n };\n\n /** Channel plugin hints (cron targets, media paths). */\n agentPrompt = {\n augmentSystemPrompt: (): string =>\n [\n 'Weixin (ilink): direct chat only. To send an image or file, use the message tool with action send and set media to a local absolute path or an HTTPS URL; relative paths may fail.',\n 'For cron or scheduled delivery to a Weixin contact, set delivery.to to the user Weixin id (ending in @im.wechat) and delivery.accountId to the bot account id, or outbound may pick the wrong account.',\n 'When using MEDIA: to attach a file, put the MEDIA: line alone on its own line, not inline with other text.',\n ].join('\\n'),\n };\n\n async init(options: ChannelPluginInitOptions): Promise<void> {\n this.bus = options.bus;\n this.cfg = options.config;\n log.debug('Weixin plugin initialized');\n }\n\n async start(options?: ChannelPluginStartOptions): Promise<void> {\n const ids = options?.accountId\n ? [options.accountId]\n : listWeixinAccountIds(this.cfg);\n\n for (const accountId of ids) {\n const account = resolveWeixinAccount(this.cfg, accountId);\n if (!account.enabled || !account.configured || !account.token) continue;\n\n if (this.abortControllers.has(accountId)) continue;\n\n restoreContextTokens(account.accountId);\n\n const ac = new AbortController();\n this.abortControllers.set(accountId, ac);\n\n void monitorWeixinProvider({\n account,\n config: this.cfg,\n bus: this.bus,\n abortSignal: ac.signal,\n }).catch((err) => {\n if ((err as { name?: string; message?: string } | undefined)?.name === 'AbortError') {\n log.debug({ accountId }, 'Weixin monitor stopped');\n return;\n }\n log.error({ err, accountId }, 'Weixin monitor exited with error');\n });\n\n log.info({ accountId }, 'Weixin monitor started');\n }\n }\n\n async stop(accountId?: string): Promise<void> {\n const ids = accountId ? [accountId] : [...this.abortControllers.keys()];\n for (const id of ids) {\n const ac = this.abortControllers.get(id);\n if (ac) {\n ac.abort();\n this.abortControllers.delete(id);\n }\n }\n }\n\n channelIsRunning(cfg: Config): boolean {\n return listWeixinAccountIds(cfg).some((id) => {\n const a = resolveWeixinAccount(cfg, id);\n return a.configured && a.enabled !== false && this.abortControllers.has(id);\n });\n }\n\n async onConfigUpdated(cfg: Config): Promise<void> {\n const prevWx = this.cfg.channels?.weixin as unknown;\n const nextWx = cfg.channels?.weixin as { enabled?: boolean } | undefined;\n const channelOff = !nextWx || nextWx.enabled !== true;\n\n if (channelOff) {\n this.cfg = cfg;\n await this.stop();\n return;\n }\n\n this.cfg = cfg;\n\n if (isDeepStrictEqual(prevWx, nextWx) && this.channelIsRunning(cfg)) {\n return;\n }\n\n await this.stop();\n await this.start();\n }\n\n /**\n * Restart long-poll monitors after credentials were written to disk without a `channels.weixin` JSON\n * delta (e.g. only token files / account index updated). Gateway calls this after QR login completes.\n *\n * Pass `bus` explicitly: if Weixin was disabled at gateway boot, `init()` was skipped and `this.bus` was never set.\n */\n async reloadMonitorsWithConfig(cfg: Config, bus: MessageBus): Promise<void> {\n this.bus = bus;\n this.cfg = cfg;\n await this.stop();\n await this.start();\n }\n}\n\nexport const weixinPlugin = new WeixinChannelPlugin();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugin.js","names":[],"sources":["../../../../extensions/weixin/src/plugin.ts"],"sourcesContent":["/**\n * Weixin (WeChat ilink) channel — long-poll getUpdates, QR login, direct messages only.\n */\n\nimport { isDeepStrictEqual } from 'node:util';\n\nimport type { Config } from '@xopcai/xopc/config/schema.js';\nimport type { MessageBus } from '@xopcai/xopc/infra/bus/index.js';\nimport type {\n ChannelCapabilities,\n ChannelPlugin,\n ChannelPluginDefaults,\n ChannelPluginInitOptions,\n ChannelPluginReloadMeta,\n ChannelPluginStartOptions,\n ChannelSecurityContext,\n ChannelStreamingAdapter,\n ChatType,\n} from '@xopcai/xopc/channels/plugin-types.js';\nimport { evaluateAccess, resolveDmPolicy } from '@xopcai/xopc/channels/security.js';\nimport { createLogger } from '@xopcai/xopc/utils/logger.js';\n\nimport { restoreContextTokens } from './messaging/inbound.js';\nimport { monitorWeixinProvider } from './monitor/monitor.js';\nimport type { ChannelCliLoginAdapter, ChannelCronDeliveryAdapter } from '@xopcai/xopc/channels/plugins/types.adapters.js';\nimport {\n listWeixinAccountIds,\n resolveWeixinAccount,\n type ResolvedWeixinAccount,\n} from './auth/accounts.js';\nimport { readFrameworkAllowFromList } from './auth/pairing.js';\nimport { createWeixinOutboundHandlers, weixinTextChunker } from './outbound-send.js';\nimport { normalizeWeixinCronDeliveryToResolved } from './delivery-to.js';\nimport { weixinConfigSurface } from './config-surface.js';\nimport { WeixinConfigSchema } from './config-schema.js';\nimport { weixinOnboardAdapter } from './adapters/onboard-cli.js';\n\nconst log = createLogger('WeixinPlugin');\n\nexport class WeixinChannelPlugin implements ChannelPlugin<ResolvedWeixinAccount> {\n readonly id = 'weixin' as const;\n\n readonly reload: ChannelPluginReloadMeta = {\n configPrefixes: ['channels.weixin'],\n };\n\n readonly meta = {\n id: 'weixin',\n label: 'Weixin',\n selectionLabel: 'Weixin (ilink)',\n docsPath: '/channels/weixin',\n blurb: 'WeChat via Tencent ilink bot API (QR login, direct chat).',\n order: 3,\n } as const;\n\n readonly capabilities: ChannelCapabilities = {\n chatTypes: ['direct'] as ChatType[],\n reactions: false,\n threads: false,\n media: true,\n polls: false,\n nativeCommands: false,\n blockStreaming: true,\n };\n\n readonly configSchema = {\n schema: {},\n validate: (raw: unknown) => {\n const r = WeixinConfigSchema.safeParse(raw);\n return r.success ? { ok: true as const } : { ok: false as const, errors: [r.error.message] };\n },\n };\n\n readonly cronDelivery: ChannelCronDeliveryAdapter = {\n async normalizeDeliveryTarget(to, sessionStore) {\n const { chatId, accountId } = await normalizeWeixinCronDeliveryToResolved(to, sessionStore);\n return { chatId, accountId };\n },\n };\n\n readonly onboard = weixinOnboardAdapter;\n\n readonly cliLogin: ChannelCliLoginAdapter = {\n async runLogin(params) {\n const { runWeixinQrLoginCli } = await import('./cli/qr-login.js');\n return runWeixinQrLoginCli({\n configPath: params.configPath,\n verbose: params.verbose,\n timeoutMs: params.timeoutMs,\n account: params.accountId,\n writeConfig: params.writeConfig,\n });\n },\n };\n\n readonly configSurface = weixinConfigSurface;\n\n readonly defaults: ChannelPluginDefaults = {\n queue: { debounceMs: 0 },\n outbound: { textChunkLimit: 4000 },\n streaming: {\n blockStreamingCoalesce: {\n minChars: 200,\n idleMs: 3000,\n },\n },\n };\n\n private bus!: ChannelPluginInitOptions['bus'];\n private cfg!: Config;\n private abortControllers = new Map<string, AbortController>();\n\n config = {\n listAccountIds: (cfg: Config) => listWeixinAccountIds(cfg),\n resolveAccount: (cfg: Config, accountId?: string | null) => resolveWeixinAccount(cfg, accountId),\n isConfigured: async (account: ResolvedWeixinAccount) => account.configured,\n describeAccount: (account: ResolvedWeixinAccount, _cfg: Config) => ({\n accountId: account.accountId,\n channelId: 'weixin',\n name: account.name,\n enabled: account.enabled,\n configured: account.configured,\n status: undefined,\n }),\n };\n\n security = {\n resolveDmPolicy: ({ account }: { account: ResolvedWeixinAccount }) =>\n resolveDmPolicy(account.dmPolicy, 'pairing'),\n checkAccess: (ctx: ChannelSecurityContext, account: ResolvedWeixinAccount, _cfg: Config) => {\n const allowFrom = [...(account.allowFrom ?? []), ...readFrameworkAllowFromList(account.accountId)];\n return evaluateAccess({\n context: {\n channel: 'weixin',\n accountId: account.accountId,\n chatId: ctx.chatId,\n senderId: ctx.senderId,\n senderName: ctx.senderName,\n isGroup: false,\n isDm: true,\n },\n dmPolicy: account.dmPolicy,\n allowFrom,\n });\n },\n };\n\n outbound = {\n deliveryMode: 'direct' as const,\n chunker: weixinTextChunker,\n chunkerMode: 'text' as const,\n textChunkLimit: 4000,\n ...createWeixinOutboundHandlers(),\n };\n\n streaming: ChannelStreamingAdapter = {\n startStream: () => null,\n };\n\n /** Channel plugin hints (cron targets, media paths). */\n agentPrompt = {\n augmentSystemPrompt: (): string =>\n [\n 'Weixin (ilink): direct chat only. To send an image or file, use the message tool with action send and set media to a local absolute path or an HTTPS URL; relative paths may fail.',\n 'For cron or scheduled delivery to a Weixin contact, set delivery.to to the user Weixin id (ending in @im.wechat) and delivery.accountId to the bot account id, or outbound may pick the wrong account.',\n 'When using MEDIA: to attach a file, put the MEDIA: line alone on its own line, not inline with other text.',\n ].join('\\n'),\n };\n\n async init(options: ChannelPluginInitOptions): Promise<void> {\n this.bus = options.bus;\n this.cfg = options.config;\n log.debug('Weixin plugin initialized');\n }\n\n async start(options?: ChannelPluginStartOptions): Promise<void> {\n const ids = options?.accountId\n ? [options.accountId]\n : listWeixinAccountIds(this.cfg);\n\n for (const accountId of ids) {\n const account = resolveWeixinAccount(this.cfg, accountId);\n if (!account.enabled || !account.configured || !account.token) continue;\n\n if (this.abortControllers.has(accountId)) continue;\n\n restoreContextTokens(account.accountId);\n\n const ac = new AbortController();\n this.abortControllers.set(accountId, ac);\n\n void monitorWeixinProvider({\n account,\n config: this.cfg,\n bus: this.bus,\n abortSignal: ac.signal,\n }).catch((err) => {\n if ((err as { name?: string; message?: string } | undefined)?.name === 'AbortError') {\n log.debug({ accountId }, 'Weixin monitor stopped');\n return;\n }\n log.error({ err, accountId }, 'Weixin monitor exited with error');\n });\n\n log.info({ accountId }, 'Weixin monitor started');\n }\n }\n\n async stop(accountId?: string): Promise<void> {\n const ids = accountId ? [accountId] : [...this.abortControllers.keys()];\n for (const id of ids) {\n const ac = this.abortControllers.get(id);\n if (ac) {\n ac.abort();\n this.abortControllers.delete(id);\n }\n }\n }\n\n channelIsRunning(cfg: Config): boolean {\n return listWeixinAccountIds(cfg).some((id) => {\n const a = resolveWeixinAccount(cfg, id);\n return a.configured && a.enabled !== false && this.abortControllers.has(id);\n });\n }\n\n async onConfigUpdated(cfg: Config): Promise<void> {\n const prevWx = this.cfg.channels?.weixin as unknown;\n const nextWx = cfg.channels?.weixin as { enabled?: boolean } | undefined;\n const channelOff = !nextWx || nextWx.enabled !== true;\n\n if (channelOff) {\n this.cfg = cfg;\n await this.stop();\n return;\n }\n\n this.cfg = cfg;\n\n if (isDeepStrictEqual(prevWx, nextWx) && this.channelIsRunning(cfg)) {\n return;\n }\n\n await this.stop();\n await this.start();\n }\n\n /**\n * Restart long-poll monitors after credentials were written to disk without a `channels.weixin` JSON\n * delta (e.g. only token files / account index updated). Gateway calls this after QR login completes.\n *\n * Pass `bus` explicitly: if Weixin was disabled at gateway boot, `init()` was skipped and `this.bus` was never set.\n */\n async reloadMonitorsWithConfig(cfg: Config, bus: MessageBus): Promise<void> {\n this.bus = bus;\n this.cfg = cfg;\n await this.stop();\n await this.start();\n }\n}\n\nexport const weixinPlugin = new WeixinChannelPlugin();\n"],"mappings":"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"}
|