create-windy 0.2.26 → 0.2.27

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/cli.js CHANGED
@@ -4335,7 +4335,8 @@ var recipes = [
4335
4335
  { id: "starter-0.2.22-to-0.2.23", from: "0.2.22", to: "0.2.23" },
4336
4336
  { id: "starter-0.2.23-to-0.2.24", from: "0.2.23", to: "0.2.24" },
4337
4337
  { id: "starter-0.2.24-to-0.2.25", from: "0.2.24", to: "0.2.25" },
4338
- { id: "starter-0.2.25-to-0.2.26", from: "0.2.25", to: "0.2.26" }
4338
+ { id: "starter-0.2.25-to-0.2.26", from: "0.2.25", to: "0.2.26" },
4339
+ { id: "starter-0.2.26-to-0.2.27", from: "0.2.26", to: "0.2.27" }
4339
4340
  ];
4340
4341
  function resolveRecipeChain(sourceVersion, targetVersion) {
4341
4342
  if (sourceVersion === targetVersion)
@@ -4457,6 +4458,9 @@ var correctCoreDescription = "创建时未选择 `work-order` 示例模块,当
4457
4458
  var wrongExampleRow = /^\|\s*示例工单\s*\|\s*已包含\s*\|$/m;
4458
4459
  var correctCoreRow = /^\|\s*示例工单\s*\|\s*未包含\s*\|$/m;
4459
4460
  function repairKnownDerivedFile(input) {
4461
+ const neutralRouterRepair = repairKnown026Downstream(input);
4462
+ if (neutralRouterRepair !== undefined)
4463
+ return neutralRouterRepair;
4460
4464
  const downstreamRepair = repairKnown023Downstream(input);
4461
4465
  if (downstreamRepair !== undefined)
4462
4466
  return downstreamRepair;
@@ -4477,6 +4481,27 @@ function repairKnownDerivedFile(input) {
4477
4481
  }
4478
4482
  return input.content.replace(wrongExampleDescription, correctCoreDescription).replace(wrongExampleRow, targetRow);
4479
4483
  }
4484
+ function repairKnown026Downstream(input) {
4485
+ if (input.sourceVersion !== "0.2.26")
4486
+ return;
4487
+ if (input.path === "apps/web/src/router/index.ts" && input.targetContent.includes("@/pages/auth/LoginPage.vue")) {
4488
+ return replaceKnown(input.content, 'import LoginPage from "@/app/auth/LijianLoginPage.vue";', 'import LoginPage from "@/pages/auth/LoginPage.vue";');
4489
+ }
4490
+ if (input.path !== "apps/web/src/router/router-test-fixtures.ts" || input.targetContent.includes("lijian.")) {
4491
+ return;
4492
+ }
4493
+ const replacements2 = [
4494
+ ["lijian.case.read", "case.read"],
4495
+ ["lijian.evidence.read", "evidence.read"],
4496
+ ["lijian.case", "case"],
4497
+ ["lijian.evidence.import", "evidence.import"],
4498
+ ["lijian.evidence", "evidence"]
4499
+ ];
4500
+ if (!replacements2.every(([source]) => input.content.includes(source))) {
4501
+ return;
4502
+ }
4503
+ return replacements2.reduce((content, [source, target]) => content.replaceAll(source, target), input.content);
4504
+ }
4480
4505
  function repairKnown023Downstream(input) {
4481
4506
  if (input.sourceVersion !== "0.2.23" || known023DownstreamHashes.get(input.path) !== contentHash(input.content)) {
4482
4507
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-windy",
3
- "version": "0.2.26",
3
+ "version": "0.2.27",
4
4
  "description": "创建单组织、单租户、私有部署优先的 Windy 企业 Dashboard Starter",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "templateCommit": "f73d192acc1af99fe232b51ac638c1e0e7d204c9",
4
- "generatorVersion": "0.2.26",
3
+ "templateCommit": "c7bfbd0a1c530a6aa68cc25ba12911763cddccb4",
4
+ "generatorVersion": "0.2.27",
5
5
  "modules": [
6
6
  {
7
7
  "name": "system",
@@ -77,8 +77,8 @@ function collectAuditActions(modules: ModuleManifest[]): string[] {
77
77
 
78
78
  export function createFoundationSnapshot(
79
79
  config: PlatformConfig = loadPlatformConfig(),
80
+ modules: ModuleManifest[] = loadFoundationModules(),
80
81
  ): FoundationSnapshot {
81
- const modules = loadFoundationModules();
82
82
  const catalogs = validateCapabilityCatalogs(
83
83
  modules,
84
84
  resolveLicenseCatalog(config.license.versions),
@@ -6,6 +6,7 @@ import {
6
6
  createFoundationSnapshot,
7
7
  loadFoundationModules,
8
8
  } from "./foundation.js";
9
+ import { runInstalledModuleMigrations } from "./module-migrations.js";
9
10
  import {
10
11
  attachInstalledBusinessModules,
11
12
  installedBusinessModules,
@@ -27,17 +28,24 @@ export async function bootstrapServerModules(
27
28
  platformConfig: PlatformConfig,
28
29
  persistence: ServerPersistence | undefined,
29
30
  ) {
31
+ const foundationModules = loadFoundationModules();
32
+ const foundationSnapshot = createFoundationSnapshot(
33
+ platformConfig,
34
+ foundationModules,
35
+ );
36
+ const moduleMigrationReport = await runInstalledModuleMigrations(
37
+ foundationModules,
38
+ persistence?.pool,
39
+ );
30
40
  // @windy-module system.configuration begin
31
41
  const configurationRuntime = await bootstrapModuleConfiguration(
32
42
  platformConfig,
33
43
  persistence?.configVersionRepository,
34
44
  );
35
45
  // @windy-module system.configuration end
36
- const foundationSnapshot = createFoundationSnapshot(platformConfig);
37
46
  // @windy-module system.configuration begin
38
47
  configurationRuntime.bindFoundation(foundationSnapshot);
39
48
  // @windy-module system.configuration end
40
- const foundationModules = loadFoundationModules();
41
49
  const moduleHosts = await initializeModuleHosts({
42
50
  modules: foundationModules,
43
51
  installations: installedBusinessModules,
@@ -78,6 +86,7 @@ export async function bootstrapServerModules(
78
86
  foundationModules,
79
87
  foundationSnapshot,
80
88
  moduleHosts,
89
+ moduleMigrationReport,
81
90
  systemRepositories,
82
91
  };
83
92
  }
@@ -0,0 +1,43 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import type { ModuleManifest } from "@southwind-ai/modules";
3
+ import { runInstalledModuleMigrations } from "./module-migrations.js";
4
+
5
+ describe("Server Module Migration 启动 seam", () => {
6
+ test("没有显式 bundle 时不占用 PostgreSQL 连接", async () => {
7
+ let connected = false;
8
+ const result = await runInstalledModuleMigrations([manifest()], {
9
+ async connect() {
10
+ connected = true;
11
+ throw new Error("不应获取连接");
12
+ },
13
+ });
14
+
15
+ expect(result).toBeUndefined();
16
+ expect(connected).toBe(false);
17
+ });
18
+
19
+ test("未配置 PostgreSQL 时保留纯结构校验启动路径", async () => {
20
+ const result = await runInstalledModuleMigrations([manifest()], undefined);
21
+ expect(result).toBeUndefined();
22
+ });
23
+ });
24
+
25
+ function manifest(): ModuleManifest {
26
+ return {
27
+ name: "customer-domain",
28
+ version: "1.0.0",
29
+ label: "客户领域",
30
+ description: "测试模块",
31
+ menus: [],
32
+ adminRoutes: [],
33
+ permissions: [],
34
+ apiPermissions: [],
35
+ features: [],
36
+ migrations: [],
37
+ schemaExports: [],
38
+ tasks: [],
39
+ tools: [],
40
+ providers: [],
41
+ auditActions: [],
42
+ };
43
+ }
@@ -0,0 +1,19 @@
1
+ import {
2
+ runPostgresMigrationBundles,
3
+ type MigrationRunReport,
4
+ type PostgresTransactionPool,
5
+ } from "@southwind-ai/database";
6
+ import type { ModuleManifest } from "@southwind-ai/modules";
7
+ import { normalizeManifestBundles } from "@southwind-ai/shared";
8
+
9
+ export async function runInstalledModuleMigrations(
10
+ modules: readonly ModuleManifest[],
11
+ pool: PostgresTransactionPool | undefined,
12
+ ): Promise<MigrationRunReport | undefined> {
13
+ const bundledModules = modules.filter((module) => module.migrationBundle);
14
+ if (!pool || bundledModules.length === 0) return undefined;
15
+ return runPostgresMigrationBundles({
16
+ pool,
17
+ bundles: normalizeManifestBundles(bundledModules),
18
+ });
19
+ }
@@ -0,0 +1,14 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import routerSource from "./index.ts?raw";
3
+ import fixtureSource from "./router-test-fixtures.ts?raw";
4
+
5
+ describe("Router shared-scaffold 中性契约", () => {
6
+ test("平台登录页与测试快照不固化下游产品命名", () => {
7
+ expect(routerSource).toContain(
8
+ 'import LoginPage from "@/pages/auth/LoginPage.vue";',
9
+ );
10
+ expect(`${routerSource}\n${fixtureSource}`).not.toMatch(
11
+ /LijianLoginPage|lijian\./,
12
+ );
13
+ });
14
+ });
@@ -45,6 +45,17 @@ Manifest 当前覆盖:
45
45
 
46
46
  这种边界允许宿主替换实现,同时保持 Manifest 的能力语义稳定。
47
47
 
48
+ ## Capability Key 重命名边界
49
+
50
+ 平台当前没有 Module、Feature、Permission、Task、Tool、Operation 或 API Key 的通用
51
+ rename/alias seam。Composition、Guard、history 和审计都按 Manifest 中的精确稳定 Key
52
+ 工作,不会把旧 Key 静默映射到新 Key。
53
+
54
+ 产品需要硬切命名时,应在停机窗口一次性更新 Manifest、Host 实现、调用方、持久化权限
55
+ 和任务数据,并通过 project-owned forward Migration 完成 schema/data rename。若产品
56
+ 确实需要跨版本兼容期,应先单独设计带期限、冲突规则和审计语义的 alias 契约;当前
57
+ 平台不会为某个下游产品内置别名。
58
+
48
59
  ## 分批落地
49
60
 
50
61
  - 第一批:类型、声明级验证和失败回归。
@@ -0,0 +1,2 @@
1
+ ALTER TABLE "windy_migration_history" ADD COLUMN "module_version" varchar(64);--> statement-breakpoint
2
+ ALTER TABLE "windy_migration_history" ADD COLUMN "migration_order" integer;