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