create-windy 0.3.19 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -13
- package/dist/cli.js +788 -280
- package/package.json +1 -1
- package/template/.agents/skills/windy-business-module/SKILL.md +34 -10
- package/template/.windy-template.json +2 -2
- package/template/AGENTS.md +18 -8
- package/template/README.md +32 -22
- package/template/apps/server/Dockerfile +1 -0
- package/template/apps/server/package.json +1 -0
- package/template/apps/server/scripts/validate-module-composition-once.ts +4 -0
- package/template/apps/server/scripts/validate-module-composition.ts +28 -0
- package/template/apps/server/src/agent/data-scope-routes.test.ts +20 -5
- package/template/apps/server/src/agent/routes.test.ts +20 -7
- package/template/apps/server/src/agent/routes.ts +14 -0
- package/template/apps/server/src/agent/runtime-bootstrap.ts +22 -6
- package/template/apps/server/src/agent/sandbox-worker.ts +2 -2
- package/template/apps/server/src/agent/unavailable-routes.ts +33 -0
- package/template/apps/server/src/app/server-composition.ts +56 -0
- package/template/apps/server/src/application-services.ts +2 -0
- package/template/apps/server/src/bulk-data/service.ts +14 -0
- package/template/apps/server/src/data-governance/export/authorization-port.ts +1 -1
- package/template/apps/server/src/data-governance/export/postgres-api-fixture.ts +18 -2
- package/template/apps/server/src/data-governance/export/postgres-recovery.integration.test.ts +10 -9
- package/template/apps/server/src/data-governance/export/routes-test-fixture.ts +6 -8
- package/template/apps/server/src/data-governance/user-plaintext-routes.test.ts +4 -2
- package/template/apps/server/src/feature/routes.authorization.test.ts +26 -1
- package/template/apps/server/src/feature/routes.ts +33 -15
- package/template/apps/server/src/foundation-activation.test.ts +60 -0
- package/template/apps/server/src/foundation.ts +64 -5
- package/template/apps/server/src/guards.test.ts +23 -0
- package/template/apps/server/src/guards.ts +12 -0
- package/template/apps/server/src/index.ts +28 -34
- package/template/apps/server/src/installed-business-modules.ts +13 -24
- package/template/apps/server/src/jobs/legacy-adapter.integration.test.ts +1 -0
- package/template/apps/server/src/jobs/legacy-adapter.test.ts +106 -0
- package/template/apps/server/src/jobs/legacy-service-runtime.ts +40 -0
- package/template/apps/server/src/license/activation.test.ts +30 -0
- package/template/apps/server/src/license/activation.ts +26 -0
- package/template/apps/server/src/license/restriction.test.ts +16 -0
- package/template/apps/server/src/license/routes-offline-code.test.ts +6 -2
- package/template/apps/server/src/license/routes.ts +20 -4
- package/template/apps/server/src/license/runtime-service.test.ts +10 -2
- package/template/apps/server/src/module-bootstrap.ts +14 -23
- package/template/apps/server/src/module-composition.test.ts +43 -2
- package/template/apps/server/src/module-composition.ts +29 -0
- package/template/apps/server/src/module-host/durable-context-guard.test.ts +172 -0
- package/template/apps/server/src/module-host/durable-context-unavailable.test.ts +50 -1
- package/template/apps/server/src/module-host/durable-context.test.ts +42 -25
- package/template/apps/server/src/module-host/durable-context.ts +42 -2
- package/template/apps/server/src/module-host/durable-handler-registration.ts +96 -5
- package/template/apps/server/src/module-host/implementation-completeness.test.ts +185 -0
- package/template/apps/server/src/module-host/implementation-completeness.ts +132 -0
- package/template/apps/server/src/module-host/initialize-contracts.ts +14 -0
- package/template/apps/server/src/module-host/initialize.test.ts +78 -2
- package/template/apps/server/src/module-host/initialize.ts +15 -4
- package/template/apps/server/src/module-host/project-attachments.test.ts +92 -0
- package/template/apps/server/src/module-host/project-attachments.ts +58 -0
- package/template/apps/server/src/module-host/project-composition-package.test.ts +186 -0
- package/template/apps/server/src/module-host/project-composition.test.ts +260 -0
- package/template/apps/server/src/module-host/project-composition.ts +311 -0
- package/template/apps/server/src/module-host/request-context.ts +3 -0
- package/template/apps/server/src/module-host/route-declaration.ts +15 -6
- package/template/apps/server/src/module-host/route-installer.test.ts +15 -2
- package/template/apps/server/src/module-host/route-installer.ts +12 -2
- package/template/apps/server/src/module-host/route-registration.test.ts +13 -4
- package/template/apps/server/src/module-host/runtime-composition-compatibility.test.ts +63 -0
- package/template/apps/server/src/module-host/runtime-composition-compatibility.ts +46 -0
- package/template/apps/server/src/module-host/runtime-composition.ts +34 -0
- package/template/apps/server/src/module-host/search-provider-registration.test.ts +64 -0
- package/template/apps/server/src/module-host/search-provider-registration.ts +35 -0
- package/template/apps/server/src/module-host/static-route-authorization.test.ts +99 -0
- package/template/apps/server/src/module-host/static-route-authorization.ts +90 -0
- package/template/apps/server/src/module-host/task-definitions.ts +1 -0
- package/template/apps/server/src/module-host/user-directory-composition.test.ts +4 -1
- package/template/apps/server/src/module-host.test.ts +2 -0
- package/template/apps/server/src/module-preflight.test.ts +289 -0
- package/template/apps/server/src/module-preflight.ts +96 -0
- package/template/apps/server/src/module-runtime-validation.ts +1 -0
- package/template/apps/server/src/platform-app-bootstrap.ts +50 -0
- package/template/apps/server/src/platform-http-runtime.ts +32 -7
- package/template/apps/server/src/route-guards.test.ts +22 -0
- package/template/apps/server/src/route-guards.ts +10 -3
- package/template/apps/server/src/runtime-audit-query.ts +50 -0
- package/template/apps/server/src/runtime-feature.test.ts +46 -0
- package/template/apps/server/src/runtime-feature.ts +5 -0
- package/template/apps/server/src/runtime.ts +10 -49
- package/template/apps/server/src/scheduler/audit-action.test.ts +49 -0
- package/template/apps/server/src/scheduler/audit.ts +1 -1
- package/template/apps/server/src/scheduler/execution-recorder.ts +10 -5
- package/template/apps/server/src/scheduler/recovery-service.test.ts +4 -3
- package/template/apps/server/src/scheduler/service-idle.test.ts +4 -3
- package/template/apps/server/src/scheduler/service.test.ts +1 -0
- package/template/apps/server/src/scheduler/service.ts +18 -21
- package/template/apps/server/src/scheduler/types.ts +5 -1
- package/template/apps/server/src/settings/drizzle-watermark-repository.integration.test.ts +4 -0
- package/template/apps/server/src/settings/drizzle-watermark-repository.ts +11 -3
- package/template/apps/server/src/settings/watermark-routes.test.ts +54 -1
- package/template/apps/server/src/settings/watermark-routes.ts +29 -1
- package/template/apps/server/src/startup-composition-validation.test.ts +35 -0
- package/template/apps/server/src/startup-composition-validation.ts +54 -0
- package/template/apps/server/src/startup-preflight.test.ts +36 -0
- package/template/apps/server/src/startup-preflight.ts +37 -0
- package/template/apps/server/src/system/audit-routes.test.ts +9 -3
- package/template/apps/server/src/system/department-routes.test.ts +5 -3
- package/template/apps/server/src/system/feature-routes.test.ts +4 -3
- package/template/apps/server/src/system/interface-catalog.test.ts +5 -3
- package/template/apps/server/src/system/interface-catalog.ts +3 -0
- package/template/apps/server/src/system/menu-routes.test.ts +5 -3
- package/template/apps/server/src/system/route-test-runtime.ts +24 -0
- package/template/apps/server/src/system/routes-validation.test.ts +7 -3
- package/template/apps/server/src/system/routes.test.ts +21 -11
- package/template/apps/server/src/system/routes.ts +11 -2
- package/template/apps/server/src/work-order/foundation-modules.test.ts +6 -4
- package/template/apps/server/src/work-order/routes.test.ts +8 -0
- package/template/apps/server/src/work-order/task.test.ts +6 -1
- package/template/apps/web/Dockerfile +5 -0
- package/template/apps/web/package.json +1 -0
- package/template/apps/web/scripts/validate-admin-ui-composition.ts +106 -0
- package/template/apps/web/src/app/web-composition.ts +24 -0
- package/template/apps/web/src/app/web-composition.webtest.ts +15 -0
- package/template/apps/web/src/composables/useWatermarkSettings.webtest.ts +14 -0
- package/template/apps/web/src/composables/watermark-settings.ts +40 -11
- package/template/apps/web/src/composables/watermark-settings.webtest.ts +19 -6
- package/template/apps/web/src/layout/AppSidebar.vue +8 -1
- package/template/apps/web/src/layout/GlobalWatermark.layering.webtest.ts +2 -0
- package/template/apps/web/src/layout/GlobalWatermark.vue +4 -8
- package/template/apps/web/src/layout/GlobalWatermark.webtest.ts +12 -5
- package/template/apps/web/src/layout/NavigationSearchDialog.vue +8 -1
- package/template/apps/web/src/layout/navigation.ts +29 -4
- package/template/apps/web/src/layout/navigation.webtest.ts +51 -0
- package/template/apps/web/src/pages/dashboard/dashboard-presenter.ts +6 -1
- package/template/apps/web/src/pages/settings/WatermarkPreview.vue +72 -0
- package/template/apps/web/src/pages/settings/WatermarkPreview.webtest.ts +55 -0
- package/template/apps/web/src/pages/settings/WatermarkSettingsSection.vue +80 -24
- package/template/apps/web/src/pages/settings/WatermarkSettingsSection.webtest.ts +115 -0
- package/template/apps/web/src/pages/work-orders/WorkOrderListPage.vue +202 -0
- package/template/apps/web/src/pages/work-orders/WorkOrderListPage.webtest.ts +51 -0
- package/template/apps/web/src/router/admin-extension-loader.ts +44 -0
- package/template/apps/web/src/router/admin-extension-loader.webtest.ts +49 -0
- package/template/apps/web/src/router/admin-ui-composition-plugin.ts +33 -0
- package/template/apps/web/src/router/admin-ui-composition-plugin.webtest.ts +20 -0
- package/template/apps/web/src/router/admin-ui-composition.ts +313 -0
- package/template/apps/web/src/router/admin-ui-composition.webtest.ts +225 -0
- package/template/apps/web/src/router/admin-ui-module-registry-plugin.ts +55 -0
- package/template/apps/web/src/router/admin-ui-module-registry-plugin.webtest.ts +46 -0
- package/template/apps/web/src/router/business-routes.ts +32 -45
- package/template/apps/web/src/router/business-routes.webtest.ts +40 -44
- package/template/apps/web/src/router/index.ts +64 -54
- package/template/apps/web/src/router/manifest-routes.ts +27 -7
- package/template/apps/web/src/router/manifest-routes.webtest.ts +10 -2
- package/template/apps/web/src/router/platform-admin-route-bindings.ts +58 -0
- package/template/apps/web/src/router/reserved-route-paths.ts +14 -0
- package/template/apps/web/src/router/shared-scaffold-neutrality.webtest.ts +10 -4
- package/template/apps/web/src/router/web-composition-host.ts +20 -0
- package/template/apps/web/src/services/work-order-api.ts +16 -0
- package/template/apps/web/src/services/work-order-api.webtest.ts +21 -0
- package/template/apps/web/src/virtual-admin-ui-modules.d.ts +5 -0
- package/template/apps/web/vite.config.ts +22 -1
- package/template/docs/architecture/migration-bundle.md +10 -7
- package/template/docs/architecture/module-manifest-composition.md +85 -3
- package/template/docs/architecture/search-provider-protocol.md +6 -1
- package/template/docs/architecture/server-module-interface.md +70 -7
- package/template/docs/development/business-web-routes.md +53 -50
- package/template/docs/development/module-lifecycle.md +48 -54
- package/template/docs/platform/navigation-registry.md +5 -4
- package/template/docs/platform/platform-shell-settings.md +15 -10
- package/template/docs/platform/web-system-crud.md +1 -1
- package/template/package.json +1 -1
- package/template/packages/config/package.json +1 -1
- package/template/packages/database/drizzle/0044_sweet_tarantula.sql +6 -0
- package/template/packages/database/drizzle/meta/0044_snapshot.json +8349 -0
- package/template/packages/database/drizzle/meta/_journal.json +7 -0
- package/template/packages/database/package.json +1 -1
- package/template/packages/database/src/schema/platform-settings.ts +3 -0
- package/template/packages/example-work-order/package.json +6 -0
- package/template/packages/example-work-order/src/admin-page.ts +78 -0
- package/template/packages/example-work-order/src/admin.ts +35 -0
- package/template/packages/example-work-order/src/manifest.test.ts +62 -5
- package/template/packages/example-work-order/src/manifest.ts +54 -7
- package/template/packages/example-work-order/src/migration-bundle.ts +8 -0
- package/template/packages/example-work-order/src/server-module.ts +2 -2
- package/template/packages/jobs/package.json +1 -1
- package/template/packages/modules/index.ts +4 -0
- package/template/packages/modules/package.json +3 -2
- package/template/packages/modules/src/admin-ui-entry.ts +8 -0
- package/template/packages/modules/src/admin-ui-manifest.test.ts +52 -0
- package/template/packages/modules/src/admin-ui-manifest.ts +53 -0
- package/template/packages/modules/src/capability-audit-validation.test.ts +127 -0
- package/template/packages/modules/src/capability-audit-validation.ts +38 -0
- package/template/packages/modules/src/capability-guard-validation.ts +148 -0
- package/template/packages/modules/src/capability-key-validation.test.ts +150 -0
- package/template/packages/modules/src/composition-fixtures.test-support.ts +7 -5
- package/template/packages/modules/src/composition.test.ts +74 -9
- package/template/packages/modules/src/composition.ts +8 -0
- package/template/packages/modules/src/manifest.ts +1 -0
- package/template/packages/modules/src/migration-bundle-validation.test.ts +23 -0
- package/template/packages/modules/src/module-host-range.test.ts +57 -0
- package/template/packages/modules/src/module-host-range.ts +125 -0
- package/template/packages/modules/src/project-module-assembly.test.ts +133 -0
- package/template/packages/modules/src/project-module-assembly.ts +126 -0
- package/template/packages/modules/src/system-admin-routes.ts +6 -5
- package/template/packages/modules/src/system-admin-ui-catalog.ts +72 -0
- package/template/packages/modules/src/system-agent-tools.ts +2 -2
- package/template/packages/modules/src/system-api-binding.ts +43 -9
- package/template/packages/modules/src/system-api-control-plane.ts +202 -0
- package/template/packages/modules/src/system-api-data-governance.ts +4 -2
- package/template/packages/modules/src/system-api-operational.ts +57 -8
- package/template/packages/modules/src/system-api-permissions.ts +115 -21
- package/template/packages/modules/src/system-api-watermark.ts +3 -0
- package/template/packages/modules/src/system-audit-actions.ts +7 -0
- package/template/packages/modules/src/system-data-governance.ts +5 -2
- package/template/packages/modules/src/system-features.ts +31 -0
- package/template/packages/modules/src/system-governed-export-bindings.ts +8 -4
- package/template/packages/modules/src/system-module-catalog.test.ts +39 -4
- package/template/packages/modules/src/system-module-catalog.ts +68 -7
- package/template/packages/modules/src/system-module-tasks.ts +8 -1
- package/template/packages/modules/src/system-modules-access.test.ts +4 -0
- package/template/packages/modules/src/system-modules.test.ts +10 -2
- package/template/packages/modules/src/system-modules.ts +6 -5
- package/template/packages/modules/src/system-permissions.ts +4 -0
- package/template/packages/modules/user/module.ts +19 -2
- package/template/packages/server-sdk/index.ts +8 -0
- package/template/packages/server-sdk/package.json +2 -1
- package/template/packages/server-sdk/src/durable-handler.ts +16 -1
- package/template/packages/server-sdk/src/module-adapter.test.ts +44 -0
- package/template/packages/server-sdk/src/module-adapter.ts +59 -0
- package/template/packages/server-sdk/src/route-definition.ts +3 -2
- package/template/packages/shared/package.json +1 -1
- package/template/packages/shared/src/audit.test.ts +7 -0
- package/template/packages/shared/src/audit.ts +16 -0
- package/template/packages/shared/src/migration-bundle-validation.ts +9 -11
- package/template/packages/shared/src/platform-settings.ts +17 -0
- package/template/packages/shared/src/rbac.ts +2 -0
- package/template/apps/web/src/app/business-routes.ts +0 -22
package/dist/cli.js
CHANGED
|
@@ -206,6 +206,39 @@ var starterProfile = {
|
|
|
206
206
|
};
|
|
207
207
|
var projectLicenseKeys = ["UNLICENSED", "MIT", "Apache-2.0"];
|
|
208
208
|
|
|
209
|
+
// src/module-distribution-validation.ts
|
|
210
|
+
function validateModuleDistributionCatalog(manifests) {
|
|
211
|
+
const names = new Set;
|
|
212
|
+
for (const manifest of manifests) {
|
|
213
|
+
if (names.has(manifest.name)) {
|
|
214
|
+
throw new Error(`\u5206\u53D1\u6A21\u5757\u91CD\u590D\uFF1A${manifest.name}`);
|
|
215
|
+
}
|
|
216
|
+
names.add(manifest.name);
|
|
217
|
+
}
|
|
218
|
+
for (const manifest of manifests) {
|
|
219
|
+
for (const dependency of manifest.dependencies) {
|
|
220
|
+
if (!names.has(dependency)) {
|
|
221
|
+
throw new Error(`${manifest.name} \u4F9D\u8D56\u672A\u77E5\u6A21\u5757\uFF1A${dependency}`);
|
|
222
|
+
}
|
|
223
|
+
if (dependency === manifest.name) {
|
|
224
|
+
throw new Error(`${manifest.name} \u4E0D\u80FD\u4F9D\u8D56\u81EA\u8EAB`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
for (const conflict of manifest.conflicts) {
|
|
228
|
+
if (!names.has(conflict)) {
|
|
229
|
+
throw new Error(`${manifest.name} \u51B2\u7A81\u6A21\u5757\u672A\u77E5\uFF1A${conflict}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (!manifest.installRecipe) {
|
|
233
|
+
throw new Error(`${manifest.name} \u7F3A\u5C11\u5B89\u88C5 recipe`);
|
|
234
|
+
}
|
|
235
|
+
if (!manifest.uninstallRecipe) {
|
|
236
|
+
throw new Error(`${manifest.name} \u7F3A\u5C11\u5378\u8F7D recipe`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return manifests;
|
|
240
|
+
}
|
|
241
|
+
|
|
209
242
|
// src/optional-module-distribution.ts
|
|
210
243
|
var optionalModuleManifests = [
|
|
211
244
|
{
|
|
@@ -213,6 +246,7 @@ var optionalModuleManifests = [
|
|
|
213
246
|
"system",
|
|
214
247
|
"system.settings"
|
|
215
248
|
]),
|
|
249
|
+
runtimeActivation: "physical-only",
|
|
216
250
|
fileRoots: [
|
|
217
251
|
"apps/server/src/storage",
|
|
218
252
|
"apps/server/src/module-host/route-installer.test.ts",
|
|
@@ -300,6 +334,7 @@ var optionalModuleManifests = [
|
|
|
300
334
|
"apps/server/src/application-services.ts",
|
|
301
335
|
"apps/server/src/module-host/durable-context.ts",
|
|
302
336
|
"apps/server/src/module-host/durable-context.test.ts",
|
|
337
|
+
"apps/server/src/module-host/durable-context-guard.test.ts",
|
|
303
338
|
"apps/server/src/module-host/durable-context-unavailable.test.ts",
|
|
304
339
|
"apps/server/src/module-host/job-port.test.ts",
|
|
305
340
|
"apps/server/src/module-host/task-definitions.ts",
|
|
@@ -436,6 +471,7 @@ var optionalModuleManifests = [
|
|
|
436
471
|
"system.workflow",
|
|
437
472
|
"system.scheduler"
|
|
438
473
|
]),
|
|
474
|
+
runtimeActivation: "physical-only",
|
|
439
475
|
fileRoots: [
|
|
440
476
|
"apps/server/src/data-governance",
|
|
441
477
|
"apps/server/src/module-host/governed-resource-routes.ts",
|
|
@@ -460,11 +496,17 @@ var optionalModuleManifests = [
|
|
|
460
496
|
"system.scheduler",
|
|
461
497
|
"system.storage"
|
|
462
498
|
]),
|
|
499
|
+
deploymentInstall: "project-composition-required",
|
|
500
|
+
runtimePackage: "@southwind-ai/example-work-order",
|
|
463
501
|
packages: ["packages/example-work-order"],
|
|
464
502
|
fileRoots: [
|
|
465
503
|
"apps/server/src/work-order",
|
|
466
504
|
"apps/server/src/example-modules.ts",
|
|
467
|
-
"apps/server/src/example-permissions.ts"
|
|
505
|
+
"apps/server/src/example-permissions.ts",
|
|
506
|
+
"apps/web/src/pages/work-orders",
|
|
507
|
+
"apps/web/src/app/web-composition.webtest.ts",
|
|
508
|
+
"apps/web/src/services/work-order-api.ts",
|
|
509
|
+
"apps/web/src/services/work-order-api.webtest.ts"
|
|
468
510
|
],
|
|
469
511
|
documentation: ["docs/development/example-work-order.md"],
|
|
470
512
|
schemaFiles: ["packages/example-work-order/src/drizzle-schema.ts"],
|
|
@@ -478,12 +520,15 @@ function module(name, label, description, dependencies) {
|
|
|
478
520
|
return {
|
|
479
521
|
name,
|
|
480
522
|
version: "0.1.0",
|
|
481
|
-
windyRange: "^0.
|
|
523
|
+
windyRange: "^0.4.0",
|
|
482
524
|
label,
|
|
483
525
|
description,
|
|
484
526
|
selection,
|
|
527
|
+
runtimeActivation: "toggle",
|
|
528
|
+
deploymentInstall: "project-composition-required",
|
|
485
529
|
dependencies,
|
|
486
530
|
conflicts: [],
|
|
531
|
+
runtimePackage: null,
|
|
487
532
|
packages: [],
|
|
488
533
|
registryDependencies: [],
|
|
489
534
|
fileRoots: [],
|
|
@@ -514,6 +559,7 @@ var platformModules = [
|
|
|
514
559
|
module2("system.identity", "\u8EAB\u4EFD\u4E0E\u6743\u9650", "\u8BA4\u8BC1\u3001\u7528\u6237\u3001\u89D2\u8272\u3001\u7EC4\u7EC7\u548C\u6570\u636E\u8303\u56F4\u3002", "required", ["system"]),
|
|
515
560
|
{
|
|
516
561
|
...module2("system.settings", "\u5E73\u53F0\u8BBE\u7F6E", "\u54C1\u724C\u3001Logo \u4E0E\u6C34\u5370\u3002", "recommended", ["system"]),
|
|
562
|
+
runtimeActivation: "physical-only",
|
|
517
563
|
fileRoots: [
|
|
518
564
|
"apps/server/src/settings",
|
|
519
565
|
"apps/web/src/pages/settings",
|
|
@@ -647,7 +693,7 @@ var platformModules = [
|
|
|
647
693
|
},
|
|
648
694
|
...optionalModuleManifests
|
|
649
695
|
];
|
|
650
|
-
var moduleDistributionCatalog =
|
|
696
|
+
var moduleDistributionCatalog = validateModuleDistributionCatalog(platformModules);
|
|
651
697
|
function resolveModuleSelection(input = {}) {
|
|
652
698
|
const known = new Map(moduleDistributionCatalog.map((item) => [item.name, item]));
|
|
653
699
|
const selected = new Set(requiredModuleNames);
|
|
@@ -702,12 +748,15 @@ function module2(name, label, description, selection, dependencies = []) {
|
|
|
702
748
|
return {
|
|
703
749
|
name,
|
|
704
750
|
version: "0.1.0",
|
|
705
|
-
windyRange: "^0.
|
|
751
|
+
windyRange: "^0.4.0",
|
|
706
752
|
label,
|
|
707
753
|
description,
|
|
708
754
|
selection,
|
|
755
|
+
runtimeActivation: "toggle",
|
|
756
|
+
deploymentInstall: "project-composition-required",
|
|
709
757
|
dependencies,
|
|
710
758
|
conflicts: [],
|
|
759
|
+
runtimePackage: null,
|
|
711
760
|
packages: [],
|
|
712
761
|
registryDependencies: [],
|
|
713
762
|
fileRoots: [],
|
|
@@ -724,33 +773,6 @@ function module2(name, label, description, selection, dependencies = []) {
|
|
|
724
773
|
uninstallRecipe: `module-${name}-uninstall`
|
|
725
774
|
};
|
|
726
775
|
}
|
|
727
|
-
function validateCatalog(manifests) {
|
|
728
|
-
const names = new Set;
|
|
729
|
-
for (const manifest of manifests) {
|
|
730
|
-
if (names.has(manifest.name))
|
|
731
|
-
throw new Error(`\u5206\u53D1\u6A21\u5757\u91CD\u590D\uFF1A${manifest.name}`);
|
|
732
|
-
names.add(manifest.name);
|
|
733
|
-
}
|
|
734
|
-
for (const manifest of manifests) {
|
|
735
|
-
for (const dependency of manifest.dependencies) {
|
|
736
|
-
if (!names.has(dependency))
|
|
737
|
-
throw new Error(`${manifest.name} \u4F9D\u8D56\u672A\u77E5\u6A21\u5757\uFF1A${dependency}`);
|
|
738
|
-
if (dependency === manifest.name)
|
|
739
|
-
throw new Error(`${manifest.name} \u4E0D\u80FD\u4F9D\u8D56\u81EA\u8EAB`);
|
|
740
|
-
}
|
|
741
|
-
for (const conflict of manifest.conflicts) {
|
|
742
|
-
if (!names.has(conflict))
|
|
743
|
-
throw new Error(`${manifest.name} \u51B2\u7A81\u6A21\u5757\u672A\u77E5\uFF1A${conflict}`);
|
|
744
|
-
}
|
|
745
|
-
if (!manifest.installRecipe) {
|
|
746
|
-
throw new Error(`${manifest.name} \u7F3A\u5C11\u5B89\u88C5 recipe`);
|
|
747
|
-
}
|
|
748
|
-
if (!manifest.uninstallRecipe) {
|
|
749
|
-
throw new Error(`${manifest.name} \u7F3A\u5C11\u5378\u8F7D recipe`);
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
return manifests;
|
|
753
|
-
}
|
|
754
776
|
|
|
755
777
|
// src/arguments.ts
|
|
756
778
|
function parseArguments(args) {
|
|
@@ -833,9 +855,12 @@ var helpText = `create-windy <\u9879\u76EE\u540D> [\u9009\u9879]
|
|
|
833
855
|
create-windy update --dry-run [--to <\u7248\u672C>] [--cwd <\u76EE\u5F55>]
|
|
834
856
|
create-windy update [--to <\u7248\u672C>] [--cwd <\u76EE\u5F55>]
|
|
835
857
|
create-windy module list [--cwd <\u76EE\u5F55>]
|
|
836
|
-
create-windy module add <key...> [--dry-run] [--
|
|
837
|
-
create-windy module
|
|
838
|
-
create-windy module
|
|
858
|
+
create-windy module add <key...> [--dry-run] [--skip-install] [--yes]
|
|
859
|
+
create-windy module enable <key...> [--dry-run] [--yes] [--cwd <\u76EE\u5F55>]
|
|
860
|
+
create-windy module disable <key...> [--dry-run] [--yes] [--cwd <\u76EE\u5F55>]
|
|
861
|
+
create-windy module update [key...] [--dry-run] [--skip-install] [--yes]
|
|
862
|
+
create-windy module remove <key...> [--dry-run] [--skip-install] [--yes]
|
|
863
|
+
[--data-disposition <\u7B56\u7565>]
|
|
839
864
|
[--data-plan <\u6587\u4EF6>] [--confirm-data-disposition] [--cwd <\u76EE\u5F55>]
|
|
840
865
|
create-windy schema handoff [--config <JSON>] [--cwd <\u76EE\u5F55>]
|
|
841
866
|
|
|
@@ -1214,12 +1239,12 @@ import {
|
|
|
1214
1239
|
copyFile,
|
|
1215
1240
|
lstat as lstat5,
|
|
1216
1241
|
mkdir as mkdir3,
|
|
1217
|
-
readFile as
|
|
1242
|
+
readFile as readFile10,
|
|
1218
1243
|
readdir as readdir5,
|
|
1219
1244
|
rm as rm4,
|
|
1220
|
-
writeFile as
|
|
1245
|
+
writeFile as writeFile9
|
|
1221
1246
|
} from "fs/promises";
|
|
1222
|
-
import { basename as basename5, extname as extname3, join as
|
|
1247
|
+
import { basename as basename5, extname as extname3, join as join11 } from "path";
|
|
1223
1248
|
|
|
1224
1249
|
// src/customer-docker.ts
|
|
1225
1250
|
import { readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
|
|
@@ -1304,9 +1329,11 @@ var ignoredFiles = new Set([
|
|
|
1304
1329
|
".windy/update-state.json"
|
|
1305
1330
|
]);
|
|
1306
1331
|
var projectOwnedRoots = [
|
|
1332
|
+
"windy.modules.json",
|
|
1307
1333
|
"module-schema.lineages.json",
|
|
1308
1334
|
"module-schema",
|
|
1309
|
-
"apps/web/src
|
|
1335
|
+
"apps/web/src",
|
|
1336
|
+
"apps/server/src/app",
|
|
1310
1337
|
"apps/agent-server/project",
|
|
1311
1338
|
"apps/server/src/installed-business-modules.ts",
|
|
1312
1339
|
"apps/server/src/domain-schema",
|
|
@@ -1323,8 +1350,6 @@ var sharedScaffoldRoots = [
|
|
|
1323
1350
|
"apps/server/Dockerfile",
|
|
1324
1351
|
"apps/server/src/index.ts",
|
|
1325
1352
|
"apps/web/Dockerfile",
|
|
1326
|
-
"apps/web/src/layout",
|
|
1327
|
-
"apps/web/src/router",
|
|
1328
1353
|
"packages/database/src/schema/index.ts"
|
|
1329
1354
|
];
|
|
1330
1355
|
async function writeManagedFilesManifest(targetDirectory, generatorVersion) {
|
|
@@ -2688,9 +2713,10 @@ MCP \u6BCF\u6B21\u8C03\u7528\u90FD\u4F1A\u91CD\u65B0\u6267\u884C Feature\u3001RB
|
|
|
2688
2713
|
\u548C \`dev:agent\` \u662F\u53E6\u4E00\u6761\u53EF\u9009\u94FE\u8DEF\u3002\u5B8C\u6574\u8FB9\u754C\u89C1
|
|
2689
2714
|
[MCP \u4E1A\u52A1\u80FD\u529B](./docs/architecture/mcp-business-capabilities.md) \u4E0E
|
|
2690
2715
|
[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
|
|
2691
|
-
\u7269\u7406\u88C1\u526A\u3002\u521B\u5EFA\u65F6\u53EF\u589E\u52A0 \`--module system.agent\` \u6216\u4F7F\u7528 \`--all-modules\`\
|
|
2692
|
-
\u9879\u76EE\
|
|
2693
|
-
\
|
|
2716
|
+
\u7269\u7406\u88C1\u526A\u3002\u521B\u5EFA\u65F6\u53EF\u589E\u52A0 \`--module system.agent\` \u6216\u4F7F\u7528 \`--all-modules\`\u3002\u5F53\u524D\u6CA1\u6709
|
|
2717
|
+
self-contained H3 \u6A21\u5757\uFF0C\u5DF2\u90E8\u7F72\u9879\u76EE\u5F53\u524D\u4E0D\u80FD\u901A\u8FC7\u6A21\u5757\u547D\u4EE4\u8865\u88C5 \`system.agent\`\uFF1B
|
|
2718
|
+
\`module add\` \u4F1A\u5728\u5199\u5165\u524D fail closed\u3002\u4E0D\u8981\u624B\u5DE5\u590D\u5236 MCP Adapter \u6216\u53E6\u5EFA\u6388\u6743\u94FE\u3002\u4ED3\u5E93
|
|
2719
|
+
Skill \u4ECD\u53EF\u7528\u4E8E\u666E\u901A\u4E1A\u52A1\u6A21\u5757\u5F00\u53D1\u3002`}
|
|
2694
2720
|
`;
|
|
2695
2721
|
}
|
|
2696
2722
|
|
|
@@ -3076,7 +3102,14 @@ function starterReadme(projectName, includeExample = true, includeOxc = true, pr
|
|
|
3076
3102
|
const selected = new Set(selectedModules);
|
|
3077
3103
|
const includeAgent = selected.has("system.agent");
|
|
3078
3104
|
const includeSearch = selected.has("system.search");
|
|
3079
|
-
const
|
|
3105
|
+
const toggleableModule = moduleDistributionCatalog.find(({ name, selection, runtimeActivation }) => selected.has(name) && selection !== "required" && runtimeActivation === "toggle" && !moduleDistributionCatalog.some((candidate) => selected.has(candidate.name) && candidate.dependencies.includes(name)))?.name;
|
|
3106
|
+
const moduleActivationCommands = toggleableModule ? [
|
|
3107
|
+
`bun run windy module disable ${toggleableModule} --dry-run`,
|
|
3108
|
+
`bun run windy module disable ${toggleableModule}`,
|
|
3109
|
+
`bun run windy module enable ${toggleableModule}`
|
|
3110
|
+
].join(`
|
|
3111
|
+
`) : "# \u5F53\u524D\u7EC4\u5408\u6CA1\u6709\u53EF\u5B89\u5168 runtime disable \u7684\u5DF2\u5B89\u88C5\u53EF\u9009\u6A21\u5757";
|
|
3112
|
+
const moduleRows = moduleDistributionCatalog.map(({ name, description, selection }) => `| \`${name}\` | ${selected.has(name) ? "\u5DF2\u5305\u542B" : "\u672A\u5305\u542B"} | ${selection === "required" ? "H0" : "H2"} | ${description} |`).join(`
|
|
3080
3113
|
`);
|
|
3081
3114
|
return `# ${projectName}
|
|
3082
3115
|
|
|
@@ -3242,22 +3275,29 @@ create-windy \u5728\u672C\u673A \`.env\` \u4E2D\u968F\u673A\u751F\u6210\u7684 \`
|
|
|
3242
3275
|
| \u6CD5\u5F8B\u8BB8\u53EF | \`${projectLicense}\` |
|
|
3243
3276
|
|
|
3244
3277
|
\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
|
|
3245
|
-
\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\
|
|
3246
|
-
\
|
|
3278
|
+
\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\u5F53\u524D\u6CA1\u6709 H3 \u6A21\u5757\uFF0C\u4E5F\u4E0D
|
|
3279
|
+
\u652F\u6301\u4EFB\u610F npm package \u540D\u79F0\u5B89\u88C5\u3002
|
|
3247
3280
|
|
|
3248
3281
|
| Module Key | \u5F53\u524D\u9879\u76EE | \u70ED\u63D2\u62D4\u53EF\u9760\u5EA6 | \u8BF4\u660E |
|
|
3249
3282
|
| ---------- | -------- | ------------ | ---- |
|
|
3250
3283
|
${moduleRows}
|
|
3251
3284
|
|
|
3252
|
-
\u9879\u76EE\
|
|
3253
|
-
\
|
|
3254
|
-
\`
|
|
3255
|
-
\
|
|
3256
|
-
\
|
|
3257
|
-
|
|
3258
|
-
\
|
|
3259
|
-
|
|
3260
|
-
\
|
|
3285
|
+
\u9879\u76EE\u88C5\u914D\u9009\u62E9\u8BB0\u5F55\u5728 project-owned \u7684 \`windy.modules.json\`\uFF0C\u53EF\u63D0\u4EA4 Git \u5E76\u7ED3\u6784\u5316\u7F16\u8F91\uFF1B
|
|
3286
|
+
\u5B83\u53EA\u4FDD\u5B58\u65E0\u7248\u672C package \u5165\u53E3\u3001\u542F\u7528\u72B6\u6001\u3001\u987A\u5E8F\u3001Admin \u53EF\u89C1\u6027\u4E0E\u6A21\u5757\u914D\u7F6E\u3002\u4F9D\u8D56\u7248\u672C\u4E8B\u5B9E
|
|
3287
|
+
\u4ECD\u53EA\u6765\u81EA \`package.json\` \u4E0E \`bun.lock\`\u3002Server \u9ED8\u8BA4\u4ECE
|
|
3288
|
+
\`apps/server/src/app/server-composition.ts\` \u88C5\u914D Adapter\uFF1BWeb \u901A\u8FC7 package \u7684
|
|
3289
|
+
browser-safe \`./admin\` \u4E0E project-owned \u7684
|
|
3290
|
+
\`apps/web/src/app/web-composition.ts\` \u88C5\u914D\u9875\u9762\uFF0C\u4E0D\u590D\u5236\u7B2C\u4E8C\u4EFD Feature\u3001Permission
|
|
3291
|
+
\u6216\u8DEF\u7531\u6E05\u5355\u3002\u6574\u4E2A \`apps/web/src\` \u4E0E\u6574\u4E2A \`apps/server/src/app\` \u90FD\u662F
|
|
3292
|
+
project-owned\uFF0C\u5BA2\u6237\u53EF\u4EE5\u4FEE\u6539 Router\u3001layout\u3001\u9875\u9762\u3001Host \u548C Server \u7EC4\u5408\uFF1B\u666E\u901A
|
|
3293
|
+
\`windy update\` \u4E0D\u4F1A\u8986\u76D6\u6216\u4E09\u65B9\u5408\u5E76\u8FD9\u4E9B\u6587\u4EF6\u3002
|
|
3294
|
+
|
|
3295
|
+
\u7CBE\u786E\u751F\u6210\u6765\u6E90\u4FDD\u7559\u5728 \`.windy/generation.json\`\u3002\u5F53\u524D\u7248\u672C\u5DF2\u63D0\u4F9B\u53EF\u56DE\u6EDA\u7684
|
|
3296
|
+
\`windy update\` \u4E0E \`windy module list/enable/disable\`\u3002\u5F53\u524D\u5185\u7F6E\u6A21\u5757\u4ECD\u4F9D\u8D56
|
|
3297
|
+
source/template \u6216 project-owned Composition\uFF1B\u5F53\u524D\u5185\u7F6E\u6A21\u5757\u7684 add/update/remove
|
|
3298
|
+
\u5B9E\u9645\u96C6\u5408\u53D8\u5316\u4F1A\u5728\u5199\u5165\u524D fail closed\u3002Feature Flag \u5173\u95ED\u3001module disable \u4E0E\u7269\u7406\u5378\u8F7D\u662F
|
|
3299
|
+
\u4E09\u4E2A\u4E0D\u540C\u52A8\u4F5C\uFF1B\`system.settings\`\u3001\`system.storage\` \u548C
|
|
3300
|
+
\`system.data-governance\` \u53EA\u80FD\u5728\u521B\u5EFA\u671F\u7269\u7406\u6392\u9664\uFF0C\u90E8\u7F72\u540E\u4E0D\u80FD\u53EA\u6539 registry \u5B89\u5168\u505C\u7528\u3002
|
|
3261
3301
|
|
|
3262
3302
|
## \u5E38\u7528\u547D\u4EE4
|
|
3263
3303
|
|
|
@@ -3274,8 +3314,7 @@ bun run windy doctor
|
|
|
3274
3314
|
bun run windy update --check
|
|
3275
3315
|
bun run windy update --dry-run
|
|
3276
3316
|
bun run windy module list
|
|
3277
|
-
|
|
3278
|
-
bun run windy module remove work-order --dry-run
|
|
3317
|
+
${moduleActivationCommands}
|
|
3279
3318
|
${includeOxc ? `bun run lint
|
|
3280
3319
|
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"}
|
|
3281
3320
|
\`\`\`
|
|
@@ -3284,7 +3323,9 @@ ${includeOxc ? "\u63D0\u4EA4\u65F6 Husky \u4F1A\u901A\u8FC7 lint-staged \u4E0E O
|
|
|
3284
3323
|
|
|
3285
3324
|
\u66F4\u65B0\u524D\u65E0\u9700\u63D0\u4EA4\u3001\u6682\u5B58\u6216\u6E05\u7406\u4E1A\u52A1\u6539\u52A8\u3002\`--dry-run\` \u53EA\u751F\u6210\u8BA1\u5212\uFF0C\u4E0D\u5199\u9879\u76EE\uFF1B\u65E0\u5173 WIP
|
|
3286
3325
|
\u4FDD\u6301\u539F\u6837\uFF0C\u547D\u4E2D\u540C\u4E00\u8DEF\u5F84\u65F6\u6309\u51BB\u7ED3\u5FEB\u7167\u4E0E\u4E09\u65B9\u5408\u5E76 fail closed\u3002\u6B63\u5F0F\u66F4\u65B0\u5148\u5907\u4EFD\uFF0C\u518D\u505A
|
|
3287
|
-
package \u5B57\u6BB5\u7EA7\u5408\u5E76\u3001\u5171\u4EAB\u811A\u624B\u67B6\u4E09\u65B9\u5408\u5E76\u4E0E\u5B8C\u6574\u9A8C\u8BC1\u3002\
|
|
3326
|
+
package \u5B57\u6BB5\u7EA7\u5408\u5E76\u3001\u5171\u4EAB\u811A\u624B\u67B6\u4E09\u65B9\u5408\u5E76\u4E0E\u5B8C\u6574\u9A8C\u8BC1\u3002\u6574\u4E2A \`apps/web/src\` \u548C
|
|
3327
|
+
\`apps/server/src/app\` \u4FDD\u6301\u9879\u76EE\u7248\u672C\u3002\u4EFB\u4F55\u51B2\u7A81\u90FD\u4F1A\u5728\u5199\u5165\u524D\u4E2D\u6B62\uFF0C\u6A21\u5757\u542F\u505C\u5728\u4EA4\u4E92
|
|
3328
|
+
\u7EC8\u7AEF\u786E\u8BA4\uFF1BCI\u3001Agent \u6216\u5176\u5B83\u975E TTY \u73AF\u5883\u5FC5\u987B\u663E\u5F0F\u4F20\u5165 \`--yes\`\u3002
|
|
3288
3329
|
\u65E0\u5E76\u53D1\u53D8\u5316\u7684\u9A8C\u8BC1\u5931\u8D25\u4F1A\u81EA\u52A8\u56DE\u6EDA\uFF1B\u4E2D\u65AD\u6062\u590D\u4F7F\u7528
|
|
3289
3330
|
\`bun run windy doctor --repair\`\u3002\u8BE5\u547D\u4EE4\u5728\u63D0\u4EA4\u70B9\u524D\u4FDD\u7559\u5E76\u53D1\u7F16\u8F91\u5E76\u56DE\u6EDA\u5176\u4F59\u8DEF\u5F84\uFF0C
|
|
3290
3331
|
\u5728 committed \u63D0\u4EA4\u70B9\u540E\u53EA\u5B8C\u6210\u4E8B\u52A1\u72B6\u6001\u4E0E\u5907\u4EFD\u6E05\u7406\uFF0C\u4E0D\u56DE\u6EDA\u9879\u76EE\u6587\u4EF6\u3002
|
|
@@ -3307,9 +3348,10 @@ create-windy \u9ED8\u8BA4\u5EFA\u7ACB \`main\` \u5206\u652F\u5E76\u521B\u5EFA \`
|
|
|
3307
3348
|
\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
|
|
3308
3349
|
|
|
3309
3350
|
\u5F53\u524D\u5DF2\u4EA4\u4ED8\u7684 Windy \u66F4\u65B0\u5668\u4F1A\u6839\u636E Project Lock \u548C\u6587\u4EF6\u6240\u6709\u6743\uFF0C\u4ECE Project Lock \u6307\u5411\u7684
|
|
3310
|
-
\u7CBE\u786E npm artifact \u91CD\u5EFA Base \u5E76\u6267\u884C\u4E09\u65B9\u5408\u5E76\uFF1B\u5B83\u4E0D\u8FDE\u63A5\u79C1\u6709\u6E90\u4ED3\u5E93\
|
|
3311
|
-
\
|
|
3312
|
-
\
|
|
3351
|
+
\u7CBE\u786E npm artifact \u91CD\u5EFA Base \u5E76\u6267\u884C\u4E09\u65B9\u5408\u5E76\uFF1B\u5B83\u4E0D\u8FDE\u63A5\u79C1\u6709\u6E90\u4ED3\u5E93\u3002
|
|
3352
|
+
\u66F4\u65B0\u5668\u4E0D\u4F1A\u9759\u9ED8\u8986\u76D6\u9879\u76EE\u4EE3\u7801\u3002\`module enable/disable\` \u53EA\u4EE5 CAS \u4E8B\u52A1\u66F4\u65B0
|
|
3353
|
+
\`windy.modules.json\`\uFF1B\u5F53\u524D\u5185\u7F6E\u6A21\u5757\u7684 add/update/remove \u5B9E\u9645\u96C6\u5408\u53D8\u5316\u5728\u751F\u6210\u66F4\u65B0
|
|
3354
|
+
\u8BA1\u5212\u524D\u5373\u88AB\u62D2\u7EDD\u3002
|
|
3313
3355
|
|
|
3314
3356
|
## License
|
|
3315
3357
|
|
|
@@ -3666,6 +3708,109 @@ async function collectFiles3(root) {
|
|
|
3666
3708
|
}
|
|
3667
3709
|
}
|
|
3668
3710
|
|
|
3711
|
+
// src/project-module-registry.ts
|
|
3712
|
+
import { createHash as createHash3 } from "crypto";
|
|
3713
|
+
import { readFile as readFile9, writeFile as writeFile8 } from "fs/promises";
|
|
3714
|
+
import { join as join10 } from "path";
|
|
3715
|
+
var projectModuleRegistryPath = "windy.modules.json";
|
|
3716
|
+
async function readProjectModuleRegistrySnapshot(projectDirectory, installedNames) {
|
|
3717
|
+
const path = join10(projectDirectory, projectModuleRegistryPath);
|
|
3718
|
+
let content;
|
|
3719
|
+
try {
|
|
3720
|
+
content = await readFile9(path);
|
|
3721
|
+
} catch (error) {
|
|
3722
|
+
if (isMissing4(error)) {
|
|
3723
|
+
throw new Error(`\u9879\u76EE\u7F3A\u5C11 ${projectModuleRegistryPath}\uFF1B\u8BF7\u5148\u8FD0\u884C bun run windy update`, { cause: error });
|
|
3724
|
+
}
|
|
3725
|
+
throw error;
|
|
3726
|
+
}
|
|
3727
|
+
const registry = parseProjectModuleRegistry(content);
|
|
3728
|
+
assertRegistryMatchesInstalled(registry, installedNames);
|
|
3729
|
+
return {
|
|
3730
|
+
content,
|
|
3731
|
+
hash: createHash3("sha256").update(content).digest("hex"),
|
|
3732
|
+
registry
|
|
3733
|
+
};
|
|
3734
|
+
}
|
|
3735
|
+
function parseProjectModuleRegistry(content) {
|
|
3736
|
+
const parsed = JSON.parse(typeof content === "string" ? content : new TextDecoder().decode(content));
|
|
3737
|
+
if (!parsed || typeof parsed !== "object")
|
|
3738
|
+
invalidRegistry();
|
|
3739
|
+
const value = parsed;
|
|
3740
|
+
if (value.schemaVersion !== 1 || !Array.isArray(value.modules)) {
|
|
3741
|
+
invalidRegistry();
|
|
3742
|
+
}
|
|
3743
|
+
const names = new Set;
|
|
3744
|
+
const orders = new Set;
|
|
3745
|
+
for (const item of value.modules) {
|
|
3746
|
+
if (!isRegistration(item))
|
|
3747
|
+
invalidRegistry();
|
|
3748
|
+
if (names.has(item.name)) {
|
|
3749
|
+
throw new Error(`\u6A21\u5757\u88C5\u914D\u6E05\u5355\u5B58\u5728\u91CD\u590D name\uFF1A${item.name}`);
|
|
3750
|
+
}
|
|
3751
|
+
if (orders.has(item.order)) {
|
|
3752
|
+
throw new Error(`\u6A21\u5757\u88C5\u914D\u6E05\u5355\u5B58\u5728\u91CD\u590D order\uFF1A${item.order}`);
|
|
3753
|
+
}
|
|
3754
|
+
names.add(item.name);
|
|
3755
|
+
orders.add(item.order);
|
|
3756
|
+
}
|
|
3757
|
+
return value;
|
|
3758
|
+
}
|
|
3759
|
+
async function writeInitialProjectModuleRegistry(targetDirectory, selectedNames) {
|
|
3760
|
+
const manifests = selectedModuleManifests(selectedNames);
|
|
3761
|
+
const modules = await Promise.all(manifests.map(async (manifest, index) => ({
|
|
3762
|
+
name: manifest.name,
|
|
3763
|
+
package: manifest.runtimePackage,
|
|
3764
|
+
enabled: true,
|
|
3765
|
+
order: (index + 1) * 100,
|
|
3766
|
+
admin: { visible: true },
|
|
3767
|
+
config: {}
|
|
3768
|
+
})));
|
|
3769
|
+
const registry = { schemaVersion: 1, modules };
|
|
3770
|
+
await writeFile8(join10(targetDirectory, projectModuleRegistryPath), `${JSON.stringify(registry, null, 2)}
|
|
3771
|
+
`);
|
|
3772
|
+
}
|
|
3773
|
+
function assertRegistryMatchesInstalled(registry, installedNames) {
|
|
3774
|
+
const installed = new Set(installedNames);
|
|
3775
|
+
const registered = new Set(registry.modules.map(({ name }) => name));
|
|
3776
|
+
const extra = registry.modules.map(({ name }) => name).filter((name) => !installed.has(name));
|
|
3777
|
+
if (extra.length) {
|
|
3778
|
+
throw new Error(`\u6A21\u5757\u88C5\u914D\u6E05\u5355\u5305\u542B\u672A\u5B89\u88C5\u6A21\u5757\uFF1A${extra.join("\u3001")}`);
|
|
3779
|
+
}
|
|
3780
|
+
const missing = installedNames.filter((name) => !registered.has(name));
|
|
3781
|
+
if (missing.length) {
|
|
3782
|
+
throw new Error(`\u5DF2\u5B89\u88C5\u6A21\u5757\u7F3A\u5C11\u88C5\u914D\u58F0\u660E\uFF1A${missing.join("\u3001")}`);
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
function isRegistration(value) {
|
|
3786
|
+
if (!value || typeof value !== "object")
|
|
3787
|
+
return false;
|
|
3788
|
+
const item = value;
|
|
3789
|
+
const admin = item.admin;
|
|
3790
|
+
return typeof item.name === "string" && item.name.length > 0 && (item.package === null || typeof item.package === "string" && isPackageName(item.package)) && typeof item.enabled === "boolean" && Number.isSafeInteger(item.order) && Number(item.order) >= 0 && admin !== undefined && typeof admin === "object" && typeof admin.visible === "boolean" && typeof item.config === "object" && item.config !== null && !Array.isArray(item.config);
|
|
3791
|
+
}
|
|
3792
|
+
function isPackageName(value) {
|
|
3793
|
+
if (!value || value.length > 214 || value !== value.toLowerCase()) {
|
|
3794
|
+
return false;
|
|
3795
|
+
}
|
|
3796
|
+
const parts = value.startsWith("@") ? value.slice(1).split("/") : [value];
|
|
3797
|
+
if (parts.length !== (value.startsWith("@") ? 2 : 1))
|
|
3798
|
+
return false;
|
|
3799
|
+
return parts.every(isPackageNamePart);
|
|
3800
|
+
}
|
|
3801
|
+
function isPackageNamePart(value) {
|
|
3802
|
+
if (!value || value === "node_modules" || value === "favicon.ico" || value.startsWith(".") || value.startsWith("_")) {
|
|
3803
|
+
return false;
|
|
3804
|
+
}
|
|
3805
|
+
return /^[a-z0-9!~*'()._-]+$/.test(value);
|
|
3806
|
+
}
|
|
3807
|
+
function invalidRegistry() {
|
|
3808
|
+
throw new Error("\u9879\u76EE\u6A21\u5757\u88C5\u914D\u6E05\u5355\u65E0\u6548");
|
|
3809
|
+
}
|
|
3810
|
+
function isMissing4(error) {
|
|
3811
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
3812
|
+
}
|
|
3813
|
+
|
|
3669
3814
|
// src/generator.ts
|
|
3670
3815
|
async function generateProject(input) {
|
|
3671
3816
|
validateProjectName(input.projectName);
|
|
@@ -3678,39 +3823,40 @@ async function generateProject(input) {
|
|
|
3678
3823
|
const selectedModules = input.selectedModules ?? templateMetadata.modules.filter(({ name }) => requestedIncludeExample || name !== "work-order").map(({ name }) => name);
|
|
3679
3824
|
const includeExample = selectedModules.includes("work-order");
|
|
3680
3825
|
for (const relativePath2 of generationTemplatePaths(true, includeOxc)) {
|
|
3681
|
-
await copyTree(await resolveTemplateSource(input.sourceRoot, relativePath2),
|
|
3826
|
+
await copyTree(await resolveTemplateSource(input.sourceRoot, relativePath2), join11(input.targetDirectory, relativePath2));
|
|
3682
3827
|
}
|
|
3683
3828
|
await materializeSelectedModules(input.targetDirectory, selectedModules);
|
|
3684
3829
|
await materializeRegistryDependencies(input.targetDirectory, selectedModuleManifests(selectedModules).flatMap(({ registryDependencies }) => registryDependencies));
|
|
3685
|
-
const packagePath =
|
|
3686
|
-
const packageJson = JSON.parse(await
|
|
3687
|
-
await
|
|
3830
|
+
const packagePath = join11(input.targetDirectory, "package.json");
|
|
3831
|
+
const packageJson = JSON.parse(await readFile10(packagePath, "utf8"));
|
|
3832
|
+
await writeFile9(packagePath, `${JSON.stringify(createStarterPackage(packageJson, input.projectName, includeOxc, projectLicense, selectedModules, templateMetadata.generatorVersion), null, 2)}
|
|
3688
3833
|
`);
|
|
3689
|
-
await
|
|
3690
|
-
await
|
|
3691
|
-
await
|
|
3692
|
-
await
|
|
3834
|
+
await writeFile9(join11(input.targetDirectory, "docker-compose.yml"), starterComposeFor(selectedModules.includes("system.agent"), selectedModules.includes("system.search")));
|
|
3835
|
+
await writeFile9(join11(input.targetDirectory, ".env.example"), environmentExample(includeExample, selectedModules.includes("system.agent"), selectedModules.includes("system.search")));
|
|
3836
|
+
await writeFile9(join11(input.targetDirectory, "README.md"), starterReadme(input.projectName, includeExample, includeOxc, projectLicense, selectedModules));
|
|
3837
|
+
await writeFile9(join11(input.targetDirectory, "docs/README.md"), starterDocsReadme(selectedModules.includes("system.license"), selectedModules.includes("system.agent"), selectedModules.includes("system.operations")));
|
|
3693
3838
|
await reflectCodeQualityChoice(input.targetDirectory, includeOxc);
|
|
3694
3839
|
await applyWindyBaseLicense(input.targetDirectory);
|
|
3695
3840
|
await applyProjectLicense(input.targetDirectory, projectLicense, input.licenseHolder);
|
|
3696
3841
|
await prepareCustomerDockerfiles(input.targetDirectory);
|
|
3697
3842
|
await writeGenerationProvenance(input.targetDirectory, templateMetadata, input.profile ?? starterProfile.key, selectedModules, includeOxc, projectLicense);
|
|
3698
|
-
await
|
|
3843
|
+
await writeInitialProjectModuleRegistry(input.targetDirectory, selectedModules);
|
|
3844
|
+
await rm4(join11(input.targetDirectory, "bun.lock"), { force: true });
|
|
3699
3845
|
await writeManagedFilesManifest(input.targetDirectory, templateMetadata.generatorVersion);
|
|
3700
3846
|
}
|
|
3701
3847
|
async function resolveTemplateSource(sourceRoot, relativePath2) {
|
|
3702
|
-
const source =
|
|
3848
|
+
const source = join11(sourceRoot, relativePath2);
|
|
3703
3849
|
try {
|
|
3704
3850
|
await lstat5(source);
|
|
3705
3851
|
return source;
|
|
3706
3852
|
} catch (error) {
|
|
3707
|
-
if (!
|
|
3853
|
+
if (!isMissing5(error))
|
|
3708
3854
|
throw error;
|
|
3709
3855
|
}
|
|
3710
3856
|
const alias = npmTemplateAliases[relativePath2];
|
|
3711
3857
|
if (!alias)
|
|
3712
3858
|
return source;
|
|
3713
|
-
return
|
|
3859
|
+
return join11(sourceRoot, alias);
|
|
3714
3860
|
}
|
|
3715
3861
|
async function assertGeneratedProjectIsClean(targetDirectory) {
|
|
3716
3862
|
const violations = [];
|
|
@@ -3739,7 +3885,7 @@ async function assertTargetAvailable(targetDirectory) {
|
|
|
3739
3885
|
if (entries.length)
|
|
3740
3886
|
throw new Error("\u76EE\u6807\u76EE\u5F55\u4E0D\u662F\u7A7A\u76EE\u5F55");
|
|
3741
3887
|
} catch (error) {
|
|
3742
|
-
if (
|
|
3888
|
+
if (isMissing5(error))
|
|
3743
3889
|
return;
|
|
3744
3890
|
throw error;
|
|
3745
3891
|
}
|
|
@@ -3752,11 +3898,11 @@ async function copyTree(source, target) {
|
|
|
3752
3898
|
if (metadata.isDirectory()) {
|
|
3753
3899
|
await mkdir3(target, { recursive: true });
|
|
3754
3900
|
for (const child of await readdir5(source)) {
|
|
3755
|
-
await copyTree(
|
|
3901
|
+
await copyTree(join11(source, child), join11(target, child));
|
|
3756
3902
|
}
|
|
3757
3903
|
return;
|
|
3758
3904
|
}
|
|
3759
|
-
await mkdir3(
|
|
3905
|
+
await mkdir3(join11(target, ".."), { recursive: true });
|
|
3760
3906
|
await copyFile(source, target);
|
|
3761
3907
|
}
|
|
3762
3908
|
function shouldExclude(name) {
|
|
@@ -3764,13 +3910,13 @@ function shouldExclude(name) {
|
|
|
3764
3910
|
}
|
|
3765
3911
|
async function walk(directory, visit) {
|
|
3766
3912
|
for (const name of await readdir5(directory)) {
|
|
3767
|
-
const path =
|
|
3913
|
+
const path = join11(directory, name);
|
|
3768
3914
|
await visit(path);
|
|
3769
3915
|
if ((await lstat5(path)).isDirectory())
|
|
3770
3916
|
await walk(path, visit);
|
|
3771
3917
|
}
|
|
3772
3918
|
}
|
|
3773
|
-
function
|
|
3919
|
+
function isMissing5(error) {
|
|
3774
3920
|
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
3775
3921
|
}
|
|
3776
3922
|
|
|
@@ -3850,7 +3996,7 @@ async function inspectTarget(path) {
|
|
|
3850
3996
|
try {
|
|
3851
3997
|
return (await readdir6(path)).length === 0 ? "empty" : "non-empty";
|
|
3852
3998
|
} catch (error) {
|
|
3853
|
-
if (
|
|
3999
|
+
if (isMissing6(error))
|
|
3854
4000
|
return "missing";
|
|
3855
4001
|
throw error;
|
|
3856
4002
|
}
|
|
@@ -3872,7 +4018,7 @@ function stageError(stage, error) {
|
|
|
3872
4018
|
function sanitizeReason(reason) {
|
|
3873
4019
|
return reason.replace(/\b([A-Z][A-Z0-9_]*(?:PASSWORD|SECRET|TOKEN|DATABASE_URL)[A-Z0-9_]*)=\S+/g, "$1=[\u5DF2\u9690\u85CF]").replace(/:\/\/([^\s:/]+):([^\s@]+)@/g, "://$1:[\u5DF2\u9690\u85CF]@");
|
|
3874
4020
|
}
|
|
3875
|
-
function
|
|
4021
|
+
function isMissing6(error) {
|
|
3876
4022
|
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
3877
4023
|
}
|
|
3878
4024
|
|
|
@@ -5620,8 +5766,8 @@ import { rm as rm10 } from "fs/promises";
|
|
|
5620
5766
|
import { resolve as resolve8 } from "path";
|
|
5621
5767
|
|
|
5622
5768
|
// src/update/doctor.ts
|
|
5623
|
-
import { readFile as
|
|
5624
|
-
import { join as
|
|
5769
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
5770
|
+
import { join as join15 } from "path";
|
|
5625
5771
|
|
|
5626
5772
|
// src/update/process.ts
|
|
5627
5773
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -6163,12 +6309,12 @@ function casError(path2, artifactPath, cause) {
|
|
|
6163
6309
|
|
|
6164
6310
|
// src/update/transaction-runtime.ts
|
|
6165
6311
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
6166
|
-
import { join as
|
|
6312
|
+
import { join as join13 } from "path";
|
|
6167
6313
|
|
|
6168
6314
|
// src/update/transaction-state-temporaries.ts
|
|
6169
6315
|
import { randomUUID } from "crypto";
|
|
6170
6316
|
import { readdir as readdir7 } from "fs/promises";
|
|
6171
|
-
import { join as
|
|
6317
|
+
import { join as join12 } from "path";
|
|
6172
6318
|
function serializeTransactionState(state) {
|
|
6173
6319
|
return `${JSON.stringify(state, null, 2)}
|
|
6174
6320
|
`;
|
|
@@ -6284,7 +6430,7 @@ function stateTemporaryName(identity, cleanup) {
|
|
|
6284
6430
|
return `${prefix}.${identity.kind}.${identity.ownerToken}.${identity.nonce}.tmp`;
|
|
6285
6431
|
}
|
|
6286
6432
|
async function listWindyDirectory(root) {
|
|
6287
|
-
return readdir7(
|
|
6433
|
+
return readdir7(join12(root, ".windy")).catch((error) => {
|
|
6288
6434
|
if (hasFsCode3(error, "ENOENT"))
|
|
6289
6435
|
return [];
|
|
6290
6436
|
throw error;
|
|
@@ -6318,7 +6464,7 @@ function createTransactionState(root, updateId, entries, manifestHash) {
|
|
|
6318
6464
|
return {
|
|
6319
6465
|
schemaVersion: 1,
|
|
6320
6466
|
updateId,
|
|
6321
|
-
backupDirectory:
|
|
6467
|
+
backupDirectory: join13(root, backupRelativePath(updateId)),
|
|
6322
6468
|
entries,
|
|
6323
6469
|
ownerToken: randomUUID2(),
|
|
6324
6470
|
phase: "claiming",
|
|
@@ -6377,7 +6523,7 @@ async function backupEntriesToDisk(root, backupPath, entries, afterEntry) {
|
|
|
6377
6523
|
if (entry.mode !== undefined && await safeFileMode(root, entry.path) !== entry.mode) {
|
|
6378
6524
|
throw new TransactionCasError(`\u5F85\u5907\u4EFD\u6587\u4EF6 mode \u5DF2\u53D8\u5316\uFF1A${entry.path}`, entry.path);
|
|
6379
6525
|
}
|
|
6380
|
-
await writeExclusive(root,
|
|
6526
|
+
await writeExclusive(root, join13(backupPath, "files", entry.path), content, undefined, entry.mode);
|
|
6381
6527
|
await afterEntry?.();
|
|
6382
6528
|
}
|
|
6383
6529
|
}
|
|
@@ -6685,7 +6831,7 @@ async function removeOwnedResidue(root, evidence, hash, mode) {
|
|
|
6685
6831
|
}
|
|
6686
6832
|
|
|
6687
6833
|
// src/update/transaction-recovery-files.ts
|
|
6688
|
-
import { join as
|
|
6834
|
+
import { join as join14 } from "path";
|
|
6689
6835
|
function matchesExpected(actualHash, actualMode, expected, expectedMode) {
|
|
6690
6836
|
return expected.kind === "missing" ? actualHash === undefined : actualHash === expected.value && (expectedMode === undefined || actualMode === expectedMode);
|
|
6691
6837
|
}
|
|
@@ -6697,7 +6843,7 @@ async function readRecoveryBackups(root, backupPath, state, preserved) {
|
|
|
6697
6843
|
await inspectSafePath(root, entry.path);
|
|
6698
6844
|
if (!entry.existed)
|
|
6699
6845
|
continue;
|
|
6700
|
-
const backupFile =
|
|
6846
|
+
const backupFile = join14(backupPath, "files", entry.path);
|
|
6701
6847
|
const content = await readSafeOptional(root, backupFile);
|
|
6702
6848
|
if (!content)
|
|
6703
6849
|
throw new Error(`\u4E8B\u52A1\u5907\u4EFD\u7F3A\u5931\uFF1A${entry.path}`);
|
|
@@ -7328,7 +7474,7 @@ async function diagnoseProject(projectDirectory, repair = false) {
|
|
|
7328
7474
|
if (file.ownership === "project-owned")
|
|
7329
7475
|
continue;
|
|
7330
7476
|
try {
|
|
7331
|
-
const changed = hashContent(await
|
|
7477
|
+
const changed = hashContent(await readFile11(join15(projectDirectory, file.path))) !== file.hash;
|
|
7332
7478
|
if (!changed)
|
|
7333
7479
|
continue;
|
|
7334
7480
|
modifiedManagedFiles.push(file.path);
|
|
@@ -7373,6 +7519,16 @@ var recipes = [
|
|
|
7373
7519
|
id: "starter-0.3.18-to-0.3.19",
|
|
7374
7520
|
from: "0.3.18",
|
|
7375
7521
|
to: "0.3.19"
|
|
7522
|
+
},
|
|
7523
|
+
{
|
|
7524
|
+
id: "starter-0.3.19-to-0.4.0",
|
|
7525
|
+
from: "0.3.19",
|
|
7526
|
+
to: "0.4.0"
|
|
7527
|
+
},
|
|
7528
|
+
{
|
|
7529
|
+
id: "starter-0.4.0-to-0.4.1",
|
|
7530
|
+
from: "0.4.0",
|
|
7531
|
+
to: "0.4.1"
|
|
7376
7532
|
}
|
|
7377
7533
|
];
|
|
7378
7534
|
function resolveRecipeChain(sourceVersion, targetVersion) {
|
|
@@ -7418,18 +7574,18 @@ function parseVersion2(version) {
|
|
|
7418
7574
|
}
|
|
7419
7575
|
|
|
7420
7576
|
// src/update/updater.ts
|
|
7421
|
-
import { readFile as
|
|
7422
|
-
import { join as
|
|
7577
|
+
import { readFile as readFile21, rm as rm8 } from "fs/promises";
|
|
7578
|
+
import { join as join26 } from "path";
|
|
7423
7579
|
|
|
7424
7580
|
// src/update/artifacts.ts
|
|
7425
|
-
import { mkdtemp, readFile as
|
|
7581
|
+
import { mkdtemp, readFile as readFile14 } from "fs/promises";
|
|
7426
7582
|
import { tmpdir } from "os";
|
|
7427
|
-
import { basename as basename8, join as
|
|
7583
|
+
import { basename as basename8, join as join18 } from "path";
|
|
7428
7584
|
|
|
7429
7585
|
// src/update/published-artifacts.ts
|
|
7430
|
-
import { createHash as
|
|
7431
|
-
import { mkdir as mkdir6, readFile as
|
|
7432
|
-
import { basename as basename7, join as
|
|
7586
|
+
import { createHash as createHash4 } from "crypto";
|
|
7587
|
+
import { mkdir as mkdir6, readFile as readFile12, writeFile as writeFile10 } from "fs/promises";
|
|
7588
|
+
import { basename as basename7, join as join16 } from "path";
|
|
7433
7589
|
|
|
7434
7590
|
// src/update/safe-archive.ts
|
|
7435
7591
|
import { mkdir as mkdir5 } from "fs/promises";
|
|
@@ -7481,17 +7637,17 @@ async function downloadPublicArtifact(temporaryRoot, label, version, expectedInt
|
|
|
7481
7637
|
}
|
|
7482
7638
|
const archive = await readBoundedResponse(response, `create-windy@${version} artifact `);
|
|
7483
7639
|
verifyArchive(metadata, archive);
|
|
7484
|
-
const destination =
|
|
7485
|
-
const archivePath =
|
|
7486
|
-
await
|
|
7640
|
+
const destination = join16(temporaryRoot, `${label}-artifact`);
|
|
7641
|
+
const archivePath = join16(temporaryRoot, `${label}.tgz`);
|
|
7642
|
+
await writeFile10(archivePath, archive);
|
|
7487
7643
|
await extractSafeTarArchive({
|
|
7488
7644
|
archivePath,
|
|
7489
7645
|
destination,
|
|
7490
7646
|
cwd: temporaryRoot
|
|
7491
7647
|
});
|
|
7492
|
-
const packageRoot2 =
|
|
7493
|
-
const packageJson = JSON.parse(await
|
|
7494
|
-
const template = await readTemplateMetadata(
|
|
7648
|
+
const packageRoot2 = join16(destination, "package");
|
|
7649
|
+
const packageJson = JSON.parse(await readFile12(join16(packageRoot2, "package.json"), "utf8"));
|
|
7650
|
+
const template = await readTemplateMetadata(join16(packageRoot2, "template"));
|
|
7495
7651
|
if (packageJson.name !== "create-windy" || packageJson.version !== version || template.generatorVersion !== version) {
|
|
7496
7652
|
throw new Error(`create-windy@${version} \u5305\u8EAB\u4EFD\u6216\u6A21\u677F\u5143\u6570\u636E\u4E0D\u4E00\u81F4`);
|
|
7497
7653
|
}
|
|
@@ -7616,17 +7772,17 @@ function boundedSizeError(label) {
|
|
|
7616
7772
|
return new Error(`${label}\u8D85\u8FC7\u5B89\u5168\u4E0A\u9650`);
|
|
7617
7773
|
}
|
|
7618
7774
|
function verifyArchive(metadata, archive) {
|
|
7619
|
-
const integrity = `sha512-${
|
|
7620
|
-
const shasum =
|
|
7775
|
+
const integrity = `sha512-${createHash4("sha512").update(archive).digest("base64")}`;
|
|
7776
|
+
const shasum = createHash4("sha1").update(archive).digest("hex");
|
|
7621
7777
|
if (integrity !== metadata.dist.integrity || shasum !== metadata.dist.shasum) {
|
|
7622
7778
|
throw new Error(`create-windy@${metadata.version} artifact \u5B8C\u6574\u6027\u6821\u9A8C\u5931\u8D25`);
|
|
7623
7779
|
}
|
|
7624
7780
|
}
|
|
7625
7781
|
async function generatePublicArtifactProject(temporaryRoot, label, projectName, packageRoot2, provenance) {
|
|
7626
|
-
const parent =
|
|
7782
|
+
const parent = join16(temporaryRoot, label);
|
|
7627
7783
|
await mkdir6(parent, { recursive: true });
|
|
7628
7784
|
const args = [
|
|
7629
|
-
|
|
7785
|
+
join16(packageRoot2, "dist/cli.js"),
|
|
7630
7786
|
projectName,
|
|
7631
7787
|
"--yes",
|
|
7632
7788
|
"--skip-install",
|
|
@@ -7646,7 +7802,7 @@ async function generatePublicArtifactProject(temporaryRoot, label, projectName,
|
|
|
7646
7802
|
}
|
|
7647
7803
|
}
|
|
7648
7804
|
await assertProcess("bun", args, parent);
|
|
7649
|
-
return
|
|
7805
|
+
return join16(parent, projectName);
|
|
7650
7806
|
}
|
|
7651
7807
|
|
|
7652
7808
|
// src/module-history.ts
|
|
@@ -7654,18 +7810,18 @@ import {
|
|
|
7654
7810
|
lstat as lstat6,
|
|
7655
7811
|
mkdir as mkdir7,
|
|
7656
7812
|
readdir as readdir8,
|
|
7657
|
-
readFile as
|
|
7658
|
-
writeFile as
|
|
7813
|
+
readFile as readFile13,
|
|
7814
|
+
writeFile as writeFile11
|
|
7659
7815
|
} from "fs/promises";
|
|
7660
|
-
import { dirname as dirname6, join as
|
|
7816
|
+
import { dirname as dirname6, join as join17, relative as relative4, sep as sep4 } from "path";
|
|
7661
7817
|
async function archiveRemovedModuleMigrations(input) {
|
|
7662
7818
|
await assertExistingHistoryIntegrity(input.projectDirectory);
|
|
7663
|
-
let changed = await copyMigrationTree(input.projectDirectory, ".windy/module-history",
|
|
7819
|
+
let changed = await copyMigrationTree(input.projectDirectory, ".windy/module-history", join17(input.targetDirectory, ".windy/module-history"));
|
|
7664
7820
|
const target = new Set(input.targetModules);
|
|
7665
7821
|
const removed = moduleDistributionCatalog.filter(({ name }) => input.sourceModules.includes(name) && !target.has(name));
|
|
7666
7822
|
for (const manifest of removed) {
|
|
7667
7823
|
for (const root of manifest.migrationRoots) {
|
|
7668
|
-
changed = await copyMigrationTree(input.projectDirectory, root,
|
|
7824
|
+
changed = await copyMigrationTree(input.projectDirectory, root, join17(input.targetDirectory, ".windy/module-history", manifest.name, root)) || changed;
|
|
7669
7825
|
}
|
|
7670
7826
|
}
|
|
7671
7827
|
if (changed) {
|
|
@@ -7673,7 +7829,7 @@ async function archiveRemovedModuleMigrations(input) {
|
|
|
7673
7829
|
}
|
|
7674
7830
|
}
|
|
7675
7831
|
async function assertExistingHistoryIntegrity(projectDirectory) {
|
|
7676
|
-
const historyRoot =
|
|
7832
|
+
const historyRoot = join17(projectDirectory, ".windy/module-history");
|
|
7677
7833
|
const metadata = await readOptionalMetadata(historyRoot);
|
|
7678
7834
|
if (!metadata)
|
|
7679
7835
|
return;
|
|
@@ -7688,13 +7844,13 @@ async function assertExistingHistoryIntegrity(projectDirectory) {
|
|
|
7688
7844
|
if (!entry || isMissingManagedFile(entry)) {
|
|
7689
7845
|
throw new Error(`\u6A21\u5757 migration \u5386\u53F2\u672A\u767B\u8BB0\u5230\u53D7\u7BA1\u6E05\u5355\uFF1A${relativePath2}`);
|
|
7690
7846
|
}
|
|
7691
|
-
if (hashContent(await
|
|
7847
|
+
if (hashContent(await readFile13(path2)) !== entry.hash) {
|
|
7692
7848
|
throw new Error(`\u6A21\u5757 migration \u5386\u53F2\u5DF2\u88AB\u4FEE\u6539\uFF1A${relativePath2}`);
|
|
7693
7849
|
}
|
|
7694
7850
|
}
|
|
7695
7851
|
}
|
|
7696
7852
|
async function copyMigrationTree(projectRoot, relativeRoot, targetRoot) {
|
|
7697
|
-
const sourceRoot =
|
|
7853
|
+
const sourceRoot = join17(projectRoot, relativeRoot);
|
|
7698
7854
|
const rootMetadata = await readOptionalMetadata(sourceRoot);
|
|
7699
7855
|
if (!rootMetadata)
|
|
7700
7856
|
return false;
|
|
@@ -7702,9 +7858,9 @@ async function copyMigrationTree(projectRoot, relativeRoot, targetRoot) {
|
|
|
7702
7858
|
throw new Error(`\u6A21\u5757 migration \u6839\u76EE\u5F55\u65E0\u6548\uFF1A${relativeRoot}`);
|
|
7703
7859
|
}
|
|
7704
7860
|
for (const source of await collectRegularFiles(sourceRoot)) {
|
|
7705
|
-
const target =
|
|
7861
|
+
const target = join17(targetRoot, relative4(sourceRoot, source).split(sep4).join("/"));
|
|
7706
7862
|
await mkdir7(dirname6(target), { recursive: true });
|
|
7707
|
-
await
|
|
7863
|
+
await writeFile11(target, await readFile13(source));
|
|
7708
7864
|
}
|
|
7709
7865
|
return true;
|
|
7710
7866
|
}
|
|
@@ -7714,7 +7870,7 @@ async function collectRegularFiles(root) {
|
|
|
7714
7870
|
return files.sort();
|
|
7715
7871
|
async function visit(directory) {
|
|
7716
7872
|
for (const name of (await readdir8(directory)).sort()) {
|
|
7717
|
-
const path2 =
|
|
7873
|
+
const path2 = join17(directory, name);
|
|
7718
7874
|
const metadata = await lstat6(path2);
|
|
7719
7875
|
if (metadata.isSymbolicLink()) {
|
|
7720
7876
|
throw new Error(`\u6A21\u5757 migration \u4E0D\u5141\u8BB8\u7B26\u53F7\u94FE\u63A5\uFF1A${path2}`);
|
|
@@ -7744,10 +7900,10 @@ class PublishedArtifactProvider {
|
|
|
7744
7900
|
this.#fetch = fetcher;
|
|
7745
7901
|
}
|
|
7746
7902
|
async prepare(projectDirectory, provenance, targetModules) {
|
|
7747
|
-
const temporaryRoot = await mkdtemp(
|
|
7903
|
+
const temporaryRoot = await mkdtemp(join18(tmpdir(), "windy-update-"));
|
|
7748
7904
|
const projectName = await readProjectName2(projectDirectory);
|
|
7749
|
-
const baseDirectory =
|
|
7750
|
-
const targetDirectory =
|
|
7905
|
+
const baseDirectory = join18(temporaryRoot, "base", projectName);
|
|
7906
|
+
const targetDirectory = join18(temporaryRoot, "target", projectName);
|
|
7751
7907
|
const baseArtifact = await downloadPublicArtifact(temporaryRoot, "base", provenance.generatorVersion, undefined, this.#fetch);
|
|
7752
7908
|
if (baseArtifact.identity.templateCommit !== provenance.templateCommit) {
|
|
7753
7909
|
throw new Error("Project Lock \u4E0E\u6765\u6E90 registry artifact \u7684 template commit \u4E0D\u4E00\u81F4");
|
|
@@ -7775,13 +7931,13 @@ class PublishedArtifactProvider {
|
|
|
7775
7931
|
}
|
|
7776
7932
|
}
|
|
7777
7933
|
async function readProjectName2(projectDirectory) {
|
|
7778
|
-
const source = JSON.parse(await
|
|
7934
|
+
const source = JSON.parse(await readFile14(join18(projectDirectory, "package.json"), "utf8"));
|
|
7779
7935
|
return source.name || basename8(projectDirectory);
|
|
7780
7936
|
}
|
|
7781
7937
|
|
|
7782
7938
|
// src/update/planner.ts
|
|
7783
|
-
import { readFile as
|
|
7784
|
-
import { dirname as dirname7, join as
|
|
7939
|
+
import { readFile as readFile19 } from "fs/promises";
|
|
7940
|
+
import { dirname as dirname7, join as join24 } from "path";
|
|
7785
7941
|
|
|
7786
7942
|
// src/update/docker-copy-update-plan.ts
|
|
7787
7943
|
async function deriveDockerfilePlans(files, snapshots, paths, targetWorkspaceManifests) {
|
|
@@ -7869,12 +8025,12 @@ function matchesWorkspace(pattern, directory) {
|
|
|
7869
8025
|
}
|
|
7870
8026
|
|
|
7871
8027
|
// src/update/migration-reconciler.ts
|
|
7872
|
-
import { readFile as
|
|
7873
|
-
import { join as
|
|
8028
|
+
import { readFile as readFile16 } from "fs/promises";
|
|
8029
|
+
import { join as join20 } from "path";
|
|
7874
8030
|
|
|
7875
8031
|
// src/update/migration-project-file.ts
|
|
7876
|
-
import { readFile as
|
|
7877
|
-
import { join as
|
|
8032
|
+
import { readFile as readFile15 } from "fs/promises";
|
|
8033
|
+
import { join as join19 } from "path";
|
|
7878
8034
|
async function readProjectJson(input, path2) {
|
|
7879
8035
|
const content = await readProjectFile(input, path2);
|
|
7880
8036
|
if (!content) {
|
|
@@ -7890,7 +8046,7 @@ async function readProjectFile(input, path2) {
|
|
|
7890
8046
|
}
|
|
7891
8047
|
let content;
|
|
7892
8048
|
try {
|
|
7893
|
-
content = await
|
|
8049
|
+
content = await readFile15(join19(input.projectDirectory, path2));
|
|
7894
8050
|
} catch (error) {
|
|
7895
8051
|
if (!isMissingFileError(error))
|
|
7896
8052
|
throw error;
|
|
@@ -8009,7 +8165,7 @@ async function reconcileDrizzleMigrations(input) {
|
|
|
8009
8165
|
const tag = `${prefix}_${name}`;
|
|
8010
8166
|
const sqlPath = `${drizzleRoot}/${tag}.sql`;
|
|
8011
8167
|
const snapshotPath = `${drizzleRoot}/meta/${prefix}_snapshot.json`;
|
|
8012
|
-
const sql = await
|
|
8168
|
+
const sql = await readFile16(join20(input.targetDirectory, `${drizzleRoot}/${addition.tag}.sql`));
|
|
8013
8169
|
merged.id = targetAfter.id;
|
|
8014
8170
|
merged.prevId = currentSnapshot.id;
|
|
8015
8171
|
const snapshot = encodeJson(merged);
|
|
@@ -8056,9 +8212,9 @@ function unchanged(targetManifest) {
|
|
|
8056
8212
|
async function readJournals(input) {
|
|
8057
8213
|
try {
|
|
8058
8214
|
const [base, project, target] = await Promise.all([
|
|
8059
|
-
readJson(
|
|
8215
|
+
readJson(join20(input.baseDirectory, journalPath)),
|
|
8060
8216
|
readProjectJson(input, journalPath),
|
|
8061
|
-
readJson(
|
|
8217
|
+
readJson(join20(input.targetDirectory, journalPath))
|
|
8062
8218
|
]);
|
|
8063
8219
|
return { base, project, target };
|
|
8064
8220
|
} catch (error) {
|
|
@@ -8096,7 +8252,7 @@ async function readSnapshot(root, tag) {
|
|
|
8096
8252
|
const match = migrationPattern.exec(tag);
|
|
8097
8253
|
if (!match)
|
|
8098
8254
|
throw new Error(`${journalPath}\uFF1Amigration tag \u683C\u5F0F\u65E0\u6548\uFF1A${tag}`);
|
|
8099
|
-
return await readJson(
|
|
8255
|
+
return await readJson(join20(root, `${drizzleRoot}/meta/${match[1]}_snapshot.json`));
|
|
8100
8256
|
}
|
|
8101
8257
|
function validateUniqueNames(journal, label, conflicts) {
|
|
8102
8258
|
const seen = new Set;
|
|
@@ -8137,27 +8293,27 @@ function encodeJson(value) {
|
|
|
8137
8293
|
`);
|
|
8138
8294
|
}
|
|
8139
8295
|
async function readJson(path2) {
|
|
8140
|
-
return JSON.parse(await
|
|
8296
|
+
return JSON.parse(await readFile16(path2, "utf8"));
|
|
8141
8297
|
}
|
|
8142
8298
|
|
|
8143
8299
|
// src/update/planner-file.ts
|
|
8144
|
-
import { readFile as
|
|
8145
|
-
import { join as
|
|
8300
|
+
import { readFile as readFile17 } from "fs/promises";
|
|
8301
|
+
import { join as join22 } from "path";
|
|
8146
8302
|
|
|
8147
8303
|
// src/update/merge.ts
|
|
8148
|
-
import { mkdtemp as mkdtemp2, rm as rm6, writeFile as
|
|
8304
|
+
import { mkdtemp as mkdtemp2, rm as rm6, writeFile as writeFile12 } from "fs/promises";
|
|
8149
8305
|
import { tmpdir as tmpdir2 } from "os";
|
|
8150
|
-
import { join as
|
|
8306
|
+
import { join as join21 } from "path";
|
|
8151
8307
|
async function mergeTextFile(base, ours, theirs) {
|
|
8152
|
-
const root = await mkdtemp2(
|
|
8308
|
+
const root = await mkdtemp2(join21(tmpdir2(), "windy-merge-"));
|
|
8153
8309
|
try {
|
|
8154
|
-
const oursPath =
|
|
8155
|
-
const basePath =
|
|
8156
|
-
const theirsPath =
|
|
8310
|
+
const oursPath = join21(root, "ours");
|
|
8311
|
+
const basePath = join21(root, "base");
|
|
8312
|
+
const theirsPath = join21(root, "theirs");
|
|
8157
8313
|
await Promise.all([
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
|
|
8314
|
+
writeFile12(oursPath, ours),
|
|
8315
|
+
writeFile12(basePath, base),
|
|
8316
|
+
writeFile12(theirsPath, theirs)
|
|
8161
8317
|
]);
|
|
8162
8318
|
const result2 = await captureProcess("git", ["merge-file", "-p", "--diff3", oursPath, basePath, theirsPath], root);
|
|
8163
8319
|
if (result2.code === 0) {
|
|
@@ -8411,10 +8567,10 @@ function conflict(path2, reason, expectedProjectContent) {
|
|
|
8411
8567
|
// src/update/planner-file.ts
|
|
8412
8568
|
async function planFile(path2, baseRoot, targetRoot, source, target, ours, provenance, targetContentOverride, manageGeneratedProjectOwned = false, forcePlatformBaseline = false) {
|
|
8413
8569
|
const [base, theirs] = await Promise.all([
|
|
8414
|
-
readOptional(
|
|
8415
|
-
targetContentOverride ? Promise.resolve(targetContentOverride) : readOptional(
|
|
8570
|
+
readOptional(join22(baseRoot, path2)),
|
|
8571
|
+
targetContentOverride ? Promise.resolve(targetContentOverride) : readOptional(join22(targetRoot, path2))
|
|
8416
8572
|
]);
|
|
8417
|
-
const ownership = source?.ownership
|
|
8573
|
+
const ownership = source?.ownership ?? target?.ownership ?? classifyOwnership(path2);
|
|
8418
8574
|
const expected = expectationForSnapshot(ours);
|
|
8419
8575
|
if (ownership === "project-owned") {
|
|
8420
8576
|
if (manageGeneratedProjectOwned) {
|
|
@@ -8519,7 +8675,7 @@ function conflict2(path2, ownership, reason, expectedProjectContent) {
|
|
|
8519
8675
|
}
|
|
8520
8676
|
async function readOptional(path2) {
|
|
8521
8677
|
try {
|
|
8522
|
-
return await
|
|
8678
|
+
return await readFile17(path2);
|
|
8523
8679
|
} catch (error) {
|
|
8524
8680
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
8525
8681
|
return;
|
|
@@ -8528,28 +8684,43 @@ async function readOptional(path2) {
|
|
|
8528
8684
|
}
|
|
8529
8685
|
}
|
|
8530
8686
|
|
|
8687
|
+
// src/update/planner-modules.ts
|
|
8688
|
+
function resolveModuleRecipeIds(request) {
|
|
8689
|
+
const lifecycle = request.lifecycle;
|
|
8690
|
+
if (!lifecycle)
|
|
8691
|
+
return [];
|
|
8692
|
+
const catalog = new Map(moduleDistributionCatalog.map((manifest) => [manifest.name, manifest]));
|
|
8693
|
+
if (lifecycle.action === "add") {
|
|
8694
|
+
return lifecycle.addedModules.map((name) => catalog.get(name).installRecipe);
|
|
8695
|
+
}
|
|
8696
|
+
if (lifecycle.action === "remove") {
|
|
8697
|
+
return lifecycle.removedModules.map((name) => catalog.get(name).uninstallRecipe);
|
|
8698
|
+
}
|
|
8699
|
+
return lifecycle.updatedModules.flatMap((name) => catalog.get(name).updateRecipes);
|
|
8700
|
+
}
|
|
8701
|
+
|
|
8531
8702
|
// src/update/planner-snapshots.ts
|
|
8532
|
-
import { readFile as
|
|
8533
|
-
import { join as
|
|
8703
|
+
import { readFile as readFile18, stat as stat2 } from "fs/promises";
|
|
8704
|
+
import { join as join23 } from "path";
|
|
8534
8705
|
async function snapshotProjectFiles(project, paths, seed) {
|
|
8535
8706
|
const snapshots = new Map(seed);
|
|
8536
8707
|
await Promise.all([...paths].filter((path2) => !snapshots.has(path2)).map(async (path2) => {
|
|
8537
|
-
snapshots.set(path2, await readOptional2(
|
|
8708
|
+
snapshots.set(path2, await readOptional2(join23(project, path2)));
|
|
8538
8709
|
}));
|
|
8539
8710
|
return snapshots;
|
|
8540
8711
|
}
|
|
8541
8712
|
async function snapshotProjectModes(project, paths) {
|
|
8542
|
-
return new Map(await Promise.all([...paths].map(async (path2) => [path2, await readModeOptional(
|
|
8713
|
+
return new Map(await Promise.all([...paths].map(async (path2) => [path2, await readModeOptional(join23(project, path2))])));
|
|
8543
8714
|
}
|
|
8544
8715
|
async function assertPlanSnapshots(project, expectations) {
|
|
8545
8716
|
const changed = [];
|
|
8546
8717
|
for (const expectation2 of expectations) {
|
|
8547
|
-
const actual = expectationForSnapshot(await readOptional2(
|
|
8718
|
+
const actual = expectationForSnapshot(await readOptional2(join23(project, expectation2.path)));
|
|
8548
8719
|
if (JSON.stringify(actual) !== JSON.stringify(expectation2.expected)) {
|
|
8549
8720
|
changed.push(expectation2.path);
|
|
8550
8721
|
continue;
|
|
8551
8722
|
}
|
|
8552
|
-
if ("mode" in expectation2 && await readModeOptional(
|
|
8723
|
+
if ("mode" in expectation2 && await readModeOptional(join23(project, expectation2.path)) !== expectation2.mode) {
|
|
8553
8724
|
changed.push(expectation2.path);
|
|
8554
8725
|
}
|
|
8555
8726
|
}
|
|
@@ -8561,7 +8732,7 @@ async function readModeOptional(path2) {
|
|
|
8561
8732
|
try {
|
|
8562
8733
|
return (await stat2(path2)).mode & 511;
|
|
8563
8734
|
} catch (error) {
|
|
8564
|
-
if (
|
|
8735
|
+
if (isMissing7(error))
|
|
8565
8736
|
return;
|
|
8566
8737
|
throw error;
|
|
8567
8738
|
}
|
|
@@ -8574,21 +8745,21 @@ async function readSourceParentMode(path2) {
|
|
|
8574
8745
|
}
|
|
8575
8746
|
return info.mode & 493 | 493;
|
|
8576
8747
|
} catch (error) {
|
|
8577
|
-
if (
|
|
8748
|
+
if (isMissing7(error))
|
|
8578
8749
|
return 493;
|
|
8579
8750
|
throw error;
|
|
8580
8751
|
}
|
|
8581
8752
|
}
|
|
8582
8753
|
async function readOptional2(path2) {
|
|
8583
8754
|
try {
|
|
8584
|
-
return await
|
|
8755
|
+
return await readFile18(path2);
|
|
8585
8756
|
} catch (error) {
|
|
8586
|
-
if (
|
|
8757
|
+
if (isMissing7(error))
|
|
8587
8758
|
return;
|
|
8588
8759
|
throw error;
|
|
8589
8760
|
}
|
|
8590
8761
|
}
|
|
8591
|
-
function
|
|
8762
|
+
function isMissing7(error) {
|
|
8592
8763
|
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
8593
8764
|
}
|
|
8594
8765
|
|
|
@@ -8625,8 +8796,8 @@ var oxcManagedPaths = new Set([
|
|
|
8625
8796
|
]);
|
|
8626
8797
|
async function createUpdatePlan(request, artifacts) {
|
|
8627
8798
|
await assertProjectReadyForUpdate(request.projectDirectory);
|
|
8628
|
-
const manifestPath =
|
|
8629
|
-
const expectedManifestHash = hashContent(await
|
|
8799
|
+
const manifestPath = join24(request.projectDirectory, ".windy/files.json");
|
|
8800
|
+
const expectedManifestHash = hashContent(await readFile19(manifestPath));
|
|
8630
8801
|
const generationSnapshot = await readGenerationProvenanceSnapshot(request.projectDirectory);
|
|
8631
8802
|
const provenance = generationSnapshot.provenance;
|
|
8632
8803
|
const targetModules = resolveUpdateTargetModules(provenance.modules.map(({ name }) => name), request.targetModules);
|
|
@@ -8672,8 +8843,8 @@ async function createUpdatePlan(request, artifacts) {
|
|
|
8672
8843
|
const paths = new Set([...sourceEntries.keys(), ...targetEntries.keys()]);
|
|
8673
8844
|
for (const path2 of paths) {
|
|
8674
8845
|
if (!projectSnapshots.has(path2)) {
|
|
8675
|
-
projectSnapshots.set(path2, await readOptional2(
|
|
8676
|
-
projectModes.set(path2, await readModeOptional(
|
|
8846
|
+
projectSnapshots.set(path2, await readOptional2(join24(request.projectDirectory, path2)));
|
|
8847
|
+
projectModes.set(path2, await readModeOptional(join24(request.projectDirectory, path2)));
|
|
8677
8848
|
}
|
|
8678
8849
|
}
|
|
8679
8850
|
const files = await planFiles({
|
|
@@ -8695,10 +8866,10 @@ async function createUpdatePlan(request, artifacts) {
|
|
|
8695
8866
|
for (const file of files) {
|
|
8696
8867
|
file.expectedProjectMode = projectModes.get(file.path);
|
|
8697
8868
|
if (file.action === "create" || file.action === "update") {
|
|
8698
|
-
file.mode = file.expectedProjectMode ?? await readModeOptional(
|
|
8869
|
+
file.mode = file.expectedProjectMode ?? await readModeOptional(join24(artifactSet.targetDirectory, file.path));
|
|
8699
8870
|
}
|
|
8700
8871
|
if (file.action === "create") {
|
|
8701
|
-
file.parentMode = await readSourceParentMode(
|
|
8872
|
+
file.parentMode = await readSourceParentMode(join24(artifactSet.targetDirectory, dirname7(file.path)));
|
|
8702
8873
|
}
|
|
8703
8874
|
}
|
|
8704
8875
|
const plannedPaths = new Set(files.map(({ path: path2 }) => path2));
|
|
@@ -8718,7 +8889,7 @@ async function createUpdatePlan(request, artifacts) {
|
|
|
8718
8889
|
...migrations.conflicts,
|
|
8719
8890
|
...files.flatMap((file) => file.conflict ? [`${file.path}\uFF1A${file.conflict}`] : [])
|
|
8720
8891
|
];
|
|
8721
|
-
if (hashContent(await
|
|
8892
|
+
if (hashContent(await readFile19(manifestPath)) !== expectedManifestHash) {
|
|
8722
8893
|
throw new Error("\u751F\u6210\u66F4\u65B0\u8BA1\u5212\u671F\u95F4\u53D7\u7BA1\u6E05\u5355\u53D1\u751F\u53D8\u5316");
|
|
8723
8894
|
}
|
|
8724
8895
|
await assertPlanSnapshots(request.projectDirectory, [
|
|
@@ -8750,19 +8921,6 @@ async function createUpdatePlan(request, artifacts) {
|
|
|
8750
8921
|
lifecycle: request.lifecycle
|
|
8751
8922
|
};
|
|
8752
8923
|
}
|
|
8753
|
-
function resolveModuleRecipeIds(request) {
|
|
8754
|
-
const lifecycle = request.lifecycle;
|
|
8755
|
-
if (!lifecycle)
|
|
8756
|
-
return [];
|
|
8757
|
-
const catalog = new Map(moduleDistributionCatalog.map((manifest) => [manifest.name, manifest]));
|
|
8758
|
-
if (lifecycle.action === "add") {
|
|
8759
|
-
return lifecycle.addedModules.map((name) => catalog.get(name).installRecipe);
|
|
8760
|
-
}
|
|
8761
|
-
if (lifecycle.action === "remove") {
|
|
8762
|
-
return lifecycle.removedModules.map((name) => catalog.get(name).uninstallRecipe);
|
|
8763
|
-
}
|
|
8764
|
-
return lifecycle.updatedModules.flatMap((name) => catalog.get(name).updateRecipes);
|
|
8765
|
-
}
|
|
8766
8924
|
async function planFiles(input) {
|
|
8767
8925
|
const files = [];
|
|
8768
8926
|
for (const path2 of [...input.paths].sort()) {
|
|
@@ -8856,9 +9014,9 @@ function frozenManifestHash(file, finalizedHashes) {
|
|
|
8856
9014
|
}
|
|
8857
9015
|
|
|
8858
9016
|
// src/update/format-stabilizer.ts
|
|
8859
|
-
import { mkdir as mkdir8, mkdtemp as mkdtemp3, readFile as
|
|
9017
|
+
import { mkdir as mkdir8, mkdtemp as mkdtemp3, readFile as readFile20, rm as rm7, writeFile as writeFile13 } from "fs/promises";
|
|
8860
9018
|
import { tmpdir as tmpdir3 } from "os";
|
|
8861
|
-
import { dirname as dirname8, extname as extname4, join as
|
|
9019
|
+
import { dirname as dirname8, extname as extname4, join as join25, resolve as resolve6, sep as sep5 } from "path";
|
|
8862
9020
|
var formattedExtensions = new Set([
|
|
8863
9021
|
".cjs",
|
|
8864
9022
|
".css",
|
|
@@ -8897,7 +9055,7 @@ async function stabilizeManagedContent(result2, execute, writeProjectFile) {
|
|
|
8897
9055
|
}
|
|
8898
9056
|
}
|
|
8899
9057
|
inputs.set(".windy/generation.json", new TextEncoder().encode(generationContent));
|
|
8900
|
-
const temporaryRoot = await mkdtemp3(
|
|
9058
|
+
const temporaryRoot = await mkdtemp3(join25(tmpdir3(), "windy-update-format-"));
|
|
8901
9059
|
try {
|
|
8902
9060
|
const stagedPaths = await stageInputs(temporaryRoot, inputs);
|
|
8903
9061
|
for (let offset = 0;offset < stagedPaths.length; offset += 80) {
|
|
@@ -8905,14 +9063,14 @@ async function stabilizeManagedContent(result2, execute, writeProjectFile) {
|
|
|
8905
9063
|
"x",
|
|
8906
9064
|
"oxfmt",
|
|
8907
9065
|
"--write",
|
|
8908
|
-
`--config=${
|
|
9066
|
+
`--config=${join25(result2.plan.projectDirectory, ".oxfmtrc.json")}`,
|
|
8909
9067
|
...stagedPaths.slice(offset, offset + 80)
|
|
8910
9068
|
], result2.plan.projectDirectory);
|
|
8911
9069
|
}
|
|
8912
9070
|
const hashes = plannedContentHashes(result2);
|
|
8913
9071
|
let formattedGeneration = generationContent;
|
|
8914
9072
|
for (const [path2, original] of inputs) {
|
|
8915
|
-
const formatted = await
|
|
9073
|
+
const formatted = await readFile20(safeTemporaryPath(temporaryRoot, path2));
|
|
8916
9074
|
if (path2 === ".windy/generation.json") {
|
|
8917
9075
|
formattedGeneration = formatted.toString();
|
|
8918
9076
|
continue;
|
|
@@ -8939,7 +9097,7 @@ async function stageInputs(temporaryRoot, inputs) {
|
|
|
8939
9097
|
for (const [path2, content] of inputs) {
|
|
8940
9098
|
const target = safeTemporaryPath(temporaryRoot, path2);
|
|
8941
9099
|
await mkdir8(dirname8(target), { recursive: true });
|
|
8942
|
-
await
|
|
9100
|
+
await writeFile13(target, content);
|
|
8943
9101
|
paths.push(target);
|
|
8944
9102
|
}
|
|
8945
9103
|
return paths;
|
|
@@ -9066,7 +9224,7 @@ class DefaultStarterUpdater {
|
|
|
9066
9224
|
const plannedPaths = new Set(result2.plan.files.map(({ path: path2 }) => path2));
|
|
9067
9225
|
replaceExpectations(result2, verificationSnapshot.filter(({ path: path2 }) => !metadataPaths2.has(path2) && !plannedPaths.has(path2)));
|
|
9068
9226
|
verificationExpectationsFrozen = true;
|
|
9069
|
-
const packageJson = JSON.parse(await
|
|
9227
|
+
const packageJson = JSON.parse(await readFile21(join26(result2.plan.projectDirectory, "package.json"), "utf8"));
|
|
9070
9228
|
for (const name of ["lint", "typecheck", "test", "build"]) {
|
|
9071
9229
|
if (!packageJson.scripts?.[name]) {
|
|
9072
9230
|
steps.push({ name: `bun run ${name}`, status: "skipped" });
|
|
@@ -9150,8 +9308,10 @@ function expectedForPath(result2, path2) {
|
|
|
9150
9308
|
}
|
|
9151
9309
|
|
|
9152
9310
|
// src/module-lifecycle.ts
|
|
9153
|
-
import {
|
|
9154
|
-
|
|
9311
|
+
import { rm as rm9 } from "fs/promises";
|
|
9312
|
+
|
|
9313
|
+
// src/project-module-activation.ts
|
|
9314
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
9155
9315
|
|
|
9156
9316
|
// src/module-version-range.ts
|
|
9157
9317
|
function isVersionInCaretRange(version, range) {
|
|
@@ -9177,67 +9337,199 @@ function compareVersion(left, right) {
|
|
|
9177
9337
|
return 0;
|
|
9178
9338
|
}
|
|
9179
9339
|
|
|
9180
|
-
// src/module-
|
|
9181
|
-
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
throw new Error("module \u53EA\u652F\u6301 list\u3001add\u3001update\u3001remove");
|
|
9185
|
-
}
|
|
9186
|
-
const log = dependencies.log ?? console.log;
|
|
9187
|
-
const provenance = await readGenerationProvenance(projectDirectory);
|
|
9188
|
-
const installed = provenance.modules.map(({ name }) => name);
|
|
9189
|
-
if (action === "list") {
|
|
9190
|
-
printModuleList(provenance.modules, log);
|
|
9191
|
-
return;
|
|
9340
|
+
// src/project-module-activation.ts
|
|
9341
|
+
function planProjectModuleActivation(input) {
|
|
9342
|
+
if (input.requestedModules.length === 0) {
|
|
9343
|
+
throw new Error(`module ${input.action} \u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u6A21\u5757 key`);
|
|
9192
9344
|
}
|
|
9193
|
-
const
|
|
9194
|
-
|
|
9195
|
-
|
|
9345
|
+
const catalog = new Map(moduleDistributionCatalog.map((manifest) => [manifest.name, manifest]));
|
|
9346
|
+
const installed = new Set(input.registry.modules.map(({ name }) => name));
|
|
9347
|
+
for (const name of input.requestedModules) {
|
|
9348
|
+
const manifest = catalog.get(name);
|
|
9349
|
+
if (!manifest)
|
|
9350
|
+
throw new Error(`\u672A\u77E5\u6A21\u5757\uFF1A${name}`);
|
|
9351
|
+
if (!installed.has(name))
|
|
9352
|
+
throw new Error(`\u672A\u5B89\u88C5\u6A21\u5757\u4E0D\u80FD\u542F\u505C\uFF1A${name}`);
|
|
9353
|
+
assertCompatible(input.windyVersion, manifest.windyRange, name);
|
|
9354
|
+
}
|
|
9355
|
+
const target = new Map(input.registry.modules.map(({ name, enabled }) => [name, enabled]));
|
|
9356
|
+
if (input.action === "enable") {
|
|
9357
|
+
for (const name of input.requestedModules) {
|
|
9358
|
+
enableWithDependencies(name, target, installed, catalog, new Set);
|
|
9359
|
+
}
|
|
9360
|
+
} else {
|
|
9361
|
+
assertOptionalModules(input.requestedModules);
|
|
9362
|
+
assertRuntimeToggleSupported(input.requestedModules, catalog);
|
|
9363
|
+
for (const name of input.requestedModules)
|
|
9364
|
+
target.set(name, false);
|
|
9365
|
+
assertNoEnabledDependents(target, catalog);
|
|
9366
|
+
}
|
|
9367
|
+
assertEnabledCompatibility(target, input.windyVersion, catalog);
|
|
9368
|
+
assertEnabledConflicts(target, catalog);
|
|
9369
|
+
const modules = input.registry.modules.map((registration) => ({
|
|
9370
|
+
...registration,
|
|
9371
|
+
enabled: target.get(registration.name)
|
|
9372
|
+
}));
|
|
9373
|
+
const changedModules = modules.filter((registration, index) => registration.enabled !== input.registry.modules[index]?.enabled).map(({ name }) => name);
|
|
9374
|
+
const registry = {
|
|
9375
|
+
schemaVersion: 1,
|
|
9376
|
+
modules
|
|
9377
|
+
};
|
|
9378
|
+
return {
|
|
9379
|
+
action: input.action,
|
|
9380
|
+
requestedModules: input.requestedModules,
|
|
9381
|
+
changedModules,
|
|
9382
|
+
expectedRegistryHash: input.expectedRegistryHash,
|
|
9383
|
+
registry,
|
|
9384
|
+
content: `${JSON.stringify(registry, null, 2)}
|
|
9385
|
+
`
|
|
9386
|
+
};
|
|
9387
|
+
}
|
|
9388
|
+
function assertRuntimeToggleSupported(names, catalog) {
|
|
9389
|
+
const unsupported = names.filter((name) => catalog.get(name)?.runtimeActivation === "physical-only");
|
|
9390
|
+
if (unsupported.length) {
|
|
9391
|
+
throw new Error(`${unsupported.join("\u3001")} \u4E0D\u652F\u6301\u5B89\u5168 runtime disable\uFF1B\u5DF2\u90E8\u7F72\u9879\u76EE\u9700\u7531\u4EBA\u5DE5\u8FC1\u79FB\u5B8C\u6210\u7269\u7406\u5378\u8F7D`);
|
|
9196
9392
|
}
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9201
|
-
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
9393
|
+
}
|
|
9394
|
+
async function applyProjectModuleActivation(projectDirectory, plan) {
|
|
9395
|
+
const state = await applyMetadataTransaction({
|
|
9396
|
+
id: `module-${plan.action}-${randomUUID4()}`,
|
|
9397
|
+
projectDirectory,
|
|
9398
|
+
guards: [
|
|
9399
|
+
{
|
|
9400
|
+
path: projectModuleRegistryPath,
|
|
9401
|
+
hash: plan.expectedRegistryHash
|
|
9402
|
+
}
|
|
9403
|
+
],
|
|
9404
|
+
writes: [{ path: projectModuleRegistryPath, content: plan.content }]
|
|
9205
9405
|
});
|
|
9206
|
-
|
|
9207
|
-
|
|
9208
|
-
log("\u6A21\u5757\u96C6\u5408\u5DF2\u6EE1\u8DB3\u8BF7\u6C42\uFF0C\u65E0\u9700\u4FEE\u6539");
|
|
9209
|
-
return;
|
|
9406
|
+
if (!state.ownerToken) {
|
|
9407
|
+
throw new Error("\u6A21\u5757\u88C5\u914D\u4E8B\u52A1\u7F3A\u5C11\u6240\u6709\u6743\u4EE4\u724C");
|
|
9210
9408
|
}
|
|
9211
|
-
|
|
9212
|
-
const updater = dependencies.updater ?? new DefaultStarterUpdater;
|
|
9213
|
-
const plan = await updater.plan({
|
|
9409
|
+
await finalizeOwnedTransaction({
|
|
9214
9410
|
projectDirectory,
|
|
9215
|
-
|
|
9216
|
-
|
|
9217
|
-
|
|
9411
|
+
ownerToken: state.ownerToken,
|
|
9412
|
+
expectations: [
|
|
9413
|
+
expectationForContent(projectModuleRegistryPath, plan.content)
|
|
9414
|
+
]
|
|
9218
9415
|
});
|
|
9219
|
-
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
|
|
9224
|
-
|
|
9416
|
+
}
|
|
9417
|
+
function enableWithDependencies(name, target, installed, catalog, visiting) {
|
|
9418
|
+
if (visiting.has(name))
|
|
9419
|
+
throw new Error(`\u6A21\u5757\u4F9D\u8D56\u5B58\u5728\u5FAA\u73AF\uFF1A${name}`);
|
|
9420
|
+
visiting.add(name);
|
|
9421
|
+
const manifest = catalog.get(name);
|
|
9422
|
+
for (const dependency of manifest.dependencies) {
|
|
9423
|
+
if (!installed.has(dependency)) {
|
|
9424
|
+
throw new Error(`${name} \u7F3A\u5C11\u5DF2\u5B89\u88C5\u4F9D\u8D56\uFF1A${dependency}`);
|
|
9425
|
+
}
|
|
9426
|
+
enableWithDependencies(dependency, target, installed, catalog, visiting);
|
|
9225
9427
|
}
|
|
9226
|
-
|
|
9227
|
-
|
|
9228
|
-
|
|
9428
|
+
visiting.delete(name);
|
|
9429
|
+
target.set(name, true);
|
|
9430
|
+
}
|
|
9431
|
+
function assertOptionalModules(names) {
|
|
9432
|
+
const required = names.filter((name) => requiredModuleNames.includes(name));
|
|
9433
|
+
if (required.length) {
|
|
9434
|
+
throw new Error(`\u6838\u5FC3\u6A21\u5757\u4E0D\u53EF\u505C\u7528\uFF1A${required.join("\u3001")}`);
|
|
9229
9435
|
}
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9436
|
+
}
|
|
9437
|
+
function assertNoEnabledDependents(target, catalog) {
|
|
9438
|
+
const blockers = [...target].filter(([, enabled]) => enabled).flatMap(([name]) => {
|
|
9439
|
+
const disabled = catalog.get(name).dependencies.filter((dependency) => !target.get(dependency));
|
|
9440
|
+
return disabled.map((dependency) => `${name}\u2192${dependency}`);
|
|
9441
|
+
});
|
|
9442
|
+
if (blockers.length) {
|
|
9443
|
+
throw new Error(`\u542F\u7528\u6A21\u5757\u4ECD\u4F9D\u8D56\u5F85\u505C\u7528\u6A21\u5757\uFF1A${blockers.join("\u3001")}`);
|
|
9233
9444
|
}
|
|
9234
|
-
const result2 = await updater.apply(plan);
|
|
9235
|
-
const report = await updater.verify(result2);
|
|
9236
|
-
log(`
|
|
9237
|
-
\u6A21\u5757${actionLabel(action)}\u5B8C\u6210\uFF1A${requested.join("\u3001")}`);
|
|
9238
|
-
log(`\u62A5\u544A\uFF1A${report.reportPath}`);
|
|
9239
9445
|
}
|
|
9240
|
-
|
|
9446
|
+
function assertEnabledCompatibility(target, version, catalog) {
|
|
9447
|
+
for (const [name, enabled] of target) {
|
|
9448
|
+
if (!enabled)
|
|
9449
|
+
continue;
|
|
9450
|
+
const manifest = catalog.get(name);
|
|
9451
|
+
assertCompatible(version, manifest.windyRange, name);
|
|
9452
|
+
}
|
|
9453
|
+
}
|
|
9454
|
+
function assertEnabledConflicts(target, catalog) {
|
|
9455
|
+
for (const [name, enabled] of target) {
|
|
9456
|
+
if (!enabled)
|
|
9457
|
+
continue;
|
|
9458
|
+
const conflict3 = catalog.get(name).conflicts.find((candidate) => target.get(candidate));
|
|
9459
|
+
if (conflict3)
|
|
9460
|
+
throw new Error(`\u6A21\u5757\u51B2\u7A81\uFF1A${name} \u4E0E ${conflict3}`);
|
|
9461
|
+
}
|
|
9462
|
+
}
|
|
9463
|
+
function assertCompatible(version, range, name) {
|
|
9464
|
+
if (!isVersionInCaretRange(version, range)) {
|
|
9465
|
+
throw new Error(`${name} \u8981\u6C42 Windy ${range}\uFF0C\u5F53\u524D\u4E3A ${version}`);
|
|
9466
|
+
}
|
|
9467
|
+
}
|
|
9468
|
+
|
|
9469
|
+
// src/module-lifecycle-plan.ts
|
|
9470
|
+
function reconcileProjectModuleRegistryPlan(plan, current, lifecycle) {
|
|
9471
|
+
const registryFile = plan.files.find(({ path: path2 }) => path2 === projectModuleRegistryPath);
|
|
9472
|
+
if (!registryFile) {
|
|
9473
|
+
throw new Error("\u6A21\u5757\u751F\u547D\u5468\u671F\u8BA1\u5212\u7F3A\u5C11 project-owned \u88C5\u914D\u9009\u62E9");
|
|
9474
|
+
}
|
|
9475
|
+
plan.conflicts = plan.conflicts.filter((conflict3) => !conflict3.startsWith(`${projectModuleRegistryPath}\uFF1A`));
|
|
9476
|
+
delete registryFile.conflict;
|
|
9477
|
+
if (lifecycle.action === "update") {
|
|
9478
|
+
registryFile.action = "preserve";
|
|
9479
|
+
registryFile.reason = "\u6A21\u5757\u66F4\u65B0\u4FDD\u7559\u5BA2\u6237\u88C5\u914D\u9009\u62E9";
|
|
9480
|
+
delete registryFile.content;
|
|
9481
|
+
return;
|
|
9482
|
+
}
|
|
9483
|
+
const removed = new Set(lifecycle.removedModules);
|
|
9484
|
+
const modules = current.modules.filter(({ name }) => !removed.has(name));
|
|
9485
|
+
let nextOrder = Math.max(0, ...modules.map(({ order }) => order)) + 100;
|
|
9486
|
+
const catalog = new Map(moduleDistributionCatalog.map((manifest) => [manifest.name, manifest]));
|
|
9487
|
+
for (const name of lifecycle.addedModules) {
|
|
9488
|
+
if (modules.some((registration) => registration.name === name))
|
|
9489
|
+
continue;
|
|
9490
|
+
const manifest = catalog.get(name);
|
|
9491
|
+
if (!manifest)
|
|
9492
|
+
throw new Error(`\u672A\u77E5\u6A21\u5757\uFF1A${name}`);
|
|
9493
|
+
modules.push(newRegistration(name, manifest.runtimePackage, nextOrder));
|
|
9494
|
+
nextOrder += 100;
|
|
9495
|
+
}
|
|
9496
|
+
const registry = { schemaVersion: 1, modules };
|
|
9497
|
+
registryFile.action = "update";
|
|
9498
|
+
registryFile.reason = "\u6309 module name \u5408\u5E76\u9879\u76EE\u88C5\u914D\u9009\u62E9";
|
|
9499
|
+
registryFile.content = new TextEncoder().encode(`${JSON.stringify(registry, null, 2)}
|
|
9500
|
+
`);
|
|
9501
|
+
}
|
|
9502
|
+
function assertModulePlanUsesStableComposition(plan) {
|
|
9503
|
+
const unsafe = plan.files.filter(({ action, path: path2, reason }) => action !== "preserve" && (isCustomerApplicationOrHost(path2) || isDockerfile(path2) && reason !== "\u6309\u4E8B\u52A1\u5B89\u5168 workspace \u89C6\u56FE\u540C\u6B65 Docker COPY \u6E05\u5355")).map(({ path: path2 }) => path2);
|
|
9504
|
+
if (unsafe.length === 0)
|
|
9505
|
+
return;
|
|
9506
|
+
throw new Error([
|
|
9507
|
+
"\u6A21\u5757\u5305/Host \u5C1A\u672A\u6EE1\u8DB3\u65B0\u534F\u8BAE\uFF0C\u62D2\u7EDD\u901A\u8FC7\u6A21\u677F\u518D\u751F\u6210\u6539\u5199\u5BA2\u6237 Admin \u6216 Host\uFF1A",
|
|
9508
|
+
...unsafe.map((path2) => ` ${path2}`)
|
|
9509
|
+
].join(`
|
|
9510
|
+
`));
|
|
9511
|
+
}
|
|
9512
|
+
function isDockerfile(path2) {
|
|
9513
|
+
return path2 === "apps/web/Dockerfile" || path2 === "apps/server/Dockerfile";
|
|
9514
|
+
}
|
|
9515
|
+
function isCustomerApplicationOrHost(path2) {
|
|
9516
|
+
return path2 === "apps/web/src" || path2.startsWith("apps/web/src/") || path2 === "apps/server/src/index.ts" || path2 === "apps/server/src/installed-business-modules.ts" || path2 === "apps/server/src/app" || path2.startsWith("apps/server/src/app/");
|
|
9517
|
+
}
|
|
9518
|
+
function newRegistration(name, runtimePackage, order) {
|
|
9519
|
+
return {
|
|
9520
|
+
name,
|
|
9521
|
+
package: runtimePackage,
|
|
9522
|
+
enabled: true,
|
|
9523
|
+
order,
|
|
9524
|
+
admin: { visible: true },
|
|
9525
|
+
config: {}
|
|
9526
|
+
};
|
|
9527
|
+
}
|
|
9528
|
+
|
|
9529
|
+
// src/module-lifecycle-resolver.ts
|
|
9530
|
+
import { access as access2 } from "fs/promises";
|
|
9531
|
+
import { resolve as resolve7 } from "path";
|
|
9532
|
+
async function resolveModuleLifecyclePlan(input) {
|
|
9241
9533
|
const known = new Map(moduleDistributionCatalog.map((manifest) => [manifest.name, manifest]));
|
|
9242
9534
|
const requested = input.action === "update" && input.requested.length === 0 ? [...input.installed] : input.requested;
|
|
9243
9535
|
if (!requested.length) {
|
|
@@ -9258,10 +9550,12 @@ async function resolveLifecyclePlan(input) {
|
|
|
9258
9550
|
const manifest = known.get(name);
|
|
9259
9551
|
assertWindyCompatible(input.windyVersion, manifest.windyRange, manifest.name);
|
|
9260
9552
|
}
|
|
9553
|
+
const addedModules = target.filter((name) => !input.installed.includes(name));
|
|
9554
|
+
assertDeploymentLifecycleSupported(addedModules, known);
|
|
9261
9555
|
return {
|
|
9262
9556
|
action: input.action,
|
|
9263
9557
|
requestedModules: requested,
|
|
9264
|
-
addedModules
|
|
9558
|
+
addedModules,
|
|
9265
9559
|
updatedModules: [],
|
|
9266
9560
|
removedModules: []
|
|
9267
9561
|
};
|
|
@@ -9271,6 +9565,7 @@ async function resolveLifecyclePlan(input) {
|
|
|
9271
9565
|
if (absent.length) {
|
|
9272
9566
|
throw new Error(`\u672A\u5B89\u88C5\u6A21\u5757\u4E0D\u80FD\u66F4\u65B0\uFF1A${absent.join("\u3001")}`);
|
|
9273
9567
|
}
|
|
9568
|
+
assertDeploymentLifecycleSupported(requested, known);
|
|
9274
9569
|
return {
|
|
9275
9570
|
action: input.action,
|
|
9276
9571
|
requestedModules: requested,
|
|
@@ -9284,6 +9579,7 @@ async function resolveLifecyclePlan(input) {
|
|
|
9284
9579
|
throw new Error(`\u6838\u5FC3\u6A21\u5757\u4E0D\u53EF\u5378\u8F7D\uFF1A${required.join("\u3001")}`);
|
|
9285
9580
|
}
|
|
9286
9581
|
const removed = requested.filter((name) => input.installed.includes(name));
|
|
9582
|
+
assertDeploymentLifecycleSupported(removed, known);
|
|
9287
9583
|
assertRemovalDependencies(input.installed, removed);
|
|
9288
9584
|
const dataDisposition = resolveDataDisposition(removed.map((name) => known.get(name).uninstallPolicy), readValue2(input.args, "--data-disposition"));
|
|
9289
9585
|
const dataPlan = readValue2(input.args, "--data-plan");
|
|
@@ -9303,7 +9599,13 @@ async function resolveLifecyclePlan(input) {
|
|
|
9303
9599
|
dataPlan
|
|
9304
9600
|
};
|
|
9305
9601
|
}
|
|
9306
|
-
function
|
|
9602
|
+
function assertDeploymentLifecycleSupported(names, catalog) {
|
|
9603
|
+
const unsupported = names.filter((name) => catalog.get(name)?.deploymentInstall === "project-composition-required");
|
|
9604
|
+
if (unsupported.length) {
|
|
9605
|
+
throw new Error(`${unsupported.join("\u3001")} \u5C1A\u672A\u63D0\u4F9B self-contained Server Adapter\uFF1B\u90E8\u7F72\u540E add/update/remove \u4F1A\u6539\u5199 project-owned \u7EC4\u5408\u58F0\u660E\uFF0C\u5F53\u524D fail closed`);
|
|
9606
|
+
}
|
|
9607
|
+
}
|
|
9608
|
+
function resolveModuleLifecycleTarget(installed, lifecycle) {
|
|
9307
9609
|
if (lifecycle.action === "add") {
|
|
9308
9610
|
return resolveModuleSelection({
|
|
9309
9611
|
requested: [...installed, ...lifecycle.addedModules],
|
|
@@ -9316,6 +9618,19 @@ function resolveTargetModules(installed, lifecycle) {
|
|
|
9316
9618
|
}
|
|
9317
9619
|
return installed;
|
|
9318
9620
|
}
|
|
9621
|
+
function readPositionalModules(args) {
|
|
9622
|
+
const valueFlags = new Set(["--data-disposition", "--data-plan", "--cwd"]);
|
|
9623
|
+
const output = [];
|
|
9624
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
9625
|
+
const value = args[index];
|
|
9626
|
+
if (valueFlags.has(value)) {
|
|
9627
|
+
index += 1;
|
|
9628
|
+
} else if (!value.startsWith("-")) {
|
|
9629
|
+
output.push(value);
|
|
9630
|
+
}
|
|
9631
|
+
}
|
|
9632
|
+
return [...new Set(output)];
|
|
9633
|
+
}
|
|
9319
9634
|
function resolveDataDisposition(policies, requested) {
|
|
9320
9635
|
const disposition = requested ?? strongestPolicy(policies);
|
|
9321
9636
|
if (disposition !== "retain-data" && disposition !== "archive-data" && disposition !== "manual") {
|
|
@@ -9351,27 +9666,219 @@ function assertWindyCompatible(version, range, moduleName) {
|
|
|
9351
9666
|
throw new Error(`${moduleName} \u8981\u6C42 Windy ${range}\uFF0C\u5F53\u524D\u4E3A ${version}`);
|
|
9352
9667
|
}
|
|
9353
9668
|
}
|
|
9354
|
-
function
|
|
9355
|
-
const
|
|
9356
|
-
|
|
9357
|
-
|
|
9669
|
+
function readValue2(args, flag) {
|
|
9670
|
+
const index = args.indexOf(flag);
|
|
9671
|
+
return index >= 0 ? args[index + 1] : undefined;
|
|
9672
|
+
}
|
|
9673
|
+
|
|
9674
|
+
// src/module-lifecycle-help.ts
|
|
9675
|
+
var moduleLifecycleHelpText = `create-windy module <\u547D\u4EE4> [\u9009\u9879]
|
|
9676
|
+
|
|
9677
|
+
\u547D\u4EE4\uFF1A
|
|
9678
|
+
module list [--cwd <\u76EE\u5F55>]
|
|
9679
|
+
module add <key...> [--dry-run] [--skip-install] [--yes]
|
|
9680
|
+
module enable <key...> [--dry-run] [--yes]
|
|
9681
|
+
module disable <key...> [--dry-run] [--yes]
|
|
9682
|
+
module update [key...] [--dry-run] [--skip-install] [--yes]
|
|
9683
|
+
module remove <key...> [--dry-run] [--skip-install] [--yes]
|
|
9684
|
+
[--data-disposition <\u7B56\u7565>] [--data-plan <\u6587\u4EF6>]
|
|
9685
|
+
[--confirm-data-disposition]
|
|
9686
|
+
|
|
9687
|
+
\u8FB9\u754C\uFF1A
|
|
9688
|
+
\u5F53\u524D\u5185\u7F6E\u6E90\u7801\u6A21\u5757\u53EA\u652F\u6301\u521B\u5EFA\u9879\u76EE\u65F6\u9009\u62E9
|
|
9689
|
+
\u90E8\u7F72\u540E add/update/remove \u4EC5\u5BF9 self-contained \u6A21\u5757\u5F00\u653E\uFF0C\u5426\u5219 fail closed
|
|
9690
|
+
system.settings\u3001system.storage\u3001system.data-governance \u4E0D\u652F\u6301 runtime disable
|
|
9691
|
+
\u5DF2\u90E8\u7F72\u9879\u76EE\u4E0D\u4F1A\u88AB\u81EA\u52A8\u6539\u5199
|
|
9692
|
+
|
|
9693
|
+
\u6B63\u5F0F\u53D8\u66F4\u5728\u4EA4\u4E92\u7EC8\u7AEF\u786E\u8BA4\u540E\u6267\u884C\uFF1B\u975E\u4EA4\u4E92\u73AF\u5883\u5FC5\u987B\u4F20\u5165 --yes\u3002`;
|
|
9694
|
+
function assertKnownModuleArguments(args) {
|
|
9695
|
+
const action = args[0];
|
|
9696
|
+
const allowed = new Set(["--cwd", "--help", "-h"]);
|
|
9697
|
+
if (action !== "list") {
|
|
9698
|
+
allowed.add("--dry-run");
|
|
9699
|
+
allowed.add("--yes");
|
|
9700
|
+
}
|
|
9701
|
+
if (action === "add" || action === "update" || action === "remove") {
|
|
9702
|
+
allowed.add("--skip-install");
|
|
9703
|
+
}
|
|
9704
|
+
if (action === "remove") {
|
|
9705
|
+
allowed.add("--data-disposition");
|
|
9706
|
+
allowed.add("--data-plan");
|
|
9707
|
+
allowed.add("--confirm-data-disposition");
|
|
9708
|
+
}
|
|
9709
|
+
const valueFlags = new Set(["--cwd", "--data-disposition", "--data-plan"]);
|
|
9710
|
+
for (let index = 1;index < args.length; index += 1) {
|
|
9358
9711
|
const value = args[index];
|
|
9359
|
-
if (
|
|
9360
|
-
|
|
9361
|
-
|
|
9362
|
-
|
|
9712
|
+
if (!value.startsWith("-"))
|
|
9713
|
+
continue;
|
|
9714
|
+
if (!allowed.has(value))
|
|
9715
|
+
throw new Error(`\u672A\u77E5 module \u53C2\u6570\uFF1A${value}`);
|
|
9716
|
+
if (!valueFlags.has(value))
|
|
9717
|
+
continue;
|
|
9718
|
+
const next = args[index + 1];
|
|
9719
|
+
if (!next || next.startsWith("-")) {
|
|
9720
|
+
throw new Error(`${value} \u7F3A\u5C11\u53C2\u6570\u503C`);
|
|
9363
9721
|
}
|
|
9722
|
+
index += 1;
|
|
9364
9723
|
}
|
|
9365
|
-
return [...new Set(output)];
|
|
9366
9724
|
}
|
|
9367
|
-
|
|
9725
|
+
|
|
9726
|
+
// src/module-lifecycle-confirmation.ts
|
|
9727
|
+
import { createInterface as createInterface3 } from "readline/promises";
|
|
9728
|
+
async function confirmModuleMutation(args, dependencies, log) {
|
|
9729
|
+
if (args.includes("--yes"))
|
|
9730
|
+
return true;
|
|
9731
|
+
const isTTY = dependencies.isTTY ?? Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
9732
|
+
if (!isTTY) {
|
|
9733
|
+
throw new Error("\u975E\u4EA4\u4E92\u73AF\u5883\u6B63\u5F0F\u53D8\u66F4\u5FC5\u987B\u4F20\u5165 --yes");
|
|
9734
|
+
}
|
|
9735
|
+
const confirm = dependencies.confirm ?? promptForConfirmation;
|
|
9736
|
+
const accepted = await confirm("\u786E\u8BA4\u6267\u884C\u4EE5\u4E0A\u6A21\u5757\u8BA1\u5212\uFF1F");
|
|
9737
|
+
if (!accepted)
|
|
9738
|
+
log("\u5DF2\u53D6\u6D88\uFF1A\u9879\u76EE\u672A\u88AB\u4FEE\u6539");
|
|
9739
|
+
return accepted;
|
|
9740
|
+
}
|
|
9741
|
+
async function promptForConfirmation(message) {
|
|
9742
|
+
const readline3 = createInterface3({
|
|
9743
|
+
input: process.stdin,
|
|
9744
|
+
output: process.stdout
|
|
9745
|
+
});
|
|
9746
|
+
try {
|
|
9747
|
+
const answer = await readline3.question(`${message} [y/N] `);
|
|
9748
|
+
return answer.trim().toLowerCase() === "y";
|
|
9749
|
+
} finally {
|
|
9750
|
+
readline3.close();
|
|
9751
|
+
}
|
|
9752
|
+
}
|
|
9753
|
+
|
|
9754
|
+
// src/module-lifecycle.ts
|
|
9755
|
+
async function runModuleLifecycleCommand(args, projectDirectory, dependencies = {}) {
|
|
9756
|
+
const log = dependencies.log ?? console.log;
|
|
9757
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
9758
|
+
log(moduleLifecycleHelpText);
|
|
9759
|
+
return;
|
|
9760
|
+
}
|
|
9761
|
+
const action = args[0];
|
|
9762
|
+
if (!isAction(action)) {
|
|
9763
|
+
throw new Error("module \u53EA\u652F\u6301 list\u3001add\u3001enable\u3001disable\u3001update\u3001remove");
|
|
9764
|
+
}
|
|
9765
|
+
assertKnownModuleArguments(args);
|
|
9766
|
+
const provenance = await readGenerationProvenance(projectDirectory);
|
|
9767
|
+
const installed = provenance.modules.map(({ name }) => name);
|
|
9768
|
+
const registrySnapshot = await readProjectModuleRegistrySnapshot(projectDirectory, installed);
|
|
9769
|
+
if (action === "list") {
|
|
9770
|
+
printModuleList(provenance.modules, registrySnapshot.registry.modules, log);
|
|
9771
|
+
return;
|
|
9772
|
+
}
|
|
9773
|
+
const cliVersion = dependencies.cliVersion ?? (await readTemplateMetadata(await resolveTemplateRoot())).generatorVersion;
|
|
9774
|
+
if (provenance.generatorVersion !== cliVersion || provenance.windyVersion !== cliVersion) {
|
|
9775
|
+
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`);
|
|
9776
|
+
}
|
|
9777
|
+
const requested = readPositionalModules(args.slice(1));
|
|
9778
|
+
if (action === "enable" || action === "disable") {
|
|
9779
|
+
const activation = planProjectModuleActivation({
|
|
9780
|
+
action,
|
|
9781
|
+
requestedModules: requested,
|
|
9782
|
+
windyVersion: provenance.windyVersion,
|
|
9783
|
+
expectedRegistryHash: registrySnapshot.hash,
|
|
9784
|
+
registry: registrySnapshot.registry
|
|
9785
|
+
});
|
|
9786
|
+
printActivationPlan(activation, log);
|
|
9787
|
+
if (!activation.changedModules.length) {
|
|
9788
|
+
log("\u6A21\u5757\u88C5\u914D\u5DF2\u6EE1\u8DB3\u8BF7\u6C42\uFF0C\u65E0\u9700\u4FEE\u6539");
|
|
9789
|
+
return;
|
|
9790
|
+
}
|
|
9791
|
+
if (args.includes("--dry-run")) {
|
|
9792
|
+
log(`
|
|
9793
|
+
\u6F14\u7EC3\u5B8C\u6210\uFF1A\u672A\u5199\u5165\u9879\u76EE\u6587\u4EF6`);
|
|
9794
|
+
return;
|
|
9795
|
+
}
|
|
9796
|
+
if (!await confirmModuleMutation(args, dependencies, log))
|
|
9797
|
+
return;
|
|
9798
|
+
await applyProjectModuleActivation(projectDirectory, activation);
|
|
9799
|
+
log(`
|
|
9800
|
+
\u6A21\u5757${action === "enable" ? "\u542F\u7528" : "\u505C\u7528"}\u5B8C\u6210`);
|
|
9801
|
+
return;
|
|
9802
|
+
}
|
|
9803
|
+
const lifecycle = await resolveModuleLifecyclePlan({
|
|
9804
|
+
action,
|
|
9805
|
+
requested,
|
|
9806
|
+
installed,
|
|
9807
|
+
windyVersion: provenance.windyVersion,
|
|
9808
|
+
args,
|
|
9809
|
+
projectDirectory
|
|
9810
|
+
});
|
|
9811
|
+
printDataPlan(lifecycle, log);
|
|
9812
|
+
if (!hasChanges(lifecycle)) {
|
|
9813
|
+
log("\u6A21\u5757\u96C6\u5408\u5DF2\u6EE1\u8DB3\u8BF7\u6C42\uFF0C\u65E0\u9700\u4FEE\u6539");
|
|
9814
|
+
return;
|
|
9815
|
+
}
|
|
9816
|
+
const targetModules = resolveModuleLifecycleTarget(installed, lifecycle);
|
|
9817
|
+
const updater = dependencies.updater ?? dependencies.updaterFactory?.({
|
|
9818
|
+
skipInstall: args.includes("--skip-install")
|
|
9819
|
+
}) ?? new DefaultStarterUpdater({
|
|
9820
|
+
skipInstall: args.includes("--skip-install")
|
|
9821
|
+
});
|
|
9822
|
+
const plan = await updater.plan({
|
|
9823
|
+
projectDirectory,
|
|
9824
|
+
targetVersion: provenance.windyVersion,
|
|
9825
|
+
targetModules,
|
|
9826
|
+
lifecycle
|
|
9827
|
+
});
|
|
9828
|
+
try {
|
|
9829
|
+
reconcileProjectModuleRegistryPlan(plan, registrySnapshot.registry, lifecycle);
|
|
9830
|
+
printModulePlan(plan, log);
|
|
9831
|
+
assertModulePlanUsesStableComposition(plan);
|
|
9832
|
+
} catch (error) {
|
|
9833
|
+
await rm9(plan.temporaryRoot, { recursive: true, force: true });
|
|
9834
|
+
throw error;
|
|
9835
|
+
}
|
|
9836
|
+
if (args.includes("--dry-run")) {
|
|
9837
|
+
await rm9(plan.temporaryRoot, { recursive: true, force: true });
|
|
9838
|
+
log(`
|
|
9839
|
+
\u6F14\u7EC3\u5B8C\u6210\uFF1A\u672A\u5199\u5165\u9879\u76EE\u6587\u4EF6`);
|
|
9840
|
+
return;
|
|
9841
|
+
}
|
|
9842
|
+
if (action === "remove" && !args.includes("--confirm-data-disposition")) {
|
|
9843
|
+
await rm9(plan.temporaryRoot, { recursive: true, force: true });
|
|
9844
|
+
throw new Error("\u5378\u8F7D\u524D\u5FC5\u987B\u5BA1\u9605\u6570\u636E\u5904\u7F6E\u8BA1\u5212\u5E76\u4F20\u5165 --confirm-data-disposition");
|
|
9845
|
+
}
|
|
9846
|
+
if (plan.conflicts.length) {
|
|
9847
|
+
await rm9(plan.temporaryRoot, { recursive: true, force: true });
|
|
9848
|
+
throw new Error("\u5B58\u5728\u6A21\u5757\u751F\u547D\u5468\u671F\u51B2\u7A81\uFF0C\u9879\u76EE\u672A\u88AB\u4FEE\u6539");
|
|
9849
|
+
}
|
|
9850
|
+
let confirmed;
|
|
9851
|
+
try {
|
|
9852
|
+
confirmed = await confirmModuleMutation(args, dependencies, log);
|
|
9853
|
+
} catch (error) {
|
|
9854
|
+
await rm9(plan.temporaryRoot, { recursive: true, force: true });
|
|
9855
|
+
throw error;
|
|
9856
|
+
}
|
|
9857
|
+
if (!confirmed) {
|
|
9858
|
+
await rm9(plan.temporaryRoot, { recursive: true, force: true });
|
|
9859
|
+
return;
|
|
9860
|
+
}
|
|
9861
|
+
const result2 = await updater.apply(plan);
|
|
9862
|
+
const report = await updater.verify(result2);
|
|
9863
|
+
log(`
|
|
9864
|
+
\u6A21\u5757${actionLabel(action)}\u5B8C\u6210\uFF1A${requested.join("\u3001")}`);
|
|
9865
|
+
log(`\u62A5\u544A\uFF1A${report.reportPath}`);
|
|
9866
|
+
}
|
|
9867
|
+
function printModuleList(installed, registered, log) {
|
|
9368
9868
|
const installedVersions = new Map(installed.map(({ name, version }) => [name, version]));
|
|
9869
|
+
const catalog = new Map(moduleDistributionCatalog.map((manifest) => [manifest.name, manifest]));
|
|
9369
9870
|
log("Windy \u6A21\u5757\uFF1A");
|
|
9871
|
+
for (const registration of [...registered].sort((left, right) => left.order - right.order)) {
|
|
9872
|
+
const manifest = catalog.get(registration.name);
|
|
9873
|
+
const installedVersion = installedVersions.get(registration.name);
|
|
9874
|
+
const status = registration.enabled ? "installed" : "disabled";
|
|
9875
|
+
log(` ${status.padEnd(9)} ${registration.name}@${installedVersion}\uFF08catalog ${manifest.version}\uFF09`);
|
|
9876
|
+
}
|
|
9370
9877
|
for (const manifest of moduleDistributionCatalog) {
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
const
|
|
9374
|
-
log(` ${status.padEnd(9)} ${version}`);
|
|
9878
|
+
if (installedVersions.has(manifest.name))
|
|
9879
|
+
continue;
|
|
9880
|
+
const status = manifest.deploymentInstall === "supported" ? "available" : "creation-only";
|
|
9881
|
+
log(` ${status.padEnd(9)} ${manifest.name}@${manifest.version}\uFF08catalog ${manifest.version}\uFF09`);
|
|
9375
9882
|
}
|
|
9376
9883
|
}
|
|
9377
9884
|
function printDataPlan(lifecycle, log) {
|
|
@@ -9384,6 +9891,11 @@ function printDataPlan(lifecycle, log) {
|
|
|
9384
9891
|
if (lifecycle.dataPlan)
|
|
9385
9892
|
log(` \u8FD0\u7EF4\u5904\u7F6E\u6587\u6863\uFF1A${lifecycle.dataPlan}`);
|
|
9386
9893
|
}
|
|
9894
|
+
function printActivationPlan(plan, log) {
|
|
9895
|
+
log(`\u6A21\u5757\u88C5\u914D\u8BA1\u5212\uFF1A${plan.action} ${plan.requestedModules.join("\u3001")}`);
|
|
9896
|
+
log(` \u53EA\u5199\u5165 windy.modules.json`);
|
|
9897
|
+
log(` \u72B6\u6001\u53D8\u5316\uFF1A${plan.changedModules.join("\u3001") || "\u65E0"}`);
|
|
9898
|
+
}
|
|
9387
9899
|
function printModulePlan(plan, log) {
|
|
9388
9900
|
const changed = plan.files.filter(({ action }) => action !== "preserve");
|
|
9389
9901
|
log(`\u6A21\u5757\u6587\u4EF6\u8BA1\u5212\uFF1A${changed.length} \u4E2A\u53D8\u66F4\uFF1B${plan.conflicts.length} \u4E2A\u51B2\u7A81`);
|
|
@@ -9396,12 +9908,8 @@ function printModulePlan(plan, log) {
|
|
|
9396
9908
|
function hasChanges(lifecycle) {
|
|
9397
9909
|
return lifecycle.addedModules.length > 0 || lifecycle.updatedModules.length > 0 || lifecycle.removedModules.length > 0;
|
|
9398
9910
|
}
|
|
9399
|
-
function readValue2(args, flag) {
|
|
9400
|
-
const index = args.indexOf(flag);
|
|
9401
|
-
return index >= 0 ? args[index + 1] : undefined;
|
|
9402
|
-
}
|
|
9403
9911
|
function isAction(value) {
|
|
9404
|
-
return value === "list" || value === "add" || value === "update" || value === "remove";
|
|
9912
|
+
return value === "list" || value === "add" || value === "enable" || value === "disable" || value === "update" || value === "remove";
|
|
9405
9913
|
}
|
|
9406
9914
|
function actionLabel(action) {
|
|
9407
9915
|
return action === "add" ? "\u5B89\u88C5" : action === "update" ? "\u66F4\u65B0" : "\u5378\u8F7D";
|
|
@@ -9634,20 +10142,20 @@ import {
|
|
|
9634
10142
|
cp,
|
|
9635
10143
|
mkdir as mkdir9,
|
|
9636
10144
|
mkdtemp as mkdtemp4,
|
|
9637
|
-
readFile as
|
|
10145
|
+
readFile as readFile23,
|
|
9638
10146
|
readdir as readdir9,
|
|
9639
10147
|
rename as rename2,
|
|
9640
10148
|
rm as rm11,
|
|
9641
|
-
writeFile as
|
|
10149
|
+
writeFile as writeFile14
|
|
9642
10150
|
} from "fs/promises";
|
|
9643
|
-
import { dirname as dirname9, join as
|
|
10151
|
+
import { dirname as dirname9, join as join27, relative as relative6 } from "path";
|
|
9644
10152
|
|
|
9645
10153
|
// src/module-schema/config.ts
|
|
9646
|
-
import { readFile as
|
|
10154
|
+
import { readFile as readFile22 } from "fs/promises";
|
|
9647
10155
|
import { isAbsolute as isAbsolute2, relative as relative5, resolve as resolve9 } from "path";
|
|
9648
10156
|
async function readModuleSchemaLineageConfig(projectDirectory, configPath) {
|
|
9649
10157
|
const absolutePath = resolveProjectPath(projectDirectory, configPath);
|
|
9650
|
-
const parsed = JSON.parse(await
|
|
10158
|
+
const parsed = JSON.parse(await readFile22(absolutePath, "utf8"));
|
|
9651
10159
|
if (!isConfig(parsed)) {
|
|
9652
10160
|
throw new Error("Module schema lineage \u914D\u7F6E\u65E0\u6548");
|
|
9653
10161
|
}
|
|
@@ -9781,17 +10289,17 @@ async function handoffModuleSchemaLineages(options) {
|
|
|
9781
10289
|
async function stageModuleLineages(project, temporaryRoot, config, execute) {
|
|
9782
10290
|
const outputs = [];
|
|
9783
10291
|
for (const [index, module3] of config.modules.entries()) {
|
|
9784
|
-
const output =
|
|
10292
|
+
const output = join27(temporaryRoot, `module-${index}`);
|
|
9785
10293
|
await mkdir9(output, { recursive: true });
|
|
9786
|
-
const generatedConfig =
|
|
10294
|
+
const generatedConfig = join27(temporaryRoot, `module-${index}.config.ts`);
|
|
9787
10295
|
await writeDrizzleConfig(generatedConfig, project, module3.schema, relative6(temporaryRoot, output));
|
|
9788
10296
|
await execute(generatedConfig, temporaryRoot);
|
|
9789
10297
|
const sqlFiles = await listSqlFiles(output);
|
|
9790
10298
|
if (sqlFiles.length !== 1) {
|
|
9791
10299
|
throw new Error(`${module3.key} baseline \u5FC5\u987B\u6070\u597D\u751F\u6210\u4E00\u4E2A migration`);
|
|
9792
10300
|
}
|
|
9793
|
-
await
|
|
9794
|
-
await
|
|
10301
|
+
await writeFile14(join27(output, sqlFiles[0]), metadataOnlySql("module"));
|
|
10302
|
+
await writeFile14(join27(output, "lineage.json"), `${JSON.stringify({
|
|
9795
10303
|
schemaVersion: 1,
|
|
9796
10304
|
moduleKey: module3.key,
|
|
9797
10305
|
schema: module3.schema,
|
|
@@ -9805,25 +10313,25 @@ async function stageModuleLineages(project, temporaryRoot, config, execute) {
|
|
|
9805
10313
|
}
|
|
9806
10314
|
async function stagePlatformLineage(project, temporaryRoot, config, execute) {
|
|
9807
10315
|
const source = resolveProjectPath(project, config.platform.out);
|
|
9808
|
-
const output =
|
|
10316
|
+
const output = join27(temporaryRoot, "platform");
|
|
9809
10317
|
await cp(source, output, { recursive: true });
|
|
9810
10318
|
const before = new Set(await listSqlFiles(output));
|
|
9811
|
-
const generatedConfig =
|
|
10319
|
+
const generatedConfig = join27(temporaryRoot, "platform.config.ts");
|
|
9812
10320
|
await writeDrizzleConfig(generatedConfig, project, config.platform.schema, relative6(temporaryRoot, output));
|
|
9813
10321
|
await execute(generatedConfig, temporaryRoot);
|
|
9814
10322
|
const created = (await listSqlFiles(output)).filter((path2) => !before.has(path2));
|
|
9815
10323
|
if (created.length !== 1) {
|
|
9816
10324
|
throw new Error("\u5E73\u53F0 lineage handoff \u5FC5\u987B\u6070\u597D\u751F\u6210\u4E00\u4E2A migration");
|
|
9817
10325
|
}
|
|
9818
|
-
const sqlPath =
|
|
10326
|
+
const sqlPath = join27(output, created[0]);
|
|
9819
10327
|
const allowed = config.modules.flatMap(({ legacyPlatformTables }) => legacyPlatformTables);
|
|
9820
|
-
validatePlatformHandoffSql(await
|
|
9821
|
-
await
|
|
10328
|
+
validatePlatformHandoffSql(await readFile23(sqlPath, "utf8"), allowed);
|
|
10329
|
+
await writeFile14(sqlPath, metadataOnlySql("platform"));
|
|
9822
10330
|
return output;
|
|
9823
10331
|
}
|
|
9824
10332
|
async function installStagedLineages(project, temporaryRoot, config, stagedModules, stagedPlatform) {
|
|
9825
10333
|
const platform = resolveProjectPath(project, config.platform.out);
|
|
9826
|
-
const backup =
|
|
10334
|
+
const backup = join27(temporaryRoot, "platform-backup");
|
|
9827
10335
|
const installed = [];
|
|
9828
10336
|
await rename2(platform, backup);
|
|
9829
10337
|
try {
|
|
@@ -9847,7 +10355,7 @@ async function installStagedLineages(project, temporaryRoot, config, stagedModul
|
|
|
9847
10355
|
}
|
|
9848
10356
|
async function writeDrizzleConfig(path2, project, schemas, out) {
|
|
9849
10357
|
const absoluteSchemas = schemas.map((schema) => resolveProjectPath(project, schema));
|
|
9850
|
-
await
|
|
10358
|
+
await writeFile14(path2, `import { defineConfig } from "drizzle-kit";
|
|
9851
10359
|
export default defineConfig(${JSON.stringify({
|
|
9852
10360
|
dialect: "postgresql",
|
|
9853
10361
|
schema: absoluteSchemas,
|
|
@@ -9870,9 +10378,9 @@ async function validateSchemaSources(project, config) {
|
|
|
9870
10378
|
}
|
|
9871
10379
|
}
|
|
9872
10380
|
async function createTemporaryRoot(project) {
|
|
9873
|
-
const windy =
|
|
10381
|
+
const windy = join27(project, ".windy");
|
|
9874
10382
|
await mkdir9(windy, { recursive: true });
|
|
9875
|
-
return await mkdtemp4(
|
|
10383
|
+
return await mkdtemp4(join27(windy, "module-schema-handoff-"));
|
|
9876
10384
|
}
|
|
9877
10385
|
async function listSqlFiles(root) {
|
|
9878
10386
|
return (await readdir9(root)).filter((path2) => path2.endsWith(".sql")).sort();
|