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.
Files changed (45) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.js +158 -95
  3. package/package.json +1 -1
  4. package/template/.windy-template.json +2 -2
  5. package/template/README.md +4 -2
  6. package/template/apps/agent-server/README.md +4 -4
  7. package/template/apps/server/src/data-access/drizzle-predicate.ts +16 -6
  8. package/template/apps/server/src/runtime-development.ts +1 -0
  9. package/template/apps/web/src/layout/AppSidebar.vue +1 -0
  10. package/template/apps/web/src/pages/ui/UiComponentPage.vue +7 -0
  11. package/template/apps/web/src/pages/ui/UiComponentPage.webtest.ts +94 -0
  12. package/template/apps/web/src/pages/ui/component-catalog.ts +248 -0
  13. package/template/apps/web/src/pages/ui/components/ComponentPreviewCard.vue +50 -0
  14. package/template/apps/web/src/pages/ui/components/DataComponentShowcases.vue +131 -0
  15. package/template/apps/web/src/pages/ui/components/FeedbackComponentShowcases.vue +158 -0
  16. package/template/apps/web/src/pages/ui/components/FoundationComponentShowcases.vue +129 -0
  17. package/template/apps/web/src/pages/ui/components/NavigationComponentShowcases.vue +155 -0
  18. package/template/apps/web/src/pages/ui/components/ProjectComponentShowcases.vue +31 -0
  19. package/template/apps/web/src/pages/ui/components/UiComponentGallery.vue +238 -0
  20. package/template/apps/web/src/router/index.ts +2 -0
  21. package/template/apps/web/src/router/manifest-routes.webtest.ts +1 -0
  22. package/template/apps/web/src/router/platform-admin-route-bindings.ts +3 -1
  23. package/template/docs/architecture/ai-egress.md +1 -1
  24. package/template/docs/architecture/ai-runtime-readiness.md +2 -2
  25. package/template/docs/architecture/ai-runtime.md +15 -15
  26. package/template/docs/architecture/module-secret-resolution.md +4 -4
  27. package/template/docs/architecture/report-staging.md +1 -1
  28. package/template/docs/development/business-web-routes.md +3 -1
  29. package/template/docs/development/custom-login-page.md +3 -3
  30. package/template/docs/development/ui-component-gallery.md +44 -0
  31. package/template/docs/license/license-offline-activation-code.md +2 -2
  32. package/template/docs/operations/incremental-delivery.md +10 -9
  33. package/template/docs/platform/agent-runtime.md +4 -4
  34. package/template/docs/platform/document-ai-runtime.md +3 -3
  35. package/template/docs/platform/speech-ai-runtime.md +1 -1
  36. package/template/docs/platform/vision-ai-runtime.md +1 -1
  37. package/template/docs/product/built-in-roles.md +9 -1
  38. package/template/packages/modules/package.json +1 -1
  39. package/template/packages/modules/src/system-admin-routes.ts +8 -0
  40. package/template/packages/modules/src/system-admin-ui-catalog.ts +1 -1
  41. package/template/packages/modules/src/system-features.ts +5 -0
  42. package/template/packages/modules/src/system-module-catalog.ts +2 -1
  43. package/template/packages/modules/src/system-modules.ts +11 -0
  44. package/template/packages/modules/src/system-permissions.ts +2 -0
  45. 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.3.17` 是 Starter 更新的最低支持基线。更新器不检查 Git 工作区是否干净:只规划
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.3.17` 的 Project Lock、旧清单 schema、损坏的 artifact lineage 或 recipe
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\u3002\u4EFB\u4F55\u51B2\u7A81\u90FD\u4F1A\u5728\u5199\u5165\u524D\u4E2D\u6B62\uFF0C\u6A21\u5757\u542F\u505C\u5728\u4EA4\u4E92
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.3.17";
7722
+ var minimumSupportedUpdateVersion = "0.6.6";
7720
7723
  var recipes = [
7721
7724
  {
7722
- id: "starter-0.3.17-to-0.3.18",
7723
- from: "0.3.17",
7724
- to: "0.3.18"
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.5-to-0.6.6",
7788
- from: "0.6.5",
7789
- to: "0.6.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.6-to-0.6.7",
7793
- from: "0.6.6",
7794
- to: "0.6.7"
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.3.17 \u57FA\u7EBF\u7684 COPY \u951A\u70B9\uFF0C\u5DF2\u505C\u6B62\u81EA\u52A8\u8FC1\u79FB\u65E7\u683C\u5F0F";
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 conflict2(path2, ownership, "\u5DF2\u53D1\u5E03 migration \u4E0D\u53EF\u5220\u9664", expected);
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 conflict2(path2, ownership, "\u5DF2\u53D1\u5E03 migration \u4E0D\u53EF\u6539\u5199\uFF0C\u53EA\u80FD\u8FFD\u52A0\u65B0\u6587\u4EF6", expected);
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) : conflict2(path2, ownership, "\u76EE\u6807\u7248\u672C\u65B0\u589E\u8DEF\u5F84\u5DF2\u88AB\u9879\u76EE\u5360\u7528", 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) : conflict2(path2, ownership, "\u5BA2\u6237\u4FEE\u6539\u540E Windy \u53C8\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 conflict2(path2, ownership, "\u6587\u4EF6\u72B6\u6001\u4E0D\u5B8C\u6574\uFF0C\u4E0D\u80FD\u5B89\u5168\u63A8\u65AD", expected);
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) : conflict2(path2, ownership, `\u5B57\u6BB5\u51B2\u7A81\uFF1A${merged.conflicts.join("\u3001")}`, expected);
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) : conflict2(path2, ownership, `\u5B57\u6BB5\u51B2\u7A81\uFF1A${merged.conflicts.join("\u3001")}`, expected);
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) : conflict2(path2, ownership, merged.conflict || "\u4E09\u65B9\u5408\u5E76\u5931\u8D25", expected);
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) : conflict2(path2, ownership, merged.conflict || "\u4E09\u65B9\u5408\u5E76\u5931\u8D25", expected);
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 conflict2(path2, ownership, "\u5BA2\u6237\u548C Windy \u5747\u5DF2\u4FEE\u6539", expected);
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 conflict2(path2, ownership, reason, expectedProjectContent) {
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 conflict3 = catalog.get(name).conflicts.find((candidate) => target.get(candidate));
10076
- if (conflict3)
10077
- throw new Error(`\u6A21\u5757\u51B2\u7A81\uFF1A${name} \u4E0E ${conflict3}`);
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((conflict3) => !conflict3.startsWith(`${projectModuleRegistryPath}\uFF1A`));
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 conflict3 of plan.conflicts)
10523
- log(` conflict ${conflict3}`);
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 conflict3 of plan.conflicts)
10696
- console.log(` conflict ${conflict3}`);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-windy",
3
- "version": "0.6.7",
3
+ "version": "0.6.9",
4
4
  "description": "创建单组织、单租户、私有部署优先的 Windy 企业 Dashboard Starter",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "templateCommit": "dcc27b44de561eb3b4e6f9aea7869ba0f4299a62",
4
- "generatorVersion": "0.6.7",
3
+ "templateCommit": "9176c4dc2db60979b5ce7fd89639da90648c49b9",
4
+ "generatorVersion": "0.6.9",
5
5
  "modules": [
6
6
  {
7
7
  "name": "system",
@@ -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
- # Southwind AI Agent Server
1
+ # Windy Agent Server
2
2
 
3
- Python 3.12 Agent 运行时。HTTP 层只公开 Southwind AI 的 canonical Agent 契约;真实业务
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
- 函数只回调 Southwind AI Tool Host,并携带当前 Run 的 opaque Execution Grant。
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
- Southwind AI Server 签发和复核,Agent Server 不能自行扩大 Operation 的
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?: AnyColumn;
11
+ readonly ownerId?: DrizzleDataScopeColumn;
8
12
  readonly tenant?:
9
- | { readonly mode: "column"; readonly column: AnyColumn }
13
+ | { readonly mode: "column"; readonly column: DrizzleDataScopeColumn }
10
14
  | { readonly mode: "fixed"; readonly tenantId: string };
11
- readonly dimensions?: Readonly<Record<string, AnyColumn>>;
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) predicates.push(inArray(column, branch.values));
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
+ }
@@ -36,6 +36,7 @@ export function developmentAdminActor(): RequestActor {
36
36
  "system.dict.manage",
37
37
  "system.feature.read",
38
38
  "system.feature.manage",
39
+ "system.ui-components.read",
39
40
  "system.search.read",
40
41
  "system.search.manage",
41
42
  "system.settings.read",
@@ -52,6 +52,7 @@ interface NavigationGroup {
52
52
  const iconMap: Record<string, Component> = {
53
53
  activity: ActivityIcon,
54
54
  bell: BellIcon,
55
+ blocks: BlocksIcon,
55
56
  "layout-dashboard": LayoutDashboardIcon,
56
57
  "book-open": BookOpenIcon,
57
58
  "building-2": Building2Icon,
@@ -0,0 +1,7 @@
1
+ <script setup lang="ts">
2
+ import UiComponentGallery from "./components/UiComponentGallery.vue";
3
+ </script>
4
+
5
+ <template>
6
+ <UiComponentGallery />
7
+ </template>