create-windy 0.3.6 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -2767,6 +2767,34 @@ function isDirectoryNotRemovable(error) {
|
|
|
2767
2767
|
// src/workspace-membership.ts
|
|
2768
2768
|
import { readdir as readdir2 } from "fs/promises";
|
|
2769
2769
|
import { join as join5 } from "path";
|
|
2770
|
+
function deriveFinalWorkspaceMembership(current, target, files) {
|
|
2771
|
+
const membersByBase = new Map;
|
|
2772
|
+
for (const expectation of [...current, ...target]) {
|
|
2773
|
+
if (!membersByBase.has(expectation.base)) {
|
|
2774
|
+
membersByBase.set(expectation.base, new Set);
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
for (const expectation of current) {
|
|
2778
|
+
const members = membersByBase.get(expectation.base);
|
|
2779
|
+
for (const path of expectation.members)
|
|
2780
|
+
members.add(path);
|
|
2781
|
+
}
|
|
2782
|
+
for (const file of files) {
|
|
2783
|
+
for (const [base, members] of membersByBase) {
|
|
2784
|
+
if (!isDirectWorkspaceManifest(base, file.path))
|
|
2785
|
+
continue;
|
|
2786
|
+
if (file.action === "delete")
|
|
2787
|
+
members.delete(file.path);
|
|
2788
|
+
if (file.action === "create" || file.action === "update") {
|
|
2789
|
+
members.add(file.path);
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
return [...membersByBase].sort(([left], [right]) => left.localeCompare(right)).map(([base, members]) => ({
|
|
2794
|
+
base,
|
|
2795
|
+
members: [...members].sort((left, right) => left.localeCompare(right))
|
|
2796
|
+
}));
|
|
2797
|
+
}
|
|
2770
2798
|
async function snapshotWorkspaceBase(root, base) {
|
|
2771
2799
|
assertSafeWorkspaceBase(base);
|
|
2772
2800
|
await inspectSafePath(root, base);
|
|
@@ -2808,6 +2836,14 @@ function assertSafeWorkspaceBase(base) {
|
|
|
2808
2836
|
throw new Error(`workspace \u4E0D\u5F97\u904D\u5386 node_modules\uFF1A${base}`);
|
|
2809
2837
|
}
|
|
2810
2838
|
}
|
|
2839
|
+
function isDirectWorkspaceManifest(base, path) {
|
|
2840
|
+
const prefix = `${base}/`;
|
|
2841
|
+
if (!path.startsWith(prefix))
|
|
2842
|
+
return false;
|
|
2843
|
+
const relative3 = path.slice(prefix.length);
|
|
2844
|
+
const segments = relative3.split("/");
|
|
2845
|
+
return segments.length === 2 && segments[0]?.length > 0 && segments[1] === "package.json";
|
|
2846
|
+
}
|
|
2811
2847
|
function isMissing(error) {
|
|
2812
2848
|
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
2813
2849
|
}
|
|
@@ -8687,7 +8723,7 @@ function conflict(path2, reason, expectedProjectContent) {
|
|
|
8687
8723
|
}
|
|
8688
8724
|
|
|
8689
8725
|
// src/update/planner-file.ts
|
|
8690
|
-
async function planFile(path2, baseRoot, targetRoot, source, target, ours, provenance, targetContentOverride, manageGeneratedProjectOwned = false) {
|
|
8726
|
+
async function planFile(path2, baseRoot, targetRoot, source, target, ours, provenance, targetContentOverride, manageGeneratedProjectOwned = false, forcePlatformBaseline = false) {
|
|
8691
8727
|
const [base, theirs] = await Promise.all([
|
|
8692
8728
|
readOptional(join19(baseRoot, path2)),
|
|
8693
8729
|
targetContentOverride ? Promise.resolve(targetContentOverride) : readOptional(join19(targetRoot, path2))
|
|
@@ -8698,7 +8734,7 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
|
|
|
8698
8734
|
if (manageGeneratedProjectOwned) {
|
|
8699
8735
|
return planGeneratedProjectOwned(path2, source, target, ours, theirs, expected);
|
|
8700
8736
|
}
|
|
8701
|
-
return !source && !ours && theirs ? readyPlannedFile(path2, ownership, "create", "\u65B0\u589E\u9879\u76EE\u6269\u5C55\u70B9", expected, theirs) : readyPlannedFile(path2, ownership, "preserve", "\
|
|
8737
|
+
return !source && !ours && theirs ? readyPlannedFile(path2, ownership, "create", "\u65B0\u589E\u9879\u76EE\u6269\u5C55\u70B9", expected, theirs) : readyPlannedFile(path2, ownership, "preserve", "\u9ED8\u8BA4\u4FDD\u7559\u9879\u76EE\u7248\u672C", expected);
|
|
8702
8738
|
}
|
|
8703
8739
|
const repaired = ours && theirs ? repairKnownDerivedFile({
|
|
8704
8740
|
path: path2,
|
|
@@ -8736,6 +8772,14 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
|
|
|
8736
8772
|
const oursChanged = hashContent(ours) !== source.hash;
|
|
8737
8773
|
const sourceArtifactHash = artifactHashOf(source);
|
|
8738
8774
|
const targetChanged = targetChangedSinceBase(sourceArtifactHash, base, theirs);
|
|
8775
|
+
if (shouldForcePlatformBaseline({
|
|
8776
|
+
forcePlatformBaseline,
|
|
8777
|
+
oursChanged,
|
|
8778
|
+
sourceArtifactHash,
|
|
8779
|
+
base
|
|
8780
|
+
})) {
|
|
8781
|
+
return readyPlannedFile(path2, ownership, "update", "\u5F3A\u5236\u91C7\u7528\u76EE\u6807\u5E73\u53F0\u57FA\u7EBF", expected, theirs);
|
|
8782
|
+
}
|
|
8739
8783
|
if (!oursChanged && !targetChanged) {
|
|
8740
8784
|
return readyPlannedFile(path2, ownership, "preserve", "\u53CC\u65B9\u672A\u4FEE\u6539", expected);
|
|
8741
8785
|
}
|
|
@@ -8752,12 +8796,15 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
|
|
|
8752
8796
|
const merged = mergePackageJson(base, ours, theirs);
|
|
8753
8797
|
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);
|
|
8754
8798
|
}
|
|
8755
|
-
if (
|
|
8799
|
+
if (base) {
|
|
8756
8800
|
const merged = await mergeTextFile(base, ours, theirs);
|
|
8757
8801
|
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);
|
|
8758
8802
|
}
|
|
8759
8803
|
return conflict2(path2, ownership, "\u5BA2\u6237\u548C Windy \u5747\u5DF2\u4FEE\u6539", expected);
|
|
8760
8804
|
}
|
|
8805
|
+
function shouldForcePlatformBaseline(input) {
|
|
8806
|
+
return input.forcePlatformBaseline && !input.oursChanged && input.base !== undefined && hashContent(input.base) !== input.sourceArtifactHash;
|
|
8807
|
+
}
|
|
8761
8808
|
function targetChangedSinceBase(sourceHash, base, target) {
|
|
8762
8809
|
return base && target ? hashContent(base) !== hashContent(target) : !!target && hashContent(target) !== sourceHash;
|
|
8763
8810
|
}
|
|
@@ -8959,7 +9006,9 @@ var recipes = [
|
|
|
8959
9006
|
{ id: "starter-0.3.2-to-0.3.3", from: "0.3.2", to: "0.3.3" },
|
|
8960
9007
|
{ id: "starter-0.3.3-to-0.3.4", from: "0.3.3", to: "0.3.4" },
|
|
8961
9008
|
{ 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" }
|
|
9009
|
+
{ id: "starter-0.3.5-to-0.3.6", from: "0.3.5", to: "0.3.6" },
|
|
9010
|
+
{ id: "starter-0.3.6-to-0.3.7", from: "0.3.6", to: "0.3.7" },
|
|
9011
|
+
{ id: "starter-0.3.7-to-0.3.8", from: "0.3.7", to: "0.3.8" }
|
|
8963
9012
|
];
|
|
8964
9013
|
function resolveRecipeChain(sourceVersion, targetVersion) {
|
|
8965
9014
|
if (sourceVersion === targetVersion)
|
|
@@ -9054,7 +9103,8 @@ async function createUpdatePlan(request, artifacts) {
|
|
|
9054
9103
|
migrations,
|
|
9055
9104
|
artifactSet,
|
|
9056
9105
|
provenance,
|
|
9057
|
-
manageGeneratedProjectOwned: request.targetModules !== undefined
|
|
9106
|
+
manageGeneratedProjectOwned: request.targetModules !== undefined,
|
|
9107
|
+
forcePlatformBaseline: request.forcePlatformBaseline === true
|
|
9058
9108
|
});
|
|
9059
9109
|
deriveWebDockerfilePlan(files, projectSnapshots, new Set([...paths, ...workspaceSnapshot.manifests.keys()]));
|
|
9060
9110
|
for (const file of files) {
|
|
@@ -9105,7 +9155,7 @@ async function createUpdatePlan(request, artifacts) {
|
|
|
9105
9155
|
files,
|
|
9106
9156
|
dependencyExpectations,
|
|
9107
9157
|
workspaceMembershipExpectations: workspaceSnapshot.membershipExpectations,
|
|
9108
|
-
finalWorkspaceMembershipExpectations: targetWorkspaceSnapshot.membershipExpectations,
|
|
9158
|
+
finalWorkspaceMembershipExpectations: deriveFinalWorkspaceMembership(workspaceSnapshot.membershipExpectations, targetWorkspaceSnapshot.membershipExpectations, files),
|
|
9109
9159
|
conflicts,
|
|
9110
9160
|
detachedToolchain,
|
|
9111
9161
|
targetProvenance,
|
|
@@ -9141,7 +9191,7 @@ async function planFiles(input) {
|
|
|
9141
9191
|
} else if (forcedContent) {
|
|
9142
9192
|
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));
|
|
9143
9193
|
} else {
|
|
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));
|
|
9194
|
+
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, input.forcePlatformBaseline));
|
|
9145
9195
|
}
|
|
9146
9196
|
}
|
|
9147
9197
|
return files;
|
|
@@ -10702,7 +10752,11 @@ async function runUpdate(args, projectDirectory) {
|
|
|
10702
10752
|
return;
|
|
10703
10753
|
}
|
|
10704
10754
|
const updater = new DefaultStarterUpdater;
|
|
10705
|
-
const plan = await updater.plan({
|
|
10755
|
+
const plan = await updater.plan({
|
|
10756
|
+
projectDirectory,
|
|
10757
|
+
targetVersion: target,
|
|
10758
|
+
forcePlatformBaseline: args.includes("--force")
|
|
10759
|
+
});
|
|
10706
10760
|
printPlan(plan);
|
|
10707
10761
|
if (args.includes("--dry-run")) {
|
|
10708
10762
|
await rm11(plan.temporaryRoot, { recursive: true, force: true });
|
package/package.json
CHANGED
package/template/AGENTS.md
CHANGED
|
@@ -31,26 +31,30 @@
|
|
|
31
31
|
- 这是 Starter 的初始配置;项目所有者可按团队需要保留、替换或扩展。
|
|
32
32
|
- 实际可用命令和提交检查以当前项目的 `package.json` 与 Git hooks 为准。
|
|
33
33
|
|
|
34
|
-
## Windy
|
|
34
|
+
## Windy 升级策略
|
|
35
35
|
|
|
36
|
-
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
- 除 `node_modules` 等依赖产物外,生成到仓库中的源码都归项目所有者所有,可以按需
|
|
37
|
+
修改、替换或删除。`.windy/files.json` 的 ownership 是兼容字段名,只表示 updater
|
|
38
|
+
的默认合并策略和冲突风险,不是源码权限控制。
|
|
39
|
+
- 业务需求优先通过自有模块和既有扩展点实现;直接修改平台核心、Composition Root、
|
|
40
|
+
共享脚手架或根工具链同样受支持,但通常会增加后续三方合并成本。
|
|
41
|
+
- 修改前可查看 ownership 评估升级风险;优先扩展 `project-owned` 路径,对
|
|
42
|
+
`windy-managed` 路径建议保持改动小而清晰。
|
|
43
|
+
- 直接修改 Windy 基线代码时,使用独立小提交记录原因和影响;升级前先运行
|
|
41
44
|
`bun run windy update --dry-run`,根据三方合并计划处理冲突。
|
|
42
45
|
- 完整定制登录页时,在 project-owned 的
|
|
43
|
-
`apps/web/src/app/auth/login-page.ts`
|
|
44
|
-
`apps/web/src/pages/auth/LoginPage.vue` 或 Router
|
|
46
|
+
`apps/web/src/app/auth/login-page.ts` 注册业务组件可获得最低升级成本。若直接修改
|
|
47
|
+
`apps/web/src/pages/auth/LoginPage.vue` 或 Router,升级器会尝试三方合并。业务页面复用
|
|
45
48
|
`useLoginFlow`、`DevelopmentAuthWarning` 和平台品牌设置,保留安全
|
|
46
49
|
`returnTo`、真实认证与开发认证提示。
|
|
47
|
-
- 定制 404、500
|
|
50
|
+
- 定制 404、500、维护中或网络异常页时,优先修改 project-owned 的
|
|
48
51
|
`apps/web/src/app/error-pages.ts`,并把业务 SFC 放在 `apps/web/src/app/`;
|
|
49
|
-
|
|
52
|
+
直接修改 Router、HTTP 核心或平台默认错误页时会增加三方合并成本。
|
|
50
53
|
- 新增业务管理页面时,在业务 Module Manifest 注册 Feature、Permission、菜单和
|
|
51
54
|
Admin Route,再把 Vue 页面绑定到 project-owned 的
|
|
52
|
-
`apps/web/src/app/business-routes.ts
|
|
53
|
-
|
|
55
|
+
`apps/web/src/app/business-routes.ts` 是推荐接入方式。直接修改 Router 或 AppSidebar
|
|
56
|
+
时同样按 Base/Ours/Theirs 合并。导航来自服务端 Manifest 快照,接入见
|
|
57
|
+
`docs/development/business-web-routes.md`。
|
|
54
58
|
- 业务 Agent Operation 开启 Provider 出网时,必须在 Manifest 同时声明最小
|
|
55
59
|
`providerDataPolicy.inputFields` JSON Pointer allowlist 与
|
|
56
60
|
`envelopeFields`;raw input 会在进入 `prepare` 前裁剪并执行 DLP。接入与升级
|
|
@@ -9,8 +9,9 @@ apps/web/src/app/error-pages.ts
|
|
|
9
9
|
|
|
10
10
|
该文件在 `.windy/files.json` 中属于 `project-owned`。Windy 升级会给尚无此文件的
|
|
11
11
|
项目创建默认选择器;文件存在后,后续更新只保留业务选择。平台默认页面
|
|
12
|
-
`apps/web/src/pages/errors/PlatformErrorPage.vue`
|
|
13
|
-
|
|
12
|
+
`apps/web/src/pages/errors/PlatformErrorPage.vue` 标记为 `windy-managed`,Router 和
|
|
13
|
+
全局错误导航标记为 `shared-scaffold`。优先使用 project-owned 接缝可降低升级合并
|
|
14
|
+
成本;项目仍可直接修改这些文件,updater 会按 Base/Ours/Theirs 尝试合并。
|
|
14
15
|
|
|
15
16
|
## 默认行为
|
|
16
17
|
|
|
@@ -8,8 +8,9 @@ apps/web/src/app/auth/login-page.ts
|
|
|
8
8
|
|
|
9
9
|
该文件在 `.windy/files.json` 中属于 `project-owned`。Windy 升级会为旧项目新增它,
|
|
10
10
|
但一旦文件存在,后续 `windy update` 只会保留,不会覆盖业务选择。平台默认登录页
|
|
11
|
-
`apps/web/src/pages/auth/LoginPage.vue`
|
|
12
|
-
`shared-scaffold
|
|
11
|
+
`apps/web/src/pages/auth/LoginPage.vue` 标记为 `windy-managed`,Router 标记为
|
|
12
|
+
`shared-scaffold`。优先使用 project-owned 接缝可降低升级合并成本;业务项目仍可直接
|
|
13
|
+
修改这两处,updater 会按 Base/Ours/Theirs 尝试合并。
|
|
13
14
|
|
|
14
15
|
## 默认行为
|
|
15
16
|
|