create-windy 0.2.26 → 0.2.28

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,9 @@ 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" },
4340
+ { id: "starter-0.2.27-to-0.2.28", from: "0.2.27", to: "0.2.28" }
4339
4341
  ];
4340
4342
  function resolveRecipeChain(sourceVersion, targetVersion) {
4341
4343
  if (sourceVersion === targetVersion)
@@ -4430,6 +4432,12 @@ import { join as join16 } from "node:path";
4430
4432
  import { createHash as createHash2 } from "node:crypto";
4431
4433
  var wrongTextVersions = new Set(["0.2.12", "0.2.13"]);
4432
4434
  var formattedBaselineVersions = new Set(["0.2.14", "0.2.15"]);
4435
+ var known026DownstreamHashes = new Map([
4436
+ [
4437
+ "apps/server/src/module-bootstrap.ts",
4438
+ "4b79ab5d0271b3111c7cb546e0b581d483da8c5de263f8d2f9671d53f60c5099"
4439
+ ]
4440
+ ]);
4433
4441
  var known023DownstreamHashes = new Map([
4434
4442
  [
4435
4443
  "apps/server/src/http-app.ts",
@@ -4457,6 +4465,9 @@ var correctCoreDescription = "创建时未选择 `work-order` 示例模块,当
4457
4465
  var wrongExampleRow = /^\|\s*示例工单\s*\|\s*已包含\s*\|$/m;
4458
4466
  var correctCoreRow = /^\|\s*示例工单\s*\|\s*未包含\s*\|$/m;
4459
4467
  function repairKnownDerivedFile(input) {
4468
+ const neutralRouterRepair = repairKnown026Downstream(input);
4469
+ if (neutralRouterRepair !== undefined)
4470
+ return neutralRouterRepair;
4460
4471
  const downstreamRepair = repairKnown023Downstream(input);
4461
4472
  if (downstreamRepair !== undefined)
4462
4473
  return downstreamRepair;
@@ -4477,6 +4488,30 @@ function repairKnownDerivedFile(input) {
4477
4488
  }
4478
4489
  return input.content.replace(wrongExampleDescription, correctCoreDescription).replace(wrongExampleRow, targetRow);
4479
4490
  }
4491
+ function repairKnown026Downstream(input) {
4492
+ if (input.sourceVersion !== "0.2.26")
4493
+ return;
4494
+ if (known026DownstreamHashes.get(input.path) === contentHash(input.content)) {
4495
+ return input.targetContent;
4496
+ }
4497
+ if (input.path === "apps/web/src/router/index.ts" && input.targetContent.includes("@/pages/auth/LoginPage.vue")) {
4498
+ return replaceKnown(input.content, 'import LoginPage from "@/app/auth/LijianLoginPage.vue";', 'import LoginPage from "@/pages/auth/LoginPage.vue";');
4499
+ }
4500
+ if (input.path !== "apps/web/src/router/router-test-fixtures.ts" || input.targetContent.includes("lijian.")) {
4501
+ return;
4502
+ }
4503
+ const replacements2 = [
4504
+ ["lijian.case.read", "case.read"],
4505
+ ["lijian.evidence.read", "evidence.read"],
4506
+ ["lijian.case", "case"],
4507
+ ["lijian.evidence.import", "evidence.import"],
4508
+ ["lijian.evidence", "evidence"]
4509
+ ];
4510
+ if (!replacements2.every(([source]) => input.content.includes(source))) {
4511
+ return;
4512
+ }
4513
+ return replacements2.reduce((content, [source, target]) => content.replaceAll(source, target), input.content);
4514
+ }
4480
4515
  function repairKnown023Downstream(input) {
4481
4516
  if (input.sourceVersion !== "0.2.23" || known023DownstreamHashes.get(input.path) !== contentHash(input.content)) {
4482
4517
  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.28",
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": "1cdccb9ee1b4e496461282ed7bdab3689fc7009f",
4
+ "generatorVersion": "0.2.28",
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;