create-windy 0.3.9 → 0.3.11

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
@@ -835,7 +835,7 @@ var helpText = `create-windy <\u9879\u76EE\u540D> [\u9009\u9879]
835
835
 
836
836
  \u9009\u9879\uFF1A
837
837
  --profile private-enterprise \u5355\u7EC4\u7EC7\u3001\u5355\u79DF\u6237\u3001\u79C1\u6709\u90E8\u7F72 profile
838
- --skip-install \u53EA\u751F\u6210\u6587\u4EF6\uFF0C\u4E0D\u6267\u884C bun install
838
+ --skip-install \u751F\u6210\u6216\u66F4\u65B0\u65F6\u4E0D\u6267\u884C bun install
839
839
  --verify \u5B89\u88C5\u540E\u6267\u884C lint\uFF08\u82E5\u6709\uFF09\u3001typecheck\u3001test \u548C build
840
840
  --keep-on-error \u5931\u8D25\u65F6\u4FDD\u7559\u65B0\u751F\u6210\u76EE\u5F55\u7528\u4E8E\u8BCA\u65AD
841
841
  --module <key> \u589E\u52A0\u6A21\u5757\uFF0C\u53EF\u91CD\u590D\u4F7F\u7528
@@ -866,7 +866,7 @@ async function runCommand(command, args, cwd) {
866
866
  await new Promise((resolve2, reject) => {
867
867
  const child = spawn(command, args, { cwd, stdio: "inherit" });
868
868
  child.once("error", reject);
869
- child.once("exit", (code, signal) => {
869
+ child.once("close", (code, signal) => {
870
870
  if (code === 0)
871
871
  resolve2();
872
872
  else
@@ -2851,8 +2851,22 @@ function isMissing(error) {
2851
2851
  // src/docker-copy-sync.ts
2852
2852
  var webDockerfilePath = "apps/web/Dockerfile";
2853
2853
  var webEntryDirectory = "apps/web";
2854
+ var serverDockerfilePath = "apps/server/Dockerfile";
2855
+ var serverEntryDirectory = "apps/server";
2854
2856
  var depsCopyAnchor = "windy-copy:deps";
2855
2857
  var buildCopyAnchor = "windy-copy:build";
2858
+ var dockerfileCopyTargets = [
2859
+ {
2860
+ dockerfilePath: serverDockerfilePath,
2861
+ entryDirectory: serverEntryDirectory,
2862
+ includeBuildClosure: false
2863
+ },
2864
+ {
2865
+ dockerfilePath: webDockerfilePath,
2866
+ entryDirectory: webEntryDirectory,
2867
+ includeBuildClosure: true
2868
+ }
2869
+ ];
2856
2870
  async function snapshotWorkspacePackages(root, options = {}) {
2857
2871
  const rootContent = await readSafeOptional(root, "package.json");
2858
2872
  if (!rootContent) {
@@ -2885,10 +2899,8 @@ async function snapshotWorkspacePackages(root, options = {}) {
2885
2899
  packages.push({
2886
2900
  name: value.name,
2887
2901
  directory: path.slice(0, -"/package.json".length),
2888
- dependencies: [
2889
- ...Object.keys(value.dependencies ?? {}),
2890
- ...Object.keys(value.devDependencies ?? {})
2891
- ]
2902
+ dependencies: dependencyNames(value),
2903
+ workspaceDependencies: workspaceDependencyNames(value)
2892
2904
  });
2893
2905
  }
2894
2906
  }
@@ -2911,6 +2923,9 @@ function workspaceDependencyClosure(packages, entryDirectory) {
2911
2923
  directoryByName.set(pkg.name, pkg.directory);
2912
2924
  packageByDirectory.set(pkg.directory, pkg);
2913
2925
  }
2926
+ if (!packageByDirectory.has(entryDirectory)) {
2927
+ throw new Error(`Docker \u5165\u53E3\u4E0D\u662F root workspace: ${entryDirectory}`);
2928
+ }
2914
2929
  const visited = new Set([entryDirectory]);
2915
2930
  const queue = [entryDirectory];
2916
2931
  while (queue.length) {
@@ -2924,6 +2939,11 @@ function workspaceDependencyClosure(packages, entryDirectory) {
2924
2939
  queue.push(directory);
2925
2940
  }
2926
2941
  }
2942
+ for (const dependency of current.workspaceDependencies ?? []) {
2943
+ if (!directoryByName.has(dependency)) {
2944
+ throw new Error(`${current.directory} \u5F15\u7528\u672A\u77E5\u6216\u8D8A\u754C workspace dependency: ${dependency}`);
2945
+ }
2946
+ }
2927
2947
  }
2928
2948
  return [...visited].sort((a, b) => a.localeCompare(b));
2929
2949
  }
@@ -2940,15 +2960,16 @@ function rewriteAnchoredSection(source, anchor, lines) {
2940
2960
  return [...all.slice(0, begin + 1), ...lines, ...all.slice(end)].join(`
2941
2961
  `);
2942
2962
  }
2943
- function hasCopyAnchors(source) {
2944
- return source.includes(`# ${depsCopyAnchor} begin`) && source.includes(`# ${buildCopyAnchor} begin`);
2963
+ function hasDockerfileCopyAnchors(source, target) {
2964
+ return source.includes(`# ${depsCopyAnchor} begin`) && source.includes(`# ${depsCopyAnchor} end`) && (!target.includeBuildClosure || source.includes(`# ${buildCopyAnchor} begin`) && source.includes(`# ${buildCopyAnchor} end`));
2945
2965
  }
2946
- function syncWebDockerfileSource(source, workspaceDirectories, buildDirectories) {
2947
- const withDeps = rewriteAnchoredSection(source, depsCopyAnchor, dockerManifestCopyLines(workspaceDirectories));
2948
- return rewriteAnchoredSection(withDeps, buildCopyAnchor, dockerCopyLines(buildDirectories));
2966
+ function syncDockerfileSource(source, target, packages) {
2967
+ const closure = workspaceDependencyClosure(packages, target.entryDirectory);
2968
+ const withDeps = rewriteAnchoredSection(source, depsCopyAnchor, dockerManifestCopyLines(packages.map(({ directory }) => directory)));
2969
+ return target.includeBuildClosure ? rewriteAnchoredSection(withDeps, buildCopyAnchor, dockerCopyLines(closure)) : withDeps;
2949
2970
  }
2950
- async function planWebDockerfileInProject(root, options = {}) {
2951
- const dockerfile = await readSafeOptional(root, webDockerfilePath);
2971
+ async function planDockerfileInProject(root, target, options = {}) {
2972
+ const dockerfile = await readSafeOptional(root, target.dockerfilePath);
2952
2973
  if (!dockerfile) {
2953
2974
  return {
2954
2975
  synced: false,
@@ -2958,27 +2979,27 @@ async function planWebDockerfileInProject(root, options = {}) {
2958
2979
  };
2959
2980
  }
2960
2981
  const source = new TextDecoder().decode(dockerfile);
2961
- if (!hasCopyAnchors(source)) {
2982
+ if (!hasDockerfileCopyAnchors(source, target)) {
2962
2983
  if (!options.requireAnchors) {
2963
2984
  return {
2964
2985
  synced: false,
2965
2986
  changed: false,
2966
- expectations: [expectation(webDockerfilePath, dockerfile)],
2987
+ expectations: [expectation(target.dockerfilePath, dockerfile)],
2967
2988
  membershipExpectations: []
2968
2989
  };
2969
2990
  }
2970
- throw new Error(`${webDockerfilePath} \u7F3A\u5C11 # ${depsCopyAnchor} / # ${buildCopyAnchor} \u951A\u70B9\u6BB5\uFF0C` + `\u8BF7\u5148\u6309\u6700\u65B0\u6A21\u677F\u4E3A deps \u4E0E build \u9636\u6BB5\u7684 COPY \u6BB5\u6DFB\u52A0\u951A\u70B9\u540E\u518D\u540C\u6B65`);
2991
+ throw new Error(`${target.dockerfilePath} \u7F3A\u5C11\u5FC5\u9700\u7684 Docker COPY \u951A\u70B9\u6BB5\uFF0C` + `\u8BF7\u5148\u6309\u6700\u65B0\u6A21\u677F\u8FC1\u79FB\u540E\u518D\u540C\u6B65`);
2971
2992
  }
2972
2993
  const snapshot = await snapshotWorkspacePackages(root);
2973
2994
  await options.afterWorkspaceSnapshot?.();
2974
2995
  const packages = snapshot.packages;
2975
- const next = syncWebDockerfileSource(source, packages.map(({ directory }) => directory), workspaceDependencyClosure(packages, webEntryDirectory));
2996
+ const next = syncDockerfileSource(source, target, packages);
2976
2997
  return {
2977
2998
  synced: true,
2978
2999
  changed: next !== source,
2979
3000
  content: next,
2980
3001
  expectations: [
2981
- expectation(webDockerfilePath, dockerfile),
3002
+ expectation(target.dockerfilePath, dockerfile),
2982
3003
  ...snapshot.expectations
2983
3004
  ],
2984
3005
  membershipExpectations: snapshot.membershipExpectations
@@ -3002,6 +3023,18 @@ function locateAnchoredSection(source, anchor) {
3002
3023
  function parseManifest(content) {
3003
3024
  return JSON.parse(new TextDecoder().decode(content));
3004
3025
  }
3026
+ function dependencyNames(manifest) {
3027
+ return Object.keys({
3028
+ ...manifest.dependencies,
3029
+ ...manifest.devDependencies
3030
+ });
3031
+ }
3032
+ function workspaceDependencyNames(manifest) {
3033
+ return Object.entries({
3034
+ ...manifest.dependencies,
3035
+ ...manifest.devDependencies
3036
+ }).filter(([, range]) => range.startsWith("workspace:")).map(([name]) => name);
3037
+ }
3005
3038
  function expectation(path, content) {
3006
3039
  return content ? { path, hash: hashContent(content) } : { path, hash: undefined };
3007
3040
  }
@@ -3019,11 +3052,13 @@ async function prepareCustomerDockerfiles(root) {
3019
3052
  const source = await readFile5(absolutePath, "utf8");
3020
3053
  await writeFile2(absolutePath, rewriteCustomerDockerfile(source));
3021
3054
  }));
3022
- const webPlan = await planWebDockerfileInProject(root, {
3023
- requireAnchors: true
3024
- });
3025
- if (webPlan.changed && webPlan.content !== undefined) {
3026
- await writeFile2(join6(root, webDockerfilePath), webPlan.content);
3055
+ for (const target of dockerfileCopyTargets) {
3056
+ const plan = await planDockerfileInProject(root, target, {
3057
+ requireAnchors: true
3058
+ });
3059
+ if (plan.changed && plan.content !== undefined) {
3060
+ await writeFile2(join6(root, target.dockerfilePath), plan.content);
3061
+ }
3027
3062
  }
3028
3063
  }
3029
3064
  function rewriteCustomerDockerfile(source) {
@@ -7325,6 +7360,31 @@ async function assertRestoredEntries(root, state, backups) {
7325
7360
  }
7326
7361
  }
7327
7362
 
7363
+ // src/update/transaction-recovery-preserves.ts
7364
+ async function unresolvedPreservePaths(root, backupPath, state) {
7365
+ const unresolved = [];
7366
+ for (const path2 of state.preservePaths ?? []) {
7367
+ const entry = state.entries.find((candidate) => candidate.path === path2);
7368
+ if (!entry) {
7369
+ unresolved.push(path2);
7370
+ continue;
7371
+ }
7372
+ const expected = entry.existed ? await backupExpectation(root, backupPath, entry.path, entry.mode) : { kind: "missing" };
7373
+ if (!matchesExpected(await hashSafePath(root, path2), await safeFileMode(root, path2), expected, entry.mode)) {
7374
+ unresolved.push(path2);
7375
+ }
7376
+ }
7377
+ return unresolved;
7378
+ }
7379
+ async function backupExpectation(root, backupPath, path2, mode) {
7380
+ const backupFile = `${backupPath}/files/${path2}`;
7381
+ const content = await readSafeOptional(root, backupFile);
7382
+ if (!content || mode !== undefined && await safeFileMode(root, backupFile) !== mode) {
7383
+ throw new Error(`\u4E8B\u52A1\u5907\u4EFD\u4E0D\u5B8C\u6574\uFF0C\u65E0\u6CD5\u89E3\u9664\u4FDD\u62A4\uFF1A${path2}`);
7384
+ }
7385
+ return { kind: "hash", value: hashContent(content) };
7386
+ }
7387
+
7328
7388
  // src/update/transaction-recovery.ts
7329
7389
  async function restoreUpdateState(projectDirectory, state, options) {
7330
7390
  const root = await resolveProjectRoot(projectDirectory);
@@ -7351,8 +7411,17 @@ async function restoreUpdateState(projectDirectory, state, options) {
7351
7411
  current = await retainTransactionConflicts(root, conflicts);
7352
7412
  }
7353
7413
  }
7414
+ const retainedPreservePaths = await unresolvedPreservePaths(root, backupPath, current);
7415
+ if (retainedPreservePaths.length !== (current.preservePaths?.length ?? 0)) {
7416
+ const next = {
7417
+ ...current,
7418
+ preservePaths: retainedPreservePaths.length ? retainedPreservePaths : undefined
7419
+ };
7420
+ await publishTransactionState(root, current, next);
7421
+ current = next;
7422
+ }
7354
7423
  const preserved = new Set([
7355
- ...current.preservePaths ?? [],
7424
+ ...retainedPreservePaths,
7356
7425
  ...options?.preservePaths ?? []
7357
7426
  ]);
7358
7427
  const recoveryExpectations = new Map;
@@ -7867,23 +7936,21 @@ import { readFile as readFile17 } from "fs/promises";
7867
7936
  import { dirname as dirname6, join as join22 } from "path";
7868
7937
 
7869
7938
  // src/update/docker-copy-update-plan.ts
7870
- function deriveWebDockerfilePlan(files, snapshots, paths) {
7871
- const dockerPlan = files.find(({ path: path2 }) => path2 === webDockerfilePath);
7872
- if (!dockerPlan || dockerPlan.conflict)
7873
- return;
7874
- const dockerSource = virtualContent(dockerPlan, snapshots);
7875
- const rootPackage = virtualPathContent("package.json", files, snapshots);
7876
- if (!dockerSource || !rootPackage)
7939
+ function deriveDockerfilePlans(files, snapshots, paths, targetWorkspaceManifests) {
7940
+ const rootPackage = virtualPathContent("package.json", files, snapshots, targetWorkspaceManifests);
7941
+ if (!rootPackage)
7877
7942
  return;
7878
7943
  const rootManifest = parsePackage(rootPackage, "package.json");
7879
7944
  const workspacePatterns = rootManifest.workspaces ?? [];
7880
7945
  const packages = [];
7881
- for (const path2 of [...paths].filter((path3) => path3.endsWith("package.json"))) {
7946
+ for (const path2 of [
7947
+ ...new Set([...paths, ...targetWorkspaceManifests.keys()])
7948
+ ].filter((path3) => path3.endsWith("package.json"))) {
7882
7949
  const directory = path2 === "package.json" ? "." : path2.slice(0, -13);
7883
7950
  if (directory !== "." && !workspacePatterns.some((pattern) => matchesWorkspace(pattern, directory))) {
7884
7951
  continue;
7885
7952
  }
7886
- const content = virtualPathContent(path2, files, snapshots);
7953
+ const content = virtualPathContent(path2, files, snapshots, targetWorkspaceManifests);
7887
7954
  if (!content)
7888
7955
  continue;
7889
7956
  const manifest = parsePackage(content, path2);
@@ -7893,20 +7960,32 @@ function deriveWebDockerfilePlan(files, snapshots, paths) {
7893
7960
  dependencies: [
7894
7961
  ...Object.keys(manifest.dependencies ?? {}),
7895
7962
  ...Object.keys(manifest.devDependencies ?? {})
7896
- ]
7963
+ ],
7964
+ workspaceDependencies: Object.entries({
7965
+ ...manifest.dependencies,
7966
+ ...manifest.devDependencies
7967
+ }).filter(([, range]) => range.startsWith("workspace:")).map(([name]) => name)
7897
7968
  });
7898
7969
  }
7899
- const source = new TextDecoder().decode(dockerSource);
7900
- const next = syncWebDockerfileSource(source, packages.filter(({ directory }) => directory !== ".").map(({ directory }) => directory).sort(), workspaceDependencyClosure(packages, webEntryDirectory));
7901
- if (next === source)
7902
- return;
7903
- dockerPlan.action = "update";
7904
- dockerPlan.reason = "\u6309\u4E8B\u52A1\u5B89\u5168 workspace \u89C6\u56FE\u540C\u6B65 Docker COPY \u6E05\u5355";
7905
- dockerPlan.content = new TextEncoder().encode(next);
7970
+ for (const target of dockerfileCopyTargets) {
7971
+ const dockerPlan = files.find(({ path: path2 }) => path2 === target.dockerfilePath);
7972
+ if (!dockerPlan || dockerPlan.conflict)
7973
+ continue;
7974
+ const dockerSource = virtualContent(dockerPlan, snapshots);
7975
+ if (!dockerSource)
7976
+ continue;
7977
+ const source = new TextDecoder().decode(dockerSource);
7978
+ const next = syncDockerfileSource(source, target, packages);
7979
+ if (next === source)
7980
+ continue;
7981
+ dockerPlan.action = "update";
7982
+ dockerPlan.reason = "\u6309\u4E8B\u52A1\u5B89\u5168 workspace \u89C6\u56FE\u540C\u6B65 Docker COPY \u6E05\u5355";
7983
+ dockerPlan.content = new TextEncoder().encode(next);
7984
+ }
7906
7985
  }
7907
- function virtualPathContent(path2, files, snapshots) {
7986
+ function virtualPathContent(path2, files, snapshots, targetWorkspaceManifests) {
7908
7987
  const plan = files.find((item) => item.path === path2);
7909
- return plan ? virtualContent(plan, snapshots) : snapshots.get(path2);
7988
+ return plan ? virtualContent(plan, snapshots) : snapshots.get(path2) ?? targetWorkspaceManifests.get(path2);
7910
7989
  }
7911
7990
  function virtualContent(plan, snapshots) {
7912
7991
  if (plan.action === "delete")
@@ -9014,7 +9093,9 @@ var recipes = [
9014
9093
  { id: "starter-0.3.5-to-0.3.6", from: "0.3.5", to: "0.3.6" },
9015
9094
  { id: "starter-0.3.6-to-0.3.7", from: "0.3.6", to: "0.3.7" },
9016
9095
  { id: "starter-0.3.7-to-0.3.8", from: "0.3.7", to: "0.3.8" },
9017
- { id: "starter-0.3.8-to-0.3.9", from: "0.3.8", to: "0.3.9" }
9096
+ { id: "starter-0.3.8-to-0.3.9", from: "0.3.8", to: "0.3.9" },
9097
+ { id: "starter-0.3.9-to-0.3.10", from: "0.3.9", to: "0.3.10" },
9098
+ { id: "starter-0.3.10-to-0.3.11", from: "0.3.10", to: "0.3.11" }
9018
9099
  ];
9019
9100
  function resolveRecipeChain(sourceVersion, targetVersion) {
9020
9101
  if (sourceVersion === targetVersion)
@@ -9112,7 +9193,11 @@ async function createUpdatePlan(request, artifacts) {
9112
9193
  manageGeneratedProjectOwned: request.targetModules !== undefined,
9113
9194
  forcePlatformBaseline: request.forcePlatformBaseline === true
9114
9195
  });
9115
- deriveWebDockerfilePlan(files, projectSnapshots, new Set([...paths, ...workspaceSnapshot.manifests.keys()]));
9196
+ deriveDockerfilePlans(files, projectSnapshots, new Set([
9197
+ ...paths,
9198
+ ...workspaceSnapshot.manifests.keys(),
9199
+ ...targetWorkspaceSnapshot.manifests.keys()
9200
+ ]), targetWorkspaceSnapshot.manifests);
9116
9201
  for (const file of files) {
9117
9202
  file.expectedProjectMode = projectModes.get(file.path);
9118
9203
  if (file.action === "create" || file.action === "update") {
@@ -10217,11 +10302,13 @@ class DefaultStarterUpdater {
10217
10302
  #execute;
10218
10303
  #beforeTransactionFinalize;
10219
10304
  #finalizeTransaction;
10305
+ #skipInstall;
10220
10306
  constructor(dependencies = {}) {
10221
10307
  this.#artifacts = dependencies.artifacts ?? new PublishedArtifactProvider;
10222
10308
  this.#execute = dependencies.execute ?? runCommand;
10223
10309
  this.#beforeTransactionFinalize = dependencies.beforeTransactionFinalize;
10224
10310
  this.#finalizeTransaction = dependencies.finalizeTransaction ?? finalizeOwnedTransaction;
10311
+ this.#skipInstall = dependencies.skipInstall ?? false;
10225
10312
  }
10226
10313
  async plan(input) {
10227
10314
  return createUpdatePlan(input, this.#artifacts);
@@ -10241,16 +10328,34 @@ class DefaultStarterUpdater {
10241
10328
  const steps = [];
10242
10329
  let verificationExpectationsFrozen = false;
10243
10330
  try {
10244
- const dockerSync = await planWebDockerfileInProject(result2.plan.projectDirectory, { requireAnchors: true });
10245
- if (dockerSync.changed) {
10246
- throw new TransactionCasError("Web Dockerfile COPY \u6E05\u5355\u672A\u5728\u66F4\u65B0\u8BA1\u5212\u4E2D\u540C\u6B65", "apps/web/Dockerfile");
10331
+ const dockerSync = await Promise.all(dockerfileCopyTargets.map((target) => planDockerfileInProject(result2.plan.projectDirectory, target, {
10332
+ requireAnchors: true
10333
+ }).then((sync) => ({ target, sync }))));
10334
+ const staleDockerfile = dockerSync.find(({ sync }) => sync.changed);
10335
+ if (staleDockerfile) {
10336
+ const plannedDockerfile = result2.plan.files.find(({ path: path2 }) => path2 === staleDockerfile.target.dockerfilePath);
10337
+ if (plannedDockerfile && plannedDockerfile.action !== "preserve" && staleDockerfile.sync.content !== undefined) {
10338
+ const content = new TextEncoder().encode(staleDockerfile.sync.content);
10339
+ await writeOwnedTransactionFile(result2.plan.projectDirectory, plannedDockerfile.path, content, expectedForPath(result2, plannedDockerfile.path));
10340
+ plannedDockerfile.action = "update";
10341
+ plannedDockerfile.content = content;
10342
+ replaceExpectations(result2, [
10343
+ expectationForContent(plannedDockerfile.path, content)
10344
+ ]);
10345
+ } else {
10346
+ throw new TransactionCasError("Dockerfile COPY \u6E05\u5355\u672A\u5728\u66F4\u65B0\u8BA1\u5212\u4E2D\u540C\u6B65", staleDockerfile.target.dockerfilePath);
10347
+ }
10247
10348
  }
10248
10349
  steps.push({
10249
- name: "\u540C\u6B65 Web Dockerfile workspace COPY \u6E05\u5355",
10250
- status: dockerSync.synced ? "passed" : "skipped"
10350
+ name: "\u540C\u6B65 Server \u4E0E Web Dockerfile workspace COPY \u6E05\u5355",
10351
+ status: dockerSync.every(({ sync }) => sync.synced) ? "passed" : "skipped"
10251
10352
  });
10252
- await this.#execute("bun", ["install", "--force"], result2.plan.projectDirectory);
10253
- steps.push({ name: "bun install --force", status: "passed" });
10353
+ if (this.#skipInstall) {
10354
+ steps.push({ name: "bun install --force", status: "skipped" });
10355
+ } else {
10356
+ await this.#execute("bun", ["install", "--force"], result2.plan.projectDirectory);
10357
+ steps.push({ name: "bun install --force", status: "passed" });
10358
+ }
10254
10359
  const stabilized = await stabilizeManagedContent(result2, this.#execute, async (path2, content) => {
10255
10360
  await writeOwnedTransactionFile(result2.plan.projectDirectory, path2, content, expectedForPath(result2, path2));
10256
10361
  replaceExpectations(result2, [expectationForContent(path2, content)]);
@@ -10650,36 +10755,43 @@ async function runLifecycleCommand(args) {
10650
10755
  return true;
10651
10756
  }
10652
10757
  if (command === "sync-docker") {
10653
- const result2 = await planWebDockerfileInProject(projectDirectory, {
10654
- requireAnchors: true
10655
- });
10656
- if (!result2.synced) {
10657
- throw new Error("\u9879\u76EE\u7F3A\u5C11 apps/web/Dockerfile\uFF0C\u65E0\u6CD5\u540C\u6B65 COPY \u6E05\u5355");
10758
+ if (args.includes("--help") || args.includes("-h")) {
10759
+ console.log("\u7528\u6CD5\uFF1Acreate-windy sync-docker [--cwd <project-directory>]");
10760
+ return true;
10658
10761
  }
10659
- if (result2.changed && result2.content !== undefined) {
10660
- await assertWorkspaceMembership(projectDirectory, result2.membershipExpectations);
10762
+ const plans = await Promise.all(dockerfileCopyTargets.map((target) => planDockerfileInProject(projectDirectory, target, {
10763
+ requireAnchors: true
10764
+ }).then((result2) => ({ target, result: result2 }))));
10765
+ if (plans.some(({ result: result2 }) => !result2.synced)) {
10766
+ throw new Error("\u9879\u76EE\u7F3A\u5C11\u53D7\u652F\u6301\u7684 Dockerfile\uFF0C\u65E0\u6CD5\u540C\u6B65 COPY \u6E05\u5355");
10767
+ }
10768
+ const changed = plans.filter(({ result: result2 }) => result2.changed && result2.content !== undefined);
10769
+ if (changed.length) {
10770
+ const membershipExpectations = plans.flatMap(({ result: result2 }) => result2.membershipExpectations);
10771
+ await assertWorkspaceMembership(projectDirectory, membershipExpectations);
10661
10772
  const state = await applyMetadataTransaction({
10662
10773
  id: `sync-docker-${Date.now()}`,
10663
10774
  projectDirectory,
10664
- guards: result2.expectations,
10665
- writes: [{ path: "apps/web/Dockerfile", content: result2.content }]
10775
+ guards: plans.flatMap(({ result: result2 }) => result2.expectations),
10776
+ writes: changed.map(({ target, result: result2 }) => ({
10777
+ path: target.dockerfilePath,
10778
+ content: result2.content
10779
+ }))
10666
10780
  });
10667
10781
  await finalizeOwnedTransaction({
10668
10782
  projectDirectory,
10669
10783
  ownerToken: state.ownerToken,
10670
- expectations: [
10671
- {
10672
- path: "apps/web/Dockerfile",
10673
- expected: {
10674
- kind: "hash",
10675
- value: hashContent(result2.content)
10676
- }
10784
+ expectations: changed.map(({ target, result: result2 }) => ({
10785
+ path: target.dockerfilePath,
10786
+ expected: {
10787
+ kind: "hash",
10788
+ value: hashContent(result2.content)
10677
10789
  }
10678
- ],
10679
- workspaceMembershipExpectations: result2.membershipExpectations
10790
+ })),
10791
+ workspaceMembershipExpectations: membershipExpectations
10680
10792
  });
10681
10793
  }
10682
- console.log(result2.changed ? "\u5DF2\u540C\u6B65 apps/web/Dockerfile workspace COPY \u6E05\u5355" : "apps/web/Dockerfile workspace COPY \u6E05\u5355\u5DF2\u662F\u6700\u65B0");
10794
+ console.log(changed.length ? "\u5DF2\u540C\u6B65 Server \u4E0E Web Dockerfile workspace COPY \u6E05\u5355" : "Server \u4E0E Web Dockerfile workspace COPY \u6E05\u5355\u5DF2\u662F\u6700\u65B0");
10683
10795
  return true;
10684
10796
  }
10685
10797
  if (command === "doctor") {
@@ -10757,7 +10869,9 @@ async function runUpdate(args, projectDirectory) {
10757
10869
  console.log(`\u9879\u76EE\u5DF2\u7ECF\u662F ${target}\uFF0C\u65E0\u9700\u66F4\u65B0`);
10758
10870
  return;
10759
10871
  }
10760
- const updater = new DefaultStarterUpdater;
10872
+ const updater = new DefaultStarterUpdater({
10873
+ skipInstall: args.includes("--skip-install")
10874
+ });
10761
10875
  const plan = await updater.plan({
10762
10876
  projectDirectory,
10763
10877
  targetVersion: target,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-windy",
3
- "version": "0.3.9",
3
+ "version": "0.3.11",
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": "fe9c5197b083b0d4ff03f9550043d96a392992a1",
4
- "generatorVersion": "0.3.9",
3
+ "templateCommit": "3adb3c8663d8b57b769e4abfef0f598c70241cde",
4
+ "generatorVersion": "0.3.11",
5
5
  "modules": [
6
6
  {
7
7
  "name": "system",
@@ -4,10 +4,11 @@ FROM oven/bun:1.3.14-alpine AS deps
4
4
  WORKDIR /app
5
5
 
6
6
  COPY package.json bun.lock ./
7
- COPY apps/server/package.json apps/server/package.json
8
- COPY apps/web/package.json apps/web/package.json
7
+ # windy-copy:deps begin
9
8
  COPY apps/license/package.json apps/license/package.json
9
+ COPY apps/server/package.json apps/server/package.json
10
10
  COPY apps/signing-service/package.json apps/signing-service/package.json
11
+ COPY apps/web/package.json apps/web/package.json
11
12
  COPY packages/ai-client/package.json packages/ai-client/package.json
12
13
  COPY packages/config/package.json packages/config/package.json
13
14
  COPY packages/create-windy/package.json packages/create-windy/package.json
@@ -20,6 +21,7 @@ COPY packages/modules/package.json packages/modules/package.json
20
21
  COPY packages/server-sdk/package.json packages/server-sdk/package.json
21
22
  COPY packages/shared/package.json packages/shared/package.json
22
23
  COPY packages/storage/package.json packages/storage/package.json
24
+ # windy-copy:deps end
23
25
  RUN bun install --frozen-lockfile
24
26
 
25
27
  FROM deps AS runner
@@ -51,6 +51,8 @@
51
51
  "ops:release": "bun run scripts/production-release.ts",
52
52
  "test:merge": "bun run scripts/merge-gate.ts",
53
53
  "release:verify": "bun run scripts/release-verify.ts",
54
+ "release:candidate": "bun run scripts/release-candidate.ts",
55
+ "release:verify:full": "bun run scripts/release-verify.ts --full",
54
56
  "test:packages:pack": "bun run scripts/platform-package-release.ts",
55
57
  "test:agent": "uv run --directory apps/agent-server pytest",
56
58
  "test:document": "uv run --directory apps/document-server pytest",