create-windy 0.5.1 → 0.5.2

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
@@ -2563,15 +2563,25 @@ async function materializeSelectedModules(targetDirectory, selectedNames) {
2563
2563
  ]),
2564
2564
  ...moduleDistributionCatalog.filter(({ databaseLineageOwner }) => databaseLineageOwner === "module").flatMap(({ databaseTables }) => databaseTables)
2565
2565
  ], removed.flatMap(({ databaseStatementTokens }) => databaseStatementTokens));
2566
- const removedRoots = removed.flatMap((manifest) => [
2566
+ const removedRoots = collapseRemovalRoots(removed.flatMap((manifest) => [
2567
2567
  ...manifest.packages,
2568
2568
  ...manifest.fileRoots,
2569
2569
  ...manifest.documentation,
2570
2570
  ...manifest.schemaFiles
2571
- ]);
2571
+ ]));
2572
2572
  await Promise.all([...new Set(removedRoots)].map((path) => rm3(join7(targetDirectory, path), { recursive: true, force: true })));
2573
2573
  await pruneWorkspaceReferences(targetDirectory, removedPackageNames, removedRoots);
2574
2574
  }
2575
+ function collapseRemovalRoots(paths) {
2576
+ const roots = [];
2577
+ for (const path of [...new Set(paths)].sort((left, right) => left.length - right.length || left.localeCompare(right))) {
2578
+ if (roots.some((root) => path === root || path.startsWith(`${root}/`))) {
2579
+ continue;
2580
+ }
2581
+ roots.push(path);
2582
+ }
2583
+ return roots.sort();
2584
+ }
2575
2585
  async function stripModuleBlocks(root, selected) {
2576
2586
  for (const path of await collectFiles2(root)) {
2577
2587
  if (!textExtensions.has(extname(path)))
@@ -7574,6 +7584,11 @@ var recipes = [
7574
7584
  id: "starter-0.5.0-to-0.5.1",
7575
7585
  from: "0.5.0",
7576
7586
  to: "0.5.1"
7587
+ },
7588
+ {
7589
+ id: "starter-0.5.1-to-0.5.2",
7590
+ from: "0.5.1",
7591
+ to: "0.5.2"
7577
7592
  }
7578
7593
  ];
7579
7594
  function resolveRecipeChain(sourceVersion, targetVersion) {
@@ -8457,6 +8472,146 @@ import { join as join23 } from "path";
8457
8472
  import { mkdtemp as mkdtemp2, rm as rm6, writeFile as writeFile12 } from "fs/promises";
8458
8473
  import { tmpdir as tmpdir2 } from "os";
8459
8474
  import { join as join22 } from "path";
8475
+
8476
+ // src/update/merge-convergent-additions.ts
8477
+ async function reconcileConvergentAdditions(input) {
8478
+ const [oursDiff, theirsDiff] = await Promise.all([
8479
+ diff(input.root, input.basePath, input.oursPath),
8480
+ diff(input.root, input.basePath, input.theirsPath)
8481
+ ]);
8482
+ if (oursDiff === undefined || theirsDiff === undefined)
8483
+ return;
8484
+ const oursAdditions = pureAdditions(oursDiff);
8485
+ const theirsAdditions = pureAdditions(theirsDiff);
8486
+ const oursByContent = new Map;
8487
+ for (const addition of oursAdditions) {
8488
+ const key = addition.lines.join(`
8489
+ `);
8490
+ oursByContent.set(key, [...oursByContent.get(key) ?? [], addition]);
8491
+ }
8492
+ const decode = (content) => new TextDecoder().decode(content);
8493
+ const baseLines = decode(input.base).split(`
8494
+ `);
8495
+ const oursLines = decode(input.ours).split(`
8496
+ `);
8497
+ const theirsLines = decode(input.theirs).split(`
8498
+ `);
8499
+ const mergedLines = input.merged.split(`
8500
+ `);
8501
+ const convergent = theirsAdditions.flatMap((addition) => {
8502
+ if (!isSubstantial(addition.lines) || !isNamedClassMethod(addition.lines)) {
8503
+ return [];
8504
+ }
8505
+ const key = addition.lines.join(`
8506
+ `);
8507
+ const matchingOurs = oursByContent.get(key);
8508
+ if (matchingOurs?.length !== 1)
8509
+ return [];
8510
+ if (theirsAdditions.filter((candidate2) => candidate2.lines.join(`
8511
+ `) === key).length !== 1) {
8512
+ return [];
8513
+ }
8514
+ const oursContainer = enclosingClass(oursLines, matchingOurs[0]);
8515
+ const theirsContainer = enclosingClass(theirsLines, addition);
8516
+ if (!oursContainer || oursContainer !== theirsContainer)
8517
+ return [];
8518
+ return countSequence(baseLines, addition.lines) === 0 && countSequence(oursLines, addition.lines) === 1 && countSequence(theirsLines, addition.lines) === 1 && countSequence(mergedLines, addition.lines) > 1 ? [{ ours: matchingOurs[0], theirs: addition }] : [];
8519
+ });
8520
+ if (convergent.length !== 1)
8521
+ return;
8522
+ const candidate = convergent[0];
8523
+ if (!candidate)
8524
+ return;
8525
+ const oursWithout = withoutAddition(oursLines, candidate.ours);
8526
+ const theirsWithout = withoutAddition(theirsLines, candidate.theirs);
8527
+ if (!oursWithout || !theirsWithout || !sameLines(oursWithout, theirsWithout)) {
8528
+ return;
8529
+ }
8530
+ return input.ours;
8531
+ }
8532
+ async function diff(root, basePath, branchPath) {
8533
+ const result2 = await captureProcess("git", ["diff", "--no-index", "--unified=0", "--no-color", basePath, branchPath], root);
8534
+ return result2.code === 0 || result2.code === 1 ? result2.stdout : undefined;
8535
+ }
8536
+ function pureAdditions(diff2) {
8537
+ const lines = diff2.split(`
8538
+ `);
8539
+ const additions = [];
8540
+ for (let index = 0;index < lines.length; index += 1) {
8541
+ const match = /^@@ -\d+(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(lines[index] ?? "");
8542
+ if (!match)
8543
+ continue;
8544
+ const oldCount = match[1] === undefined ? 1 : Number(match[1]);
8545
+ const start = Number(match[2]);
8546
+ const newCount = match[3] === undefined ? 1 : Number(match[3]);
8547
+ if (oldCount !== 0 || newCount === 0)
8548
+ continue;
8549
+ const added = [];
8550
+ for (let cursor = index + 1;cursor < lines.length; cursor += 1) {
8551
+ const line = lines[cursor] ?? "";
8552
+ if (line.startsWith("@@ "))
8553
+ break;
8554
+ if (line.startsWith("+"))
8555
+ added.push(line.slice(1));
8556
+ }
8557
+ if (added.length === newCount)
8558
+ additions.push({ start, lines: added });
8559
+ }
8560
+ return additions;
8561
+ }
8562
+ function isSubstantial(lines) {
8563
+ return lines.filter((line) => line.trim()).length >= 3 && lines.join(`
8564
+ `).length >= 32;
8565
+ }
8566
+ function isNamedClassMethod(lines) {
8567
+ const first = lines.find((line) => line.trim())?.trim() ?? "";
8568
+ const last = [...lines].reverse().find((line) => line.trim())?.trim() ?? "";
8569
+ return /^(?:(?:public|protected|private|static|abstract|override|async|declare|get|set)\s+)*(?:\*\s*)?[A-Za-z_$][\w$]*\s*(?:<[^>{}]*>)?\s*\(/.test(first) && lines.some((line) => line.includes("{")) && /^}\s*;?$/.test(last);
8570
+ }
8571
+ function enclosingClass(lines, addition) {
8572
+ const memberIndent = leadingWhitespace(addition.lines.find((line) => line.trim()) ?? "");
8573
+ for (let index = addition.start - 2;index >= 0; index -= 1) {
8574
+ const line = lines[index] ?? "";
8575
+ if (!line.trim() || leadingWhitespace(line) >= memberIndent)
8576
+ continue;
8577
+ const match = /^(\s*)(?:(?:export|default|abstract|declare)\s+)*class\s+([A-Za-z_$][\w$]*)\b/.exec(line);
8578
+ if (!match)
8579
+ return;
8580
+ const name = match[2] ?? "";
8581
+ const ordinal = lines.slice(0, index + 1).filter((candidate) => new RegExp(`^\\s*(?:(?:export|default|abstract|declare)\\s+)*class\\s+${escapeRegExp2(name)}\\b`).test(candidate)).length;
8582
+ return `${name}#${ordinal}`;
8583
+ }
8584
+ }
8585
+ function leadingWhitespace(line) {
8586
+ return /^\s*/.exec(line)?.[0].length ?? 0;
8587
+ }
8588
+ function escapeRegExp2(value) {
8589
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8590
+ }
8591
+ function countSequence(lines, sequence) {
8592
+ let count = 0;
8593
+ for (let index = 0;index <= lines.length - sequence.length; index += 1) {
8594
+ if (sameLines(lines.slice(index, index + sequence.length), sequence)) {
8595
+ count += 1;
8596
+ }
8597
+ }
8598
+ return count;
8599
+ }
8600
+ function withoutAddition(lines, addition) {
8601
+ const index = addition.start - 1;
8602
+ if (!sameLines(lines.slice(index, index + addition.lines.length), addition.lines)) {
8603
+ return;
8604
+ }
8605
+ return [
8606
+ ...lines.slice(0, index),
8607
+ ...lines.slice(index + addition.lines.length)
8608
+ ];
8609
+ }
8610
+ function sameLines(left, right) {
8611
+ return left.length === right.length && left.every((line, index) => line === right[index]);
8612
+ }
8613
+
8614
+ // src/update/merge.ts
8460
8615
  async function mergeTextFile(base, ours, theirs) {
8461
8616
  const root = await mkdtemp2(join22(tmpdir2(), "windy-merge-"));
8462
8617
  try {
@@ -8470,6 +8625,19 @@ async function mergeTextFile(base, ours, theirs) {
8470
8625
  ]);
8471
8626
  const result2 = await captureProcess("git", ["merge-file", "-p", "--diff3", oursPath, basePath, theirsPath], root);
8472
8627
  if (result2.code === 0) {
8628
+ const reconciledContent = await reconcileConvergentAdditions({
8629
+ root,
8630
+ basePath,
8631
+ oursPath,
8632
+ theirsPath,
8633
+ base,
8634
+ ours,
8635
+ theirs,
8636
+ merged: result2.stdout
8637
+ });
8638
+ if (reconciledContent !== undefined) {
8639
+ return { content: reconciledContent };
8640
+ }
8473
8641
  return { content: new TextEncoder().encode(result2.stdout) };
8474
8642
  }
8475
8643
  if (result2.code === 1) {
@@ -8866,6 +9034,33 @@ function resolveModuleRecipeIds(request) {
8866
9034
  return lifecycle.updatedModules.flatMap((name) => catalog.get(name).updateRecipes);
8867
9035
  }
8868
9036
 
9037
+ // src/update/planner-project-owned-tests.ts
9038
+ var testSuffixes = [
9039
+ ".webtest.ts",
9040
+ ".webtest.tsx",
9041
+ ".test.ts",
9042
+ ".test.tsx"
9043
+ ];
9044
+ var sourceExtensions = [".vue", ".ts", ".tsx", ".js", ".jsx"];
9045
+ function preserveTestsForExistingProjectOwnedSources(files, sourceEntries) {
9046
+ const projectOwnedSourcePaths = new Set([...sourceEntries.values()].filter(({ ownership }) => ownership === "project-owned").map(({ path: path2 }) => path2));
9047
+ for (const file of files) {
9048
+ if (file.ownership !== "project-owned" || file.action !== "create" || !hasExistingSourceForTest(file.path, projectOwnedSourcePaths)) {
9049
+ continue;
9050
+ }
9051
+ file.action = "preserve";
9052
+ file.reason = "\u9879\u76EE\u81EA\u6709\u5B9E\u73B0\u5DF2\u5B58\u5728\uFF0C\u4E0D\u65B0\u589E\u4E0A\u6E38\u884C\u4E3A\u6D4B\u8BD5";
9053
+ delete file.content;
9054
+ }
9055
+ }
9056
+ function hasExistingSourceForTest(path2, sourcePaths) {
9057
+ const suffix = testSuffixes.find((candidate) => path2.endsWith(candidate));
9058
+ if (!suffix)
9059
+ return false;
9060
+ const stem = path2.slice(0, -suffix.length);
9061
+ return sourceExtensions.some((extension) => sourcePaths.has(`${stem}${extension}`));
9062
+ }
9063
+
8869
9064
  // src/update/planner-snapshots.ts
8870
9065
  import { readFile as readFile20, stat as stat2 } from "fs/promises";
8871
9066
  import { join as join24 } from "path";
@@ -9025,6 +9220,7 @@ async function createUpdatePlan(request, artifacts) {
9025
9220
  manageGeneratedProjectOwned: request.targetModules !== undefined,
9026
9221
  forcePlatformBaseline: request.forcePlatformBaseline === true
9027
9222
  });
9223
+ preserveTestsForExistingProjectOwnedSources(files, sourceEntries);
9028
9224
  await deriveDockerfilePlans(files, projectSnapshots, new Set([
9029
9225
  ...paths,
9030
9226
  ...workspaceSnapshot.manifests.keys(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-windy",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
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": "25b98ed98562c416c6dcfe48940cd0cae43252d4",
4
- "generatorVersion": "0.5.1",
3
+ "templateCommit": "b4fdd1a323b9445461c149ce93191292283bce6b",
4
+ "generatorVersion": "0.5.2",
5
5
  "modules": [
6
6
  {
7
7
  "name": "system",
@@ -1,7 +1,26 @@
1
1
  <script setup lang="ts">
2
- import type { OperationSnapshot } from "@/services/operations-api";
2
+ interface GpuMonitorSnapshot {
3
+ status: "available" | "not-detected" | "unavailable";
4
+ provider: "NVIDIA";
5
+ message: string;
6
+ devices: Array<{
7
+ index: number;
8
+ uuid: string;
9
+ name: string;
10
+ usagePercent: number | null;
11
+ memoryUsedBytes: number | null;
12
+ memoryTotalBytes: number | null;
13
+ memoryUsagePercent: number | null;
14
+ temperatureCelsius: number | null;
15
+ processes: Array<{
16
+ pid: number;
17
+ name: string;
18
+ usedMemoryBytes: number | null;
19
+ }>;
20
+ }>;
21
+ }
3
22
 
4
- defineProps<{ gpu: OperationSnapshot["gpuMonitor"] }>();
23
+ defineProps<{ gpu: GpuMonitorSnapshot }>();
5
24
 
6
25
  function formatBytes(value: number | null) {
7
26
  if (value === null) return "未知";