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