@zhin.js/scaffold-wizard 0.1.9 → 0.2.1
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/README.md +2 -1
- package/lib/adapter-configurers.d.ts +10 -0
- package/lib/adapter-configurers.d.ts.map +1 -1
- package/lib/adapter-configurers.js +428 -24
- package/lib/adapter-configurers.js.map +1 -1
- package/lib/adapter.d.ts +43 -0
- package/lib/adapter.d.ts.map +1 -1
- package/lib/adapter.js +163 -33
- package/lib/adapter.js.map +1 -1
- package/lib/ai.d.ts +6 -0
- package/lib/ai.d.ts.map +1 -1
- package/lib/ai.js +20 -4
- package/lib/ai.js.map +1 -1
- package/lib/apply.d.ts +11 -6
- package/lib/apply.d.ts.map +1 -1
- package/lib/apply.js +84 -15
- package/lib/apply.js.map +1 -1
- package/lib/env.d.ts +14 -0
- package/lib/env.d.ts.map +1 -0
- package/lib/env.js +89 -0
- package/lib/env.js.map +1 -0
- package/lib/index.d.ts +4 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -2
- package/lib/index.js.map +1 -1
- package/lib/optional-peers.d.ts.map +1 -1
- package/lib/optional-peers.js +11 -0
- package/lib/optional-peers.js.map +1 -1
- package/lib/project-config-plan.d.ts +0 -1
- package/lib/project-config-plan.d.ts.map +1 -1
- package/lib/project-config-plan.js +0 -8
- package/lib/project-config-plan.js.map +1 -1
- package/lib/project-deps.d.ts +2 -1
- package/lib/project-deps.d.ts.map +1 -1
- package/lib/project-deps.js +13 -4
- package/lib/project-deps.js.map +1 -1
- package/lib/weixin-ilink-login.d.ts +33 -0
- package/lib/weixin-ilink-login.d.ts.map +1 -0
- package/lib/weixin-ilink-login.js +90 -0
- package/lib/weixin-ilink-login.js.map +1 -0
- package/lib/zhin-stack-deps.d.ts +4 -3
- package/lib/zhin-stack-deps.d.ts.map +1 -1
- package/lib/zhin-stack-deps.js +4 -20
- package/lib/zhin-stack-deps.js.map +1 -1
- package/package.json +3 -1
- package/src/adapter-configurers.ts +456 -24
- package/src/adapter.ts +171 -34
- package/src/ai.ts +21 -4
- package/src/apply.ts +98 -14
- package/src/env.ts +113 -0
- package/src/index.ts +12 -2
- package/src/optional-peers.ts +9 -0
- package/src/project-config-plan.ts +0 -9
- package/src/project-deps.ts +13 -4
- package/src/stack-versions.generated.json +36 -38
- package/src/weixin-ilink-login.ts +151 -0
- package/src/zhin-stack-deps.ts +4 -22
package/src/index.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export type { InitOptions, DatabaseConfig } from './types.js';
|
|
2
2
|
export { DATABASE_PACKAGES } from './types.js';
|
|
3
3
|
|
|
4
|
-
export type { AdapterSetupResult, AdapterPluginInstance } from './adapter.js';
|
|
4
|
+
export type { AdapterSetupResult, AdapterPluginInstance, AdapterDefinition } from './adapter.js';
|
|
5
5
|
export {
|
|
6
|
+
ADAPTERS,
|
|
7
|
+
findAdapterByPackage,
|
|
6
8
|
configureAdapters,
|
|
9
|
+
buildFieldBasedInstanceConfig,
|
|
7
10
|
generateAdapterEnvVars,
|
|
8
11
|
collectAdapterPluginConfigs,
|
|
9
12
|
collectAdapterPluginManifest,
|
|
@@ -30,6 +33,12 @@ export {
|
|
|
30
33
|
|
|
31
34
|
export { configureDatabaseOptions } from './database.js';
|
|
32
35
|
|
|
36
|
+
export {
|
|
37
|
+
formatEnvValue,
|
|
38
|
+
mergeEnvText,
|
|
39
|
+
generateDatabaseEnvVars,
|
|
40
|
+
} from './env.js';
|
|
41
|
+
|
|
33
42
|
export {
|
|
34
43
|
AI_STACK_VERSIONS,
|
|
35
44
|
MCP_SDK_VERSION,
|
|
@@ -99,13 +108,14 @@ export type {
|
|
|
99
108
|
} from './project-config-plan.js';
|
|
100
109
|
|
|
101
110
|
export {
|
|
102
|
-
CONSOLE_HOST_PLUGINS,
|
|
103
111
|
applyDatabaseToConfig,
|
|
104
112
|
applyAdaptersToConfig,
|
|
105
113
|
applyAIToConfig,
|
|
106
114
|
appendWizardEnvVars,
|
|
107
115
|
collectWizardDependencies,
|
|
116
|
+
collectWizardFeatures,
|
|
108
117
|
mergeDependenciesIntoPackageJson,
|
|
118
|
+
mergeFeaturesIntoPackageJson,
|
|
109
119
|
mergePluginManifestIntoPackageJson,
|
|
110
120
|
finalizeWizardOptions,
|
|
111
121
|
applyWizardOptionsToConfig,
|
package/src/optional-peers.ts
CHANGED
|
@@ -46,6 +46,15 @@ function configUsesHtmlImageAdapter(config: Record<string, unknown>): boolean {
|
|
|
46
46
|
if (plugin.includes(`adapter-${ctx}`)) return true;
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
+
// 新 runtime 配置形态:plugins 为 instanceKey → 配置 的映射,instanceKey 即适配器 context
|
|
50
|
+
if (config.plugins && typeof config.plugins === 'object' && !Array.isArray(config.plugins)) {
|
|
51
|
+
for (const instanceKey of Object.keys(config.plugins as Record<string, unknown>)) {
|
|
52
|
+
if (ADAPTERS_PREFER_HTML_IMAGE.has(instanceKey)) return true;
|
|
53
|
+
for (const ctx of ADAPTERS_PREFER_HTML_IMAGE) {
|
|
54
|
+
if (instanceKey.includes(`adapter-${ctx}`)) return true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
49
58
|
const endpoints = Array.isArray(config.endpoints) ? config.endpoints : [];
|
|
50
59
|
for (const ep of endpoints) {
|
|
51
60
|
if (!ep || typeof ep !== 'object' || Array.isArray(ep)) continue;
|
|
@@ -12,8 +12,6 @@ const CONFIG_CANDIDATES = [
|
|
|
12
12
|
'zhin.config.toml',
|
|
13
13
|
'zhin.config.ts',
|
|
14
14
|
] as const;
|
|
15
|
-
/** @deprecated Plugin Runtime 由 CLI 装配 Console Host,无需在配置中声明;仅用于 legacy 数组配置诊断 */
|
|
16
|
-
const CONSOLE_HOST_PLUGINS = ['@zhin.js/host-router', '@zhin.js/host-api'] as const;
|
|
17
15
|
const SANDBOX_PLUGIN = '@zhin.js/adapter-sandbox';
|
|
18
16
|
const LEGACY_AI_PROVIDER_FIELDS = ['driver', 'api', 'preset', 'spec'] as const;
|
|
19
17
|
|
|
@@ -66,7 +64,6 @@ export interface ProjectConfigPlan {
|
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
export interface ConsoleConfigDiagnosis {
|
|
69
|
-
missingHostPlugins: string[];
|
|
70
67
|
missingSandboxPlugin: boolean;
|
|
71
68
|
missingConsoleOrigin: boolean;
|
|
72
69
|
missingHttpToken: boolean;
|
|
@@ -344,10 +341,6 @@ export function createProjectConfigPlan(options: ProjectConfigPlanOptions): Proj
|
|
|
344
341
|
const mutations: string[] = [];
|
|
345
342
|
|
|
346
343
|
if (loaded.status === 'loaded' || options.config) {
|
|
347
|
-
if (options.ensureConsole && Array.isArray(after.plugins)) {
|
|
348
|
-
// legacy 数组形态:host 插件仍需写入列表(旧项目行为不变)
|
|
349
|
-
ensurePlugins(after, CONSOLE_HOST_PLUGINS, mutations);
|
|
350
|
-
}
|
|
351
344
|
if (options.ensureSandbox) {
|
|
352
345
|
ensurePlugins(after, [SANDBOX_PLUGIN], mutations);
|
|
353
346
|
}
|
|
@@ -406,7 +399,6 @@ export function diagnoseConsoleConfig(config: Record<string, unknown>): ConsoleC
|
|
|
406
399
|
// legacy 数组形式配置
|
|
407
400
|
const plugins = config.plugins.filter((p): p is string => typeof p === 'string');
|
|
408
401
|
return {
|
|
409
|
-
missingHostPlugins: CONSOLE_HOST_PLUGINS.filter((plugin) => !plugins.includes(plugin)),
|
|
410
402
|
missingSandboxPlugin: !plugins.includes(SANDBOX_PLUGIN),
|
|
411
403
|
missingConsoleOrigin: !hasConsoleOrigin(corsOrigins.filter((origin): origin is string => typeof origin === 'string')),
|
|
412
404
|
missingHttpToken: typeof http.token !== 'string' || http.token.trim().length === 0,
|
|
@@ -418,7 +410,6 @@ export function diagnoseConsoleConfig(config: Record<string, unknown>): ConsoleC
|
|
|
418
410
|
? config.plugins as Record<string, unknown>
|
|
419
411
|
: {};
|
|
420
412
|
return {
|
|
421
|
-
missingHostPlugins: [],
|
|
422
413
|
missingSandboxPlugin: !('sandbox' in plugins),
|
|
423
414
|
missingConsoleOrigin: !hasConsoleOrigin(corsOrigins.filter((origin): origin is string => typeof origin === 'string')),
|
|
424
415
|
missingHttpToken: typeof http.token !== 'string' || http.token.trim().length === 0,
|
package/src/project-deps.ts
CHANGED
|
@@ -211,7 +211,7 @@ export function findInstalledAiStackIncompatibilities(
|
|
|
211
211
|
/** 启用 AI 时将写入 package.json 的依赖名(用于向导提示与 CLI 输出) */
|
|
212
212
|
export function listAIDependencyNames(provider?: string, options?: { includeMcp?: boolean }): string[] {
|
|
213
213
|
const names = ['@zhin.js/agent', 'zod', 'ai'];
|
|
214
|
-
if (options?.includeMcp
|
|
214
|
+
if (options?.includeMcp === true) {
|
|
215
215
|
names.push('@modelcontextprotocol/sdk');
|
|
216
216
|
}
|
|
217
217
|
const sdk = providerSdkPackage(provider);
|
|
@@ -314,7 +314,11 @@ export function findUnresolvedPackageInstalls(cwd: string, packageNames: string[
|
|
|
314
314
|
try {
|
|
315
315
|
req.resolve(`${name}/package.json`);
|
|
316
316
|
} catch {
|
|
317
|
-
|
|
317
|
+
// exports map 未暴露 ./package.json(ERR_PACKAGE_PATH_NOT_EXPORTED,如 zhin.js)
|
|
318
|
+
// 时 resolve 必炸,退到 node_modules 文件系统判断(pnpm 顶层 symlink 可直达)。
|
|
319
|
+
if (!fs.existsSync(path.join(cwd, 'node_modules', name, 'package.json'))) {
|
|
320
|
+
missing.push(name);
|
|
321
|
+
}
|
|
318
322
|
}
|
|
319
323
|
}
|
|
320
324
|
return missing;
|
|
@@ -376,7 +380,8 @@ export function formatAIDependencyFixCommand(packages: string[], required: Recor
|
|
|
376
380
|
}
|
|
377
381
|
|
|
378
382
|
/**
|
|
379
|
-
* AI 启用时安装 agent 栈 + 所选 provider 的 @ai-sdk
|
|
383
|
+
* AI 启用时安装 agent 栈 + 所选 provider 的 @ai-sdk/*。
|
|
384
|
+
* `@modelcontextprotocol/sdk` 仅在 memoryMcp / mcpServers 时写入(与 doctor 对齐)。
|
|
380
385
|
*/
|
|
381
386
|
export function getAIDependencies(ai?: AISetupConfig): Record<string, string> {
|
|
382
387
|
if (!ai?.enabled) return {};
|
|
@@ -385,9 +390,13 @@ export function getAIDependencies(ai?: AISetupConfig): Record<string, string> {
|
|
|
385
390
|
'@zhin.js/agent': AI_STACK_VERSIONS['@zhin.js/agent'],
|
|
386
391
|
zod: AI_STACK_VERSIONS.zod,
|
|
387
392
|
ai: AI_STACK_VERSIONS.ai,
|
|
388
|
-
'@modelcontextprotocol/sdk': AI_STACK_VERSIONS['@modelcontextprotocol/sdk'],
|
|
389
393
|
...collectSdkPackagesFromSetup(ai),
|
|
390
394
|
};
|
|
395
|
+
const needsMcp = ai.memoryMcp === true
|
|
396
|
+
|| (Array.isArray(ai.mcpServers) && ai.mcpServers.length > 0);
|
|
397
|
+
if (needsMcp) {
|
|
398
|
+
deps['@modelcontextprotocol/sdk'] = AI_STACK_VERSIONS['@modelcontextprotocol/sdk'];
|
|
399
|
+
}
|
|
391
400
|
|
|
392
401
|
return deps;
|
|
393
402
|
}
|
|
@@ -1,48 +1,46 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "Auto-generated by scripts/sync-scaffold-deps.mjs — do not edit; run pnpm sync:scaffold-deps",
|
|
3
3
|
"zhinStack": {
|
|
4
|
-
"zhin.js": "^
|
|
5
|
-
"@zhin.js/cli": "^
|
|
6
|
-
"@zhin.js/agent": "^1.0.
|
|
7
|
-
"@zhin.js/database": "^1.0.
|
|
8
|
-
"@zhin.js/
|
|
9
|
-
"@zhin.js/
|
|
10
|
-
"@zhin.js/
|
|
11
|
-
"@zhin.js/
|
|
12
|
-
"@zhin.js/
|
|
13
|
-
"@zhin.js/
|
|
14
|
-
"@zhin.js/
|
|
15
|
-
"@zhin.js/
|
|
16
|
-
"@zhin.js/adapter-
|
|
17
|
-
"@zhin.js/adapter-
|
|
18
|
-
"@zhin.js/adapter-
|
|
19
|
-
"@zhin.js/adapter-
|
|
20
|
-
"@zhin.js/adapter-
|
|
21
|
-
"@zhin.js/adapter-
|
|
22
|
-
"@zhin.js/adapter-
|
|
23
|
-
"@zhin.js/adapter-
|
|
24
|
-
"@zhin.js/adapter-
|
|
25
|
-
"@zhin.js/adapter-
|
|
26
|
-
"@zhin.js/adapter-
|
|
27
|
-
"@zhin.js/adapter-
|
|
28
|
-
"@zhin.js/adapter-
|
|
29
|
-
"@zhin.js/adapter-
|
|
30
|
-
"@zhin.js/adapter-
|
|
31
|
-
"@zhin.js/adapter-
|
|
32
|
-
"@zhin.js/adapter-
|
|
33
|
-
"@zhin.js/adapter-
|
|
34
|
-
"@zhin.js/adapter-wecom": "^2.0.0",
|
|
35
|
-
"@zhin.js/adapter-weixin-ilink": "^3.0.0"
|
|
4
|
+
"zhin.js": "^5.0.0",
|
|
5
|
+
"@zhin.js/cli": "^2.0.0",
|
|
6
|
+
"@zhin.js/agent": "^1.0.5",
|
|
7
|
+
"@zhin.js/database": "^1.0.77",
|
|
8
|
+
"@zhin.js/client": "^2.1.0",
|
|
9
|
+
"@zhin.js/contract": "^1.0.5",
|
|
10
|
+
"@zhin.js/satori": "^1.0.16",
|
|
11
|
+
"@zhin.js/speech": "^2.0.0",
|
|
12
|
+
"@zhin.js/html-renderer": "^2.0.0",
|
|
13
|
+
"@zhin.js/mcp": "^5.0.0",
|
|
14
|
+
"@zhin.js/adapter-sandbox": "^6.0.0",
|
|
15
|
+
"@zhin.js/adapter-dingtalk": "^5.0.0",
|
|
16
|
+
"@zhin.js/adapter-discord": "^6.0.0",
|
|
17
|
+
"@zhin.js/adapter-email": "^4.0.0",
|
|
18
|
+
"@zhin.js/adapter-github": "^4.0.0",
|
|
19
|
+
"@zhin.js/adapter-icqq": "^7.0.0",
|
|
20
|
+
"@zhin.js/adapter-kook": "^6.0.0",
|
|
21
|
+
"@zhin.js/adapter-lark": "^5.0.0",
|
|
22
|
+
"@zhin.js/adapter-line": "^3.0.0",
|
|
23
|
+
"@zhin.js/adapter-milky": "^5.0.0",
|
|
24
|
+
"@zhin.js/adapter-napcat": "^5.0.0",
|
|
25
|
+
"@zhin.js/adapter-onebot11": "^5.0.0",
|
|
26
|
+
"@zhin.js/adapter-onebot12": "^4.0.0",
|
|
27
|
+
"@zhin.js/adapter-qq": "^6.0.0",
|
|
28
|
+
"@zhin.js/adapter-satori": "^4.0.0",
|
|
29
|
+
"@zhin.js/adapter-slack": "^5.0.0",
|
|
30
|
+
"@zhin.js/adapter-telegram": "^6.0.0",
|
|
31
|
+
"@zhin.js/adapter-wechat-mp": "^4.0.0",
|
|
32
|
+
"@zhin.js/adapter-wecom": "^3.0.0",
|
|
33
|
+
"@zhin.js/adapter-weixin-ilink": "^4.0.0"
|
|
36
34
|
},
|
|
37
35
|
"aiStack": {
|
|
38
|
-
"@zhin.js/agent": "^1.0.
|
|
36
|
+
"@zhin.js/agent": "^1.0.5",
|
|
39
37
|
"ai": "^7.0.0",
|
|
40
38
|
"zod": "^4.0.0",
|
|
41
|
-
"@ai-sdk/openai": "^4.0.
|
|
42
|
-
"@ai-sdk/anthropic": "^4.0.
|
|
43
|
-
"@ai-sdk/google": "^4.0.
|
|
44
|
-
"@ai-sdk/deepseek": "^3.0.
|
|
45
|
-
"@ai-sdk/openai-compatible": "^3.0.
|
|
39
|
+
"@ai-sdk/openai": "^4.0.8",
|
|
40
|
+
"@ai-sdk/anthropic": "^4.0.9",
|
|
41
|
+
"@ai-sdk/google": "^4.0.9",
|
|
42
|
+
"@ai-sdk/deepseek": "^3.0.5",
|
|
43
|
+
"@ai-sdk/openai-compatible": "^3.0.5",
|
|
46
44
|
"@modelcontextprotocol/sdk": "^1.29.0"
|
|
47
45
|
}
|
|
48
46
|
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 微信 iLink(ClawBot)扫码登录流程 — 向导内联实现。
|
|
3
|
+
* 协议与 plugins/adapters/weixin-ilink/src/login.ts 一致(SSOT),
|
|
4
|
+
* 此处复制最小 HTTP 面,避免向导在适配器包安装前产生依赖。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface IlinkQrLoginResult {
|
|
8
|
+
readonly botToken: string;
|
|
9
|
+
readonly ilinkUserId?: string;
|
|
10
|
+
readonly ilinkBotId?: string;
|
|
11
|
+
readonly baseUrl: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface QrCodeResponse {
|
|
15
|
+
qrcode: string;
|
|
16
|
+
qrcode_img_content: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type QrStatus =
|
|
20
|
+
| 'wait'
|
|
21
|
+
| 'scaned'
|
|
22
|
+
| 'confirmed'
|
|
23
|
+
| 'expired'
|
|
24
|
+
| 'scaned_but_redirect'
|
|
25
|
+
| 'need_verifycode'
|
|
26
|
+
| 'verify_code_blocked'
|
|
27
|
+
| 'binded_redirect';
|
|
28
|
+
|
|
29
|
+
interface StatusResponse {
|
|
30
|
+
status: QrStatus;
|
|
31
|
+
bot_token?: string;
|
|
32
|
+
ilink_endpoint_id?: string;
|
|
33
|
+
baseurl?: string;
|
|
34
|
+
ilink_user_id?: string;
|
|
35
|
+
redirect_host?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const DEFAULT_BASE_URL = 'https://ilinkai.weixin.qq.com';
|
|
39
|
+
const DEFAULT_BOT_TYPE = '3';
|
|
40
|
+
const POLL_INTERVAL_MS = 500;
|
|
41
|
+
const QR_LONG_POLL_TIMEOUT_MS = 35_000;
|
|
42
|
+
|
|
43
|
+
export interface IlinkQrLoginOptions {
|
|
44
|
+
readonly baseUrl?: string;
|
|
45
|
+
readonly timeoutMs?: number;
|
|
46
|
+
/** 拿到二维码内容(URL)后回调,由调用方负责展示(终端 QR / 链接)。 */
|
|
47
|
+
readonly onQrCode: (url: string) => void | Promise<void>;
|
|
48
|
+
/** 扫码状态变化提示(scaned → 已扫码待确认)。 */
|
|
49
|
+
readonly onStatus?: (status: QrStatus) => void;
|
|
50
|
+
readonly fetchImpl?: typeof fetch;
|
|
51
|
+
readonly sleep?: (ms: number) => Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export class IlinkQrLoginError extends Error {
|
|
55
|
+
constructor(
|
|
56
|
+
message: string,
|
|
57
|
+
readonly reason: 'expired' | 'timeout' | 'network' | 'protocol',
|
|
58
|
+
) {
|
|
59
|
+
super(message);
|
|
60
|
+
this.name = 'IlinkQrLoginError';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** 与 adapter login.ts 的 buildBaseInfo 对齐的最小结构。 */
|
|
65
|
+
function buildBaseInfo(): Record<string, string> {
|
|
66
|
+
return { channel_version: '0.0.0', bot_agent: 'Zhin.js' };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 微信 iLink 扫码登录:获取二维码 → 展示 → 长轮询直至 confirmed。
|
|
71
|
+
* 成功返回 bot_token 等凭证;过期/超时/网络失败抛 IlinkQrLoginError。
|
|
72
|
+
*/
|
|
73
|
+
export async function loginWithIlinkQr(options: IlinkQrLoginOptions): Promise<IlinkQrLoginResult> {
|
|
74
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
75
|
+
const sleep = options.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)));
|
|
76
|
+
const apiBaseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
|
|
77
|
+
const timeoutMs = options.timeoutMs ?? 480_000;
|
|
78
|
+
|
|
79
|
+
let qr: QrCodeResponse;
|
|
80
|
+
try {
|
|
81
|
+
const res = await fetchImpl(
|
|
82
|
+
`${apiBaseUrl}/ilink/bot/get_bot_qrcode?bot_type=${encodeURIComponent(DEFAULT_BOT_TYPE)}`,
|
|
83
|
+
{
|
|
84
|
+
method: 'POST',
|
|
85
|
+
headers: { 'content-type': 'application/json' },
|
|
86
|
+
body: JSON.stringify({ local_token_list: [], base_info: buildBaseInfo() }),
|
|
87
|
+
},
|
|
88
|
+
);
|
|
89
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
90
|
+
qr = await res.json() as QrCodeResponse;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
throw new IlinkQrLoginError(
|
|
93
|
+
`获取登录二维码失败:${error instanceof Error ? error.message : String(error)}`,
|
|
94
|
+
'network',
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const qrcodeUrl = qr.qrcode_img_content || qr.qrcode;
|
|
99
|
+
await options.onQrCode(qrcodeUrl);
|
|
100
|
+
|
|
101
|
+
const deadline = Date.now() + timeoutMs;
|
|
102
|
+
let currentBaseUrl = apiBaseUrl;
|
|
103
|
+
let lastStatus: QrStatus | undefined;
|
|
104
|
+
|
|
105
|
+
while (Date.now() < deadline) {
|
|
106
|
+
let status: StatusResponse;
|
|
107
|
+
try {
|
|
108
|
+
const res = await fetchImpl(
|
|
109
|
+
`${currentBaseUrl}/ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(qr.qrcode)}`,
|
|
110
|
+
{ signal: AbortSignal.timeout(QR_LONG_POLL_TIMEOUT_MS) },
|
|
111
|
+
);
|
|
112
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
113
|
+
status = await res.json() as StatusResponse;
|
|
114
|
+
} catch {
|
|
115
|
+
// 长轮询超时/瞬断视为继续等待
|
|
116
|
+
await sleep(POLL_INTERVAL_MS);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (status.status !== lastStatus) {
|
|
121
|
+
lastStatus = status.status;
|
|
122
|
+
options.onStatus?.(status.status);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (status.status === 'scaned_but_redirect' && status.redirect_host) {
|
|
126
|
+
currentBaseUrl = status.redirect_host.startsWith('http')
|
|
127
|
+
? status.redirect_host
|
|
128
|
+
: `https://${status.redirect_host}`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (status.status === 'confirmed' || status.status === 'binded_redirect') {
|
|
132
|
+
if (!status.bot_token) {
|
|
133
|
+
throw new IlinkQrLoginError('扫码成功但未返回 bot_token,请重试或改用手动输入', 'protocol');
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
botToken: status.bot_token,
|
|
137
|
+
...(status.ilink_user_id ? { ilinkUserId: status.ilink_user_id } : {}),
|
|
138
|
+
...(status.ilink_endpoint_id ? { ilinkBotId: status.ilink_endpoint_id } : {}),
|
|
139
|
+
baseUrl: status.baseurl ?? currentBaseUrl,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (status.status === 'expired') {
|
|
144
|
+
throw new IlinkQrLoginError('二维码已过期', 'expired');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
await sleep(POLL_INTERVAL_MS);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
throw new IlinkQrLoginError('微信扫码登录超时', 'timeout');
|
|
151
|
+
}
|
package/src/zhin-stack-deps.ts
CHANGED
|
@@ -20,8 +20,6 @@ export const ZHIN_STACK_VERSIONS = {
|
|
|
20
20
|
'@zhin.js/component': 'latest',
|
|
21
21
|
'@zhin.js/core': 'latest',
|
|
22
22
|
'@zhin.js/tool': 'latest',
|
|
23
|
-
'@zhin.js/host-router': 'latest',
|
|
24
|
-
'@zhin.js/host-api': 'latest',
|
|
25
23
|
'@zhin.js/client': 'latest',
|
|
26
24
|
'@zhin.js/contract': 'latest',
|
|
27
25
|
'@zhin.js/satori': 'latest',
|
|
@@ -52,11 +50,6 @@ export const ZHIN_STACK_VERSIONS = {
|
|
|
52
50
|
|
|
53
51
|
export type ZhinStackPackage = keyof typeof ZHIN_STACK_VERSIONS;
|
|
54
52
|
|
|
55
|
-
const HOST_CONSOLE_PLUGINS = new Set([
|
|
56
|
-
'@zhin.js/host-router',
|
|
57
|
-
'@zhin.js/host-api',
|
|
58
|
-
]);
|
|
59
|
-
|
|
60
53
|
function parseMajor(versionSpec: string | undefined): number | undefined {
|
|
61
54
|
if (!versionSpec?.trim()) return undefined;
|
|
62
55
|
if (versionSpec === 'workspace:*') return undefined;
|
|
@@ -115,17 +108,13 @@ export function getCreateBotPnpmConfig(_aiEnabled?: boolean): Record<string, unk
|
|
|
115
108
|
};
|
|
116
109
|
}
|
|
117
110
|
|
|
118
|
-
/**
|
|
111
|
+
/**
|
|
112
|
+
* create-zhin-app Plugin Runtime 骨架 production 依赖(不含适配器 / AI / 数据库驱动)。
|
|
113
|
+
* Stable Features(adapter/command/component/middleware)由 `@zhin.js/core` 的 `package.json#zhin.features` 继承;创作面 API 经 `zhin.js/*` 便利入口。
|
|
114
|
+
*/
|
|
119
115
|
export function getCreateBotBaseDependencies(): Record<string, string> {
|
|
120
116
|
return {
|
|
121
117
|
'zhin.js': ZHIN_STACK_VERSIONS['zhin.js'],
|
|
122
|
-
'@zhin.js/plugin-runtime': ZHIN_STACK_VERSIONS['@zhin.js/plugin-runtime'],
|
|
123
|
-
'@zhin.js/runtime': ZHIN_STACK_VERSIONS['@zhin.js/runtime'],
|
|
124
|
-
'@zhin.js/adapter': ZHIN_STACK_VERSIONS['@zhin.js/adapter'],
|
|
125
|
-
'@zhin.js/command': ZHIN_STACK_VERSIONS['@zhin.js/command'],
|
|
126
|
-
'@zhin.js/component': ZHIN_STACK_VERSIONS['@zhin.js/component'],
|
|
127
|
-
'@zhin.js/core': ZHIN_STACK_VERSIONS['@zhin.js/core'],
|
|
128
|
-
'@zhin.js/satori': ZHIN_STACK_VERSIONS['@zhin.js/satori'],
|
|
129
118
|
};
|
|
130
119
|
}
|
|
131
120
|
|
|
@@ -149,13 +138,6 @@ export function getRequiredZhinDependenciesForConfig(config: Record<string, unkn
|
|
|
149
138
|
}
|
|
150
139
|
}
|
|
151
140
|
|
|
152
|
-
const usesHost = collectZhinPluginsFromConfig(config).some((p) => HOST_CONSOLE_PLUGINS.has(p));
|
|
153
|
-
if (usesHost) {
|
|
154
|
-
for (const pkg of ['@zhin.js/host-router', '@zhin.js/host-api'] as const) {
|
|
155
|
-
deps[pkg] = ZHIN_STACK_VERSIONS[pkg];
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
141
|
return deps;
|
|
160
142
|
}
|
|
161
143
|
|