create-windy 0.3.4 → 0.3.6

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 (101) hide show
  1. package/README.md +20 -3
  2. package/dist/cli.js +585 -111
  3. package/package.json +1 -1
  4. package/template/.windy-template.json +2 -2
  5. package/template/AGENTS.md +4 -0
  6. package/template/README.md +18 -11
  7. package/template/apps/server/src/application-services.ts +16 -0
  8. package/template/apps/server/src/data-governance/export/authorization-port.test.ts +5 -1
  9. package/template/apps/server/src/data-governance/export/drizzle-repository.integration.test.ts +2 -0
  10. package/template/apps/server/src/data-governance/export/drizzle-repository.ts +1 -0
  11. package/template/apps/server/src/data-governance/export/job-runtime.test.ts +3 -1
  12. package/template/apps/server/src/data-governance/export/job-runtime.ts +53 -14
  13. package/template/apps/server/src/data-governance/export/ndjson-stream.ts +8 -0
  14. package/template/apps/server/src/data-governance/export/postgres-recovery.integration.test.ts +2 -0
  15. package/template/apps/server/src/data-governance/export/renderer-job-runtime.test.ts +235 -0
  16. package/template/apps/server/src/data-governance/export/renderer-runtime.ts +293 -0
  17. package/template/apps/server/src/data-governance/export/renderer-selection.test.ts +67 -0
  18. package/template/apps/server/src/data-governance/export/repository.test.ts +2 -0
  19. package/template/apps/server/src/data-governance/export/request-fingerprint.test.ts +13 -0
  20. package/template/apps/server/src/data-governance/export/request-fingerprint.ts +2 -0
  21. package/template/apps/server/src/data-governance/export/routes.ts +11 -1
  22. package/template/apps/server/src/data-governance/export/service-support.ts +61 -4
  23. package/template/apps/server/src/data-governance/export/service.ts +8 -2
  24. package/template/apps/server/src/data-governance/export/types.ts +27 -0
  25. package/template/apps/server/src/index.ts +1 -0
  26. package/template/apps/server/src/jobs/artifact-service.test.ts +14 -2
  27. package/template/apps/server/src/jobs/artifact-service.ts +10 -0
  28. package/template/apps/server/src/jobs/drizzle-execution-repository.ts +17 -18
  29. package/template/apps/server/src/jobs/drizzle-execution.integration.test.ts +19 -1
  30. package/template/apps/server/src/jobs/drizzle-mappers.ts +3 -1
  31. package/template/apps/server/src/jobs/drizzle-recovery-repository.ts +49 -2
  32. package/template/apps/server/src/jobs/execution-repository.ts +17 -0
  33. package/template/apps/server/src/jobs/in-memory-control.ts +135 -0
  34. package/template/apps/server/src/jobs/in-memory-execution.ts +34 -65
  35. package/template/apps/server/src/jobs/worker.ts +27 -3
  36. package/template/apps/server/src/module-host/governed-export-route-support.ts +24 -5
  37. package/template/apps/server/src/module-host/governed-export-routes.test.ts +5 -1
  38. package/template/apps/server/src/module-host/governed-export-routes.ts +1 -2
  39. package/template/apps/server/src/module-host/governed-renderer-registration.test.ts +247 -0
  40. package/template/apps/server/src/module-host/governed-resources.test.ts +1 -0
  41. package/template/apps/server/src/module-host/governed-resources.ts +56 -0
  42. package/template/apps/server/src/module-host/http-runtime.ts +3 -0
  43. package/template/apps/server/src/module-host/job-port.test.ts +262 -0
  44. package/template/apps/server/src/module-host/job-port.ts +334 -0
  45. package/template/apps/server/src/module-host/request-context.ts +14 -26
  46. package/template/apps/server/src/module-host/route-installer.ts +11 -0
  47. package/template/apps/web/src/app/business-routes.ts +22 -0
  48. package/template/apps/web/src/components/common/AccessSnapshotBoundary.vue +112 -0
  49. package/template/apps/web/src/components/common/AccessSnapshotBoundary.webtest.ts +130 -0
  50. package/template/apps/web/src/components/common/AccessSnapshotNotice.vue +117 -0
  51. package/template/apps/web/src/composables/access-snapshot-change.ts +131 -0
  52. package/template/apps/web/src/composables/access-snapshot-change.webtest.ts +103 -0
  53. package/template/apps/web/src/composables/useAccessSnapshot.ts +48 -2
  54. package/template/apps/web/src/composables/useAccessSnapshot.webtest.ts +54 -0
  55. package/template/apps/web/src/composables/useAccessSnapshotMonitor.ts +42 -0
  56. package/template/apps/web/src/layout/AppShell.vue +28 -25
  57. package/template/apps/web/src/layout/AppShell.webtest.ts +1 -0
  58. package/template/apps/web/src/router/business-routes.ts +68 -0
  59. package/template/apps/web/src/router/business-routes.webtest.ts +85 -0
  60. package/template/apps/web/src/router/index.ts +7 -0
  61. package/template/apps/web/src/router/shared-scaffold-neutrality.webtest.ts +12 -0
  62. package/template/apps/web/src/services/access-api.ts +5 -1
  63. package/template/apps/web/src/services/access-api.webtest.ts +35 -0
  64. package/template/docs/architecture/ai-egress.md +12 -9
  65. package/template/docs/architecture/durable-jobs.md +7 -1
  66. package/template/docs/architecture/foundation-infrastructure.md +163 -0
  67. package/template/docs/architecture/module-host.md +115 -0
  68. package/template/docs/architecture/server-module-interface.md +39 -0
  69. package/template/docs/architecture/web-access-snapshot-resilience.md +60 -0
  70. package/template/docs/development/business-web-routes.md +66 -0
  71. package/template/docs/development/custom-login-page.md +3 -3
  72. package/template/docs/development/module-lifecycle.md +71 -0
  73. package/template/docs/operations/observability.md +5 -1
  74. package/template/docs/platform/agent-runtime.md +6 -6
  75. package/template/docs/platform/agent-tool-sandbox.md +58 -0
  76. package/template/docs/platform/document-ai-runtime.md +204 -0
  77. package/template/docs/platform/governed-export-renderers.md +132 -0
  78. package/template/docs/platform/navigation-registry.md +5 -0
  79. package/template/docs/platform/organization-membership.md +2 -1
  80. package/template/docs/platform/speech-ai-runtime.md +156 -0
  81. package/template/docs/platform/system-crud-api.md +7 -1
  82. package/template/docs/platform/vision-ai-runtime.md +97 -0
  83. package/template/docs/platform/web-system-crud.md +6 -0
  84. package/template/packages/config/package.json +1 -1
  85. package/template/packages/database/drizzle/0042_puzzling_rumiko_fujikawa.sql +27 -0
  86. package/template/packages/database/drizzle/meta/0042_snapshot.json +8541 -0
  87. package/template/packages/database/drizzle/meta/_journal.json +7 -0
  88. package/template/packages/database/package.json +1 -1
  89. package/template/packages/database/src/schema/durable-jobs.ts +1 -0
  90. package/template/packages/database/src/schema/governed-exports.ts +15 -0
  91. package/template/packages/database/src/schema-governed-exports.test.ts +21 -1
  92. package/template/packages/jobs/package.json +1 -1
  93. package/template/packages/jobs/src/handlers.ts +1 -0
  94. package/template/packages/jobs/src/types.ts +1 -0
  95. package/template/packages/modules/package.json +1 -1
  96. package/template/packages/server-sdk/index.ts +11 -0
  97. package/template/packages/server-sdk/package.json +1 -1
  98. package/template/packages/server-sdk/src/data-governance-registration.ts +46 -0
  99. package/template/packages/server-sdk/src/jobs-port.ts +69 -0
  100. package/template/packages/server-sdk/src/request-context.ts +2 -2
  101. package/template/packages/shared/package.json +1 -1
package/dist/cli.js CHANGED
@@ -295,6 +295,7 @@ var optionalModuleManifests = [
295
295
  "apps/server/src/application-services.ts",
296
296
  "apps/server/src/module-host/durable-context.ts",
297
297
  "apps/server/src/module-host/durable-context.test.ts",
298
+ "apps/server/src/module-host/job-port.test.ts",
298
299
  "apps/server/src/module-host/task-definitions.ts",
299
300
  "packages/database/src/schema-durable-recovery.test.ts",
300
301
  "apps/web/src/pages/system/components/SchedulerOperationsPanel.vue",
@@ -460,6 +461,7 @@ var optionalModuleManifests = [
460
461
  ],
461
462
  documentation: ["docs/development/example-work-order.md"],
462
463
  schemaFiles: ["packages/example-work-order/src/drizzle-schema.ts"],
464
+ migrationRoots: ["packages/example-work-order/drizzle"],
463
465
  databaseTables: ["work_orders"],
464
466
  databaseLineageOwner: "module"
465
467
  }
@@ -469,6 +471,7 @@ function module(name, label, description, dependencies) {
469
471
  return {
470
472
  name,
471
473
  version: "0.1.0",
474
+ windyRange: "^0.3.0",
472
475
  label,
473
476
  description,
474
477
  selection,
@@ -479,11 +482,15 @@ function module(name, label, description, dependencies) {
479
482
  fileRoots: [],
480
483
  documentation: [],
481
484
  schemaFiles: [],
485
+ migrationRoots: [],
482
486
  databaseTables: [],
483
487
  databaseLineageOwner: "platform",
484
488
  transientDatabaseTables: [],
485
489
  databaseStatementTokens: [],
486
- uninstallPolicy: "retain-data"
490
+ uninstallPolicy: "retain-data",
491
+ installRecipe: `module-${name}-install`,
492
+ updateRecipes: [`module-${name}-update-0.1.0`],
493
+ uninstallRecipe: `module-${name}-uninstall`
487
494
  };
488
495
  }
489
496
 
@@ -688,6 +695,7 @@ function module2(name, label, description, selection, dependencies = []) {
688
695
  return {
689
696
  name,
690
697
  version: "0.1.0",
698
+ windyRange: "^0.3.0",
691
699
  label,
692
700
  description,
693
701
  selection,
@@ -698,11 +706,15 @@ function module2(name, label, description, selection, dependencies = []) {
698
706
  fileRoots: [],
699
707
  documentation: [],
700
708
  schemaFiles: [],
709
+ migrationRoots: [],
701
710
  databaseTables: [],
702
711
  databaseLineageOwner: "platform",
703
712
  transientDatabaseTables: [],
704
713
  databaseStatementTokens: [],
705
- uninstallPolicy: "retain-data"
714
+ uninstallPolicy: "retain-data",
715
+ installRecipe: `module-${name}-install`,
716
+ updateRecipes: [`module-${name}-update-0.1.0`],
717
+ uninstallRecipe: `module-${name}-uninstall`
706
718
  };
707
719
  }
708
720
  function validateCatalog(manifests) {
@@ -723,6 +735,12 @@ function validateCatalog(manifests) {
723
735
  if (!names.has(conflict))
724
736
  throw new Error(`${manifest.name} \u51B2\u7A81\u6A21\u5757\u672A\u77E5\uFF1A${conflict}`);
725
737
  }
738
+ if (!manifest.installRecipe) {
739
+ throw new Error(`${manifest.name} \u7F3A\u5C11\u5B89\u88C5 recipe`);
740
+ }
741
+ if (!manifest.uninstallRecipe) {
742
+ throw new Error(`${manifest.name} \u7F3A\u5C11\u5378\u8F7D recipe`);
743
+ }
726
744
  }
727
745
  return manifests;
728
746
  }
@@ -807,6 +825,11 @@ var helpText = `create-windy <\u9879\u76EE\u540D> [\u9009\u9879]
807
825
  create-windy update --check [--cwd <\u76EE\u5F55>]
808
826
  create-windy update --dry-run [--to <\u7248\u672C>] [--cwd <\u76EE\u5F55>]
809
827
  create-windy update [--to <\u7248\u672C>] [--cwd <\u76EE\u5F55>]
828
+ create-windy module list [--cwd <\u76EE\u5F55>]
829
+ create-windy module add <key...> [--dry-run] [--cwd <\u76EE\u5F55>]
830
+ create-windy module update [key...] [--dry-run] [--cwd <\u76EE\u5F55>]
831
+ create-windy module remove <key...> [--dry-run] [--data-disposition <\u7B56\u7565>]
832
+ [--data-plan <\u6587\u4EF6>] [--confirm-data-disposition] [--cwd <\u76EE\u5F55>]
810
833
  create-windy reconcile --to <\u7CBE\u786E\u7248\u672C> [--cwd <\u76EE\u5F55>] [--apply]
811
834
  create-windy schema handoff [--config <JSON>] [--cwd <\u76EE\u5F55>]
812
835
 
@@ -1940,6 +1963,7 @@ var projectOwnedRoots = [
1940
1963
  ];
1941
1964
  var sharedScaffoldRoots = [
1942
1965
  "README.md",
1966
+ "docs",
1943
1967
  "AGENTS.md",
1944
1968
  ".env.example",
1945
1969
  "docker-compose.yml",
@@ -3253,9 +3277,9 @@ MCP \u6BCF\u6B21\u8C03\u7528\u90FD\u4F1A\u91CD\u65B0\u6267\u884C Feature\u3001RB
3253
3277
  \u548C \`dev:agent\` \u662F\u53E6\u4E00\u6761\u53EF\u9009\u94FE\u8DEF\u3002\u5B8C\u6574\u8FB9\u754C\u89C1
3254
3278
  [MCP \u4E1A\u52A1\u80FD\u529B](./docs/architecture/mcp-business-capabilities.md) \u4E0E
3255
3279
  [Agent Tool](./docs/platform/agent-tools.md)\u3002` : `\u5F53\u524D\u7EC4\u5408\u672A\u5305\u542B \`system.agent\`\uFF0CMCP Server\u3001Agent Tool Host \u548C\u76F8\u5173\u6587\u6863\u5DF2\u88AB
3256
- \u7269\u7406\u88C1\u526A\u3002\u82E5\u9879\u76EE\u5C1A\u53EF\u91CD\u65B0\u751F\u6210\uFF0C\u8BF7\u5728\u521B\u5EFA\u65F6\u589E\u52A0 \`--module system.agent\` \u6216\u4F7F\u7528
3257
- \`--all-modules\`\uFF1B\u90E8\u7F72\u540E\u7684\u901A\u7528 \`module add\` \u5C1A\u672A\u4EA4\u4ED8\uFF0C\u4E0D\u8981\u624B\u5DE5\u590D\u5236 MCP Adapter
3258
- \u6216\u53E6\u5EFA\u6388\u6743\u94FE\u3002\u4ED3\u5E93 Skill \u4ECD\u53EF\u7528\u4E8E\u666E\u901A\u4E1A\u52A1\u6A21\u5757\u5F00\u53D1\u3002`}
3280
+ \u7269\u7406\u88C1\u526A\u3002\u521B\u5EFA\u65F6\u53EF\u589E\u52A0 \`--module system.agent\` \u6216\u4F7F\u7528 \`--all-modules\`\uFF1B\u5DF2\u90E8\u7F72
3281
+ \u9879\u76EE\u4F7F\u7528 \`bun run windy module add system.agent\`\uFF0C\u4E0D\u8981\u624B\u5DE5\u590D\u5236 MCP Adapter \u6216
3282
+ \u53E6\u5EFA\u6388\u6743\u94FE\u3002\u4ED3\u5E93 Skill \u4ECD\u53EF\u7528\u4E8E\u666E\u901A\u4E1A\u52A1\u6A21\u5757\u5F00\u53D1\u3002`}
3259
3283
  `;
3260
3284
  }
3261
3285
 
@@ -3654,7 +3678,7 @@ OPENSEARCH_PASSWORD=
3654
3678
  `;
3655
3679
  }
3656
3680
  // src/project-files.ts
3657
- function starterDocsReadme(includeOfflineLicense = true, includeAgent = true) {
3681
+ function starterDocsReadme(includeOfflineLicense = true, includeAgent = true, includeOperations = true) {
3658
3682
  return `# Windy Starter \u6587\u6863
3659
3683
 
3660
3684
  \u672C\u76EE\u5F55\u53EA\u5305\u542B\u5BA2\u6237\u8FD0\u884C\u9879\u76EE\u9700\u8981\u7684\u5E73\u53F0\u67B6\u6784\u3001\u5F00\u53D1\u63A5\u5165\u548C\u8FD0\u7EF4\u53EF\u89C2\u6D4B\u6027\u6587\u6863\u3002
@@ -3664,9 +3688,11 @@ License \u7B7E\u53D1\u4E2D\u5FC3\u3001\u72EC\u7ACB\u7B7E\u540D\u670D\u52A1\u3001
3664
3688
  - \u67B6\u6784\uFF1A\u4ECE [Module Manifest \u7EC4\u5408](./architecture/module-manifest-composition.md) \u5F00\u59CB\u3002
3665
3689
  - \u6570\u636E\u5E93\uFF1A\u4E1A\u52A1\u8868\u4F7F\u7528 [Migration Bundle \u4E0E\u72EC\u7ACB Drizzle lineage](./architecture/migration-bundle.md)\u3002
3666
3690
  - \u5E73\u53F0\u5F00\u53D1\uFF1A\u4ECE [\u7CFB\u7EDF CRUD API](./platform/system-crud-api.md) \u548C [CRUD \u751F\u6210\u5668](./development/crud-generator.md) \u5F00\u59CB\u3002
3691
+ - Web \u4E1A\u52A1\u9875\u9762\uFF1A[project-owned \u4E1A\u52A1 Web \u8DEF\u7531](./development/business-web-routes.md)\u3002
3692
+ - \u90E8\u7F72\u671F\u6A21\u5757\u7BA1\u7406\uFF1A[\u6A21\u5757\u751F\u547D\u5468\u671F](./development/module-lifecycle.md)\u3002
3667
3693
  - \u4E1A\u52A1\u6A21\u5757\u5F00\u53D1\uFF1A[windy-business-module Skill](../.agents/skills/windy-business-module/SKILL.md)\u3002
3668
3694
  ${includeOfflineLicense ? "- License \u6D88\u8D39\u7AEF\uFF1A[\u79BB\u7EBF\u6FC0\u6D3B\u4E0E\u5B89\u88C5\u534F\u8BAE](./license/license-offline-activation-code.md)\uFF1B\u8FD0\u884C\u65F6\u80FD\u529B\u7531 npm \u4F9D\u8D56 `@southwind-ai/license` \u63D0\u4F9B\u3002" : ""}
3669
- - \u8FD0\u7EF4\uFF1A[\u53EF\u89C2\u6D4B\u6027](./operations/observability.md) \u4E0E [\u8FD0\u7EF4\u603B\u89C8](./platform/operations-overview.md)\u3002
3695
+ - \u8FD0\u7EF4\uFF1A[\u53EF\u89C2\u6D4B\u6027](./operations/observability.md)${includeOperations ? " \u4E0E [\u8FD0\u7EF4\u603B\u89C8](./platform/operations-overview.md)" : ""}\u3002
3670
3696
  ${includeAgent ? "- Agent\u3001\u591A\u6A21\u6001 Runtime \u4E0E MCP\uFF1A[Agent Runtime \u63A5\u5165](./platform/agent-runtime.md)\u3001[Document AI Runtime](./platform/document-ai-runtime.md)\u3001[Speech AI Runtime](./platform/speech-ai-runtime.md)\u3001[\u53D7\u63A7\u5DE5\u5177](./platform/agent-tools.md)\u4E0E[MCP \u4E1A\u52A1\u80FD\u529B](./architecture/mcp-business-capabilities.md)\u3002" : ""}
3671
3697
  - \u517C\u5BB9\uFF1A[RuoYi-Vue Adapter](./adapters/ruoyi-vue-compatibility.md)\u3002
3672
3698
  `;
@@ -3675,7 +3701,7 @@ function starterReadme(projectName, includeExample = true, includeOxc = true, pr
3675
3701
  const selected = new Set(selectedModules);
3676
3702
  const includeAgent = selected.has("system.agent");
3677
3703
  const includeSearch = selected.has("system.search");
3678
- const moduleRows = moduleDistributionCatalog.map(({ name, description, selection }) => `| \`${name}\` | ${selected.has(name) ? "\u5DF2\u5305\u542B" : "\u672A\u5305\u542B"} | ${selection === "required" ? "H0" : "H2"} | ${description} |`).join(`
3704
+ const moduleRows = moduleDistributionCatalog.map(({ name, description, selection }) => `| \`${name}\` | ${selected.has(name) ? "\u5DF2\u5305\u542B" : "\u672A\u5305\u542B"} | ${selection === "required" ? "H0" : name === "work-order" ? "H3" : "H2"} | ${description} |`).join(`
3679
3705
  `);
3680
3706
  return `# ${projectName}
3681
3707
 
@@ -3832,19 +3858,22 @@ create-windy \u5728\u672C\u673A \`.env\` \u4E2D\u968F\u673A\u751F\u6210\u7684 \`
3832
3858
  | \u6CD5\u5F8B\u8BB8\u53EF | \`${projectLicense}\` |
3833
3859
 
3834
3860
  \u5E73\u53F0\u5F53\u524D\u6CE8\u518C\u7684\u5168\u90E8\u6A21\u5757\u5982\u4E0B\u3002H0 \u8868\u793A profile \u9501\u5B9A\u6838\u5FC3\uFF1BH2 \u8868\u793A\u521B\u5EFA\u65F6\u53EF\u4EE5\u7269\u7406\u5305\u542B\u6216
3835
- \u6392\u9664\uFF0C\u5E76\u5DF2\u6709\u751F\u6210\u3001\u7C7B\u578B\u68C0\u67E5\u3001\u6D4B\u8BD5\u548C\u6784\u5EFA\u8BC1\u636E\u3002H2 \u4E0D\u4EE3\u8868\u9879\u76EE\u90E8\u7F72\u540E\u5DF2\u7ECF\u652F\u6301\u65E0\u635F\u5B89\u88C5\u3001
3836
- \u5347\u7EA7\u6216\u5378\u8F7D\uFF1B\u90A3\u9700\u8981 H3 \u7684\u751F\u547D\u5468\u671F\u547D\u4EE4\u4E0E\u6570\u636E\u5904\u7F6E\u8BC1\u636E\u3002
3861
+ \u6392\u9664\uFF1BH3 \u8FD8\u5177\u5907\u90E8\u7F72\u671F\u5B89\u88C5\u3001\u66F4\u65B0\u3001\u6570\u636E\u4FDD\u7559\u5378\u8F7D\u548C\u91CD\u88C5\u8BC1\u636E\u3002\u901A\u7528\u751F\u547D\u5468\u671F\u547D\u4EE4\u4F1A\u4FDD\u5B88
3862
+ \u5904\u7406\u6240\u6709\u76EE\u5F55\u6A21\u5757\uFF0C\u4F46\u53EA\u6709\u901A\u8FC7\u5B8C\u6574 H3 \u56DE\u5F52\u7684\u6A21\u5757\u624D\u6807\u8BB0\u4E3A H3\u3002
3837
3863
 
3838
3864
  | Module Key | \u5F53\u524D\u9879\u76EE | \u70ED\u63D2\u62D4\u53EF\u9760\u5EA6 | \u8BF4\u660E |
3839
3865
  | ---------- | -------- | ------------ | ---- |
3840
3866
  ${moduleRows}
3841
3867
 
3842
3868
  \u9879\u76EE\u81EA\u6709\u4E1A\u52A1\u6A21\u5757\u4EE5 \`apps/server/src/installed-business-modules.ts\` \u88C5\u914D\u7684 Module Manifest
3843
- \u4E3A\u51C6\uFF1Bshared-scaffold README \u4E0D\u590D\u5236\u9879\u76EE\u4E1A\u52A1 Key\uFF0C\u907F\u514D\u5E73\u53F0\u5347\u7EA7\u56FA\u5316\u4EA7\u54C1\u547D\u540D\u3002
3869
+ \u4E3A\u51C6\uFF1B\u5BF9\u5E94 Vue \u9875\u9762\u5728 project-owned \u7684
3870
+ \`apps/web/src/app/business-routes.ts\` \u6CE8\u518C\uFF0C\u4FA7\u680F\u7EE7\u7EED\u4ECE\u670D\u52A1\u7AEF Manifest \u5FEB\u7167\u751F\u6210\u3002
3871
+ \u4E0D\u8981\u4E3A\u589E\u52A0\u4E1A\u52A1\u9875\u9762\u4FEE\u6539 shared-scaffold Router \u6216 AppSidebar\u3002shared-scaffold README
3872
+ \u4E0D\u590D\u5236\u9879\u76EE\u4E1A\u52A1 Key\uFF0C\u907F\u514D\u5E73\u53F0\u5347\u7EA7\u56FA\u5316\u4EA7\u54C1\u547D\u540D\u3002
3844
3873
 
3845
3874
  \u7CBE\u786E\u751F\u6210\u6765\u6E90\u548C\u9009\u62E9\u8BB0\u5F55\u5728 \`.windy/generation.json\`\u3002\u5F53\u524D\u7248\u672C\u5DF2\u63D0\u4F9B\u53EF\u56DE\u6EDA\u7684
3846
- \`windy update\`\uFF1B\u901A\u7528 \`module add/remove\` \u5C1A\u672A\u4EA4\u4ED8\uFF0C\u4E0D\u8981\u628A Feature Flag \u5173\u95ED\u5F53\u6210
3847
- \u6A21\u5757\u5DF2\u7ECF\u5378\u8F7D\u3002
3875
+ \`windy update\` \u4E0E \`windy module list/add/update/remove\`\u3002Feature Flag \u5173\u95ED\u4ECD\u4E0D
3876
+ \u7B49\u4E8E\u6A21\u5757\u5378\u8F7D\u3002
3848
3877
 
3849
3878
  ## \u5E38\u7528\u547D\u4EE4
3850
3879
 
@@ -3860,6 +3889,9 @@ bun run build
3860
3889
  bun run windy doctor
3861
3890
  bun run windy update --check
3862
3891
  bun run windy update --dry-run
3892
+ bun run windy module list
3893
+ bun run windy module add work-order --dry-run
3894
+ bun run windy module remove work-order --dry-run
3863
3895
  bun run windy reconcile --to <\u7CBE\u786E\u76EE\u6807\u7248\u672C>
3864
3896
  ${includeOxc ? `bun run lint
3865
3897
  bun run format` : "# \u672C\u9879\u76EE\u672A\u9884\u88C5 lint/format \u5DE5\u5177\uFF0C\u53EF\u6309\u56E2\u961F\u9700\u8981\u81EA\u884C\u9009\u62E9\u3002"}
@@ -3896,8 +3928,9 @@ create-windy \u9ED8\u8BA4\u5EFA\u7ACB \`main\` \u5206\u652F\u5E76\u521B\u5EFA \`
3896
3928
  \u6CA1\u6709\u914D\u7F6E Git \u7528\u6237\u8EAB\u4EFD\uFF0C\u6587\u4EF6\u4F1A\u4FDD\u7559\u5728\u6682\u5B58\u533A\uFF1B\u914D\u7F6E\u8EAB\u4EFD\u540E\u624B\u52A8\u63D0\u4EA4\u5373\u53EF\u3002
3897
3929
 
3898
3930
  \u5F53\u524D\u5DF2\u4EA4\u4ED8\u7684 Windy \u66F4\u65B0\u5668\u4F1A\u6839\u636E Project Lock \u548C\u6587\u4EF6\u6240\u6709\u6743\uFF0C\u4ECE npm \u5386\u53F2 artifact
3899
- \u91CD\u5EFA Base \u5E76\u6267\u884C\u4E09\u65B9\u5408\u5E76\uFF1B\u5B83\u4E0D\u8FDE\u63A5\u79C1\u6709\u6E90\u4ED3\u5E93\uFF0C\u4E5F\u4E0D\u4F1A\u9759\u9ED8\u8986\u76D6\u9879\u76EE\u4EE3\u7801\u3002\u90E8\u7F72\u671F\u901A\u7528
3900
- \`module add/update/remove\` \u5C1A\u672A\u4EA4\u4ED8\u3002
3931
+ \u91CD\u5EFA Base \u5E76\u6267\u884C\u4E09\u65B9\u5408\u5E76\uFF1B\u5B83\u4E0D\u8FDE\u63A5\u79C1\u6709\u6E90\u4ED3\u5E93\uFF0C\u4E5F\u4E0D\u4F1A\u9759\u9ED8\u8986\u76D6\u9879\u76EE\u4EE3\u7801\u3002\u6A21\u5757
3932
+ \u751F\u547D\u5468\u671F\u547D\u4EE4\u590D\u7528\u540C\u4E00\u8BA1\u5212\u3001\u4E8B\u52A1\u3001\u9A8C\u8BC1\u4E0E\u6062\u590D\u8FB9\u754C\uFF1B\u5378\u8F7D\u9ED8\u8BA4\u4FDD\u7559\u6570\u636E\u5E93\u6570\u636E\uFF0C\u5E76\u8981\u6C42
3933
+ \u663E\u5F0F\u786E\u8BA4\u6570\u636E\u5904\u7F6E\u8BA1\u5212\u3002
3901
3934
 
3902
3935
  ## License
3903
3936
 
@@ -4017,23 +4050,32 @@ var templateDocumentationFiles = [
4017
4050
  "docs/architecture/ai-runtime.md",
4018
4051
  "docs/architecture/data-scope-query-enforcement.md",
4019
4052
  "docs/architecture/durable-jobs.md",
4053
+ "docs/architecture/foundation-infrastructure.md",
4020
4054
  "docs/architecture/minimal-approval-workflow.md",
4021
4055
  "docs/architecture/mcp-business-capabilities.md",
4022
4056
  "docs/architecture/migration-bundle.md",
4057
+ "docs/architecture/module-host.md",
4023
4058
  "docs/architecture/module-manifest-composition.md",
4024
4059
  "docs/architecture/object-storage.md",
4025
4060
  "docs/architecture/search-provider-protocol.md",
4061
+ "docs/architecture/server-module-interface.md",
4062
+ "docs/architecture/web-access-snapshot-resilience.md",
4063
+ "docs/development/business-web-routes.md",
4026
4064
  "docs/development/crud-generator.md",
4027
4065
  "docs/development/custom-error-pages.md",
4028
4066
  "docs/development/custom-login-page.md",
4067
+ "docs/development/module-lifecycle.md",
4029
4068
  "docs/license/license-offline-activation-code.md",
4030
4069
  "docs/operations/observability.md",
4031
4070
  "docs/platform/agent-tools.md",
4032
4071
  "docs/platform/agent-runtime.md",
4072
+ "docs/platform/agent-tool-sandbox.md",
4033
4073
  "docs/platform/audit-reliability.md",
4034
4074
  "docs/platform/bulk-data-jobs.md",
4035
4075
  "docs/platform/business-user-directory.md",
4036
4076
  "docs/platform/data-access-control.md",
4077
+ "docs/platform/document-ai-runtime.md",
4078
+ "docs/platform/governed-export-renderers.md",
4037
4079
  "docs/platform/module-configuration.md",
4038
4080
  "docs/platform/navigation-registry.md",
4039
4081
  "docs/platform/notifications.md",
@@ -4042,7 +4084,9 @@ var templateDocumentationFiles = [
4042
4084
  "docs/platform/platform-authentication.md",
4043
4085
  "docs/platform/platform-shell-settings.md",
4044
4086
  "docs/platform/scheduled-task-executor.md",
4087
+ "docs/platform/speech-ai-runtime.md",
4045
4088
  "docs/platform/system-crud-api.md",
4089
+ "docs/platform/vision-ai-runtime.md",
4046
4090
  "docs/platform/web-system-crud.md",
4047
4091
  "docs/product/built-in-roles.md"
4048
4092
  ];
@@ -4263,7 +4307,7 @@ async function generateProject(input) {
4263
4307
  await writeFile8(join12(input.targetDirectory, "docker-compose.yml"), starterComposeFor(selectedModules.includes("system.agent"), selectedModules.includes("system.search")));
4264
4308
  await writeFile8(join12(input.targetDirectory, ".env.example"), environmentExample(includeExample, selectedModules.includes("system.agent"), selectedModules.includes("system.search")));
4265
4309
  await writeFile8(join12(input.targetDirectory, "README.md"), starterReadme(input.projectName, includeExample, includeOxc, projectLicense, selectedModules));
4266
- await writeFile8(join12(input.targetDirectory, "docs/README.md"), starterDocsReadme(selectedModules.includes("system.license"), selectedModules.includes("system.agent")));
4310
+ await writeFile8(join12(input.targetDirectory, "docs/README.md"), starterDocsReadme(selectedModules.includes("system.license"), selectedModules.includes("system.agent"), selectedModules.includes("system.operations")));
4267
4311
  await reflectCodeQualityChoice(input.targetDirectory, includeOxc);
4268
4312
  await applyWindyBaseLicense(input.targetDirectory);
4269
4313
  await applyProjectLicense(input.targetDirectory, projectLicense, input.licenseHolder);
@@ -6190,8 +6234,8 @@ function sentenceWithoutStop(value) {
6190
6234
  }
6191
6235
 
6192
6236
  // src/update/cli.ts
6193
- import { rm as rm10 } from "fs/promises";
6194
- import { resolve as resolve7 } from "path";
6237
+ import { rm as rm11 } from "fs/promises";
6238
+ import { resolve as resolve8 } from "path";
6195
6239
 
6196
6240
  // src/reconcile/managed-reconciler.ts
6197
6241
  import { rm as rm6 } from "fs/promises";
@@ -8599,8 +8643,51 @@ function isObject(value) {
8599
8643
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8600
8644
  }
8601
8645
 
8646
+ // src/update/planner-project-owned.ts
8647
+ function planGeneratedProjectOwned(path2, source, target, ours, theirs, expected) {
8648
+ if (!source && target) {
8649
+ return !ours && theirs ? ready(path2, "create", "\u6A21\u5757\u5B89\u88C5\u65B0\u589E\u9879\u76EE\u6269\u5C55\u70B9", expected, theirs) : conflict(path2, "\u6A21\u5757\u65B0\u589E\u8DEF\u5F84\u5DF2\u88AB\u9879\u76EE\u5360\u7528", expected);
8650
+ }
8651
+ if (source && !target) {
8652
+ if (!ours) {
8653
+ return ready(path2, "preserve", "\u6A21\u5757\u8DEF\u5F84\u5DF2\u79FB\u9664", expected);
8654
+ }
8655
+ return hashContent(ours) === source.hash ? ready(path2, "delete", "\u6A21\u5757\u5378\u8F7D\u79FB\u9664\u672A\u4FEE\u6539\u6269\u5C55\u70B9", expected) : conflict(path2, "\u5BA2\u6237\u4FEE\u6539\u8FC7\u6A21\u5757\u6269\u5C55\u70B9\uFF0C\u62D2\u7EDD\u5378\u8F7D", expected);
8656
+ }
8657
+ if (!source || !target || !ours || !theirs) {
8658
+ return ready(path2, "preserve", "\u9879\u76EE\u62E5\u6709\uFF0C\u6A21\u5757\u7EC4\u5408\u672A\u6539\u53D8", expected);
8659
+ }
8660
+ if (hashContent(ours) === target.hash) {
8661
+ return ready(path2, "preserve", "\u5DF2\u5305\u542B\u76EE\u6807\u6A21\u5757\u7EC4\u5408", expected);
8662
+ }
8663
+ if (source.hash === target.hash) {
8664
+ return ready(path2, "preserve", "\u6A21\u5757\u7EC4\u5408\u672A\u6539\u53D8", expected);
8665
+ }
8666
+ return hashContent(ours) === source.hash ? ready(path2, "update", "\u66F4\u65B0\u672A\u4FEE\u6539\u7684\u6A21\u5757\u7EC4\u5408\u6269\u5C55\u70B9", expected, theirs) : conflict(path2, "\u5BA2\u6237\u4FEE\u6539\u8FC7\u6A21\u5757\u7EC4\u5408\u6269\u5C55\u70B9", expected);
8667
+ }
8668
+ function ready(path2, action, reason, expectedProjectContent, content) {
8669
+ return {
8670
+ path: path2,
8671
+ ownership: "project-owned",
8672
+ action,
8673
+ reason,
8674
+ expectedProjectContent,
8675
+ content
8676
+ };
8677
+ }
8678
+ function conflict(path2, reason, expectedProjectContent) {
8679
+ return {
8680
+ path: path2,
8681
+ ownership: "project-owned",
8682
+ action: "preserve",
8683
+ reason: "\u5BA2\u6237\u5DF2\u4FEE\u6539",
8684
+ expectedProjectContent,
8685
+ conflict: reason
8686
+ };
8687
+ }
8688
+
8602
8689
  // src/update/planner-file.ts
8603
- async function planFile(path2, baseRoot, targetRoot, source, target, ours, provenance, targetContentOverride) {
8690
+ async function planFile(path2, baseRoot, targetRoot, source, target, ours, provenance, targetContentOverride, manageGeneratedProjectOwned = false) {
8604
8691
  const [base, theirs] = await Promise.all([
8605
8692
  readOptional(join19(baseRoot, path2)),
8606
8693
  targetContentOverride ? Promise.resolve(targetContentOverride) : readOptional(join19(targetRoot, path2))
@@ -8608,6 +8695,9 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
8608
8695
  const ownership = source?.ownership === "project-owned" ? source.ownership : target?.ownership || source?.ownership || classifyOwnership(path2);
8609
8696
  const expected = expectationForSnapshot(ours);
8610
8697
  if (ownership === "project-owned") {
8698
+ if (manageGeneratedProjectOwned) {
8699
+ return planGeneratedProjectOwned(path2, source, target, ours, theirs, expected);
8700
+ }
8611
8701
  return !source && !ours && theirs ? readyPlannedFile(path2, ownership, "create", "\u65B0\u589E\u9879\u76EE\u6269\u5C55\u70B9", expected, theirs) : readyPlannedFile(path2, ownership, "preserve", "\u9879\u76EE\u62E5\u6709\uFF0CWindy \u4E0D\u8986\u76D6", expected);
8612
8702
  }
8613
8703
  const repaired = ours && theirs ? repairKnownDerivedFile({
@@ -8622,35 +8712,34 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
8622
8712
  }
8623
8713
  if (path2.startsWith("packages/database/drizzle/") && path2.endsWith(".sql")) {
8624
8714
  if (source && !target) {
8625
- return conflict(path2, ownership, "\u5DF2\u53D1\u5E03 migration \u4E0D\u53EF\u5220\u9664", expected);
8715
+ return conflict2(path2, ownership, "\u5DF2\u53D1\u5E03 migration \u4E0D\u53EF\u5220\u9664", expected);
8626
8716
  }
8627
8717
  if (source && target && source.hash !== target.hash) {
8628
- return conflict(path2, ownership, "\u5DF2\u53D1\u5E03 migration \u4E0D\u53EF\u6539\u5199\uFF0C\u53EA\u80FD\u8FFD\u52A0\u65B0\u6587\u4EF6", expected);
8718
+ return conflict2(path2, ownership, "\u5DF2\u53D1\u5E03 migration \u4E0D\u53EF\u6539\u5199\uFF0C\u53EA\u80FD\u8FFD\u52A0\u65B0\u6587\u4EF6", expected);
8629
8719
  }
8630
8720
  }
8631
8721
  if (!source && target) {
8632
8722
  if (!ours) {
8633
8723
  return readyPlannedFile(path2, ownership, "create", "\u76EE\u6807\u7248\u672C\u65B0\u589E", expected, theirs);
8634
8724
  }
8635
- return theirs && hashContent(ours) === target.hash ? readyPlannedFile(path2, ownership, "preserve", "\u5DF2\u5305\u542B\u76EE\u6807\u5185\u5BB9", expected) : conflict(path2, ownership, "\u76EE\u6807\u7248\u672C\u65B0\u589E\u8DEF\u5F84\u5DF2\u88AB\u9879\u76EE\u5360\u7528", expected);
8725
+ return theirs && hashContent(ours) === target.hash ? readyPlannedFile(path2, ownership, "preserve", "\u5DF2\u5305\u542B\u76EE\u6807\u5185\u5BB9", expected) : conflict2(path2, ownership, "\u76EE\u6807\u7248\u672C\u65B0\u589E\u8DEF\u5F84\u5DF2\u88AB\u9879\u76EE\u5360\u7528", expected);
8636
8726
  }
8637
8727
  if (source && !target) {
8638
8728
  if (!ours) {
8639
8729
  return readyPlannedFile(path2, ownership, "preserve", "\u9879\u76EE\u5DF2\u5220\u9664", expected);
8640
8730
  }
8641
- return hashContent(ours) === source.hash ? readyPlannedFile(path2, ownership, "delete", "\u76EE\u6807\u7248\u672C\u5220\u9664", expected) : conflict(path2, ownership, "\u5BA2\u6237\u4FEE\u6539\u540E Windy \u53C8\u5220\u9664", expected);
8731
+ return hashContent(ours) === source.hash ? readyPlannedFile(path2, ownership, "delete", "\u76EE\u6807\u7248\u672C\u5220\u9664", expected) : conflict2(path2, ownership, "\u5BA2\u6237\u4FEE\u6539\u540E Windy \u53C8\u5220\u9664", expected);
8642
8732
  }
8643
8733
  if (!source || !target || !ours || !theirs) {
8644
- return conflict(path2, ownership, "\u6587\u4EF6\u72B6\u6001\u4E0D\u5B8C\u6574\uFF0C\u4E0D\u80FD\u5B89\u5168\u63A8\u65AD", expected);
8734
+ return conflict2(path2, ownership, "\u6587\u4EF6\u72B6\u6001\u4E0D\u5B8C\u6574\uFF0C\u4E0D\u80FD\u5B89\u5168\u63A8\u65AD", expected);
8645
8735
  }
8646
8736
  const oursChanged = hashContent(ours) !== source.hash;
8647
8737
  const sourceArtifactHash = artifactHashOf(source);
8648
8738
  const targetChanged = targetChangedSinceBase(sourceArtifactHash, base, theirs);
8649
- const reconstructedBaseDrifted = !!base && hashContent(base) !== sourceArtifactHash;
8650
8739
  if (!oursChanged && !targetChanged) {
8651
8740
  return readyPlannedFile(path2, ownership, "preserve", "\u53CC\u65B9\u672A\u4FEE\u6539", expected);
8652
8741
  }
8653
- if (!oursChanged && !reconstructedBaseDrifted) {
8742
+ if (!oursChanged) {
8654
8743
  return readyPlannedFile(path2, ownership, "update", "\u4EC5 Windy \u4FEE\u6539", expected, theirs);
8655
8744
  }
8656
8745
  if (!targetChanged) {
@@ -8661,13 +8750,13 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
8661
8750
  }
8662
8751
  if (path2.endsWith("package.json") && base) {
8663
8752
  const merged = mergePackageJson(base, ours, theirs);
8664
- return merged.content ? readyPlannedFile(path2, ownership, "update", "package.json \u5B57\u6BB5\u7EA7\u5408\u5E76", expected, merged.content) : conflict(path2, ownership, `\u5B57\u6BB5\u51B2\u7A81\uFF1A${merged.conflicts.join("\u3001")}`, expected);
8753
+ return merged.content ? readyPlannedFile(path2, ownership, "update", "package.json \u5B57\u6BB5\u7EA7\u5408\u5E76", expected, merged.content) : conflict2(path2, ownership, `\u5B57\u6BB5\u51B2\u7A81\uFF1A${merged.conflicts.join("\u3001")}`, expected);
8665
8754
  }
8666
8755
  if (ownership === "shared-scaffold" && base) {
8667
8756
  const merged = await mergeTextFile(base, ours, theirs);
8668
- return merged.content ? readyPlannedFile(path2, ownership, "update", "\u4E09\u65B9\u5408\u5E76", expected, merged.content) : conflict(path2, ownership, merged.conflict || "\u4E09\u65B9\u5408\u5E76\u5931\u8D25", expected);
8757
+ return merged.content ? readyPlannedFile(path2, ownership, "update", "\u4E09\u65B9\u5408\u5E76", expected, merged.content) : conflict2(path2, ownership, merged.conflict || "\u4E09\u65B9\u5408\u5E76\u5931\u8D25", expected);
8669
8758
  }
8670
- return conflict(path2, ownership, "\u5BA2\u6237\u548C Windy \u5747\u5DF2\u4FEE\u6539", expected);
8759
+ return conflict2(path2, ownership, "\u5BA2\u6237\u548C Windy \u5747\u5DF2\u4FEE\u6539", expected);
8671
8760
  }
8672
8761
  function targetChangedSinceBase(sourceHash, base, target) {
8673
8762
  return base && target ? hashContent(base) !== hashContent(target) : !!target && hashContent(target) !== sourceHash;
@@ -8685,7 +8774,7 @@ function readyPlannedFile(path2, ownership, action, reason, expectedProjectConte
8685
8774
  function expectationForSnapshot(content) {
8686
8775
  return content ? { kind: "hash", value: hashContent(content) } : { kind: "missing" };
8687
8776
  }
8688
- function conflict(path2, ownership, reason, expectedProjectContent) {
8777
+ function conflict2(path2, ownership, reason, expectedProjectContent) {
8689
8778
  return {
8690
8779
  path: path2,
8691
8780
  ownership,
@@ -8868,7 +8957,9 @@ var recipes = [
8868
8957
  { id: "starter-0.3.0-to-0.3.1", from: "0.3.0", to: "0.3.1" },
8869
8958
  { id: "starter-0.3.1-to-0.3.2", from: "0.3.1", to: "0.3.2" },
8870
8959
  { id: "starter-0.3.2-to-0.3.3", from: "0.3.2", to: "0.3.3" },
8871
- { id: "starter-0.3.3-to-0.3.4", from: "0.3.3", to: "0.3.4" }
8960
+ { id: "starter-0.3.3-to-0.3.4", from: "0.3.3", to: "0.3.4" },
8961
+ { id: "starter-0.3.4-to-0.3.5", from: "0.3.4", to: "0.3.5" },
8962
+ { id: "starter-0.3.5-to-0.3.6", from: "0.3.5", to: "0.3.6" }
8872
8963
  ];
8873
8964
  function resolveRecipeChain(sourceVersion, targetVersion) {
8874
8965
  if (sourceVersion === targetVersion)
@@ -8909,13 +9000,15 @@ async function createUpdatePlan(request, artifacts) {
8909
9000
  const expectedManifestHash = hashContent(await readFile17(manifestPath));
8910
9001
  const generationSnapshot = await readGenerationProvenanceSnapshot(request.projectDirectory);
8911
9002
  const provenance = generationSnapshot.provenance;
8912
- const artifactSet = await artifacts.prepare(request.projectDirectory, provenance);
9003
+ const artifactSet = await artifacts.prepare(request.projectDirectory, provenance, request.targetModules);
8913
9004
  const targetProvenance = await readGenerationProvenance(artifactSet.targetDirectory);
8914
9005
  const targetVersion = request.targetVersion || targetProvenance.generatorVersion;
8915
9006
  if (targetVersion !== targetProvenance.generatorVersion) {
8916
9007
  throw new Error(`\u5F53\u524D CLI \u53EA\u80FD\u66F4\u65B0\u5230 ${targetProvenance.generatorVersion}\uFF0C\u8BF7\u8FD0\u884C create-windy@${targetVersion}`);
8917
9008
  }
8918
- const recipes2 = resolveRecipeChain(provenance.windyVersion, targetVersion);
9009
+ const versionRecipes = resolveRecipeChain(provenance.windyVersion, targetVersion);
9010
+ const moduleRecipes = resolveModuleRecipeIds(request);
9011
+ const recipes2 = [...versionRecipes.map(({ id }) => id), ...moduleRecipes];
8919
9012
  const [rawSourceManifest, rawTargetManifest] = await Promise.all([
8920
9013
  readManagedFilesManifest(request.projectDirectory),
8921
9014
  readManagedFilesManifest(artifactSet.targetDirectory)
@@ -8928,6 +9021,7 @@ async function createUpdatePlan(request, artifacts) {
8928
9021
  ...generatedTargetManifest.files.map(({ path: path2 }) => path2)
8929
9022
  ]);
8930
9023
  const workspaceSnapshot = await snapshotWorkspacePackages(request.projectDirectory, { allowMissingRoot: true });
9024
+ const targetWorkspaceSnapshot = await snapshotWorkspacePackages(artifactSet.targetDirectory, { allowMissingRoot: true });
8931
9025
  const projectSnapshots = await snapshotProjectFiles(request.projectDirectory, initialPaths, workspaceSnapshot.manifests);
8932
9026
  projectSnapshots.set(generationMetadataFile, generationSnapshot.content);
8933
9027
  const projectModes = await snapshotProjectModes(request.projectDirectory, initialPaths);
@@ -8941,8 +9035,7 @@ async function createUpdatePlan(request, artifacts) {
8941
9035
  });
8942
9036
  const targetManifest = await carryReconciledBaselines(sourceManifest, migrations.targetManifest, projectSnapshots, artifactSet.targetDirectory);
8943
9037
  targetProvenance.appliedRecipes = [
8944
- ...provenance.appliedRecipes,
8945
- ...recipes2.map(({ id }) => id)
9038
+ ...new Set([...provenance.appliedRecipes, ...recipes2])
8946
9039
  ];
8947
9040
  const sourceEntries = new Map(sourceManifest.files.map((item) => [item.path, item]));
8948
9041
  const targetEntries = new Map(targetManifest.files.map((item) => [item.path, item]));
@@ -8960,7 +9053,8 @@ async function createUpdatePlan(request, artifacts) {
8960
9053
  targetEntries,
8961
9054
  migrations,
8962
9055
  artifactSet,
8963
- provenance
9056
+ provenance,
9057
+ manageGeneratedProjectOwned: request.targetModules !== undefined
8964
9058
  });
8965
9059
  deriveWebDockerfilePlan(files, projectSnapshots, new Set([...paths, ...workspaceSnapshot.manifests.keys()]));
8966
9060
  for (const file of files) {
@@ -9007,18 +9101,33 @@ async function createUpdatePlan(request, artifacts) {
9007
9101
  projectDirectory: request.projectDirectory,
9008
9102
  sourceVersion: provenance.windyVersion,
9009
9103
  targetVersion,
9010
- recipes: recipes2.map(({ id }) => id),
9104
+ recipes: recipes2,
9011
9105
  files,
9012
9106
  dependencyExpectations,
9013
9107
  workspaceMembershipExpectations: workspaceSnapshot.membershipExpectations,
9108
+ finalWorkspaceMembershipExpectations: targetWorkspaceSnapshot.membershipExpectations,
9014
9109
  conflicts,
9015
9110
  detachedToolchain,
9016
9111
  targetProvenance,
9017
9112
  sourceManifest,
9018
9113
  targetManifest,
9019
- temporaryRoot: artifactSet.temporaryRoot
9114
+ temporaryRoot: artifactSet.temporaryRoot,
9115
+ lifecycle: request.lifecycle
9020
9116
  };
9021
9117
  }
9118
+ function resolveModuleRecipeIds(request) {
9119
+ const lifecycle = request.lifecycle;
9120
+ if (!lifecycle)
9121
+ return [];
9122
+ const catalog = new Map(moduleDistributionCatalog.map((manifest) => [manifest.name, manifest]));
9123
+ if (lifecycle.action === "add") {
9124
+ return lifecycle.addedModules.map((name) => catalog.get(name).installRecipe);
9125
+ }
9126
+ if (lifecycle.action === "remove") {
9127
+ return lifecycle.removedModules.map((name) => catalog.get(name).uninstallRecipe);
9128
+ }
9129
+ return lifecycle.updatedModules.flatMap((name) => catalog.get(name).updateRecipes);
9130
+ }
9022
9131
  async function planFiles(input) {
9023
9132
  const files = [];
9024
9133
  for (const path2 of [...input.paths].sort()) {
@@ -9032,7 +9141,7 @@ async function planFiles(input) {
9032
9141
  } else if (forcedContent) {
9033
9142
  files.push(readyPlannedFile(path2, input.targetEntries.get(path2)?.ownership ?? input.sourceEntries.get(path2)?.ownership ?? classifyOwnership(path2), "update", "\u5408\u5E76\u5E73\u53F0\u4E0E\u4E0B\u6E38 migration \u5386\u53F2", expected, forcedContent));
9034
9143
  } else {
9035
- files.push(await planFile(path2, input.artifactSet.baseDirectory, input.artifactSet.targetDirectory, input.sourceEntries.get(path2), input.targetEntries.get(path2), ours, input.provenance, input.migrations.contentOverrides.get(path2)));
9144
+ files.push(await planFile(path2, input.artifactSet.baseDirectory, input.artifactSet.targetDirectory, input.sourceEntries.get(path2), input.targetEntries.get(path2), ours, input.provenance, input.migrations.contentOverrides.get(path2), input.manageGeneratedProjectOwned));
9036
9145
  }
9037
9146
  }
9038
9147
  return files;
@@ -9749,23 +9858,113 @@ async function diagnoseProject(projectDirectory, repair = false) {
9749
9858
  }
9750
9859
 
9751
9860
  // src/update/updater.ts
9752
- import { readFile as readFile23, rm as rm9 } from "fs/promises";
9753
- import { join as join30 } from "path";
9861
+ import { readFile as readFile24, rm as rm9 } from "fs/promises";
9862
+ import { join as join31 } from "path";
9754
9863
 
9755
9864
  // src/update/artifacts.ts
9756
- import { mkdtemp as mkdtemp3, readFile as readFile21 } from "fs/promises";
9865
+ import { mkdtemp as mkdtemp3, readFile as readFile22 } from "fs/promises";
9757
9866
  import { tmpdir as tmpdir3 } from "os";
9758
- import { basename as basename8, join as join28 } from "path";
9867
+ import { basename as basename8, join as join29 } from "path";
9868
+
9869
+ // src/module-history.ts
9870
+ import {
9871
+ lstat as lstat5,
9872
+ mkdir as mkdir7,
9873
+ readdir as readdir8,
9874
+ readFile as readFile21,
9875
+ writeFile as writeFile11
9876
+ } from "fs/promises";
9877
+ import { dirname as dirname7, join as join28, relative as relative4, sep as sep4 } from "path";
9878
+ async function archiveRemovedModuleMigrations(input) {
9879
+ await assertExistingHistoryIntegrity(input.projectDirectory);
9880
+ let changed = await copyMigrationTree(input.projectDirectory, ".windy/module-history", join28(input.targetDirectory, ".windy/module-history"));
9881
+ const target = new Set(input.targetModules);
9882
+ const removed = moduleDistributionCatalog.filter(({ name }) => input.sourceModules.includes(name) && !target.has(name));
9883
+ for (const manifest of removed) {
9884
+ for (const root of manifest.migrationRoots) {
9885
+ changed = await copyMigrationTree(input.projectDirectory, root, join28(input.targetDirectory, ".windy/module-history", manifest.name, root)) || changed;
9886
+ }
9887
+ }
9888
+ if (changed) {
9889
+ await writeManagedFilesManifest(input.targetDirectory, input.generatorVersion);
9890
+ }
9891
+ }
9892
+ async function assertExistingHistoryIntegrity(projectDirectory) {
9893
+ const historyRoot = join28(projectDirectory, ".windy/module-history");
9894
+ const metadata = await readOptionalMetadata(historyRoot);
9895
+ if (!metadata)
9896
+ return;
9897
+ if (metadata.isSymbolicLink() || !metadata.isDirectory()) {
9898
+ throw new Error("\u6A21\u5757 migration \u5386\u53F2\u76EE\u5F55\u65E0\u6548");
9899
+ }
9900
+ const manifest = await readManagedFilesManifest(projectDirectory);
9901
+ const expected = new Map(manifest.files.map((entry) => [entry.path, entry]));
9902
+ for (const path2 of await collectRegularFiles(historyRoot)) {
9903
+ const relativePath2 = relative4(projectDirectory, path2).split(sep4).join("/");
9904
+ const entry = expected.get(relativePath2);
9905
+ if (!entry || isMissingManagedFile(entry)) {
9906
+ throw new Error(`\u6A21\u5757 migration \u5386\u53F2\u672A\u767B\u8BB0\u5230\u53D7\u7BA1\u6E05\u5355\uFF1A${relativePath2}`);
9907
+ }
9908
+ if (hashContent(await readFile21(path2)) !== entry.hash) {
9909
+ throw new Error(`\u6A21\u5757 migration \u5386\u53F2\u5DF2\u88AB\u4FEE\u6539\uFF1A${relativePath2}`);
9910
+ }
9911
+ }
9912
+ }
9913
+ async function copyMigrationTree(projectRoot, relativeRoot, targetRoot) {
9914
+ const sourceRoot = join28(projectRoot, relativeRoot);
9915
+ const rootMetadata = await readOptionalMetadata(sourceRoot);
9916
+ if (!rootMetadata)
9917
+ return false;
9918
+ if (rootMetadata.isSymbolicLink() || !rootMetadata.isDirectory()) {
9919
+ throw new Error(`\u6A21\u5757 migration \u6839\u76EE\u5F55\u65E0\u6548\uFF1A${relativeRoot}`);
9920
+ }
9921
+ for (const source of await collectRegularFiles(sourceRoot)) {
9922
+ const target = join28(targetRoot, relative4(sourceRoot, source).split(sep4).join("/"));
9923
+ await mkdir7(dirname7(target), { recursive: true });
9924
+ await writeFile11(target, await readFile21(source));
9925
+ }
9926
+ return true;
9927
+ }
9928
+ async function collectRegularFiles(root) {
9929
+ const files = [];
9930
+ await visit(root);
9931
+ return files.sort();
9932
+ async function visit(directory) {
9933
+ for (const name of (await readdir8(directory)).sort()) {
9934
+ const path2 = join28(directory, name);
9935
+ const metadata = await lstat5(path2);
9936
+ if (metadata.isSymbolicLink()) {
9937
+ throw new Error(`\u6A21\u5757 migration \u4E0D\u5141\u8BB8\u7B26\u53F7\u94FE\u63A5\uFF1A${path2}`);
9938
+ }
9939
+ if (metadata.isDirectory())
9940
+ await visit(path2);
9941
+ else if (metadata.isFile())
9942
+ files.push(path2);
9943
+ }
9944
+ }
9945
+ }
9946
+ async function readOptionalMetadata(path2) {
9947
+ try {
9948
+ return await lstat5(path2);
9949
+ } catch (error) {
9950
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
9951
+ return;
9952
+ }
9953
+ throw error;
9954
+ }
9955
+ }
9956
+
9957
+ // src/update/artifacts.ts
9759
9958
  class PublishedArtifactProvider {
9760
9959
  #fetch;
9761
9960
  constructor(fetcher = globalThis.fetch) {
9762
9961
  this.#fetch = fetcher;
9763
9962
  }
9764
- async prepare(projectDirectory, provenance) {
9765
- const temporaryRoot = await mkdtemp3(join28(tmpdir3(), "windy-update-"));
9963
+ async prepare(projectDirectory, provenance, targetModules) {
9964
+ const temporaryRoot = await mkdtemp3(join29(tmpdir3(), "windy-update-"));
9766
9965
  const projectName = await readProjectName3(projectDirectory);
9767
- const baseDirectory = join28(temporaryRoot, "base", projectName);
9768
- const targetDirectory = join28(temporaryRoot, "target", projectName);
9966
+ const baseDirectory = join29(temporaryRoot, "base", projectName);
9967
+ const targetDirectory = join29(temporaryRoot, "target", projectName);
9769
9968
  const baseArtifact = await downloadPublicArtifact(temporaryRoot, "base", provenance.generatorVersion, undefined, this.#fetch);
9770
9969
  if (baseArtifact.identity.templateCommit !== provenance.templateCommit) {
9771
9970
  throw new Error("Project Lock \u4E0E\u6765\u6E90 registry artifact \u7684 template commit \u4E0D\u4E00\u81F4");
@@ -9775,18 +9974,25 @@ class PublishedArtifactProvider {
9775
9974
  sourceRoot: await resolveTemplateRoot(),
9776
9975
  targetDirectory,
9777
9976
  projectName,
9778
- selectedModules: provenance.modules.map(({ name }) => name),
9779
- includeExample: provenance.choices.includeExample,
9977
+ selectedModules: targetModules ?? provenance.modules.map(({ name }) => name),
9978
+ includeExample: (targetModules ?? provenance.modules.map(({ name }) => name)).includes("work-order"),
9780
9979
  includeOxc: provenance.choices.includeOxc,
9781
9980
  projectLicense: provenance.legalLicense,
9782
9981
  licenseHolder: provenance.legalLicense === "MIT" ? "Windy project owner" : undefined,
9783
9982
  profile: provenance.profile
9784
9983
  });
9984
+ await archiveRemovedModuleMigrations({
9985
+ projectDirectory,
9986
+ targetDirectory,
9987
+ sourceModules: provenance.modules.map(({ name }) => name),
9988
+ targetModules: targetModules ?? provenance.modules.map(({ name }) => name),
9989
+ generatorVersion: (await readGenerationProvenance(targetDirectory)).generatorVersion
9990
+ });
9785
9991
  return { temporaryRoot, baseDirectory, targetDirectory };
9786
9992
  }
9787
9993
  }
9788
9994
  async function readProjectName3(projectDirectory) {
9789
- const source = JSON.parse(await readFile21(join28(projectDirectory, "package.json"), "utf8"));
9995
+ const source = JSON.parse(await readFile22(join29(projectDirectory, "package.json"), "utf8"));
9790
9996
  return source.name || basename8(projectDirectory);
9791
9997
  }
9792
9998
 
@@ -9853,9 +10059,9 @@ function frozenManifestHash(file, finalizedHashes) {
9853
10059
  }
9854
10060
 
9855
10061
  // src/update/format-stabilizer.ts
9856
- import { mkdir as mkdir7, mkdtemp as mkdtemp4, readFile as readFile22, rm as rm8, writeFile as writeFile11 } from "fs/promises";
10062
+ import { mkdir as mkdir8, mkdtemp as mkdtemp4, readFile as readFile23, rm as rm8, writeFile as writeFile12 } from "fs/promises";
9857
10063
  import { tmpdir as tmpdir4 } from "os";
9858
- import { dirname as dirname7, extname as extname4, join as join29, resolve as resolve6, sep as sep4 } from "path";
10064
+ import { dirname as dirname8, extname as extname4, join as join30, resolve as resolve6, sep as sep5 } from "path";
9859
10065
  var formattedExtensions = new Set([
9860
10066
  ".cjs",
9861
10067
  ".css",
@@ -9894,7 +10100,7 @@ async function stabilizeManagedContent(result2, execute, writeProjectFile) {
9894
10100
  }
9895
10101
  }
9896
10102
  inputs.set(".windy/generation.json", new TextEncoder().encode(generationContent));
9897
- const temporaryRoot = await mkdtemp4(join29(tmpdir4(), "windy-update-format-"));
10103
+ const temporaryRoot = await mkdtemp4(join30(tmpdir4(), "windy-update-format-"));
9898
10104
  try {
9899
10105
  const stagedPaths = await stageInputs(temporaryRoot, inputs);
9900
10106
  for (let offset = 0;offset < stagedPaths.length; offset += 80) {
@@ -9902,14 +10108,14 @@ async function stabilizeManagedContent(result2, execute, writeProjectFile) {
9902
10108
  "x",
9903
10109
  "oxfmt",
9904
10110
  "--write",
9905
- `--config=${join29(result2.plan.projectDirectory, ".oxfmtrc.json")}`,
10111
+ `--config=${join30(result2.plan.projectDirectory, ".oxfmtrc.json")}`,
9906
10112
  ...stagedPaths.slice(offset, offset + 80)
9907
10113
  ], result2.plan.projectDirectory);
9908
10114
  }
9909
10115
  const hashes = plannedContentHashes(result2);
9910
10116
  let formattedGeneration = generationContent;
9911
10117
  for (const [path2, original] of inputs) {
9912
- const formatted = await readFile22(safeTemporaryPath(temporaryRoot, path2));
10118
+ const formatted = await readFile23(safeTemporaryPath(temporaryRoot, path2));
9913
10119
  if (path2 === ".windy/generation.json") {
9914
10120
  formattedGeneration = formatted.toString();
9915
10121
  continue;
@@ -9935,15 +10141,15 @@ async function stageInputs(temporaryRoot, inputs) {
9935
10141
  const paths = [];
9936
10142
  for (const [path2, content] of inputs) {
9937
10143
  const target = safeTemporaryPath(temporaryRoot, path2);
9938
- await mkdir7(dirname7(target), { recursive: true });
9939
- await writeFile11(target, content);
10144
+ await mkdir8(dirname8(target), { recursive: true });
10145
+ await writeFile12(target, content);
9940
10146
  paths.push(target);
9941
10147
  }
9942
10148
  return paths;
9943
10149
  }
9944
10150
  function safeTemporaryPath(root, path2) {
9945
10151
  const target = resolve6(root, path2);
9946
- if (!target.startsWith(`${resolve6(root)}${sep4}`)) {
10152
+ if (!target.startsWith(`${resolve6(root)}${sep5}`)) {
9947
10153
  throw new Error(`\u683C\u5F0F\u5316\u8DEF\u5F84\u8D8A\u51FA\u4E34\u65F6\u76EE\u5F55\uFF1A${path2}`);
9948
10154
  }
9949
10155
  return target;
@@ -10006,7 +10212,7 @@ class DefaultStarterUpdater {
10006
10212
  const plannedPaths = new Set(result2.plan.files.map(({ path: path2 }) => path2));
10007
10213
  replaceExpectations(result2, verificationSnapshot.filter(({ path: path2 }) => !metadataPaths2.has(path2) && !plannedPaths.has(path2)));
10008
10214
  verificationExpectationsFrozen = true;
10009
- const packageJson = JSON.parse(await readFile23(join30(result2.plan.projectDirectory, "package.json"), "utf8"));
10215
+ const packageJson = JSON.parse(await readFile24(join31(result2.plan.projectDirectory, "package.json"), "utf8"));
10010
10216
  for (const name of ["lint", "typecheck", "test", "build"]) {
10011
10217
  if (!packageJson.scripts?.[name]) {
10012
10218
  steps.push({ name: `bun run ${name}`, status: "skipped" });
@@ -10025,7 +10231,7 @@ class DefaultStarterUpdater {
10025
10231
  projectDirectory: result2.plan.projectDirectory,
10026
10232
  ownerToken: result2.transactionOwnerToken,
10027
10233
  expectations: result2.finalizationExpectations,
10028
- workspaceMembershipExpectations: result2.plan.workspaceMembershipExpectations
10234
+ workspaceMembershipExpectations: result2.plan.finalWorkspaceMembershipExpectations ?? result2.plan.workspaceMembershipExpectations
10029
10235
  });
10030
10236
  return { updateId: result2.plan.id, status: "passed", steps, reportPath };
10031
10237
  } catch (error) {
@@ -10089,6 +10295,12 @@ async function writeReport(result2, steps, relativePath2) {
10089
10295
  `- \u6765\u6E90\u7248\u672C\uFF1A${result2.plan.sourceVersion}`,
10090
10296
  `- \u76EE\u6807\u7248\u672C\uFF1A${result2.plan.targetVersion}`,
10091
10297
  `- Recipe\uFF1A${result2.plan.recipes.join("\u3001") || "\u65E0"}`,
10298
+ ...result2.plan.lifecycle ? [
10299
+ `- \u6A21\u5757\u52A8\u4F5C\uFF1A${result2.plan.lifecycle.action}`,
10300
+ `- \u8BF7\u6C42\u6A21\u5757\uFF1A${result2.plan.lifecycle.requestedModules.join("\u3001")}`,
10301
+ `- \u6570\u636E\u5904\u7F6E\uFF1A${result2.plan.lifecycle.dataDisposition ?? "\u4E0D\u9002\u7528"}`,
10302
+ `- \u6570\u636E\u5904\u7F6E\u6587\u6863\uFF1A${result2.plan.lifecycle.dataPlan ?? "\u65E0"}`
10303
+ ] : [],
10092
10304
  `- \u4FEE\u6539\u6587\u4EF6\uFF1A${result2.changedFiles.length}`,
10093
10305
  `- Oxc \u4EE3\u7BA1\uFF1A${result2.plan.detachedToolchain ? "\u5DF2\u68C0\u6D4B\u5230\u5BA2\u6237\u63A5\u7BA1\u5E76\u4FDD\u7559" : "\u4FDD\u6301"}`,
10094
10306
  "",
@@ -10112,13 +10324,275 @@ function expectedForPath(result2, path2) {
10112
10324
  return expectation2.expected;
10113
10325
  }
10114
10326
 
10327
+ // src/module-lifecycle.ts
10328
+ import { access as access2, rm as rm10 } from "fs/promises";
10329
+ import { resolve as resolve7 } from "path";
10330
+
10331
+ // src/module-version-range.ts
10332
+ function isVersionInCaretRange(version, range) {
10333
+ const current = parseVersion2(version);
10334
+ const base = range.startsWith("^") ? parseVersion2(range.slice(1)) : undefined;
10335
+ if (!current || !base || compareVersion(current, base) < 0)
10336
+ return false;
10337
+ const upper = base[0] > 0 ? [base[0] + 1, 0, 0] : base[1] > 0 ? [0, base[1] + 1, 0] : [0, 0, base[2] + 1];
10338
+ return compareVersion(current, upper) < 0;
10339
+ }
10340
+ function parseVersion2(value) {
10341
+ const match = value.match(/^(\d+)\.(\d+)\.(\d+)$/);
10342
+ if (!match)
10343
+ return;
10344
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
10345
+ }
10346
+ function compareVersion(left, right) {
10347
+ for (let index = 0;index < 3; index += 1) {
10348
+ const difference = left[index] - right[index];
10349
+ if (difference)
10350
+ return difference;
10351
+ }
10352
+ return 0;
10353
+ }
10354
+
10355
+ // src/module-lifecycle.ts
10356
+ async function runModuleLifecycleCommand(args, projectDirectory, dependencies = {}) {
10357
+ const action = args[0];
10358
+ if (!isAction(action)) {
10359
+ throw new Error("module \u53EA\u652F\u6301 list\u3001add\u3001update\u3001remove");
10360
+ }
10361
+ const log = dependencies.log ?? console.log;
10362
+ const provenance = await readGenerationProvenance(projectDirectory);
10363
+ const installed = provenance.modules.map(({ name }) => name);
10364
+ if (action === "list") {
10365
+ printModuleList(provenance.modules, log);
10366
+ return;
10367
+ }
10368
+ const cliVersion = dependencies.cliVersion ?? (await readTemplateMetadata(await resolveTemplateRoot())).generatorVersion;
10369
+ if (provenance.generatorVersion !== cliVersion || provenance.windyVersion !== cliVersion) {
10370
+ throw new Error(`module \u547D\u4EE4\u8981\u6C42 CLI \u4E0E\u9879\u76EE Windy \u7248\u672C\u4E00\u81F4\uFF1A\u9879\u76EE ${provenance.windyVersion}\uFF0CCLI ${cliVersion}\uFF1B\u8BF7\u5148\u8FD0\u884C bun run windy update`);
10371
+ }
10372
+ const requested = positionalModules(args.slice(1));
10373
+ const lifecycle = await resolveLifecyclePlan({
10374
+ action,
10375
+ requested,
10376
+ installed,
10377
+ windyVersion: provenance.windyVersion,
10378
+ args,
10379
+ projectDirectory
10380
+ });
10381
+ printDataPlan(lifecycle, log);
10382
+ if (!hasChanges(lifecycle)) {
10383
+ log("\u6A21\u5757\u96C6\u5408\u5DF2\u6EE1\u8DB3\u8BF7\u6C42\uFF0C\u65E0\u9700\u4FEE\u6539");
10384
+ return;
10385
+ }
10386
+ const targetModules = resolveTargetModules(installed, lifecycle);
10387
+ const updater = dependencies.updater ?? new DefaultStarterUpdater;
10388
+ const plan = await updater.plan({
10389
+ projectDirectory,
10390
+ targetVersion: provenance.windyVersion,
10391
+ targetModules,
10392
+ lifecycle
10393
+ });
10394
+ printModulePlan(plan, log);
10395
+ if (args.includes("--dry-run")) {
10396
+ await rm10(plan.temporaryRoot, { recursive: true, force: true });
10397
+ log(`
10398
+ \u6F14\u7EC3\u5B8C\u6210\uFF1A\u672A\u5199\u5165\u9879\u76EE\u6587\u4EF6`);
10399
+ return;
10400
+ }
10401
+ if (action === "remove" && !args.includes("--confirm-data-disposition")) {
10402
+ await rm10(plan.temporaryRoot, { recursive: true, force: true });
10403
+ throw new Error("\u5378\u8F7D\u524D\u5FC5\u987B\u5BA1\u9605\u6570\u636E\u5904\u7F6E\u8BA1\u5212\u5E76\u4F20\u5165 --confirm-data-disposition");
10404
+ }
10405
+ if (plan.conflicts.length) {
10406
+ await rm10(plan.temporaryRoot, { recursive: true, force: true });
10407
+ throw new Error("\u5B58\u5728\u6A21\u5757\u751F\u547D\u5468\u671F\u51B2\u7A81\uFF0C\u9879\u76EE\u672A\u88AB\u4FEE\u6539");
10408
+ }
10409
+ const result2 = await updater.apply(plan);
10410
+ const report = await updater.verify(result2);
10411
+ log(`
10412
+ \u6A21\u5757${actionLabel(action)}\u5B8C\u6210\uFF1A${requested.join("\u3001")}`);
10413
+ log(`\u62A5\u544A\uFF1A${report.reportPath}`);
10414
+ }
10415
+ async function resolveLifecyclePlan(input) {
10416
+ const known = new Map(moduleDistributionCatalog.map((manifest) => [manifest.name, manifest]));
10417
+ const requested = input.action === "update" && input.requested.length === 0 ? [...input.installed] : input.requested;
10418
+ if (!requested.length) {
10419
+ throw new Error(`module ${input.action} \u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u6A21\u5757 key`);
10420
+ }
10421
+ for (const name of requested) {
10422
+ const manifest = known.get(name);
10423
+ if (!manifest)
10424
+ throw new Error(`\u672A\u77E5\u6A21\u5757\uFF1A${name}`);
10425
+ assertWindyCompatible(input.windyVersion, manifest.windyRange, name);
10426
+ }
10427
+ if (input.action === "add") {
10428
+ const target = resolveModuleSelection({
10429
+ requested: [...input.installed, ...requested],
10430
+ includeRecommended: false
10431
+ });
10432
+ for (const name of target) {
10433
+ const manifest = known.get(name);
10434
+ assertWindyCompatible(input.windyVersion, manifest.windyRange, manifest.name);
10435
+ }
10436
+ return {
10437
+ action: input.action,
10438
+ requestedModules: requested,
10439
+ addedModules: target.filter((name) => !input.installed.includes(name)),
10440
+ updatedModules: [],
10441
+ removedModules: []
10442
+ };
10443
+ }
10444
+ if (input.action === "update") {
10445
+ const absent = requested.filter((name) => !input.installed.includes(name));
10446
+ if (absent.length) {
10447
+ throw new Error(`\u672A\u5B89\u88C5\u6A21\u5757\u4E0D\u80FD\u66F4\u65B0\uFF1A${absent.join("\u3001")}`);
10448
+ }
10449
+ return {
10450
+ action: input.action,
10451
+ requestedModules: requested,
10452
+ addedModules: [],
10453
+ updatedModules: requested,
10454
+ removedModules: []
10455
+ };
10456
+ }
10457
+ const required = requested.filter((name) => requiredModuleNames.includes(name));
10458
+ if (required.length) {
10459
+ throw new Error(`\u6838\u5FC3\u6A21\u5757\u4E0D\u53EF\u5378\u8F7D\uFF1A${required.join("\u3001")}`);
10460
+ }
10461
+ const removed = requested.filter((name) => input.installed.includes(name));
10462
+ assertRemovalDependencies(input.installed, removed);
10463
+ const dataDisposition = resolveDataDisposition(removed.map((name) => known.get(name).uninstallPolicy), readValue2(input.args, "--data-disposition"));
10464
+ const dataPlan = readValue2(input.args, "--data-plan");
10465
+ if (dataDisposition !== "retain-data") {
10466
+ if (!dataPlan) {
10467
+ throw new Error(`${dataDisposition} \u5378\u8F7D\u5FC5\u987B\u901A\u8FC7 --data-plan \u63D0\u4F9B\u5DF2\u5BA1\u9605\u7684\u5904\u7F6E\u6587\u6863`);
10468
+ }
10469
+ await access2(resolve7(input.projectDirectory, dataPlan));
10470
+ }
10471
+ return {
10472
+ action: input.action,
10473
+ requestedModules: requested,
10474
+ addedModules: [],
10475
+ updatedModules: [],
10476
+ removedModules: removed,
10477
+ dataDisposition,
10478
+ dataPlan
10479
+ };
10480
+ }
10481
+ function resolveTargetModules(installed, lifecycle) {
10482
+ if (lifecycle.action === "add") {
10483
+ return resolveModuleSelection({
10484
+ requested: [...installed, ...lifecycle.addedModules],
10485
+ includeRecommended: false
10486
+ });
10487
+ }
10488
+ if (lifecycle.action === "remove") {
10489
+ const removed = new Set(lifecycle.removedModules);
10490
+ return installed.filter((name) => !removed.has(name));
10491
+ }
10492
+ return installed;
10493
+ }
10494
+ function resolveDataDisposition(policies, requested) {
10495
+ const disposition = requested ?? strongestPolicy(policies);
10496
+ if (disposition !== "retain-data" && disposition !== "archive-data" && disposition !== "manual") {
10497
+ throw new Error(`\u4E0D\u652F\u6301\u7684\u6570\u636E\u5904\u7F6E\u7B56\u7565\uFF1A${disposition}`);
10498
+ }
10499
+ const minimum = strongestPolicy(policies);
10500
+ const rank = {
10501
+ "retain-data": 0,
10502
+ "archive-data": 1,
10503
+ manual: 2
10504
+ };
10505
+ if (rank[disposition] < rank[minimum]) {
10506
+ throw new Error(`\u6A21\u5757\u76EE\u5F55\u8981\u6C42 ${minimum}\uFF0C\u4E0D\u80FD\u964D\u7EA7\u4E3A ${disposition}`);
10507
+ }
10508
+ return disposition;
10509
+ }
10510
+ function strongestPolicy(policies) {
10511
+ if (policies.includes("manual"))
10512
+ return "manual";
10513
+ if (policies.includes("archive-data"))
10514
+ return "archive-data";
10515
+ return "retain-data";
10516
+ }
10517
+ function assertRemovalDependencies(installed, removed) {
10518
+ const removedSet = new Set(removed);
10519
+ const blockers = moduleDistributionCatalog.filter(({ name, dependencies }) => installed.includes(name) && !removedSet.has(name) && dependencies.some((dependency) => removedSet.has(dependency))).map(({ name }) => name);
10520
+ if (blockers.length) {
10521
+ throw new Error(`\u4ECD\u6709\u5DF2\u5B89\u88C5\u6A21\u5757\u4F9D\u8D56\u5F85\u5378\u8F7D\u6A21\u5757\uFF1A${blockers.join("\u3001")}`);
10522
+ }
10523
+ }
10524
+ function assertWindyCompatible(version, range, moduleName) {
10525
+ if (!isVersionInCaretRange(version, range)) {
10526
+ throw new Error(`${moduleName} \u8981\u6C42 Windy ${range}\uFF0C\u5F53\u524D\u4E3A ${version}`);
10527
+ }
10528
+ }
10529
+ function positionalModules(args) {
10530
+ const valueFlags = new Set(["--data-disposition", "--data-plan", "--cwd"]);
10531
+ const output = [];
10532
+ for (let index = 0;index < args.length; index += 1) {
10533
+ const value = args[index];
10534
+ if (valueFlags.has(value)) {
10535
+ index += 1;
10536
+ } else if (!value.startsWith("-")) {
10537
+ output.push(value);
10538
+ }
10539
+ }
10540
+ return [...new Set(output)];
10541
+ }
10542
+ function printModuleList(installed, log) {
10543
+ const installedVersions = new Map(installed.map(({ name, version }) => [name, version]));
10544
+ log("Windy \u6A21\u5757\uFF1A");
10545
+ for (const manifest of moduleDistributionCatalog) {
10546
+ const installedVersion = installedVersions.get(manifest.name);
10547
+ const status = installedVersion ? "installed" : "available";
10548
+ const version = installedVersion ? `${manifest.name}@${installedVersion}\uFF08catalog ${manifest.version}\uFF09` : `${manifest.name}@${manifest.version}`;
10549
+ log(` ${status.padEnd(9)} ${version}`);
10550
+ }
10551
+ }
10552
+ function printDataPlan(lifecycle, log) {
10553
+ if (lifecycle.action !== "remove")
10554
+ return;
10555
+ log("\u6A21\u5757\u5378\u8F7D\u6570\u636E\u5904\u7F6E\u8BA1\u5212\uFF1A");
10556
+ log(` \u6A21\u5757\uFF1A${lifecycle.removedModules.join("\u3001") || "\u5747\u672A\u5B89\u88C5"}`);
10557
+ log(` \u6570\u636E\uFF1A${lifecycle.dataDisposition ?? "retain-data"}`);
10558
+ log(" migration\uFF1A\u4FDD\u7559\u5230 .windy/module-history\uFF0C\u4E0D\u6267\u884C down migration");
10559
+ if (lifecycle.dataPlan)
10560
+ log(` \u8FD0\u7EF4\u5904\u7F6E\u6587\u6863\uFF1A${lifecycle.dataPlan}`);
10561
+ }
10562
+ function printModulePlan(plan, log) {
10563
+ const changed = plan.files.filter(({ action }) => action !== "preserve");
10564
+ log(`\u6A21\u5757\u6587\u4EF6\u8BA1\u5212\uFF1A${changed.length} \u4E2A\u53D8\u66F4\uFF1B${plan.conflicts.length} \u4E2A\u51B2\u7A81`);
10565
+ for (const file of changed) {
10566
+ log(` ${file.action.padEnd(6)} ${file.path}\uFF08${file.reason}\uFF09`);
10567
+ }
10568
+ for (const conflict3 of plan.conflicts)
10569
+ log(` conflict ${conflict3}`);
10570
+ }
10571
+ function hasChanges(lifecycle) {
10572
+ return lifecycle.addedModules.length > 0 || lifecycle.updatedModules.length > 0 || lifecycle.removedModules.length > 0;
10573
+ }
10574
+ function readValue2(args, flag) {
10575
+ const index = args.indexOf(flag);
10576
+ return index >= 0 ? args[index + 1] : undefined;
10577
+ }
10578
+ function isAction(value) {
10579
+ return value === "list" || value === "add" || value === "update" || value === "remove";
10580
+ }
10581
+ function actionLabel(action) {
10582
+ return action === "add" ? "\u5B89\u88C5" : action === "update" ? "\u66F4\u65B0" : "\u5378\u8F7D";
10583
+ }
10584
+
10115
10585
  // src/update/cli.ts
10116
10586
  async function runLifecycleCommand(args) {
10117
10587
  const command = args[0];
10118
- if (command !== "doctor" && command !== "update" && command !== "reconcile" && command !== "sync-docker") {
10588
+ if (command !== "doctor" && command !== "update" && command !== "module" && command !== "reconcile" && command !== "sync-docker") {
10119
10589
  return false;
10120
10590
  }
10121
- const projectDirectory = resolve7(readValue2(args, "--cwd") || process.cwd());
10591
+ const projectDirectory = resolve8(readValue3(args, "--cwd") || process.cwd());
10592
+ if (command === "module") {
10593
+ await runModuleLifecycleCommand(args.slice(1), projectDirectory);
10594
+ return true;
10595
+ }
10122
10596
  if (command === "sync-docker") {
10123
10597
  const result2 = await planWebDockerfileInProject(projectDirectory, {
10124
10598
  requireAnchors: true
@@ -10175,7 +10649,7 @@ async function runReconcile(args, projectDirectory) {
10175
10649
  });
10176
10650
  const plan = await reconciler.plan({
10177
10651
  projectDirectory,
10178
- targetVersion: readValue2(args, "--to") ?? ""
10652
+ targetVersion: readValue3(args, "--to") ?? ""
10179
10653
  });
10180
10654
  console.log(`Windy \u5BF9\u8D26\u8BA1\u5212\uFF1A${plan.sourceVersion} \u2192 ${plan.targetVersion}\uFF1B\u53EF\u8BC1\u660E ${plan.reconciled.length}\uFF1B\u4FDD\u5B88\u672A\u51B3 ${plan.unresolved.length}`);
10181
10655
  for (const item of plan.reconciled) {
@@ -10185,7 +10659,7 @@ async function runReconcile(args, projectDirectory) {
10185
10659
  console.log(` unresolved ${item.path}\uFF08${item.reason}\uFF09`);
10186
10660
  }
10187
10661
  if (!args.includes("--apply")) {
10188
- await rm10(plan.temporaryRoot, { recursive: true, force: true });
10662
+ await rm11(plan.temporaryRoot, { recursive: true, force: true });
10189
10663
  console.log(`
10190
10664
  \u6F14\u7EC3\u5B8C\u6210\uFF1A\u672A\u5199\u5165\u9879\u76EE\u6587\u4EF6\uFF1B\u4F7F\u7528 --apply \u4EC5\u63D0\u4EA4\u5BF9\u8D26\u5143\u6570\u636E`);
10191
10665
  return;
@@ -10196,12 +10670,12 @@ async function runReconcile(args, projectDirectory) {
10196
10670
  \u5BF9\u8D26\u5B8C\u6210\uFF1AProject Lock \u4ECD\u4E3A ${plan.sourceVersion}`);
10197
10671
  console.log(`\u62A5\u544A\uFF1A${result2.reportPath}`);
10198
10672
  } finally {
10199
- await rm10(plan.temporaryRoot, { recursive: true, force: true });
10673
+ await rm11(plan.temporaryRoot, { recursive: true, force: true });
10200
10674
  }
10201
10675
  }
10202
10676
  async function runUpdate(args, projectDirectory) {
10203
10677
  const template = await readTemplateMetadata(await resolveTemplateRoot());
10204
- const requested = readValue2(args, "--to");
10678
+ const requested = readValue3(args, "--to");
10205
10679
  const registryVersion = requested ? undefined : await readRegistryLatest();
10206
10680
  if (registryVersion && compareVersions2(registryVersion, template.generatorVersion) > 0 && !args.includes("--no-delegate")) {
10207
10681
  if (args.includes("--check")) {
@@ -10231,13 +10705,13 @@ async function runUpdate(args, projectDirectory) {
10231
10705
  const plan = await updater.plan({ projectDirectory, targetVersion: target });
10232
10706
  printPlan(plan);
10233
10707
  if (args.includes("--dry-run")) {
10234
- await rm10(plan.temporaryRoot, { recursive: true, force: true });
10708
+ await rm11(plan.temporaryRoot, { recursive: true, force: true });
10235
10709
  console.log(`
10236
10710
  \u6F14\u7EC3\u5B8C\u6210\uFF1A\u672A\u5199\u5165\u9879\u76EE\u6587\u4EF6`);
10237
10711
  return;
10238
10712
  }
10239
10713
  if (plan.conflicts.length) {
10240
- await rm10(plan.temporaryRoot, { recursive: true, force: true });
10714
+ await rm11(plan.temporaryRoot, { recursive: true, force: true });
10241
10715
  throw new Error("\u5B58\u5728\u66F4\u65B0\u51B2\u7A81\uFF1B\u8BF7\u6309\u4E0A\u65B9\u6E05\u5355\u5904\u7406\u540E\u91CD\u65B0\u8FD0\u884C\uFF0C\u9879\u76EE\u672A\u88AB\u4FEE\u6539");
10242
10716
  }
10243
10717
  const result2 = await updater.apply(plan);
@@ -10271,8 +10745,8 @@ function printPlan(plan) {
10271
10745
  console.log(`\u8BA1\u5212\u6539\u52A8\uFF1A${changed.length} \u4E2A\u6587\u4EF6\uFF1B\u51B2\u7A81\uFF1A${plan.conflicts.length}`);
10272
10746
  for (const file of changed)
10273
10747
  console.log(` ${file.action.padEnd(6)} ${file.path}\uFF08${file.reason}\uFF09`);
10274
- for (const conflict2 of plan.conflicts)
10275
- console.log(` conflict ${conflict2}`);
10748
+ for (const conflict3 of plan.conflicts)
10749
+ console.log(` conflict ${conflict3}`);
10276
10750
  if (plan.detachedToolchain)
10277
10751
  console.log("Oxc\uFF1A\u68C0\u6D4B\u5230\u5BA2\u6237\u63A5\u7BA1\uFF0C\u76F8\u5173\u914D\u7F6E\u4FDD\u6301\u4E0D\u53D8");
10278
10752
  }
@@ -10295,7 +10769,7 @@ function printDoctor(report) {
10295
10769
  console.log("\u6062\u590D\uFF1A\u5DF2\u4ECE\u4E8B\u52A1\u5907\u4EFD\u56DE\u6EDA");
10296
10770
  }
10297
10771
  }
10298
- function readValue2(args, flag) {
10772
+ function readValue3(args, flag) {
10299
10773
  const index = args.indexOf(flag);
10300
10774
  return index >= 0 ? args[index + 1] : undefined;
10301
10775
  }
@@ -10322,28 +10796,28 @@ function compareVersions2(left, right) {
10322
10796
  }
10323
10797
 
10324
10798
  // src/module-schema/cli.ts
10325
- import { resolve as resolve9 } from "path";
10799
+ import { resolve as resolve10 } from "path";
10326
10800
 
10327
10801
  // src/module-schema/handoff.ts
10328
10802
  import {
10329
- access as access2,
10803
+ access as access3,
10330
10804
  cp,
10331
- mkdir as mkdir8,
10805
+ mkdir as mkdir9,
10332
10806
  mkdtemp as mkdtemp5,
10333
- readFile as readFile25,
10334
- readdir as readdir8,
10807
+ readFile as readFile26,
10808
+ readdir as readdir9,
10335
10809
  rename,
10336
- rm as rm11,
10337
- writeFile as writeFile12
10810
+ rm as rm12,
10811
+ writeFile as writeFile13
10338
10812
  } from "fs/promises";
10339
- import { dirname as dirname8, join as join31, relative as relative5 } from "path";
10813
+ import { dirname as dirname9, join as join32, relative as relative6 } from "path";
10340
10814
 
10341
10815
  // src/module-schema/config.ts
10342
- import { readFile as readFile24 } from "fs/promises";
10343
- import { isAbsolute as isAbsolute2, relative as relative4, resolve as resolve8 } from "path";
10816
+ import { readFile as readFile25 } from "fs/promises";
10817
+ import { isAbsolute as isAbsolute2, relative as relative5, resolve as resolve9 } from "path";
10344
10818
  async function readModuleSchemaLineageConfig(projectDirectory, configPath) {
10345
10819
  const absolutePath = resolveProjectPath(projectDirectory, configPath);
10346
- const parsed = JSON.parse(await readFile24(absolutePath, "utf8"));
10820
+ const parsed = JSON.parse(await readFile25(absolutePath, "utf8"));
10347
10821
  if (!isConfig(parsed)) {
10348
10822
  throw new Error("Module schema lineage \u914D\u7F6E\u65E0\u6548");
10349
10823
  }
@@ -10357,8 +10831,8 @@ async function readModuleSchemaLineageConfig(projectDirectory, configPath) {
10357
10831
  function resolveProjectPath(projectDirectory, path2) {
10358
10832
  if (isAbsolute2(path2))
10359
10833
  throw new Error(`\u8DEF\u5F84\u5FC5\u987B\u76F8\u5BF9\u9879\u76EE\u6839\u76EE\u5F55\uFF1A${path2}`);
10360
- const resolved = resolve8(projectDirectory, path2);
10361
- const projectRelative = relative4(projectDirectory, resolved);
10834
+ const resolved = resolve9(projectDirectory, path2);
10835
+ const projectRelative = relative5(projectDirectory, resolved);
10362
10836
  if (projectRelative.startsWith("..") || isAbsolute2(projectRelative)) {
10363
10837
  throw new Error(`\u8DEF\u5F84\u8D8A\u51FA\u9879\u76EE\u6839\u76EE\u5F55\uFF1A${path2}`);
10364
10838
  }
@@ -10467,7 +10941,7 @@ async function handoffModuleSchemaLineages(options) {
10467
10941
  const stagedPlatform = await stagePlatformLineage(project, temporaryRoot, config, execute);
10468
10942
  await installStagedLineages(project, temporaryRoot, config, stagedModules, stagedPlatform);
10469
10943
  } finally {
10470
- await rm11(temporaryRoot, { recursive: true, force: true });
10944
+ await rm12(temporaryRoot, { recursive: true, force: true });
10471
10945
  }
10472
10946
  return {
10473
10947
  moduleCount: config.modules.length,
@@ -10477,17 +10951,17 @@ async function handoffModuleSchemaLineages(options) {
10477
10951
  async function stageModuleLineages(project, temporaryRoot, config, execute) {
10478
10952
  const outputs = [];
10479
10953
  for (const [index, module3] of config.modules.entries()) {
10480
- const output = join31(temporaryRoot, `module-${index}`);
10481
- await mkdir8(output, { recursive: true });
10482
- const generatedConfig = join31(temporaryRoot, `module-${index}.config.ts`);
10483
- await writeDrizzleConfig(generatedConfig, project, module3.schema, relative5(temporaryRoot, output));
10954
+ const output = join32(temporaryRoot, `module-${index}`);
10955
+ await mkdir9(output, { recursive: true });
10956
+ const generatedConfig = join32(temporaryRoot, `module-${index}.config.ts`);
10957
+ await writeDrizzleConfig(generatedConfig, project, module3.schema, relative6(temporaryRoot, output));
10484
10958
  await execute(generatedConfig, temporaryRoot);
10485
10959
  const sqlFiles = await listSqlFiles(output);
10486
10960
  if (sqlFiles.length !== 1) {
10487
10961
  throw new Error(`${module3.key} baseline \u5FC5\u987B\u6070\u597D\u751F\u6210\u4E00\u4E2A migration`);
10488
10962
  }
10489
- await writeFile12(join31(output, sqlFiles[0]), metadataOnlySql("module"));
10490
- await writeFile12(join31(output, "lineage.json"), `${JSON.stringify({
10963
+ await writeFile13(join32(output, sqlFiles[0]), metadataOnlySql("module"));
10964
+ await writeFile13(join32(output, "lineage.json"), `${JSON.stringify({
10491
10965
  schemaVersion: 1,
10492
10966
  moduleKey: module3.key,
10493
10967
  schema: module3.schema,
@@ -10501,25 +10975,25 @@ async function stageModuleLineages(project, temporaryRoot, config, execute) {
10501
10975
  }
10502
10976
  async function stagePlatformLineage(project, temporaryRoot, config, execute) {
10503
10977
  const source = resolveProjectPath(project, config.platform.out);
10504
- const output = join31(temporaryRoot, "platform");
10978
+ const output = join32(temporaryRoot, "platform");
10505
10979
  await cp(source, output, { recursive: true });
10506
10980
  const before = new Set(await listSqlFiles(output));
10507
- const generatedConfig = join31(temporaryRoot, "platform.config.ts");
10508
- await writeDrizzleConfig(generatedConfig, project, config.platform.schema, relative5(temporaryRoot, output));
10981
+ const generatedConfig = join32(temporaryRoot, "platform.config.ts");
10982
+ await writeDrizzleConfig(generatedConfig, project, config.platform.schema, relative6(temporaryRoot, output));
10509
10983
  await execute(generatedConfig, temporaryRoot);
10510
10984
  const created = (await listSqlFiles(output)).filter((path2) => !before.has(path2));
10511
10985
  if (created.length !== 1) {
10512
10986
  throw new Error("\u5E73\u53F0 lineage handoff \u5FC5\u987B\u6070\u597D\u751F\u6210\u4E00\u4E2A migration");
10513
10987
  }
10514
- const sqlPath = join31(output, created[0]);
10988
+ const sqlPath = join32(output, created[0]);
10515
10989
  const allowed = config.modules.flatMap(({ legacyPlatformTables }) => legacyPlatformTables);
10516
- validatePlatformHandoffSql(await readFile25(sqlPath, "utf8"), allowed);
10517
- await writeFile12(sqlPath, metadataOnlySql("platform"));
10990
+ validatePlatformHandoffSql(await readFile26(sqlPath, "utf8"), allowed);
10991
+ await writeFile13(sqlPath, metadataOnlySql("platform"));
10518
10992
  return output;
10519
10993
  }
10520
10994
  async function installStagedLineages(project, temporaryRoot, config, stagedModules, stagedPlatform) {
10521
10995
  const platform = resolveProjectPath(project, config.platform.out);
10522
- const backup = join31(temporaryRoot, "platform-backup");
10996
+ const backup = join32(temporaryRoot, "platform-backup");
10523
10997
  const installed = [];
10524
10998
  await rename(platform, backup);
10525
10999
  try {
@@ -10529,21 +11003,21 @@ async function installStagedLineages(project, temporaryRoot, config, stagedModul
10529
11003
  if (await exists(output)) {
10530
11004
  throw new Error(`${module3.key} lineage \u8F93\u51FA\u5DF2\u5B58\u5728\uFF0C\u7981\u6B62\u8986\u76D6`);
10531
11005
  }
10532
- await mkdir8(dirname8(output), { recursive: true });
11006
+ await mkdir9(dirname9(output), { recursive: true });
10533
11007
  await rename(stagedModules[index], output);
10534
11008
  installed.push(output);
10535
11009
  }
10536
11010
  } catch (error) {
10537
- await rm11(platform, { recursive: true, force: true });
11011
+ await rm12(platform, { recursive: true, force: true });
10538
11012
  await rename(backup, platform);
10539
11013
  for (const output of installed)
10540
- await rm11(output, { recursive: true, force: true });
11014
+ await rm12(output, { recursive: true, force: true });
10541
11015
  throw error;
10542
11016
  }
10543
11017
  }
10544
11018
  async function writeDrizzleConfig(path2, project, schemas, out) {
10545
11019
  const absoluteSchemas = schemas.map((schema) => resolveProjectPath(project, schema));
10546
- await writeFile12(path2, `import { defineConfig } from "drizzle-kit";
11020
+ await writeFile13(path2, `import { defineConfig } from "drizzle-kit";
10547
11021
  export default defineConfig(${JSON.stringify({
10548
11022
  dialect: "postgresql",
10549
11023
  schema: absoluteSchemas,
@@ -10557,7 +11031,7 @@ async function validateSchemaSources(project, config) {
10557
11031
  ...config.platform.schema,
10558
11032
  ...config.modules.flatMap(({ schema: schema2 }) => schema2)
10559
11033
  ]) {
10560
- await access2(resolveProjectPath(project, schema));
11034
+ await access3(resolveProjectPath(project, schema));
10561
11035
  }
10562
11036
  for (const module3 of config.modules) {
10563
11037
  if (await exists(resolveProjectPath(project, module3.out))) {
@@ -10566,12 +11040,12 @@ async function validateSchemaSources(project, config) {
10566
11040
  }
10567
11041
  }
10568
11042
  async function createTemporaryRoot(project) {
10569
- const windy = join31(project, ".windy");
10570
- await mkdir8(windy, { recursive: true });
10571
- return await mkdtemp5(join31(windy, "module-schema-handoff-"));
11043
+ const windy = join32(project, ".windy");
11044
+ await mkdir9(windy, { recursive: true });
11045
+ return await mkdtemp5(join32(windy, "module-schema-handoff-"));
10572
11046
  }
10573
11047
  async function listSqlFiles(root) {
10574
- return (await readdir8(root)).filter((path2) => path2.endsWith(".sql")).sort();
11048
+ return (await readdir9(root)).filter((path2) => path2.endsWith(".sql")).sort();
10575
11049
  }
10576
11050
  async function executeDrizzleGenerate(configPath, cwd) {
10577
11051
  await assertProcess("bunx", ["--bun", "drizzle-kit", "generate", "--config", configPath], cwd, true);
@@ -10584,7 +11058,7 @@ async function assertCleanGit(project) {
10584
11058
  }
10585
11059
  async function exists(path2) {
10586
11060
  try {
10587
- await access2(path2);
11061
+ await access3(path2);
10588
11062
  return true;
10589
11063
  } catch {
10590
11064
  return false;
@@ -10598,15 +11072,15 @@ async function runModuleSchemaCommand(args) {
10598
11072
  if (args[1] !== "handoff") {
10599
11073
  throw new Error("\u5F53\u524D schema \u547D\u4EE4\u53EA\u652F\u6301 handoff");
10600
11074
  }
10601
- const projectDirectory = resolve9(readValue3(args, "--cwd") || process.cwd());
11075
+ const projectDirectory = resolve10(readValue4(args, "--cwd") || process.cwd());
10602
11076
  const result2 = await handoffModuleSchemaLineages({
10603
11077
  projectDirectory,
10604
- configPath: readValue3(args, "--config")
11078
+ configPath: readValue4(args, "--config")
10605
11079
  });
10606
11080
  console.log(`Module schema lineage \u4EA4\u63A5\u5B8C\u6210\uFF1A${result2.moduleCount} \u4E2A\u6A21\u5757\u3001${result2.tableCount} \u5F20\u65E7\u5E73\u53F0 snapshot \u8868`);
10607
11081
  return true;
10608
11082
  }
10609
- function readValue3(args, flag) {
11083
+ function readValue4(args, flag) {
10610
11084
  const index = args.indexOf(flag);
10611
11085
  return index >= 0 ? args[index + 1] : undefined;
10612
11086
  }