@zhin.js/scaffold-wizard 0.1.7 → 0.1.9

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.
Files changed (41) hide show
  1. package/README.md +4 -0
  2. package/lib/adapter-configurers.d.ts.map +1 -1
  3. package/lib/adapter-configurers.js +14 -53
  4. package/lib/adapter-configurers.js.map +1 -1
  5. package/lib/adapter.d.ts +17 -9
  6. package/lib/adapter.d.ts.map +1 -1
  7. package/lib/adapter.js +77 -94
  8. package/lib/adapter.js.map +1 -1
  9. package/lib/apply.d.ts +22 -1
  10. package/lib/apply.d.ts.map +1 -1
  11. package/lib/apply.js +156 -23
  12. package/lib/apply.js.map +1 -1
  13. package/lib/index.d.ts +4 -4
  14. package/lib/index.d.ts.map +1 -1
  15. package/lib/index.js +3 -3
  16. package/lib/index.js.map +1 -1
  17. package/lib/optional-peers.d.ts +1 -1
  18. package/lib/optional-peers.d.ts.map +1 -1
  19. package/lib/optional-peers.js +1 -1
  20. package/lib/optional-peers.js.map +1 -1
  21. package/lib/project-config-plan.d.ts +2 -0
  22. package/lib/project-config-plan.d.ts.map +1 -1
  23. package/lib/project-config-plan.js +66 -17
  24. package/lib/project-config-plan.js.map +1 -1
  25. package/lib/upgrade-l4.d.ts +1 -2
  26. package/lib/upgrade-l4.d.ts.map +1 -1
  27. package/lib/upgrade-l4.js +1 -1
  28. package/lib/upgrade-l4.js.map +1 -1
  29. package/lib/zhin-stack-deps.d.ts +10 -2
  30. package/lib/zhin-stack-deps.d.ts.map +1 -1
  31. package/lib/zhin-stack-deps.js +27 -11
  32. package/lib/zhin-stack-deps.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/adapter-configurers.ts +14 -52
  35. package/src/adapter.ts +91 -99
  36. package/src/apply.ts +170 -21
  37. package/src/index.ts +9 -4
  38. package/src/optional-peers.ts +1 -5
  39. package/src/project-config-plan.ts +67 -17
  40. package/src/upgrade-l4.ts +2 -10
  41. package/src/zhin-stack-deps.ts +27 -16
@@ -12,10 +12,19 @@ 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 数组配置诊断 */
15
16
  const CONSOLE_HOST_PLUGINS = ['@zhin.js/host-router', '@zhin.js/host-api'] as const;
16
17
  const SANDBOX_PLUGIN = '@zhin.js/adapter-sandbox';
17
18
  const LEGACY_AI_PROVIDER_FIELDS = ['driver', 'api', 'preset', 'spec'] as const;
18
19
 
20
+ /** 由插件包名推导默认 instanceKey(@zhin.js/adapter-telegram → telegram) */
21
+ export function packageToInstanceKey(packageName: string): string {
22
+ const name = packageName.includes('/')
23
+ ? packageName.split('/').pop() ?? packageName
24
+ : packageName;
25
+ return name.replace(/^(adapter|plugin|service)-/, '');
26
+ }
27
+
19
28
  export type ProjectConfigFormat = 'yaml' | 'json' | 'toml' | 'ts';
20
29
 
21
30
  export interface LoadedProjectConfig {
@@ -164,17 +173,34 @@ export function loadProjectConfig(cwd = process.cwd(), configPath?: string): Loa
164
173
  }
165
174
 
166
175
  function ensurePlugins(config: Record<string, unknown>, pluginsToAdd: readonly string[], mutations: string[]): void {
167
- const plugins = Array.isArray(config.plugins)
168
- ? config.plugins.filter((p): p is string => typeof p === 'string')
169
- : [];
176
+ if (Array.isArray(config.plugins)) {
177
+ // legacy 数组形式:保持原形态追加,避免改写旧项目结构
178
+ const plugins = config.plugins.filter((p): p is string => typeof p === 'string');
179
+ let changed = false;
180
+ for (const plugin of pluginsToAdd) {
181
+ if (plugins.includes(plugin)) continue;
182
+ plugins.push(plugin);
183
+ mutations.push(`added ${plugin} to plugins`);
184
+ changed = true;
185
+ }
186
+ if (changed) {
187
+ config.plugins = plugins;
188
+ }
189
+ return;
190
+ }
191
+ // 新 Plugin Runtime:plugins 为 <instanceKey>: <配置> 映射
192
+ const plugins = config.plugins && typeof config.plugins === 'object'
193
+ ? { ...(config.plugins as Record<string, unknown>) }
194
+ : {};
170
195
  let changed = false;
171
- for (const plugin of pluginsToAdd) {
172
- if (plugins.includes(plugin)) continue;
173
- plugins.push(plugin);
174
- mutations.push(`added ${plugin} to plugins`);
196
+ for (const pkg of pluginsToAdd) {
197
+ const instanceKey = packageToInstanceKey(pkg);
198
+ if (instanceKey in plugins) continue;
199
+ plugins[instanceKey] = {};
200
+ mutations.push(`added ${instanceKey} (${pkg}) to plugins`);
175
201
  changed = true;
176
202
  }
177
- if (changed || !Array.isArray(config.plugins)) {
203
+ if (changed || !config.plugins || typeof config.plugins !== 'object') {
178
204
  config.plugins = plugins;
179
205
  }
180
206
  }
@@ -188,7 +214,7 @@ function ensureHttp(config: Record<string, unknown>, mutations: string[]): void
188
214
  : [];
189
215
 
190
216
  let changed = false;
191
- if (!corsOrigins.includes(CONSOLE_URL)) {
217
+ if (!hasConsoleOrigin(corsOrigins)) {
192
218
  corsOrigins.push(CONSOLE_URL);
193
219
  http.corsOrigins = corsOrigins;
194
220
  mutations.push(`added ${CONSOLE_URL} to http.corsOrigins`);
@@ -318,7 +344,8 @@ export function createProjectConfigPlan(options: ProjectConfigPlanOptions): Proj
318
344
  const mutations: string[] = [];
319
345
 
320
346
  if (loaded.status === 'loaded' || options.config) {
321
- if (options.ensureConsole) {
347
+ if (options.ensureConsole && Array.isArray(after.plugins)) {
348
+ // legacy 数组形态:host 插件仍需写入列表(旧项目行为不变)
322
349
  ensurePlugins(after, CONSOLE_HOST_PLUGINS, mutations);
323
350
  }
324
351
  if (options.ensureSandbox) {
@@ -327,7 +354,8 @@ export function createProjectConfigPlan(options: ProjectConfigPlanOptions): Proj
327
354
  if (options.enablePlugins?.length) {
328
355
  ensurePlugins(after, options.enablePlugins, mutations);
329
356
  }
330
- if (options.ensureHttp) {
357
+ if (options.ensureConsole || options.ensureHttp) {
358
+ // 新形态下 Console Host 由 CLI composition root 装配;Console 可达只需 http.token + corsOrigins
331
359
  ensureHttp(after, mutations);
332
360
  }
333
361
  if (options.migrateAiLegacy) {
@@ -369,22 +397,44 @@ export async function applyProjectConfigPlan(plan: ProjectConfigPlan): Promise<b
369
397
  }
370
398
 
371
399
  export function diagnoseConsoleConfig(config: Record<string, unknown>): ConsoleConfigDiagnosis {
372
- const plugins = Array.isArray(config.plugins)
373
- ? config.plugins.filter((p): p is string => typeof p === 'string')
374
- : [];
375
400
  const http = config.http && typeof config.http === 'object' && !Array.isArray(config.http)
376
401
  ? config.http as Record<string, unknown>
377
402
  : {};
378
403
  const corsOrigins = Array.isArray(http.corsOrigins) ? http.corsOrigins : [];
379
404
 
405
+ if (Array.isArray(config.plugins)) {
406
+ // legacy 数组形式配置
407
+ const plugins = config.plugins.filter((p): p is string => typeof p === 'string');
408
+ return {
409
+ missingHostPlugins: CONSOLE_HOST_PLUGINS.filter((plugin) => !plugins.includes(plugin)),
410
+ missingSandboxPlugin: !plugins.includes(SANDBOX_PLUGIN),
411
+ missingConsoleOrigin: !hasConsoleOrigin(corsOrigins.filter((origin): origin is string => typeof origin === 'string')),
412
+ missingHttpToken: typeof http.token !== 'string' || http.token.trim().length === 0,
413
+ };
414
+ }
415
+
416
+ // 新 Plugin Runtime:Console Host 由 CLI 装配,无需 host 插件;Sandbox 为 plugins.sandbox 实例
417
+ const plugins = config.plugins && typeof config.plugins === 'object'
418
+ ? config.plugins as Record<string, unknown>
419
+ : {};
380
420
  return {
381
- missingHostPlugins: CONSOLE_HOST_PLUGINS.filter((plugin) => !plugins.includes(plugin)),
382
- missingSandboxPlugin: !plugins.includes(SANDBOX_PLUGIN),
383
- missingConsoleOrigin: !corsOrigins.includes(CONSOLE_URL),
421
+ missingHostPlugins: [],
422
+ missingSandboxPlugin: !('sandbox' in plugins),
423
+ missingConsoleOrigin: !hasConsoleOrigin(corsOrigins.filter((origin): origin is string => typeof origin === 'string')),
384
424
  missingHttpToken: typeof http.token !== 'string' || http.token.trim().length === 0,
385
425
  };
386
426
  }
387
427
 
428
+ function hasConsoleOrigin(origins: readonly string[]): boolean {
429
+ return origins.some((origin) => {
430
+ try {
431
+ return new URL(origin).origin === CONSOLE_URL;
432
+ } catch {
433
+ return false;
434
+ }
435
+ });
436
+ }
437
+
388
438
  export function applyConsoleConfigFixes(config: Record<string, unknown>): boolean {
389
439
  const plan = createProjectConfigPlan({
390
440
  cwd: process.cwd(),
package/src/upgrade-l4.ts CHANGED
@@ -1,15 +1,7 @@
1
1
  import fs from 'fs-extra';
2
2
  import path from 'node:path';
3
- import type { PackageJsonLike } from './project-deps.js';
4
- import {
5
- diagnoseAIDependencies,
6
- formatAIDependencyFixCommand,
7
- getRequiredAIDependenciesForConfig,
8
- isAiEnabledInConfig,
9
- findMissingPackageDependencies,
10
- findUnresolvedPackageInstalls,
11
- packagesNeedingAiStackFix,
12
- } from './project-deps.js';
3
+ import { diagnoseAIDependencies, formatAIDependencyFixCommand, getRequiredAIDependenciesForConfig, isAiEnabledInConfig, findMissingPackageDependencies, findUnresolvedPackageInstalls, packagesNeedingAiStackFix, type PackageJsonLike } from './project-deps.js';
4
+
13
5
  import { diagnoseOptionalPeers, formatOptionalPeerFixCommand, getOptionalPeerDependencies } from './optional-peers.js';
14
6
 
15
7
  export interface UpgradeToL4Diagnosis {
@@ -2,21 +2,24 @@ import { createRequire } from 'node:module';
2
2
  import fs from 'fs-extra';
3
3
  import path from 'node:path';
4
4
  import { DATABASE_PACKAGES } from './types.js';
5
- import type { PackageJsonLike } from './project-deps.js';
6
- import {
7
- findMissingPackageDependencies,
8
- findUnresolvedPackageInstalls,
9
- isAiEnabledInConfig,
10
- } from './project-deps.js';
5
+ import { findMissingPackageDependencies, findUnresolvedPackageInstalls, isAiEnabledInConfig, type PackageJsonLike } from './project-deps.js';
11
6
 
12
7
  /**
13
8
  * User project dependency policy: scaffolded dependencies intentionally float to latest.
9
+ * WARNING: this is not reproducible; pin versions for production. See scaffold-wizard README.
14
10
  */
15
11
  export const ZHIN_STACK_VERSIONS = {
16
12
  'zhin.js': 'latest',
17
13
  '@zhin.js/cli': 'latest',
18
14
  '@zhin.js/agent': 'latest',
19
15
  '@zhin.js/database': 'latest',
16
+ '@zhin.js/plugin-runtime': 'latest',
17
+ '@zhin.js/runtime': 'latest',
18
+ '@zhin.js/adapter': 'latest',
19
+ '@zhin.js/command': 'latest',
20
+ '@zhin.js/component': 'latest',
21
+ '@zhin.js/core': 'latest',
22
+ '@zhin.js/tool': 'latest',
20
23
  '@zhin.js/host-router': 'latest',
21
24
  '@zhin.js/host-api': 'latest',
22
25
  '@zhin.js/client': 'latest',
@@ -86,10 +89,17 @@ function resolveStackVersion(packageName: string): string {
86
89
  }
87
90
 
88
91
  function collectZhinPluginsFromConfig(config: Record<string, unknown>): string[] {
89
- const plugins = Array.isArray(config.plugins)
90
- ? config.plugins.filter((p): p is string => typeof p === 'string')
91
- : [];
92
- return [...new Set(plugins.filter((p) => p.startsWith('@zhin.js/')))];
92
+ // legacy 数组形式:条目即包名
93
+ if (Array.isArray(config.plugins)) {
94
+ const plugins = config.plugins.filter((p): p is string => typeof p === 'string');
95
+ return [...new Set(plugins.filter((p) => p.startsWith('@zhin.js/')))];
96
+ }
97
+ // 新 runtime:plugins 为 instanceKey 映射,包名在 package.json zhin.plugins 清单中,
98
+ // 无法从配置推导;仅收集直接以包名出现的键(防御性)
99
+ if (config.plugins && typeof config.plugins === 'object') {
100
+ return Object.keys(config.plugins as Record<string, unknown>).filter((key) => key.startsWith('@zhin.js/'));
101
+ }
102
+ return [];
93
103
  }
94
104
 
95
105
  /** create-zhin / minimal-bot 默认 Host 端口(避免与常见 8086 占用冲突) */
@@ -105,15 +115,16 @@ export function getCreateBotPnpmConfig(_aiEnabled?: boolean): Record<string, unk
105
115
  };
106
116
  }
107
117
 
108
- /** create-zhin-app 默认 bot 骨架依赖(不含适配器 / AI / 数据库驱动) */
118
+ /** create-zhin-app Plugin Runtime 骨架 production 依赖(不含适配器 / AI / 数据库驱动) */
109
119
  export function getCreateBotBaseDependencies(): Record<string, string> {
110
120
  return {
111
121
  'zhin.js': ZHIN_STACK_VERSIONS['zhin.js'],
112
- '@zhin.js/cli': ZHIN_STACK_VERSIONS['@zhin.js/cli'],
113
- '@zhin.js/host-router': ZHIN_STACK_VERSIONS['@zhin.js/host-router'],
114
- '@zhin.js/client': ZHIN_STACK_VERSIONS['@zhin.js/client'],
115
- '@zhin.js/host-api': ZHIN_STACK_VERSIONS['@zhin.js/host-api'],
116
- '@zhin.js/contract': ZHIN_STACK_VERSIONS['@zhin.js/contract'],
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'],
117
128
  '@zhin.js/satori': ZHIN_STACK_VERSIONS['@zhin.js/satori'],
118
129
  };
119
130
  }