create-windy 0.6.7 → 0.6.9
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 +2 -2
- package/dist/cli.js +158 -95
- package/package.json +1 -1
- package/template/.windy-template.json +2 -2
- package/template/README.md +4 -2
- package/template/apps/agent-server/README.md +4 -4
- package/template/apps/server/src/data-access/drizzle-predicate.ts +16 -6
- package/template/apps/server/src/runtime-development.ts +1 -0
- package/template/apps/web/src/layout/AppSidebar.vue +1 -0
- package/template/apps/web/src/pages/ui/UiComponentPage.vue +7 -0
- package/template/apps/web/src/pages/ui/UiComponentPage.webtest.ts +94 -0
- package/template/apps/web/src/pages/ui/component-catalog.ts +248 -0
- package/template/apps/web/src/pages/ui/components/ComponentPreviewCard.vue +50 -0
- package/template/apps/web/src/pages/ui/components/DataComponentShowcases.vue +131 -0
- package/template/apps/web/src/pages/ui/components/FeedbackComponentShowcases.vue +158 -0
- package/template/apps/web/src/pages/ui/components/FoundationComponentShowcases.vue +129 -0
- package/template/apps/web/src/pages/ui/components/NavigationComponentShowcases.vue +155 -0
- package/template/apps/web/src/pages/ui/components/ProjectComponentShowcases.vue +31 -0
- package/template/apps/web/src/pages/ui/components/UiComponentGallery.vue +238 -0
- package/template/apps/web/src/router/index.ts +2 -0
- package/template/apps/web/src/router/manifest-routes.webtest.ts +1 -0
- package/template/apps/web/src/router/platform-admin-route-bindings.ts +3 -1
- package/template/docs/architecture/ai-egress.md +1 -1
- package/template/docs/architecture/ai-runtime-readiness.md +2 -2
- package/template/docs/architecture/ai-runtime.md +15 -15
- package/template/docs/architecture/module-secret-resolution.md +4 -4
- package/template/docs/architecture/report-staging.md +1 -1
- package/template/docs/development/business-web-routes.md +3 -1
- package/template/docs/development/custom-login-page.md +3 -3
- package/template/docs/development/ui-component-gallery.md +44 -0
- package/template/docs/license/license-offline-activation-code.md +2 -2
- package/template/docs/operations/incremental-delivery.md +10 -9
- package/template/docs/platform/agent-runtime.md +4 -4
- package/template/docs/platform/document-ai-runtime.md +3 -3
- package/template/docs/platform/speech-ai-runtime.md +1 -1
- package/template/docs/platform/vision-ai-runtime.md +1 -1
- package/template/docs/product/built-in-roles.md +9 -1
- package/template/packages/modules/package.json +1 -1
- package/template/packages/modules/src/system-admin-routes.ts +8 -0
- package/template/packages/modules/src/system-admin-ui-catalog.ts +1 -1
- package/template/packages/modules/src/system-features.ts +5 -0
- package/template/packages/modules/src/system-module-catalog.ts +2 -1
- package/template/packages/modules/src/system-modules.ts +11 -0
- package/template/packages/modules/src/system-permissions.ts +2 -0
- package/template/packages/modules/src/system-ui-components.test.ts +36 -0
package/README.md
CHANGED
|
@@ -137,7 +137,7 @@ bun run windy update --dry-run
|
|
|
137
137
|
bun run windy update
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
-
`0.
|
|
140
|
+
`0.6.6` 是 Starter 更新的最低支持基线。更新器不检查 Git 工作区是否干净:只规划
|
|
141
141
|
目标版本实际变更的受管文件,从 source Project Lock 指向的精确 npm artifact 重建
|
|
142
142
|
Base,并以 Base/Ours/Theirs 合并共享脚手架。未触及的业务修改不会进入更新判断;
|
|
143
143
|
`package.json` 使用字段级合并;已发布 migration 只允许追加;冲突发生时不写项目,
|
|
@@ -146,7 +146,7 @@ Base,并以 Base/Ours/Theirs 合并共享脚手架。未触及的业务修改
|
|
|
146
146
|
|
|
147
147
|
受管清单使用 schema v4:`hash` 冻结下游实际正文,`artifactHash` 在两者不同时记录
|
|
148
148
|
公开模板基线;无正文的 missing tombstone 记住客户删除的 `project-owned` 路径。
|
|
149
|
-
低于 `0.
|
|
149
|
+
低于 `0.6.6` 的 Project Lock、旧清单 schema、损坏的 artifact lineage 或 recipe
|
|
150
150
|
缺口都会在写文件前 fail closed,不提供旧状态的自动迁移路径。
|
|
151
151
|
|
|
152
152
|
生成后的整个 `apps/web/src` 与整个 `apps/server/src/app` 都是 project-owned。普通
|
package/dist/cli.js
CHANGED
|
@@ -3480,7 +3480,8 @@ browser-safe \`./admin\` \u4E0E project-owned \u7684
|
|
|
3480
3480
|
\`apps/web/src/app/web-composition.ts\` \u88C5\u914D\u9875\u9762\uFF0C\u4E0D\u590D\u5236\u7B2C\u4E8C\u4EFD Feature\u3001Permission
|
|
3481
3481
|
\u6216\u8DEF\u7531\u6E05\u5355\u3002\u6574\u4E2A \`apps/web/src\` \u4E0E\u6574\u4E2A \`apps/server/src/app\` \u90FD\u662F
|
|
3482
3482
|
project-owned\uFF0C\u5BA2\u6237\u53EF\u4EE5\u4FEE\u6539 Router\u3001layout\u3001\u9875\u9762\u3001Host \u548C Server \u7EC4\u5408\uFF1B\u666E\u901A
|
|
3483
|
-
\`windy update\` \u4E0D\u4F1A\u8986\u76D6\u6216\u4E09\u65B9\u5408\u5E76\u8FD9\u4E9B\u6587\u4EF6\u3002
|
|
3483
|
+
\`windy update\` \u4E0D\u4F1A\u6574\u6587\u4EF6\u8986\u76D6\u6216\u4E09\u65B9\u5408\u5E76\u8FD9\u4E9B\u6587\u4EF6\u3002\u7248\u672C recipe \u53EA\u6709\u5728\u663E\u5F0F\u767B\u8BB0
|
|
3484
|
+
path \u4E0E\u786E\u5B9A\u6027\u8BED\u4E49\u951A\u70B9\u540E\u624D\u80FD\u505A\u5E42\u7B49\u8FFD\u52A0\uFF1B\u951A\u70B9\u7F3A\u5931\u6216\u4E0D\u552F\u4E00\u65F6\u5FC5\u987B\u5728\u5199\u5165\u524D\u505C\u6B62\u3002
|
|
3484
3485
|
|
|
3485
3486
|
\u7CBE\u786E\u751F\u6210\u6765\u6E90\u4FDD\u7559\u5728 \`.windy/generation.json\`\u3002\u5F53\u524D\u7248\u672C\u5DF2\u63D0\u4F9B\u53EF\u56DE\u6EDA\u7684
|
|
3486
3487
|
\`windy update\` \u4E0E \`windy module list/enable/disable\`\u3002\u5F53\u524D\u5185\u7F6E\u6A21\u5757\u4ECD\u4F9D\u8D56
|
|
@@ -3514,7 +3515,8 @@ ${includeOxc ? "\u63D0\u4EA4\u65F6 Husky \u4F1A\u901A\u8FC7 lint-staged \u4E0E O
|
|
|
3514
3515
|
\u66F4\u65B0\u524D\u65E0\u9700\u63D0\u4EA4\u3001\u6682\u5B58\u6216\u6E05\u7406\u4E1A\u52A1\u6539\u52A8\u3002\`--dry-run\` \u53EA\u751F\u6210\u8BA1\u5212\uFF0C\u4E0D\u5199\u9879\u76EE\uFF1B\u65E0\u5173 WIP
|
|
3515
3516
|
\u4FDD\u6301\u539F\u6837\uFF0C\u547D\u4E2D\u540C\u4E00\u8DEF\u5F84\u65F6\u6309\u51BB\u7ED3\u5FEB\u7167\u4E0E\u4E09\u65B9\u5408\u5E76 fail closed\u3002\u6B63\u5F0F\u66F4\u65B0\u5148\u5907\u4EFD\uFF0C\u518D\u505A
|
|
3516
3517
|
package \u5B57\u6BB5\u7EA7\u5408\u5E76\u3001\u5171\u4EAB\u811A\u624B\u67B6\u4E09\u65B9\u5408\u5E76\u4E0E\u5B8C\u6574\u9A8C\u8BC1\u3002\u6574\u4E2A \`apps/web/src\` \u548C
|
|
3517
|
-
\`apps/server/src/app\` \u4FDD\u6301\u9879\u76EE\u7248\u672C\
|
|
3518
|
+
\`apps/server/src/app\` \u9ED8\u8BA4\u4FDD\u6301\u9879\u76EE\u7248\u672C\uFF1B\u5DF2\u767B\u8BB0\u7248\u672C recipe \u53EA\u4FEE\u6539\u5176\u58F0\u660E\u7684\u7A84\u951A\u70B9\u3002
|
|
3519
|
+
\u4EFB\u4F55\u51B2\u7A81\u90FD\u4F1A\u5728\u5199\u5165\u524D\u4E2D\u6B62\uFF0C\u6A21\u5757\u542F\u505C\u5728\u4EA4\u4E92
|
|
3518
3520
|
\u7EC8\u7AEF\u786E\u8BA4\uFF1BCI\u3001Agent \u6216\u5176\u5B83\u975E TTY \u73AF\u5883\u5FC5\u987B\u663E\u5F0F\u4F20\u5165 \`--yes\`\u3002
|
|
3519
3521
|
\u65E0\u5E76\u53D1\u53D8\u5316\u7684\u9A8C\u8BC1\u5931\u8D25\u4F1A\u81EA\u52A8\u56DE\u6EDA\uFF1B\u4E2D\u65AD\u6062\u590D\u4F7F\u7528
|
|
3520
3522
|
\`bun run windy doctor --repair\`\u3002\u8BE5\u547D\u4EE4\u5728\u63D0\u4EA4\u70B9\u524D\u4FDD\u7559\u5E76\u53D1\u7F16\u8F91\u5E76\u56DE\u6EDA\u5176\u4F59\u8DEF\u5F84\uFF0C
|
|
@@ -3694,6 +3696,7 @@ var templateDocumentationFiles = [
|
|
|
3694
3696
|
"docs/development/custom-error-pages.md",
|
|
3695
3697
|
"docs/development/custom-login-page.md",
|
|
3696
3698
|
"docs/development/module-lifecycle.md",
|
|
3699
|
+
"docs/development/ui-component-gallery.md",
|
|
3697
3700
|
"docs/license/license-offline-activation-code.md",
|
|
3698
3701
|
"docs/operations/observability.md",
|
|
3699
3702
|
"docs/operations/incremental-delivery.md",
|
|
@@ -7716,82 +7719,22 @@ async function diagnoseProject(projectDirectory, repair = false) {
|
|
|
7716
7719
|
}
|
|
7717
7720
|
|
|
7718
7721
|
// src/update/recipes.ts
|
|
7719
|
-
var minimumSupportedUpdateVersion = "0.
|
|
7722
|
+
var minimumSupportedUpdateVersion = "0.6.6";
|
|
7720
7723
|
var recipes = [
|
|
7721
7724
|
{
|
|
7722
|
-
id: "starter-0.
|
|
7723
|
-
from: "0.
|
|
7724
|
-
to: "0.
|
|
7725
|
-
},
|
|
7726
|
-
{
|
|
7727
|
-
id: "starter-0.3.18-to-0.3.19",
|
|
7728
|
-
from: "0.3.18",
|
|
7729
|
-
to: "0.3.19"
|
|
7730
|
-
},
|
|
7731
|
-
{
|
|
7732
|
-
id: "starter-0.3.19-to-0.4.0",
|
|
7733
|
-
from: "0.3.19",
|
|
7734
|
-
to: "0.4.0"
|
|
7735
|
-
},
|
|
7736
|
-
{
|
|
7737
|
-
id: "starter-0.4.0-to-0.4.1",
|
|
7738
|
-
from: "0.4.0",
|
|
7739
|
-
to: "0.4.1"
|
|
7740
|
-
},
|
|
7741
|
-
{
|
|
7742
|
-
id: "starter-0.4.1-to-0.5.0",
|
|
7743
|
-
from: "0.4.1",
|
|
7744
|
-
to: "0.5.0"
|
|
7745
|
-
},
|
|
7746
|
-
{
|
|
7747
|
-
id: "starter-0.5.0-to-0.5.1",
|
|
7748
|
-
from: "0.5.0",
|
|
7749
|
-
to: "0.5.1"
|
|
7750
|
-
},
|
|
7751
|
-
{
|
|
7752
|
-
id: "starter-0.5.1-to-0.5.2",
|
|
7753
|
-
from: "0.5.1",
|
|
7754
|
-
to: "0.5.2"
|
|
7755
|
-
},
|
|
7756
|
-
{
|
|
7757
|
-
id: "starter-0.5.2-to-0.6.0",
|
|
7758
|
-
from: "0.5.2",
|
|
7759
|
-
to: "0.6.0"
|
|
7760
|
-
},
|
|
7761
|
-
{
|
|
7762
|
-
id: "starter-0.6.0-to-0.6.1",
|
|
7763
|
-
from: "0.6.0",
|
|
7764
|
-
to: "0.6.1"
|
|
7765
|
-
},
|
|
7766
|
-
{
|
|
7767
|
-
id: "starter-0.6.1-to-0.6.2",
|
|
7768
|
-
from: "0.6.1",
|
|
7769
|
-
to: "0.6.2"
|
|
7770
|
-
},
|
|
7771
|
-
{
|
|
7772
|
-
id: "starter-0.6.2-to-0.6.3",
|
|
7773
|
-
from: "0.6.2",
|
|
7774
|
-
to: "0.6.3"
|
|
7775
|
-
},
|
|
7776
|
-
{
|
|
7777
|
-
id: "starter-0.6.3-to-0.6.4",
|
|
7778
|
-
from: "0.6.3",
|
|
7779
|
-
to: "0.6.4"
|
|
7780
|
-
},
|
|
7781
|
-
{
|
|
7782
|
-
id: "starter-0.6.4-to-0.6.5",
|
|
7783
|
-
from: "0.6.4",
|
|
7784
|
-
to: "0.6.5"
|
|
7725
|
+
id: "starter-0.6.6-to-0.6.7",
|
|
7726
|
+
from: "0.6.6",
|
|
7727
|
+
to: "0.6.7"
|
|
7785
7728
|
},
|
|
7786
7729
|
{
|
|
7787
|
-
id: "starter-0.6.
|
|
7788
|
-
from: "0.6.
|
|
7789
|
-
to: "0.6.
|
|
7730
|
+
id: "starter-0.6.7-to-0.6.8",
|
|
7731
|
+
from: "0.6.7",
|
|
7732
|
+
to: "0.6.8"
|
|
7790
7733
|
},
|
|
7791
7734
|
{
|
|
7792
|
-
id: "starter-0.6.
|
|
7793
|
-
from: "0.6.
|
|
7794
|
-
to: "0.6.
|
|
7735
|
+
id: "starter-0.6.8-to-0.6.9",
|
|
7736
|
+
from: "0.6.8",
|
|
7737
|
+
to: "0.6.9"
|
|
7795
7738
|
}
|
|
7796
7739
|
];
|
|
7797
7740
|
function resolveRecipeChain(sourceVersion, targetVersion) {
|
|
@@ -8246,7 +8189,7 @@ async function deriveDockerfilePlans(files, snapshots, paths, targetWorkspaceMan
|
|
|
8246
8189
|
continue;
|
|
8247
8190
|
const source = new TextDecoder().decode(dockerSource);
|
|
8248
8191
|
if (!hasDockerfileCopyAnchors(source, target)) {
|
|
8249
|
-
dockerPlan.conflict = "Dockerfile \u7F3A\u5C11 0.
|
|
8192
|
+
dockerPlan.conflict = "Dockerfile \u7F3A\u5C11 0.6.6 \u57FA\u7EBF\u7684 COPY \u951A\u70B9\uFF0C\u5DF2\u505C\u6B62\u81EA\u52A8\u8FC1\u79FB\u65E7\u683C\u5F0F";
|
|
8250
8193
|
continue;
|
|
8251
8194
|
}
|
|
8252
8195
|
let next;
|
|
@@ -9153,8 +9096,123 @@ function conflict(path2, reason, expectedProjectContent) {
|
|
|
9153
9096
|
};
|
|
9154
9097
|
}
|
|
9155
9098
|
|
|
9099
|
+
// src/update/recipe-project-owned.ts
|
|
9100
|
+
var managedPathsByRecipe = {
|
|
9101
|
+
"starter-0.6.8-to-0.6.9": [
|
|
9102
|
+
"apps/web/src/router/index.ts",
|
|
9103
|
+
"apps/web/src/router/platform-admin-route-bindings.ts"
|
|
9104
|
+
]
|
|
9105
|
+
};
|
|
9106
|
+
function recipeManagedProjectOwnedPaths(recipes2) {
|
|
9107
|
+
return new Set(recipes2.flatMap((recipe) => managedPathsByRecipe[recipe] ?? []));
|
|
9108
|
+
}
|
|
9109
|
+
async function planRecipeProjectOwned(input) {
|
|
9110
|
+
if (!input.ours) {
|
|
9111
|
+
return conflict2(input, "\u7248\u672C recipe \u6240\u9700\u7684\u9879\u76EE\u951A\u70B9\u7F3A\u5931");
|
|
9112
|
+
}
|
|
9113
|
+
const source = new TextDecoder().decode(input.ours);
|
|
9114
|
+
const transformed = transformProjectAdminAnchor(input.path, source);
|
|
9115
|
+
if ("error" in transformed)
|
|
9116
|
+
return conflict2(input, transformed.error);
|
|
9117
|
+
if (transformed.content === source) {
|
|
9118
|
+
return preserve(input, "\u5DF2\u5305\u542B\u7248\u672C recipe \u76EE\u6807\u5185\u5BB9");
|
|
9119
|
+
}
|
|
9120
|
+
return update(input, new TextEncoder().encode(transformed.content));
|
|
9121
|
+
}
|
|
9122
|
+
function transformProjectAdminAnchor(path2, source) {
|
|
9123
|
+
if (path2 === "apps/web/src/router/index.ts") {
|
|
9124
|
+
return addComponentPageLoader(source);
|
|
9125
|
+
}
|
|
9126
|
+
if (path2 === "apps/web/src/router/platform-admin-route-bindings.ts") {
|
|
9127
|
+
return addComponentRouteBinding(source);
|
|
9128
|
+
}
|
|
9129
|
+
return { error: `\u7248\u672C recipe \u672A\u767B\u8BB0\u9879\u76EE\u951A\u70B9\uFF1A${path2}` };
|
|
9130
|
+
}
|
|
9131
|
+
function addComponentPageLoader(source) {
|
|
9132
|
+
if (/^\s*"ui-components"\s*:/m.test(source))
|
|
9133
|
+
return { content: source };
|
|
9134
|
+
const declaration = source.indexOf("const platformAdminPageComponents");
|
|
9135
|
+
const start = source.indexOf("= {", declaration);
|
|
9136
|
+
const end = source.indexOf(`
|
|
9137
|
+
};`, start);
|
|
9138
|
+
if (declaration < 0 || start < 0 || end < 0) {
|
|
9139
|
+
return { error: "\u627E\u4E0D\u5230 platformAdminPageComponents \u9879\u76EE\u951A\u70B9" };
|
|
9140
|
+
}
|
|
9141
|
+
const block = source.slice(start, end);
|
|
9142
|
+
const profiles = [...block.matchAll(/^(\s*)profile:\s*.*,$/gm)];
|
|
9143
|
+
if (profiles.length !== 1) {
|
|
9144
|
+
return { error: "platformAdminPageComponents profile \u951A\u70B9\u4E0D\u552F\u4E00" };
|
|
9145
|
+
}
|
|
9146
|
+
const profile = profiles[0];
|
|
9147
|
+
const insertion = `${profile[0]}
|
|
9148
|
+
${profile[1]}"ui-components": () => import("@/pages/ui/UiComponentPage.vue"),`;
|
|
9149
|
+
return {
|
|
9150
|
+
content: source.slice(0, start) + block.replace(profile[0], insertion) + source.slice(end)
|
|
9151
|
+
};
|
|
9152
|
+
}
|
|
9153
|
+
function addComponentRouteBinding(source) {
|
|
9154
|
+
const unionStart = source.indexOf("export type PlatformAdminPageKey =");
|
|
9155
|
+
const interfaceStart = source.indexOf("export interface PlatformAdminRouteBinding", unionStart);
|
|
9156
|
+
if (unionStart < 0 || interfaceStart < 0) {
|
|
9157
|
+
return { error: "\u627E\u4E0D\u5230 PlatformAdminPageKey \u9879\u76EE\u951A\u70B9" };
|
|
9158
|
+
}
|
|
9159
|
+
let content = source;
|
|
9160
|
+
const union = content.slice(unionStart, interfaceStart);
|
|
9161
|
+
if (!union.includes('"ui-components"')) {
|
|
9162
|
+
const semicolon = content.lastIndexOf(";", interfaceStart);
|
|
9163
|
+
if (semicolon < unionStart) {
|
|
9164
|
+
return { error: "PlatformAdminPageKey \u7ED3\u675F\u951A\u70B9\u7F3A\u5931" };
|
|
9165
|
+
}
|
|
9166
|
+
content = `${content.slice(0, semicolon)}
|
|
9167
|
+
| "ui-components"${content.slice(semicolon)}`;
|
|
9168
|
+
}
|
|
9169
|
+
if (content.includes('routeKey: "system.ui-components"')) {
|
|
9170
|
+
return { content };
|
|
9171
|
+
}
|
|
9172
|
+
const features = [
|
|
9173
|
+
...content.matchAll(/^(\s*)\{ routeKey: "system\.feature", page: "resource", resourceKey: "features" \},$/gm)
|
|
9174
|
+
];
|
|
9175
|
+
if (features.length !== 1) {
|
|
9176
|
+
return { error: "system.feature Admin Route \u951A\u70B9\u4E0D\u552F\u4E00" };
|
|
9177
|
+
}
|
|
9178
|
+
const feature = features[0];
|
|
9179
|
+
return {
|
|
9180
|
+
content: content.replace(feature[0], `${feature[0]}
|
|
9181
|
+
${feature[1]}{ routeKey: "system.ui-components", page: "ui-components" },`)
|
|
9182
|
+
};
|
|
9183
|
+
}
|
|
9184
|
+
function preserve(input, reason) {
|
|
9185
|
+
return {
|
|
9186
|
+
path: input.path,
|
|
9187
|
+
ownership: "project-owned",
|
|
9188
|
+
action: "preserve",
|
|
9189
|
+
reason,
|
|
9190
|
+
expectedProjectContent: input.expected
|
|
9191
|
+
};
|
|
9192
|
+
}
|
|
9193
|
+
function update(input, content) {
|
|
9194
|
+
return {
|
|
9195
|
+
path: input.path,
|
|
9196
|
+
ownership: "project-owned",
|
|
9197
|
+
action: "update",
|
|
9198
|
+
reason: "\u7248\u672C recipe \u66F4\u65B0\u9879\u76EE Admin \u6269\u5C55\u951A\u70B9",
|
|
9199
|
+
expectedProjectContent: input.expected,
|
|
9200
|
+
content
|
|
9201
|
+
};
|
|
9202
|
+
}
|
|
9203
|
+
function conflict2(input, message) {
|
|
9204
|
+
return {
|
|
9205
|
+
path: input.path,
|
|
9206
|
+
ownership: "project-owned",
|
|
9207
|
+
action: "preserve",
|
|
9208
|
+
reason: "\u5BA2\u6237\u5DF2\u4FEE\u6539",
|
|
9209
|
+
expectedProjectContent: input.expected,
|
|
9210
|
+
conflict: message
|
|
9211
|
+
};
|
|
9212
|
+
}
|
|
9213
|
+
|
|
9156
9214
|
// src/update/planner-file.ts
|
|
9157
|
-
async function planFile(path2, baseRoot, targetRoot, source, target, ours, provenance, targetContentOverride, manageGeneratedProjectOwned = false, forcePlatformBaseline = false) {
|
|
9215
|
+
async function planFile(path2, baseRoot, targetRoot, source, target, ours, provenance, targetContentOverride, manageGeneratedProjectOwned = false, forcePlatformBaseline = false, manageRecipeProjectOwned = false) {
|
|
9158
9216
|
const [base, theirs] = await Promise.all([
|
|
9159
9217
|
readOptional(join23(baseRoot, path2)),
|
|
9160
9218
|
targetContentOverride ? Promise.resolve(targetContentOverride) : readOptional(join23(targetRoot, path2))
|
|
@@ -9162,6 +9220,9 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
|
|
|
9162
9220
|
const ownership = source?.ownership ?? target?.ownership ?? classifyOwnership(path2);
|
|
9163
9221
|
const expected = expectationForSnapshot(ours);
|
|
9164
9222
|
if (ownership === "project-owned") {
|
|
9223
|
+
if (manageRecipeProjectOwned) {
|
|
9224
|
+
return planRecipeProjectOwned({ path: path2, ours, expected });
|
|
9225
|
+
}
|
|
9165
9226
|
if (manageGeneratedProjectOwned) {
|
|
9166
9227
|
return planGeneratedProjectOwned(path2, source, target, ours, theirs, expected);
|
|
9167
9228
|
}
|
|
@@ -9169,26 +9230,26 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
|
|
|
9169
9230
|
}
|
|
9170
9231
|
if (path2.startsWith("packages/database/drizzle/") && path2.endsWith(".sql")) {
|
|
9171
9232
|
if (source && !target) {
|
|
9172
|
-
return
|
|
9233
|
+
return conflict3(path2, ownership, "\u5DF2\u53D1\u5E03 migration \u4E0D\u53EF\u5220\u9664", expected);
|
|
9173
9234
|
}
|
|
9174
9235
|
if (source && target && source.hash !== target.hash) {
|
|
9175
|
-
return
|
|
9236
|
+
return conflict3(path2, ownership, "\u5DF2\u53D1\u5E03 migration \u4E0D\u53EF\u6539\u5199\uFF0C\u53EA\u80FD\u8FFD\u52A0\u65B0\u6587\u4EF6", expected);
|
|
9176
9237
|
}
|
|
9177
9238
|
}
|
|
9178
9239
|
if (!source && target) {
|
|
9179
9240
|
if (!ours) {
|
|
9180
9241
|
return readyPlannedFile(path2, ownership, "create", "\u76EE\u6807\u7248\u672C\u65B0\u589E", expected, theirs);
|
|
9181
9242
|
}
|
|
9182
|
-
return theirs && hashContent(ours) === target.hash ? readyPlannedFile(path2, ownership, "preserve", "\u5DF2\u5305\u542B\u76EE\u6807\u5185\u5BB9", expected) :
|
|
9243
|
+
return theirs && hashContent(ours) === target.hash ? readyPlannedFile(path2, ownership, "preserve", "\u5DF2\u5305\u542B\u76EE\u6807\u5185\u5BB9", expected) : conflict3(path2, ownership, "\u76EE\u6807\u7248\u672C\u65B0\u589E\u8DEF\u5F84\u5DF2\u88AB\u9879\u76EE\u5360\u7528", expected);
|
|
9183
9244
|
}
|
|
9184
9245
|
if (source && !target) {
|
|
9185
9246
|
if (!ours) {
|
|
9186
9247
|
return readyPlannedFile(path2, ownership, "preserve", "\u9879\u76EE\u5DF2\u5220\u9664", expected);
|
|
9187
9248
|
}
|
|
9188
|
-
return hashContent(ours) === source.hash ? readyPlannedFile(path2, ownership, "delete", "\u76EE\u6807\u7248\u672C\u5220\u9664", expected) :
|
|
9249
|
+
return hashContent(ours) === source.hash ? readyPlannedFile(path2, ownership, "delete", "\u76EE\u6807\u7248\u672C\u5220\u9664", expected) : conflict3(path2, ownership, "\u5BA2\u6237\u4FEE\u6539\u540E Windy \u53C8\u5220\u9664", expected);
|
|
9189
9250
|
}
|
|
9190
9251
|
if (!source || !target || !ours || !theirs) {
|
|
9191
|
-
return
|
|
9252
|
+
return conflict3(path2, ownership, "\u6587\u4EF6\u72B6\u6001\u4E0D\u5B8C\u6574\uFF0C\u4E0D\u80FD\u5B89\u5168\u63A8\u65AD", expected);
|
|
9192
9253
|
}
|
|
9193
9254
|
const oursChanged = hashContent(ours) !== source.hash;
|
|
9194
9255
|
const sourceArtifactHash = artifactHashOf(source);
|
|
@@ -9202,7 +9263,7 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
|
|
|
9202
9263
|
});
|
|
9203
9264
|
if (forceTargetBaseline && path2.endsWith("package.json") && base) {
|
|
9204
9265
|
const merged = mergePackageJson(base, ours, theirs);
|
|
9205
|
-
return merged.content ? readyPlannedFile(path2, ownership, "update", "package.json \u5B57\u6BB5\u7EA7\u5408\u5E76", expected, merged.content) :
|
|
9266
|
+
return merged.content ? readyPlannedFile(path2, ownership, "update", "package.json \u5B57\u6BB5\u7EA7\u5408\u5E76", expected, merged.content) : conflict3(path2, ownership, `\u5B57\u6BB5\u51B2\u7A81\uFF1A${merged.conflicts.join("\u3001")}`, expected);
|
|
9206
9267
|
}
|
|
9207
9268
|
if (forceTargetBaseline) {
|
|
9208
9269
|
return readyPlannedFile(path2, ownership, "update", "\u5F3A\u5236\u91C7\u7528\u76EE\u6807\u5E73\u53F0\u57FA\u7EBF", expected, theirs);
|
|
@@ -9212,11 +9273,11 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
|
|
|
9212
9273
|
}
|
|
9213
9274
|
if (targetChanged && path2.endsWith("package.json") && base) {
|
|
9214
9275
|
const merged = mergePackageJson(base, ours, theirs);
|
|
9215
|
-
return merged.content ? readyPlannedFile(path2, ownership, "update", "package.json \u5B57\u6BB5\u7EA7\u5408\u5E76", expected, merged.content) :
|
|
9276
|
+
return merged.content ? readyPlannedFile(path2, ownership, "update", "package.json \u5B57\u6BB5\u7EA7\u5408\u5E76", expected, merged.content) : conflict3(path2, ownership, `\u5B57\u6BB5\u51B2\u7A81\uFF1A${merged.conflicts.join("\u3001")}`, expected);
|
|
9216
9277
|
}
|
|
9217
9278
|
if (!oursChanged && targetChanged && adoptedProjectDelta && base) {
|
|
9218
9279
|
const merged = await mergeTextFile(base, ours, theirs);
|
|
9219
|
-
return merged.content ? readyPlannedFile(path2, ownership, "update", "\u4E09\u65B9\u5408\u5E76\u5DF2\u91C7\u7EB3\u9879\u76EE\u589E\u91CF", expected, merged.content) :
|
|
9280
|
+
return merged.content ? readyPlannedFile(path2, ownership, "update", "\u4E09\u65B9\u5408\u5E76\u5DF2\u91C7\u7EB3\u9879\u76EE\u589E\u91CF", expected, merged.content) : conflict3(path2, ownership, merged.conflict || "\u4E09\u65B9\u5408\u5E76\u5931\u8D25", expected);
|
|
9220
9281
|
}
|
|
9221
9282
|
if (!oursChanged) {
|
|
9222
9283
|
return readyPlannedFile(path2, ownership, "update", "\u4EC5 Windy \u4FEE\u6539", expected, theirs);
|
|
@@ -9229,9 +9290,9 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
|
|
|
9229
9290
|
}
|
|
9230
9291
|
if (base) {
|
|
9231
9292
|
const merged = await mergeTextFile(base, ours, theirs);
|
|
9232
|
-
return merged.content ? readyPlannedFile(path2, ownership, "update", "\u4E09\u65B9\u5408\u5E76", expected, merged.content) :
|
|
9293
|
+
return merged.content ? readyPlannedFile(path2, ownership, "update", "\u4E09\u65B9\u5408\u5E76", expected, merged.content) : conflict3(path2, ownership, merged.conflict || "\u4E09\u65B9\u5408\u5E76\u5931\u8D25", expected);
|
|
9233
9294
|
}
|
|
9234
|
-
return
|
|
9295
|
+
return conflict3(path2, ownership, "\u5BA2\u6237\u548C Windy \u5747\u5DF2\u4FEE\u6539", expected);
|
|
9235
9296
|
}
|
|
9236
9297
|
function shouldForcePlatformBaseline(input) {
|
|
9237
9298
|
return input.forcePlatformBaseline && !input.oursChanged && input.base !== undefined && hashContent(input.base) !== input.sourceArtifactHash;
|
|
@@ -9252,7 +9313,7 @@ function readyPlannedFile(path2, ownership, action, reason, expectedProjectConte
|
|
|
9252
9313
|
function expectationForSnapshot(content) {
|
|
9253
9314
|
return content ? { kind: "hash", value: hashContent(content) } : { kind: "missing" };
|
|
9254
9315
|
}
|
|
9255
|
-
function
|
|
9316
|
+
function conflict3(path2, ownership, reason, expectedProjectContent) {
|
|
9256
9317
|
return {
|
|
9257
9318
|
path: path2,
|
|
9258
9319
|
ownership,
|
|
@@ -9426,6 +9487,7 @@ async function createUpdatePlan(request, artifacts, dependencies = {}) {
|
|
|
9426
9487
|
const versionRecipes = (dependencies.resolveVersionRecipes ?? resolveRecipeChain)(provenance.windyVersion, targetVersion);
|
|
9427
9488
|
const moduleRecipes = resolveModuleRecipeIds(request);
|
|
9428
9489
|
const recipes2 = [...versionRecipes.map(({ id }) => id), ...moduleRecipes];
|
|
9490
|
+
const recipeProjectOwnedPaths = recipeManagedProjectOwnedPaths(recipes2);
|
|
9429
9491
|
const [rawSourceManifest, rawTargetManifest] = await Promise.all([
|
|
9430
9492
|
readManagedFilesManifest(request.projectDirectory),
|
|
9431
9493
|
readManagedFilesManifest(artifactSet.targetDirectory)
|
|
@@ -9472,7 +9534,8 @@ async function createUpdatePlan(request, artifacts, dependencies = {}) {
|
|
|
9472
9534
|
artifactSet,
|
|
9473
9535
|
provenance,
|
|
9474
9536
|
manageGeneratedProjectOwned: request.targetModules !== undefined,
|
|
9475
|
-
forcePlatformBaseline: request.forcePlatformBaseline === true
|
|
9537
|
+
forcePlatformBaseline: request.forcePlatformBaseline === true,
|
|
9538
|
+
recipeProjectOwnedPaths
|
|
9476
9539
|
});
|
|
9477
9540
|
preserveTestsForExistingProjectOwnedSources(files, sourceEntries);
|
|
9478
9541
|
await deriveDockerfilePlans(files, projectSnapshots, new Set([
|
|
@@ -9551,7 +9614,7 @@ async function planFiles(input) {
|
|
|
9551
9614
|
} else if (forcedContent) {
|
|
9552
9615
|
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));
|
|
9553
9616
|
} else {
|
|
9554
|
-
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));
|
|
9617
|
+
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, input.recipeProjectOwnedPaths.has(path2)));
|
|
9555
9618
|
}
|
|
9556
9619
|
}
|
|
9557
9620
|
return files;
|
|
@@ -10072,9 +10135,9 @@ function assertEnabledConflicts(target, catalog) {
|
|
|
10072
10135
|
for (const [name, enabled] of target) {
|
|
10073
10136
|
if (!enabled)
|
|
10074
10137
|
continue;
|
|
10075
|
-
const
|
|
10076
|
-
if (
|
|
10077
|
-
throw new Error(`\u6A21\u5757\u51B2\u7A81\uFF1A${name} \u4E0E ${
|
|
10138
|
+
const conflict4 = catalog.get(name).conflicts.find((candidate) => target.get(candidate));
|
|
10139
|
+
if (conflict4)
|
|
10140
|
+
throw new Error(`\u6A21\u5757\u51B2\u7A81\uFF1A${name} \u4E0E ${conflict4}`);
|
|
10078
10141
|
}
|
|
10079
10142
|
}
|
|
10080
10143
|
function assertCompatible(version, range, name) {
|
|
@@ -10089,7 +10152,7 @@ function reconcileProjectModuleRegistryPlan(plan, current, lifecycle) {
|
|
|
10089
10152
|
if (!registryFile) {
|
|
10090
10153
|
throw new Error("\u6A21\u5757\u751F\u547D\u5468\u671F\u8BA1\u5212\u7F3A\u5C11 project-owned \u88C5\u914D\u9009\u62E9");
|
|
10091
10154
|
}
|
|
10092
|
-
plan.conflicts = plan.conflicts.filter((
|
|
10155
|
+
plan.conflicts = plan.conflicts.filter((conflict4) => !conflict4.startsWith(`${projectModuleRegistryPath}\uFF1A`));
|
|
10093
10156
|
delete registryFile.conflict;
|
|
10094
10157
|
if (lifecycle.action === "update") {
|
|
10095
10158
|
registryFile.action = "preserve";
|
|
@@ -10519,8 +10582,8 @@ function printModulePlan(plan, log) {
|
|
|
10519
10582
|
for (const file of changed) {
|
|
10520
10583
|
log(` ${file.action.padEnd(6)} ${file.path}\uFF08${file.reason}\uFF09`);
|
|
10521
10584
|
}
|
|
10522
|
-
for (const
|
|
10523
|
-
log(` conflict ${
|
|
10585
|
+
for (const conflict4 of plan.conflicts)
|
|
10586
|
+
log(` conflict ${conflict4}`);
|
|
10524
10587
|
}
|
|
10525
10588
|
function hasChanges(lifecycle) {
|
|
10526
10589
|
return lifecycle.addedModules.length > 0 || lifecycle.updatedModules.length > 0 || lifecycle.removedModules.length > 0;
|
|
@@ -10692,8 +10755,8 @@ function printPlan(plan) {
|
|
|
10692
10755
|
console.log(`\u8BA1\u5212\u6539\u52A8\uFF1A${changed.length} \u4E2A\u6587\u4EF6\uFF1B\u51B2\u7A81\uFF1A${plan.conflicts.length}`);
|
|
10693
10756
|
for (const file of changed)
|
|
10694
10757
|
console.log(` ${file.action.padEnd(6)} ${file.path}\uFF08${file.reason}\uFF09`);
|
|
10695
|
-
for (const
|
|
10696
|
-
console.log(` conflict ${
|
|
10758
|
+
for (const conflict4 of plan.conflicts)
|
|
10759
|
+
console.log(` conflict ${conflict4}`);
|
|
10697
10760
|
if (plan.detachedToolchain)
|
|
10698
10761
|
console.log("Oxc\uFF1A\u68C0\u6D4B\u5230\u5BA2\u6237\u63A5\u7BA1\uFF0C\u76F8\u5173\u914D\u7F6E\u4FDD\u6301\u4E0D\u53D8");
|
|
10699
10762
|
}
|
package/package.json
CHANGED
package/template/README.md
CHANGED
|
@@ -132,7 +132,8 @@ browser-safe `./admin` 与 project-owned 的
|
|
|
132
132
|
`apps/web/src/app/web-composition.ts` 装配页面,不复制第二份 Feature、Permission
|
|
133
133
|
或路由清单。整个 `apps/web/src` 与整个 `apps/server/src/app` 都是
|
|
134
134
|
project-owned,客户可以修改 Router、layout、页面、Host 和 Server 组合;普通
|
|
135
|
-
`windy update`
|
|
135
|
+
`windy update` 不会整文件覆盖或三方合并这些文件。版本 recipe 只有在显式登记
|
|
136
|
+
path 与确定性语义锚点后才能做幂等追加;锚点缺失或不唯一时必须在写入前停止。
|
|
136
137
|
|
|
137
138
|
精确生成来源保留在 `.windy/generation.json`。当前版本已提供可回滚的
|
|
138
139
|
`windy update` 与 `windy module list/enable/disable`。当前内置模块仍依赖
|
|
@@ -166,7 +167,8 @@ bun run format
|
|
|
166
167
|
更新前无需提交、暂存或清理业务改动。`--dry-run` 只生成计划,不写项目;无关 WIP
|
|
167
168
|
保持原样,命中同一路径时按冻结快照与三方合并 fail closed。正式更新先备份,再做
|
|
168
169
|
package 字段级合并、共享脚手架三方合并与完整验证。整个 `apps/web/src` 和
|
|
169
|
-
`apps/server/src/app`
|
|
170
|
+
`apps/server/src/app` 默认保持项目版本;已登记版本 recipe 只修改其声明的窄锚点。
|
|
171
|
+
任何冲突都会在写入前中止,模块启停在交互
|
|
170
172
|
终端确认;CI、Agent 或其它非 TTY 环境必须显式传入 `--yes`。
|
|
171
173
|
无并发变化的验证失败会自动回滚;中断恢复使用
|
|
172
174
|
`bun run windy doctor --repair`。该命令在提交点前保留并发编辑并回滚其余路径,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Windy Agent Server
|
|
2
2
|
|
|
3
|
-
Python 3.12 Agent 运行时。HTTP 层只公开
|
|
3
|
+
Python 3.12 Agent 运行时。HTTP 层只公开 Windy 的 canonical Agent 契约;真实业务
|
|
4
4
|
Run 在内部通过 Google ADK 2.5 的 Runner、Session、LlmAgent 和 Event 执行,ADK 类型不会
|
|
5
5
|
越过 `AgentEngineAdapter`。模型调用继续复用受治理的 OpenAI-compatible
|
|
6
6
|
`/chat/completions` Provider。
|
|
@@ -64,12 +64,12 @@ HTTP。Provider 请求包含连接和总超时、响应大小限制、错误脱
|
|
|
64
64
|
readiness。缺少 URL/Model 时回退
|
|
65
65
|
未配置的 `AdkEngineAdapter` 并返回 unavailable,不调用模型。测试另使用
|
|
66
66
|
`DeterministicEngineAdapter`。每个 ADK Tool 只声明 Operation 已允许的 Key;其执行
|
|
67
|
-
函数只回调
|
|
67
|
+
函数只回调 Windy Tool Host,并携带当前 Run 的 opaque Execution Grant。
|
|
68
68
|
|
|
69
69
|
未设置 `AGENT_RUN_STORE_PATH` 时使用的 `InMemoryRunStore` **仅用于 deterministic
|
|
70
70
|
测试**。配置路径后使用有界 SQLite Store,可在单副本重启后保留 Run/Event/Result 和
|
|
71
71
|
cursor;多副本部署仍必须替换为共享 Store。Execution Grant 与 Tool 授权由
|
|
72
|
-
|
|
72
|
+
Windy Server 签发和复核,Agent Server 不能自行扩大 Operation 的
|
|
73
73
|
`allowedToolKeys`。
|
|
74
74
|
|
|
75
75
|
每次实际 `/chat/completions` HTTP 调用前,Runtime 会对 Manifest 允许的输入 JSON
|
|
@@ -3,12 +3,16 @@ import type { DataScopeQuerySpecification } from "./query-specification.js";
|
|
|
3
3
|
|
|
4
4
|
export class DataScopeBindingError extends Error {}
|
|
5
5
|
|
|
6
|
+
export interface DrizzleDataScopeColumn {
|
|
7
|
+
getSQL(): unknown;
|
|
8
|
+
}
|
|
9
|
+
|
|
6
10
|
export interface DrizzleDataScopeBinding {
|
|
7
|
-
readonly ownerId?:
|
|
11
|
+
readonly ownerId?: DrizzleDataScopeColumn;
|
|
8
12
|
readonly tenant?:
|
|
9
|
-
| { readonly mode: "column"; readonly column:
|
|
13
|
+
| { readonly mode: "column"; readonly column: DrizzleDataScopeColumn }
|
|
10
14
|
| { readonly mode: "fixed"; readonly tenantId: string };
|
|
11
|
-
readonly dimensions?: Readonly<Record<string,
|
|
15
|
+
readonly dimensions?: Readonly<Record<string, DrizzleDataScopeColumn>>;
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
export function compileDrizzleDataScopePredicate(
|
|
@@ -28,13 +32,13 @@ export function compileDrizzleDataScopePredicate(
|
|
|
28
32
|
if (tenant.tenantId === branch.tenantId) return undefined;
|
|
29
33
|
continue;
|
|
30
34
|
}
|
|
31
|
-
predicates.push(eq(tenant.column, branch.tenantId));
|
|
35
|
+
predicates.push(eq(drizzleColumn(tenant.column), branch.tenantId));
|
|
32
36
|
}
|
|
33
37
|
if (branch.kind === "owner") {
|
|
34
38
|
if (!binding.ownerId) {
|
|
35
39
|
throw new DataScopeBindingError("scope binding missing ownerId");
|
|
36
40
|
}
|
|
37
|
-
predicates.push(eq(binding.ownerId, branch.ownerId));
|
|
41
|
+
predicates.push(eq(drizzleColumn(binding.ownerId), branch.ownerId));
|
|
38
42
|
}
|
|
39
43
|
if (branch.kind === "dimension") {
|
|
40
44
|
const column = binding.dimensions?.[branch.dimension];
|
|
@@ -43,8 +47,14 @@ export function compileDrizzleDataScopePredicate(
|
|
|
43
47
|
`scope binding missing dimension: ${branch.dimension}`,
|
|
44
48
|
);
|
|
45
49
|
}
|
|
46
|
-
if (branch.values.length)
|
|
50
|
+
if (branch.values.length) {
|
|
51
|
+
predicates.push(inArray(drizzleColumn(column), branch.values));
|
|
52
|
+
}
|
|
47
53
|
}
|
|
48
54
|
}
|
|
49
55
|
return or(...predicates) || sql<boolean>`false`;
|
|
50
56
|
}
|
|
57
|
+
|
|
58
|
+
function drizzleColumn(column: DrizzleDataScopeColumn): AnyColumn {
|
|
59
|
+
return column as unknown as AnyColumn;
|
|
60
|
+
}
|