create-windy 0.6.8 → 0.6.10
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 +4 -1
- package/dist/cli.js +1012 -329
- package/package.json +1 -1
- package/template/.windy-template.json +3 -3
- package/template/README.md +8 -2
- package/template/apps/agent-server/src/southwind_agent_server/contracts.py +2 -0
- package/template/apps/agent-server/tests/test_multimodal.py +30 -0
- package/template/apps/agent-server/tests/test_postgres_store.py +1 -0
- package/template/apps/agent-server/tests/test_sqlite_store.py +1 -0
- package/template/apps/server/src/agent/remote-runtime.test.ts +1 -0
- package/template/apps/server/src/agent/run-audit.ts +1 -0
- package/template/apps/server/src/agent/run-contracts.ts +1 -0
- package/template/apps/server/src/agent/run-facade.ts +2 -2
- package/template/apps/server/src/agent/run-operation-registry.ts +7 -0
- package/template/apps/server/src/agent/run-output-schema.ts +15 -0
- package/template/apps/server/src/agent/run-release.ts +11 -0
- package/template/apps/server/src/agent/supervisor-output-schema.test.ts +95 -0
- package/template/apps/server/src/agent/vision-input.ts +37 -2
- package/template/apps/server/src/license/pairing-http.ts +138 -0
- package/template/apps/server/src/license/pairing-routes.test.ts +282 -0
- package/template/apps/server/src/license/pairing-routes.ts +257 -0
- package/template/apps/server/src/license/pairing-service.test.ts +320 -0
- package/template/apps/server/src/license/pairing-service.ts +321 -0
- package/template/apps/server/src/license/restriction.test.ts +11 -0
- package/template/apps/server/src/license/restriction.ts +5 -0
- package/template/apps/server/src/license/routes.ts +8 -1
- package/template/apps/server/src/license/runtime-service.ts +20 -0
- package/template/apps/server/src/runtime-development.ts +1 -0
- package/template/apps/web/package.json +6 -4
- package/template/apps/web/src/components/license/LicensePairingCard.vue +177 -0
- package/template/apps/web/src/components/license/LicensePairingCard.webtest.ts +113 -0
- package/template/apps/web/src/composables/useLicensePairing.ts +168 -0
- package/template/apps/web/src/composables/useLicenseRuntime.ts +11 -0
- package/template/apps/web/src/layout/AppSidebar.vue +1 -0
- package/template/apps/web/src/pages/license/LicensePage.vue +8 -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/apps/web/src/services/license-api.ts +60 -0
- package/template/apps/web/src/style.webtest.ts +5 -6
- package/template/docs/architecture/ai-runtime.md +5 -0
- package/template/docs/development/business-web-routes.md +3 -1
- package/template/docs/development/ui-component-gallery.md +44 -0
- package/template/docs/license/license-pairing-activation.md +67 -0
- package/template/docs/operations/incremental-delivery.md +10 -9
- package/template/docs/platform/agent-supervisor-output-contract.md +80 -0
- package/template/packages/ai-client/package.json +1 -1
- package/template/packages/ai-client/src/agent/contracts/final-answer.test.ts +67 -0
- package/template/packages/ai-client/src/agent/contracts/final-answer.ts +53 -0
- package/template/packages/ai-client/src/agent/contracts/index.ts +1 -0
- package/template/packages/modules/index.ts +1 -0
- 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 +6 -2
- package/template/packages/modules/src/system-agent-supervisor.test.ts +48 -0
- package/template/packages/modules/src/system-agent-supervisor.ts +101 -0
- package/template/packages/modules/src/system-api-control-plane.ts +37 -0
- package/template/packages/modules/src/system-features.ts +5 -0
- package/template/packages/modules/src/system-license-pairing.test.ts +44 -0
- package/template/packages/modules/src/system-module-catalog.ts +10 -19
- package/template/packages/modules/src/system-module-menu-selection.ts +15 -0
- package/template/packages/modules/src/system-module-schema-catalog.ts +14 -0
- package/template/packages/modules/src/system-modules.ts +13 -0
- package/template/packages/modules/src/system-permissions.ts +2 -0
- package/template/packages/modules/src/system-ui-components.test.ts +36 -0
- package/template/packages/server-sdk/index.ts +5 -0
- package/template/packages/server-sdk/package.json +3 -1
- package/template/packages/server-sdk/src/ai-operation-registration.ts +4 -0
- package/template/packages/server-sdk/src/system-agent-supervisor.test.ts +87 -0
- package/template/packages/server-sdk/src/system-agent-supervisor.ts +89 -0
package/dist/cli.js
CHANGED
|
@@ -388,6 +388,7 @@ var optionalModuleManifests = [
|
|
|
388
388
|
"docs/platform/agent-run-attestation.md",
|
|
389
389
|
"docs/platform/agent-runtime.md",
|
|
390
390
|
"docs/platform/agent-runtime-observability.md",
|
|
391
|
+
"docs/platform/agent-supervisor-output-contract.md",
|
|
391
392
|
"docs/platform/agent-tools.md",
|
|
392
393
|
"docs/platform/agent-tool-approval.md",
|
|
393
394
|
"docs/platform/agent-tool-sandbox.md",
|
|
@@ -653,7 +654,17 @@ var platformModules = [
|
|
|
653
654
|
{
|
|
654
655
|
sourceName: "@southwind-ai/license",
|
|
655
656
|
name: "@southwind-ai/license",
|
|
656
|
-
version: "^0.1.
|
|
657
|
+
version: "^0.1.9"
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
sourceName: "qrcode",
|
|
661
|
+
name: "qrcode",
|
|
662
|
+
version: "^1.5.4"
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
sourceName: "@types/qrcode",
|
|
666
|
+
name: "@types/qrcode",
|
|
667
|
+
version: "^1.5.6"
|
|
657
668
|
}
|
|
658
669
|
],
|
|
659
670
|
fileRoots: [
|
|
@@ -663,11 +674,16 @@ var platformModules = [
|
|
|
663
674
|
"apps/web/src/composables/useLicenseReminderRefresh.ts",
|
|
664
675
|
"apps/web/src/composables/useLicenseReminderRefresh.webtest.ts",
|
|
665
676
|
"apps/web/src/composables/useLicenseRuntime.ts",
|
|
677
|
+
"apps/web/src/composables/useLicensePairing.ts",
|
|
666
678
|
"apps/web/src/services/license-api.ts",
|
|
667
679
|
"apps/web/src/pages/dashboard/dashboard-presenter.webtest.ts",
|
|
668
|
-
"apps/web/src/router/index.webtest.ts"
|
|
680
|
+
"apps/web/src/router/index.webtest.ts",
|
|
681
|
+
"packages/modules/src/system-license-pairing.test.ts"
|
|
682
|
+
],
|
|
683
|
+
documentation: [
|
|
684
|
+
"docs/license/license-offline-activation-code.md",
|
|
685
|
+
"docs/license/license-pairing-activation.md"
|
|
669
686
|
],
|
|
670
|
-
documentation: ["docs/license/license-offline-activation-code.md"],
|
|
671
687
|
schemaFiles: [
|
|
672
688
|
"packages/database/src/schema/license-legacy.ts",
|
|
673
689
|
"packages/database/src/schema/license-v1.ts"
|
|
@@ -1309,11 +1325,11 @@ import {
|
|
|
1309
1325
|
rm as rm4,
|
|
1310
1326
|
writeFile as writeFile9
|
|
1311
1327
|
} from "fs/promises";
|
|
1312
|
-
import { basename as
|
|
1328
|
+
import { basename as basename6, extname as extname3, join as join12 } from "path";
|
|
1313
1329
|
|
|
1314
1330
|
// src/customer-docker.ts
|
|
1315
1331
|
import { readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
|
|
1316
|
-
import { join as
|
|
1332
|
+
import { join as join5 } from "path";
|
|
1317
1333
|
|
|
1318
1334
|
// src/managed-files.ts
|
|
1319
1335
|
import { createHash } from "crypto";
|
|
@@ -1533,37 +1549,38 @@ function matchesRoot(path, roots) {
|
|
|
1533
1549
|
}
|
|
1534
1550
|
|
|
1535
1551
|
// src/update/transaction-paths.ts
|
|
1536
|
-
import { constants as
|
|
1552
|
+
import { constants as constants4, closeSync as closeSync5 } from "fs";
|
|
1537
1553
|
import { realpath, stat } from "fs/promises";
|
|
1538
|
-
import { dirname as
|
|
1554
|
+
import { dirname as dirname3, resolve as resolve3 } from "path";
|
|
1539
1555
|
|
|
1540
1556
|
// src/update/transaction-native.ts
|
|
1541
1557
|
import {
|
|
1542
|
-
constants,
|
|
1543
|
-
closeSync,
|
|
1558
|
+
constants as constants2,
|
|
1559
|
+
closeSync as closeSync2,
|
|
1544
1560
|
fchmodSync,
|
|
1545
|
-
fstatSync,
|
|
1561
|
+
fstatSync as fstatSync2,
|
|
1546
1562
|
fsyncSync as fsyncSync2,
|
|
1547
1563
|
readFileSync,
|
|
1548
1564
|
writeSync
|
|
1549
1565
|
} from "fs";
|
|
1550
|
-
import { open as
|
|
1566
|
+
import { open as open3 } from "fs/promises";
|
|
1551
1567
|
import {
|
|
1552
|
-
basename as
|
|
1553
|
-
dirname,
|
|
1568
|
+
basename as basename3,
|
|
1569
|
+
dirname as dirname2,
|
|
1554
1570
|
isAbsolute,
|
|
1555
|
-
relative as
|
|
1571
|
+
relative as relative3,
|
|
1556
1572
|
resolve as resolve2,
|
|
1557
1573
|
sep as sep2
|
|
1558
1574
|
} from "path";
|
|
1559
|
-
import { dlopen, FFIType, ptr, read } from "bun:ffi";
|
|
1575
|
+
import { dlopen as dlopen2, FFIType as FFIType2, ptr as ptr2, read } from "bun:ffi";
|
|
1560
1576
|
|
|
1561
1577
|
// src/update/transaction-native-durability.ts
|
|
1562
1578
|
import { fsyncSync } from "fs";
|
|
1563
1579
|
var observer;
|
|
1564
1580
|
function syncMutatedDirectory(operation, directoryFd) {
|
|
1565
1581
|
observer?.({ operation, phase: "mutation", directoryFd });
|
|
1566
|
-
|
|
1582
|
+
if (process.platform !== "win32")
|
|
1583
|
+
fsyncSync(directoryFd);
|
|
1567
1584
|
observer?.({ operation, phase: "directory-fsync", directoryFd });
|
|
1568
1585
|
}
|
|
1569
1586
|
|
|
@@ -1624,38 +1641,305 @@ function libcCandidates() {
|
|
|
1624
1641
|
];
|
|
1625
1642
|
}
|
|
1626
1643
|
|
|
1644
|
+
// src/update/transaction-native-windows.ts
|
|
1645
|
+
import {
|
|
1646
|
+
closeSync,
|
|
1647
|
+
constants,
|
|
1648
|
+
fstatSync,
|
|
1649
|
+
linkSync,
|
|
1650
|
+
lstatSync,
|
|
1651
|
+
mkdirSync,
|
|
1652
|
+
openSync,
|
|
1653
|
+
rmdirSync,
|
|
1654
|
+
unlinkSync
|
|
1655
|
+
} from "fs";
|
|
1656
|
+
import { open as open2 } from "fs/promises";
|
|
1657
|
+
import { basename as basename2, dirname, join as join3, relative as relative2 } from "path";
|
|
1658
|
+
|
|
1659
|
+
// src/update/transaction-windows-api.ts
|
|
1660
|
+
import { dlopen, FFIType, ptr } from "bun:ffi";
|
|
1661
|
+
var moveFileWriteThrough = 8;
|
|
1662
|
+
var replaceFileWriteThrough = 2;
|
|
1663
|
+
var kernel32;
|
|
1664
|
+
function replaceWindowsFile(target, replacement, backup) {
|
|
1665
|
+
const api = windowsApi();
|
|
1666
|
+
const targetBuffer = wideString(target);
|
|
1667
|
+
const replacementBuffer = wideString(replacement);
|
|
1668
|
+
const backupBuffer = backup ? wideString(backup) : undefined;
|
|
1669
|
+
const result = api.symbols.ReplaceFileW(ptr(targetBuffer), ptr(replacementBuffer), backupBuffer ? ptr(backupBuffer) : null, replaceFileWriteThrough, null, null);
|
|
1670
|
+
if (!result)
|
|
1671
|
+
throw windowsError("ReplaceFileW", target);
|
|
1672
|
+
}
|
|
1673
|
+
function moveWindowsFileNoReplace(source, target) {
|
|
1674
|
+
const api = windowsApi();
|
|
1675
|
+
const sourceBuffer = wideString(source);
|
|
1676
|
+
const targetBuffer = wideString(target);
|
|
1677
|
+
if (!api.symbols.MoveFileExW(ptr(sourceBuffer), ptr(targetBuffer), moveFileWriteThrough)) {
|
|
1678
|
+
throw windowsError("MoveFileExW", `${source} -> ${target}`);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
function windowsApi() {
|
|
1682
|
+
if (process.env.WINDY_TEST_NATIVE_UNAVAILABLE === "1") {
|
|
1683
|
+
throw new Error("\u5F53\u524D\u5E73\u53F0\u65E0\u6CD5\u52A0\u8F7D\u5B89\u5168\u76EE\u5F55\u53E5\u67C4 API\uFF1A\u6D4B\u8BD5\u4E0D\u53EF\u7528\u5E73\u53F0");
|
|
1684
|
+
}
|
|
1685
|
+
if (process.platform !== "win32") {
|
|
1686
|
+
throw new Error("Windows \u539F\u5B50\u76EE\u5F55\u9879 API \u5728\u5F53\u524D\u5E73\u53F0\u4E0D\u53EF\u7528");
|
|
1687
|
+
}
|
|
1688
|
+
return kernel32 ??= openWindowsApi();
|
|
1689
|
+
}
|
|
1690
|
+
function openWindowsApi() {
|
|
1691
|
+
return dlopen("kernel32.dll", {
|
|
1692
|
+
GetLastError: { args: [], returns: FFIType.u32 },
|
|
1693
|
+
MoveFileExW: {
|
|
1694
|
+
args: [FFIType.ptr, FFIType.ptr, FFIType.u32],
|
|
1695
|
+
returns: FFIType.i32
|
|
1696
|
+
},
|
|
1697
|
+
ReplaceFileW: {
|
|
1698
|
+
args: [
|
|
1699
|
+
FFIType.ptr,
|
|
1700
|
+
FFIType.ptr,
|
|
1701
|
+
FFIType.ptr,
|
|
1702
|
+
FFIType.u32,
|
|
1703
|
+
FFIType.ptr,
|
|
1704
|
+
FFIType.ptr
|
|
1705
|
+
],
|
|
1706
|
+
returns: FFIType.i32
|
|
1707
|
+
}
|
|
1708
|
+
});
|
|
1709
|
+
}
|
|
1710
|
+
function windowsError(syscall, path) {
|
|
1711
|
+
const nativeCode = windowsApi().symbols.GetLastError();
|
|
1712
|
+
const code = nativeCode === 2 || nativeCode === 3 ? "ENOENT" : nativeCode === 80 || nativeCode === 183 ? "EEXIST" : nativeCode === 145 ? "ENOTEMPTY" : nativeCode === 5 ? "EACCES" : "EIO";
|
|
1713
|
+
return Object.assign(new Error(`${syscall} ${path} \u5931\u8D25\uFF08${nativeCode}\uFF09`), {
|
|
1714
|
+
code,
|
|
1715
|
+
errno: nativeCode,
|
|
1716
|
+
syscall,
|
|
1717
|
+
path
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1720
|
+
function wideString(value) {
|
|
1721
|
+
return Buffer.from(`${value}\x00`, "utf16le");
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
// src/update/transaction-native-windows.ts
|
|
1725
|
+
var directoryPaths = new Map;
|
|
1726
|
+
async function openWindowsAnchoredParent(root, target, createParents, createdDirectoryMode) {
|
|
1727
|
+
const parentPath = dirname(target);
|
|
1728
|
+
const relativeParent = relative2(root, parentPath);
|
|
1729
|
+
const components = relativeParent ? relativeParent.split(/[\\/]/) : [];
|
|
1730
|
+
const handles = [];
|
|
1731
|
+
const rootHandle = await openCheckedDirectory(root);
|
|
1732
|
+
handles.push(rootHandle);
|
|
1733
|
+
let currentPath = root;
|
|
1734
|
+
try {
|
|
1735
|
+
for (const component of components) {
|
|
1736
|
+
currentPath = join3(currentPath, component);
|
|
1737
|
+
try {
|
|
1738
|
+
assertDirectoryPath(currentPath);
|
|
1739
|
+
} catch (error) {
|
|
1740
|
+
if (!createParents || !hasFsCode(error, "ENOENT"))
|
|
1741
|
+
throw error;
|
|
1742
|
+
mkdirSync(currentPath, { mode: createdDirectoryMode });
|
|
1743
|
+
syncMutatedDirectory("mkdirat", handles.at(-1).fd);
|
|
1744
|
+
}
|
|
1745
|
+
handles.push(await openCheckedDirectory(currentPath));
|
|
1746
|
+
}
|
|
1747
|
+
} catch (error) {
|
|
1748
|
+
await closeHandles(handles);
|
|
1749
|
+
throw error;
|
|
1750
|
+
}
|
|
1751
|
+
const directoryHandle = handles.at(-1);
|
|
1752
|
+
return {
|
|
1753
|
+
fd: directoryHandle.fd,
|
|
1754
|
+
leaf: basename2(target),
|
|
1755
|
+
directoryPath: currentPath,
|
|
1756
|
+
async close() {
|
|
1757
|
+
await closeHandles(handles);
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1760
|
+
}
|
|
1761
|
+
function windowsOpenFileAt(parent, flags, mode) {
|
|
1762
|
+
const directoryPath = parent.directoryPath ?? windowsDirectoryPath(parent.fd);
|
|
1763
|
+
assertDirectoryHandle(parent.fd, directoryPath);
|
|
1764
|
+
const path = childPath(directoryPath, parent.leaf);
|
|
1765
|
+
let before;
|
|
1766
|
+
try {
|
|
1767
|
+
before = lstatSync(path, { bigint: true });
|
|
1768
|
+
if (before.isSymbolicLink())
|
|
1769
|
+
throw reparseError(path);
|
|
1770
|
+
} catch (error) {
|
|
1771
|
+
if (!hasFsCode(error, "ENOENT"))
|
|
1772
|
+
throw error;
|
|
1773
|
+
}
|
|
1774
|
+
const fd = openSync(path, flags, mode);
|
|
1775
|
+
try {
|
|
1776
|
+
if (before) {
|
|
1777
|
+
const opened = fstatSync(fd, { bigint: true });
|
|
1778
|
+
if (opened.dev !== before.dev || opened.ino !== before.ino) {
|
|
1779
|
+
throw reparseError(path);
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
return fd;
|
|
1783
|
+
} catch (error) {
|
|
1784
|
+
closeSync(fd);
|
|
1785
|
+
throw error;
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
function windowsLinkAt(parent, sourceName, targetName) {
|
|
1789
|
+
assertDirectoryHandle(parent.fd, parent.directoryPath);
|
|
1790
|
+
linkSync(childPath(parent.directoryPath, sourceName), childPath(parent.directoryPath, targetName));
|
|
1791
|
+
}
|
|
1792
|
+
function windowsUnlinkAt(parent, name, directory) {
|
|
1793
|
+
assertDirectoryHandle(parent.fd, parent.directoryPath);
|
|
1794
|
+
const path = childPath(parent.directoryPath, name);
|
|
1795
|
+
const info = lstatSync(path);
|
|
1796
|
+
if (info.isSymbolicLink())
|
|
1797
|
+
throw reparseError(path);
|
|
1798
|
+
if (directory)
|
|
1799
|
+
rmdirSync(path);
|
|
1800
|
+
else
|
|
1801
|
+
unlinkSync(path);
|
|
1802
|
+
}
|
|
1803
|
+
function windowsOpenChildDirectoryAt(directoryFd, name) {
|
|
1804
|
+
const parentPath = windowsDirectoryPath(directoryFd);
|
|
1805
|
+
assertDirectoryHandle(directoryFd, parentPath);
|
|
1806
|
+
const path = childPath(parentPath, name);
|
|
1807
|
+
assertDirectoryPath(path);
|
|
1808
|
+
const fd = openSync(path, constants.O_RDONLY);
|
|
1809
|
+
try {
|
|
1810
|
+
registerDirectory(fd, path);
|
|
1811
|
+
assertDirectoryHandle(fd, path);
|
|
1812
|
+
return fd;
|
|
1813
|
+
} catch (error) {
|
|
1814
|
+
directoryPaths.delete(fd);
|
|
1815
|
+
closeSync(fd);
|
|
1816
|
+
throw error;
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
function closeWindowsDirectoryFd(fd) {
|
|
1820
|
+
directoryPaths.delete(fd);
|
|
1821
|
+
closeSync(fd);
|
|
1822
|
+
}
|
|
1823
|
+
function windowsExchangeAt(parent, left, right) {
|
|
1824
|
+
assertDirectoryHandle(parent.fd, parent.directoryPath);
|
|
1825
|
+
const leftPath = childPath(parent.directoryPath, left);
|
|
1826
|
+
const rightPath = childPath(parent.directoryPath, right);
|
|
1827
|
+
const backupPath = `${leftPath}.exchange-backup`;
|
|
1828
|
+
assertMissing(backupPath);
|
|
1829
|
+
replaceWindowsFile(rightPath, leftPath, backupPath);
|
|
1830
|
+
try {
|
|
1831
|
+
moveWindowsFileNoReplace(backupPath, leftPath);
|
|
1832
|
+
} catch (error) {
|
|
1833
|
+
try {
|
|
1834
|
+
replaceWindowsFile(rightPath, backupPath);
|
|
1835
|
+
} catch {}
|
|
1836
|
+
throw error;
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
function windowsMoveNoReplaceAt(parent, source, target) {
|
|
1840
|
+
assertDirectoryHandle(parent.fd, parent.directoryPath);
|
|
1841
|
+
moveWindowsFileNoReplace(childPath(parent.directoryPath, source), childPath(parent.directoryPath, target));
|
|
1842
|
+
}
|
|
1843
|
+
function windowsDirectoryPath(fd) {
|
|
1844
|
+
const path = directoryPaths.get(fd);
|
|
1845
|
+
if (!path)
|
|
1846
|
+
throw new Error("Windows \u4E8B\u52A1\u76EE\u5F55\u53E5\u67C4\u672A\u6CE8\u518C\uFF0C\u4E8B\u52A1\u5B89\u5168\u5173\u95ED");
|
|
1847
|
+
return path;
|
|
1848
|
+
}
|
|
1849
|
+
async function openCheckedDirectory(path) {
|
|
1850
|
+
assertDirectoryPath(path);
|
|
1851
|
+
const handle = await open2(path, constants.O_RDONLY);
|
|
1852
|
+
try {
|
|
1853
|
+
registerDirectory(handle.fd, path);
|
|
1854
|
+
assertDirectoryHandle(handle.fd, path);
|
|
1855
|
+
return handle;
|
|
1856
|
+
} catch (error) {
|
|
1857
|
+
directoryPaths.delete(handle.fd);
|
|
1858
|
+
await handle.close();
|
|
1859
|
+
throw error;
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
function registerDirectory(fd, path) {
|
|
1863
|
+
directoryPaths.set(fd, path);
|
|
1864
|
+
}
|
|
1865
|
+
async function closeHandles(handles) {
|
|
1866
|
+
for (const handle of handles.reverse()) {
|
|
1867
|
+
directoryPaths.delete(handle.fd);
|
|
1868
|
+
await handle.close();
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
function assertDirectoryPath(path) {
|
|
1872
|
+
const info = lstatSync(path, { bigint: true });
|
|
1873
|
+
if (info.isSymbolicLink())
|
|
1874
|
+
throw reparseError(path);
|
|
1875
|
+
if (!info.isDirectory())
|
|
1876
|
+
throw fsError("ENOTDIR", path);
|
|
1877
|
+
}
|
|
1878
|
+
function assertDirectoryHandle(fd, path) {
|
|
1879
|
+
const opened = fstatSync(fd, { bigint: true });
|
|
1880
|
+
const current = lstatSync(path, { bigint: true });
|
|
1881
|
+
if (current.isSymbolicLink() || !opened.isDirectory() || !current.isDirectory() || opened.dev !== current.dev || opened.ino !== current.ino) {
|
|
1882
|
+
throw reparseError(path);
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
function childPath(directory, name) {
|
|
1886
|
+
if (!name || name.includes("/") || name.includes("\\") || name.includes("\x00")) {
|
|
1887
|
+
throw new Error(`Windows \u4E8B\u52A1\u76EE\u5F55\u9879\u540D\u79F0\u4E0D\u5B89\u5168\uFF1A${name}`);
|
|
1888
|
+
}
|
|
1889
|
+
return join3(directory, name);
|
|
1890
|
+
}
|
|
1891
|
+
function assertMissing(path) {
|
|
1892
|
+
try {
|
|
1893
|
+
lstatSync(path);
|
|
1894
|
+
} catch (error) {
|
|
1895
|
+
if (hasFsCode(error, "ENOENT"))
|
|
1896
|
+
return;
|
|
1897
|
+
throw error;
|
|
1898
|
+
}
|
|
1899
|
+
throw fsError("EEXIST", path);
|
|
1900
|
+
}
|
|
1901
|
+
function reparseError(path) {
|
|
1902
|
+
return fsError("ELOOP", path);
|
|
1903
|
+
}
|
|
1904
|
+
function fsError(code, path) {
|
|
1905
|
+
return Object.assign(new Error(`${code}: ${path}`), { code, path });
|
|
1906
|
+
}
|
|
1907
|
+
function hasFsCode(error, code) {
|
|
1908
|
+
return error instanceof Error && "code" in error && error.code === code;
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1627
1911
|
// src/update/transaction-native.ts
|
|
1628
1912
|
var nativeSymbols = {
|
|
1629
1913
|
openat: {
|
|
1630
|
-
args: [
|
|
1631
|
-
returns:
|
|
1914
|
+
args: [FFIType2.i32, FFIType2.ptr, FFIType2.i32, FFIType2.i32],
|
|
1915
|
+
returns: FFIType2.i32
|
|
1632
1916
|
},
|
|
1633
1917
|
mkdirat: {
|
|
1634
|
-
args: [
|
|
1635
|
-
returns:
|
|
1918
|
+
args: [FFIType2.i32, FFIType2.ptr, FFIType2.i32],
|
|
1919
|
+
returns: FFIType2.i32
|
|
1636
1920
|
},
|
|
1637
1921
|
linkat: {
|
|
1638
|
-
args: [
|
|
1639
|
-
returns:
|
|
1922
|
+
args: [FFIType2.i32, FFIType2.ptr, FFIType2.i32, FFIType2.ptr, FFIType2.i32],
|
|
1923
|
+
returns: FFIType2.i32
|
|
1640
1924
|
},
|
|
1641
1925
|
unlinkat: {
|
|
1642
|
-
args: [
|
|
1643
|
-
returns:
|
|
1926
|
+
args: [FFIType2.i32, FFIType2.ptr, FFIType2.i32],
|
|
1927
|
+
returns: FFIType2.i32
|
|
1644
1928
|
},
|
|
1645
1929
|
[process.platform === "darwin" ? "__error" : "__errno_location"]: {
|
|
1646
1930
|
args: [],
|
|
1647
|
-
returns:
|
|
1931
|
+
returns: FFIType2.ptr
|
|
1648
1932
|
}
|
|
1649
1933
|
};
|
|
1650
|
-
var directoryFlags =
|
|
1934
|
+
var directoryFlags = constants2.O_RDONLY | constants2.O_DIRECTORY | constants2.O_NOFOLLOW;
|
|
1651
1935
|
var removeDirectoryFlag = process.platform === "darwin" ? 128 : 512;
|
|
1652
|
-
var getLibc = createLazyLibcLoader((candidate) =>
|
|
1936
|
+
var getLibc = createLazyLibcLoader((candidate) => dlopen2(candidate, nativeSymbols), "\u5F53\u524D\u5E73\u53F0\u65E0\u6CD5\u52A0\u8F7D\u5B89\u5168\u76EE\u5F55\u53E5\u67C4 API");
|
|
1653
1937
|
function resolveSafeTarget(root, path) {
|
|
1654
1938
|
if (!path || isAbsolute(path) || path.includes("\x00") || path.split(/[\\/]/).includes("..")) {
|
|
1655
1939
|
throw new Error(`\u66F4\u65B0\u8BA1\u5212\u5305\u542B\u4E0D\u5B89\u5168\u8DEF\u5F84\uFF1A${path}`);
|
|
1656
1940
|
}
|
|
1657
1941
|
const target = resolve2(root, path);
|
|
1658
|
-
const pathFromRoot =
|
|
1942
|
+
const pathFromRoot = relative3(root, target);
|
|
1659
1943
|
if (pathFromRoot === ".." || pathFromRoot.startsWith(`..${sep2}`) || isAbsolute(pathFromRoot)) {
|
|
1660
1944
|
throw new Error(`\u66F4\u65B0\u8BA1\u5212\u5305\u542B\u4E0D\u5B89\u5168\u8DEF\u5F84\uFF1A${path}`);
|
|
1661
1945
|
}
|
|
@@ -1663,9 +1947,15 @@ function resolveSafeTarget(root, path) {
|
|
|
1663
1947
|
}
|
|
1664
1948
|
async function openAnchoredParent(root, path, createParents, createdDirectoryMode = 448) {
|
|
1665
1949
|
const target = resolveSafeTarget(root, path);
|
|
1666
|
-
|
|
1950
|
+
if (process.platform === "win32") {
|
|
1951
|
+
if (process.env.WINDY_TEST_NATIVE_UNAVAILABLE === "1") {
|
|
1952
|
+
throw new Error("\u5F53\u524D\u5E73\u53F0\u65E0\u6CD5\u52A0\u8F7D\u5B89\u5168\u76EE\u5F55\u53E5\u67C4 API\uFF1A\u6D4B\u8BD5\u4E0D\u53EF\u7528\u5E73\u53F0");
|
|
1953
|
+
}
|
|
1954
|
+
return openWindowsAnchoredParent(root, target, createParents, createdDirectoryMode);
|
|
1955
|
+
}
|
|
1956
|
+
const parentPath = relative3(root, dirname2(target));
|
|
1667
1957
|
const components = parentPath === "" ? [] : parentPath.split(sep2).filter(Boolean);
|
|
1668
|
-
const rootHandle = await
|
|
1958
|
+
const rootHandle = await open3(root, directoryFlags);
|
|
1669
1959
|
const childDescriptors = [];
|
|
1670
1960
|
let current = rootHandle.fd;
|
|
1671
1961
|
try {
|
|
@@ -1675,13 +1965,13 @@ async function openAnchoredParent(root, path, createParents, createdDirectoryMod
|
|
|
1675
1965
|
try {
|
|
1676
1966
|
child = nativeOpenAt(current, component, directoryFlags);
|
|
1677
1967
|
} catch (error) {
|
|
1678
|
-
if (!createParents || !
|
|
1968
|
+
if (!createParents || !hasFsCode2(error, "ENOENT"))
|
|
1679
1969
|
throw error;
|
|
1680
1970
|
try {
|
|
1681
1971
|
nativeMkdirAt(current, component, createdDirectoryMode);
|
|
1682
1972
|
created = true;
|
|
1683
1973
|
} catch (mkdirError) {
|
|
1684
|
-
if (!
|
|
1974
|
+
if (!hasFsCode2(mkdirError, "EEXIST"))
|
|
1685
1975
|
throw mkdirError;
|
|
1686
1976
|
}
|
|
1687
1977
|
child = nativeOpenAt(current, component, directoryFlags);
|
|
@@ -1698,7 +1988,7 @@ async function openAnchoredParent(root, path, createParents, createdDirectoryMod
|
|
|
1698
1988
|
}
|
|
1699
1989
|
return {
|
|
1700
1990
|
fd: current,
|
|
1701
|
-
leaf:
|
|
1991
|
+
leaf: basename3(target),
|
|
1702
1992
|
async close() {
|
|
1703
1993
|
closeDescriptors(childDescriptors);
|
|
1704
1994
|
await rootHandle.close();
|
|
@@ -1706,32 +1996,35 @@ async function openAnchoredParent(root, path, createParents, createdDirectoryMod
|
|
|
1706
1996
|
};
|
|
1707
1997
|
}
|
|
1708
1998
|
function openFileAt(parent, flags, mode = 384) {
|
|
1999
|
+
if (process.platform === "win32") {
|
|
2000
|
+
return windowsOpenFileAt(parent, flags, mode);
|
|
2001
|
+
}
|
|
1709
2002
|
return nativeOpenAt(parent.fd, parent.leaf, flags, mode);
|
|
1710
2003
|
}
|
|
1711
2004
|
function readFileAt(parent) {
|
|
1712
|
-
const fd = openFileAt(parent,
|
|
2005
|
+
const fd = openFileAt(parent, constants2.O_RDONLY | constants2.O_NOFOLLOW);
|
|
1713
2006
|
try {
|
|
1714
|
-
const info =
|
|
2007
|
+
const info = fstatSync2(fd);
|
|
1715
2008
|
if (!info.isFile())
|
|
1716
2009
|
throw new Error(`\u4E8B\u52A1\u76EE\u6807\u4E0D\u662F\u666E\u901A\u6587\u4EF6\uFF1A${parent.leaf}`);
|
|
1717
2010
|
return readFileSync(fd);
|
|
1718
2011
|
} finally {
|
|
1719
|
-
|
|
2012
|
+
closeSync2(fd);
|
|
1720
2013
|
}
|
|
1721
2014
|
}
|
|
1722
2015
|
function fileModeAt(parent) {
|
|
1723
|
-
const fd = openFileAt(parent,
|
|
2016
|
+
const fd = openFileAt(parent, constants2.O_RDONLY | constants2.O_NOFOLLOW);
|
|
1724
2017
|
try {
|
|
1725
|
-
const info =
|
|
2018
|
+
const info = fstatSync2(fd);
|
|
1726
2019
|
if (!info.isFile())
|
|
1727
2020
|
throw new Error(`\u4E8B\u52A1\u76EE\u6807\u4E0D\u662F\u666E\u901A\u6587\u4EF6\uFF1A${parent.leaf}`);
|
|
1728
2021
|
return info.mode & 511;
|
|
1729
2022
|
} finally {
|
|
1730
|
-
|
|
2023
|
+
closeSync2(fd);
|
|
1731
2024
|
}
|
|
1732
2025
|
}
|
|
1733
2026
|
function writeExclusiveAt(parent, content, mode = 384) {
|
|
1734
|
-
const fd = openFileAt(parent,
|
|
2027
|
+
const fd = openFileAt(parent, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL | constants2.O_NOFOLLOW, mode);
|
|
1735
2028
|
try {
|
|
1736
2029
|
fchmodSync(fd, mode);
|
|
1737
2030
|
const buffer = typeof content === "string" ? Buffer.from(content) : Buffer.from(content);
|
|
@@ -1741,34 +2034,58 @@ function writeExclusiveAt(parent, content, mode = 384) {
|
|
|
1741
2034
|
}
|
|
1742
2035
|
fsyncSync2(fd);
|
|
1743
2036
|
} finally {
|
|
1744
|
-
|
|
2037
|
+
closeSync2(fd);
|
|
1745
2038
|
}
|
|
1746
2039
|
syncMutatedDirectory("create", parent.fd);
|
|
1747
2040
|
}
|
|
1748
2041
|
function linkAt(parent, sourceName, targetName) {
|
|
2042
|
+
if (process.platform === "win32") {
|
|
2043
|
+
windowsLinkAt(parent, sourceName, targetName);
|
|
2044
|
+
syncMutatedDirectory("linkat", parent.fd);
|
|
2045
|
+
return;
|
|
2046
|
+
}
|
|
1749
2047
|
const libc = getLibc();
|
|
1750
2048
|
const sourceBuffer = cString(sourceName);
|
|
1751
2049
|
const targetBuffer = cString(targetName);
|
|
1752
|
-
if (libc.symbols.linkat(parent.fd,
|
|
2050
|
+
if (libc.symbols.linkat(parent.fd, ptr2(sourceBuffer), parent.fd, ptr2(targetBuffer), 0) < 0) {
|
|
1753
2051
|
throw nativeError("linkat", `${sourceName} -> ${targetName}`);
|
|
1754
2052
|
}
|
|
1755
2053
|
syncMutatedDirectory("linkat", parent.fd);
|
|
1756
2054
|
}
|
|
1757
2055
|
function unlinkAt(parent, directory = false) {
|
|
2056
|
+
if (process.platform === "win32") {
|
|
2057
|
+
windowsUnlinkAt(parent, parent.leaf, directory);
|
|
2058
|
+
syncMutatedDirectory("unlinkat", parent.fd);
|
|
2059
|
+
return;
|
|
2060
|
+
}
|
|
1758
2061
|
nativeUnlinkAt(parent.fd, parent.leaf, directory ? removeDirectoryFlag : 0);
|
|
1759
2062
|
syncMutatedDirectory("unlinkat", parent.fd);
|
|
1760
2063
|
}
|
|
1761
2064
|
function openChildDirectoryAt(directoryFd, name) {
|
|
2065
|
+
if (process.platform === "win32") {
|
|
2066
|
+
return windowsOpenChildDirectoryAt(directoryFd, name);
|
|
2067
|
+
}
|
|
1762
2068
|
return nativeOpenAt(directoryFd, name, directoryFlags);
|
|
1763
2069
|
}
|
|
1764
2070
|
function unlinkNameAt(directoryFd, name, directory = false) {
|
|
2071
|
+
if (process.platform === "win32") {
|
|
2072
|
+
const parent = {
|
|
2073
|
+
fd: directoryFd,
|
|
2074
|
+
leaf: name,
|
|
2075
|
+
directoryPath: windowsDirectoryPath(directoryFd),
|
|
2076
|
+
async close() {}
|
|
2077
|
+
};
|
|
2078
|
+
windowsUnlinkAt(parent, name, directory);
|
|
2079
|
+
syncMutatedDirectory("unlinkat", directoryFd);
|
|
2080
|
+
return;
|
|
2081
|
+
}
|
|
1765
2082
|
nativeUnlinkAt(directoryFd, name, directory ? removeDirectoryFlag : 0);
|
|
1766
2083
|
syncMutatedDirectory("unlinkat", directoryFd);
|
|
1767
2084
|
}
|
|
1768
2085
|
function nativeOpenAt(directoryFd, name, flags, mode = 0) {
|
|
1769
2086
|
const libc = getLibc();
|
|
1770
2087
|
const nameBuffer = cString(name);
|
|
1771
|
-
const result = libc.symbols.openat(directoryFd,
|
|
2088
|
+
const result = libc.symbols.openat(directoryFd, ptr2(nameBuffer), flags, mode);
|
|
1772
2089
|
if (result < 0)
|
|
1773
2090
|
throw nativeError("openat", name);
|
|
1774
2091
|
return result;
|
|
@@ -1776,7 +2093,7 @@ function nativeOpenAt(directoryFd, name, flags, mode = 0) {
|
|
|
1776
2093
|
function nativeMkdirAt(directoryFd, name, mode) {
|
|
1777
2094
|
const libc = getLibc();
|
|
1778
2095
|
const nameBuffer = cString(name);
|
|
1779
|
-
if (libc.symbols.mkdirat(directoryFd,
|
|
2096
|
+
if (libc.symbols.mkdirat(directoryFd, ptr2(nameBuffer), mode) < 0) {
|
|
1780
2097
|
throw nativeError("mkdirat", name);
|
|
1781
2098
|
}
|
|
1782
2099
|
syncMutatedDirectory("mkdirat", directoryFd);
|
|
@@ -1784,7 +2101,7 @@ function nativeMkdirAt(directoryFd, name, mode) {
|
|
|
1784
2101
|
function nativeUnlinkAt(directoryFd, name, flags) {
|
|
1785
2102
|
const libc = getLibc();
|
|
1786
2103
|
const nameBuffer = cString(name);
|
|
1787
|
-
if (libc.symbols.unlinkat(directoryFd,
|
|
2104
|
+
if (libc.symbols.unlinkat(directoryFd, ptr2(nameBuffer), flags) < 0) {
|
|
1788
2105
|
throw nativeError("unlinkat", name);
|
|
1789
2106
|
}
|
|
1790
2107
|
}
|
|
@@ -1808,35 +2125,38 @@ function cString(value) {
|
|
|
1808
2125
|
}
|
|
1809
2126
|
function closeDescriptors(descriptors) {
|
|
1810
2127
|
for (const descriptor of descriptors.reverse())
|
|
1811
|
-
|
|
2128
|
+
closeSync2(descriptor);
|
|
1812
2129
|
}
|
|
1813
|
-
function
|
|
2130
|
+
function hasFsCode2(error, code) {
|
|
1814
2131
|
return error instanceof Error && "code" in error && error.code === code;
|
|
1815
2132
|
}
|
|
1816
2133
|
|
|
1817
2134
|
// src/update/transaction-tree.ts
|
|
1818
|
-
import { constants as
|
|
2135
|
+
import { constants as constants3, closeSync as closeSync4, fstatSync as fstatSync3 } from "fs";
|
|
1819
2136
|
|
|
1820
2137
|
// src/update/transaction-native-directory.ts
|
|
1821
|
-
import { closeSync as
|
|
1822
|
-
import { dlopen as
|
|
2138
|
+
import { closeSync as closeSync3, readdirSync } from "fs";
|
|
2139
|
+
import { dlopen as dlopen3, FFIType as FFIType3, read as read2, toArrayBuffer } from "bun:ffi";
|
|
1823
2140
|
var errnoName = process.platform === "darwin" ? "__error" : "__errno_location";
|
|
1824
2141
|
var symbols = {
|
|
1825
|
-
dup: { args: [
|
|
1826
|
-
fdopendir: { args: [
|
|
1827
|
-
readdir: { args: [
|
|
1828
|
-
closedir: { args: [
|
|
1829
|
-
[errnoName]: { args: [], returns:
|
|
2142
|
+
dup: { args: [FFIType3.i32], returns: FFIType3.i32 },
|
|
2143
|
+
fdopendir: { args: [FFIType3.i32], returns: FFIType3.ptr },
|
|
2144
|
+
readdir: { args: [FFIType3.ptr], returns: FFIType3.ptr },
|
|
2145
|
+
closedir: { args: [FFIType3.ptr], returns: FFIType3.i32 },
|
|
2146
|
+
[errnoName]: { args: [], returns: FFIType3.ptr }
|
|
1830
2147
|
};
|
|
1831
|
-
var getLibc2 = createLazyLibcLoader((candidate) =>
|
|
2148
|
+
var getLibc2 = createLazyLibcLoader((candidate) => dlopen3(candidate, symbols), "\u65E0\u6CD5\u52A0\u8F7D\u5B89\u5168\u76EE\u5F55\u679A\u4E3E API\uFF0C\u4E8B\u52A1\u5B89\u5168\u5173\u95ED");
|
|
1832
2149
|
function readDirectoryNames(directoryFd) {
|
|
2150
|
+
if (process.platform === "win32") {
|
|
2151
|
+
return readdirSync(windowsDirectoryPath(directoryFd));
|
|
2152
|
+
}
|
|
1833
2153
|
const libc = getLibc2();
|
|
1834
2154
|
const duplicate = libc.symbols.dup(directoryFd);
|
|
1835
2155
|
if (duplicate < 0)
|
|
1836
2156
|
throw new Error("\u65E0\u6CD5\u590D\u5236\u5907\u4EFD\u76EE\u5F55\u53E5\u67C4\uFF0C\u4E8B\u52A1\u5B89\u5168\u5173\u95ED");
|
|
1837
2157
|
const directory = libc.symbols.fdopendir(duplicate);
|
|
1838
2158
|
if (!directory) {
|
|
1839
|
-
|
|
2159
|
+
closeSync3(duplicate);
|
|
1840
2160
|
throw new Error("\u65E0\u6CD5\u8BFB\u53D6\u5907\u4EFD\u76EE\u5F55\u53E5\u67C4\uFF0C\u4E8B\u52A1\u5B89\u5168\u5173\u95ED");
|
|
1841
2161
|
}
|
|
1842
2162
|
const names = [];
|
|
@@ -1891,7 +2211,7 @@ async function removeKnownTree(root, path, knownFiles, hooks) {
|
|
|
1891
2211
|
try {
|
|
1892
2212
|
parent = await openAnchoredParent(root, path, false);
|
|
1893
2213
|
} catch (error) {
|
|
1894
|
-
if (
|
|
2214
|
+
if (hasFsCode3(error, "ENOENT"))
|
|
1895
2215
|
return;
|
|
1896
2216
|
throw safePathError(error, path);
|
|
1897
2217
|
}
|
|
@@ -1908,11 +2228,11 @@ async function removeKnownTree(root, path, knownFiles, hooks) {
|
|
|
1908
2228
|
}
|
|
1909
2229
|
unlinkAt(parent, true);
|
|
1910
2230
|
} catch (error) {
|
|
1911
|
-
if (!
|
|
2231
|
+
if (!hasFsCode3(error, "ENOENT"))
|
|
1912
2232
|
throw safePathError(error, path);
|
|
1913
2233
|
} finally {
|
|
1914
2234
|
if (treeFd !== undefined)
|
|
1915
|
-
|
|
2235
|
+
closeDirectory(treeFd);
|
|
1916
2236
|
await parent.close();
|
|
1917
2237
|
}
|
|
1918
2238
|
}
|
|
@@ -1934,7 +2254,7 @@ function inspectDirectory(directoryFd, directory, expected) {
|
|
|
1934
2254
|
try {
|
|
1935
2255
|
inspectDirectory(childFd, directory ? `${directory}/${name}` : name, expected);
|
|
1936
2256
|
} finally {
|
|
1937
|
-
|
|
2257
|
+
closeDirectory(childFd);
|
|
1938
2258
|
}
|
|
1939
2259
|
}
|
|
1940
2260
|
}
|
|
@@ -1944,13 +2264,13 @@ function assertRegularFile(directoryFd, name) {
|
|
|
1944
2264
|
leaf: name,
|
|
1945
2265
|
async close() {}
|
|
1946
2266
|
};
|
|
1947
|
-
const fileFd = openFileAt(parent,
|
|
2267
|
+
const fileFd = openFileAt(parent, constants3.O_RDONLY | constants3.O_NOFOLLOW | constants3.O_NONBLOCK);
|
|
1948
2268
|
try {
|
|
1949
|
-
if (!
|
|
2269
|
+
if (!fstatSync3(fileFd).isFile()) {
|
|
1950
2270
|
throw new Error(`\u5907\u4EFD\u6761\u76EE\u7C7B\u578B\u5F02\u5E38\uFF1A${name}`);
|
|
1951
2271
|
}
|
|
1952
2272
|
} finally {
|
|
1953
|
-
|
|
2273
|
+
closeSync4(fileFd);
|
|
1954
2274
|
}
|
|
1955
2275
|
}
|
|
1956
2276
|
function expectedTree(files) {
|
|
@@ -1996,13 +2316,19 @@ async function removeTreeEntry(treeFd, path, directory) {
|
|
|
1996
2316
|
}
|
|
1997
2317
|
unlinkNameAt(current, leaf, directory);
|
|
1998
2318
|
} catch (error) {
|
|
1999
|
-
if (!
|
|
2319
|
+
if (!hasFsCode3(error, "ENOENT"))
|
|
2000
2320
|
throw error;
|
|
2001
2321
|
} finally {
|
|
2002
2322
|
for (const descriptor of descriptors.reverse())
|
|
2003
|
-
|
|
2323
|
+
closeDirectory(descriptor);
|
|
2004
2324
|
}
|
|
2005
2325
|
}
|
|
2326
|
+
function closeDirectory(fd) {
|
|
2327
|
+
if (process.platform === "win32")
|
|
2328
|
+
closeWindowsDirectoryFd(fd);
|
|
2329
|
+
else
|
|
2330
|
+
closeSync4(fd);
|
|
2331
|
+
}
|
|
2006
2332
|
function assertKnownTreePath(path) {
|
|
2007
2333
|
const parts = path.split("/");
|
|
2008
2334
|
if (!path || path.includes("\\") || path.includes("\x00") || parts.some((part) => !part || part === "." || part === "..")) {
|
|
@@ -2011,14 +2337,14 @@ function assertKnownTreePath(path) {
|
|
|
2011
2337
|
return parts.join("/");
|
|
2012
2338
|
}
|
|
2013
2339
|
function safePathError(error, path) {
|
|
2014
|
-
if (
|
|
2340
|
+
if (hasFsCode3(error, "ELOOP") || hasFsCode3(error, "ENOTDIR")) {
|
|
2015
2341
|
return new Error(`\u4E8B\u52A1\u8DEF\u5F84\u5305\u542B\u7B26\u53F7\u94FE\u63A5\u6216\u975E\u76EE\u5F55\u7EC4\u4EF6\uFF1A${path}`, {
|
|
2016
2342
|
cause: error
|
|
2017
2343
|
});
|
|
2018
2344
|
}
|
|
2019
2345
|
return error;
|
|
2020
2346
|
}
|
|
2021
|
-
function
|
|
2347
|
+
function hasFsCode3(error, code) {
|
|
2022
2348
|
return error instanceof Error && "code" in error && error.code === code;
|
|
2023
2349
|
}
|
|
2024
2350
|
|
|
@@ -2041,15 +2367,15 @@ async function inspectSafePath(root, path) {
|
|
|
2041
2367
|
try {
|
|
2042
2368
|
parent = await openAnchoredParent(root, path, false);
|
|
2043
2369
|
} catch (error) {
|
|
2044
|
-
if (
|
|
2370
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
2045
2371
|
return target;
|
|
2046
2372
|
throw safePathError2(error, path);
|
|
2047
2373
|
}
|
|
2048
2374
|
try {
|
|
2049
|
-
const fd = openFileAt(parent,
|
|
2050
|
-
|
|
2375
|
+
const fd = openFileAt(parent, constants4.O_RDONLY | constants4.O_NOFOLLOW);
|
|
2376
|
+
closeSync5(fd);
|
|
2051
2377
|
} catch (error) {
|
|
2052
|
-
if (
|
|
2378
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
2053
2379
|
return target;
|
|
2054
2380
|
throw safePathError2(error, path);
|
|
2055
2381
|
} finally {
|
|
@@ -2062,16 +2388,16 @@ async function safePathExists(root, path) {
|
|
|
2062
2388
|
try {
|
|
2063
2389
|
parent = await openAnchoredParent(root, path, false);
|
|
2064
2390
|
} catch (error) {
|
|
2065
|
-
if (
|
|
2391
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
2066
2392
|
return false;
|
|
2067
2393
|
throw safePathError2(error, path);
|
|
2068
2394
|
}
|
|
2069
2395
|
try {
|
|
2070
|
-
const fd = openFileAt(parent,
|
|
2071
|
-
|
|
2396
|
+
const fd = openFileAt(parent, constants4.O_RDONLY | constants4.O_NOFOLLOW);
|
|
2397
|
+
closeSync5(fd);
|
|
2072
2398
|
return true;
|
|
2073
2399
|
} catch (error) {
|
|
2074
|
-
if (
|
|
2400
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
2075
2401
|
return false;
|
|
2076
2402
|
throw safePathError2(error, path);
|
|
2077
2403
|
} finally {
|
|
@@ -2083,14 +2409,14 @@ async function readSafeOptional(root, path) {
|
|
|
2083
2409
|
try {
|
|
2084
2410
|
parent = await openAnchoredParent(root, path, false);
|
|
2085
2411
|
} catch (error) {
|
|
2086
|
-
if (
|
|
2412
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
2087
2413
|
return;
|
|
2088
2414
|
throw safePathError2(error, path);
|
|
2089
2415
|
}
|
|
2090
2416
|
try {
|
|
2091
2417
|
return readFileAt(parent);
|
|
2092
2418
|
} catch (error) {
|
|
2093
|
-
if (
|
|
2419
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
2094
2420
|
return;
|
|
2095
2421
|
throw safePathError2(error, path);
|
|
2096
2422
|
} finally {
|
|
@@ -2102,14 +2428,14 @@ async function safeFileMode(root, path) {
|
|
|
2102
2428
|
try {
|
|
2103
2429
|
parent = await openAnchoredParent(root, path, false);
|
|
2104
2430
|
} catch (error) {
|
|
2105
|
-
if (
|
|
2431
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
2106
2432
|
return;
|
|
2107
2433
|
throw safePathError2(error, path);
|
|
2108
2434
|
}
|
|
2109
2435
|
try {
|
|
2110
2436
|
return fileModeAt(parent);
|
|
2111
2437
|
} catch (error) {
|
|
2112
|
-
if (
|
|
2438
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
2113
2439
|
return;
|
|
2114
2440
|
throw safePathError2(error, path);
|
|
2115
2441
|
} finally {
|
|
@@ -2146,7 +2472,7 @@ async function validateBackupDirectory(root, updateId, backupDirectory) {
|
|
|
2146
2472
|
return relativePath;
|
|
2147
2473
|
}
|
|
2148
2474
|
async function removeEmptyDeletedFileParents(deletedFile, projectRoot) {
|
|
2149
|
-
let directory =
|
|
2475
|
+
let directory = dirname3(deletedFile);
|
|
2150
2476
|
while (directory !== ".") {
|
|
2151
2477
|
try {
|
|
2152
2478
|
await removeEmptyDirectorySafe(projectRoot, directory);
|
|
@@ -2155,7 +2481,7 @@ async function removeEmptyDeletedFileParents(deletedFile, projectRoot) {
|
|
|
2155
2481
|
return;
|
|
2156
2482
|
throw error;
|
|
2157
2483
|
}
|
|
2158
|
-
directory =
|
|
2484
|
+
directory = dirname3(directory);
|
|
2159
2485
|
}
|
|
2160
2486
|
}
|
|
2161
2487
|
async function removeEmptyDirectorySafe(root, path) {
|
|
@@ -2163,24 +2489,24 @@ async function removeEmptyDirectorySafe(root, path) {
|
|
|
2163
2489
|
try {
|
|
2164
2490
|
parent = await openAnchoredParent(root, path, false);
|
|
2165
2491
|
} catch (error) {
|
|
2166
|
-
if (
|
|
2492
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
2167
2493
|
return;
|
|
2168
2494
|
throw safePathError2(error, path);
|
|
2169
2495
|
}
|
|
2170
2496
|
try {
|
|
2171
2497
|
unlinkAt(parent, true);
|
|
2172
2498
|
} catch (error) {
|
|
2173
|
-
if (!
|
|
2499
|
+
if (!hasFsCode4(error, "ENOENT"))
|
|
2174
2500
|
throw safePathError2(error, path);
|
|
2175
2501
|
} finally {
|
|
2176
2502
|
await parent.close();
|
|
2177
2503
|
}
|
|
2178
2504
|
}
|
|
2179
|
-
function
|
|
2505
|
+
function hasFsCode4(error, code) {
|
|
2180
2506
|
return error instanceof Error && "code" in error && error.code === code;
|
|
2181
2507
|
}
|
|
2182
2508
|
function safePathError2(error, path) {
|
|
2183
|
-
if (
|
|
2509
|
+
if (hasFsCode4(error, "ELOOP") || hasFsCode4(error, "ENOTDIR")) {
|
|
2184
2510
|
return new Error(`\u4E8B\u52A1\u8DEF\u5F84\u5305\u542B\u7B26\u53F7\u94FE\u63A5\u6216\u975E\u76EE\u5F55\u7EC4\u4EF6\uFF1A${path}`, {
|
|
2185
2511
|
cause: error
|
|
2186
2512
|
});
|
|
@@ -2196,7 +2522,7 @@ function isDirectoryNotRemovable(error) {
|
|
|
2196
2522
|
|
|
2197
2523
|
// src/workspace-membership.ts
|
|
2198
2524
|
import { readdir as readdir2 } from "fs/promises";
|
|
2199
|
-
import { join as
|
|
2525
|
+
import { join as join4 } from "path";
|
|
2200
2526
|
function deriveFinalWorkspaceMembership(current, target, files) {
|
|
2201
2527
|
const membersByBase = new Map;
|
|
2202
2528
|
for (const expectation of [...current, ...target]) {
|
|
@@ -2228,7 +2554,7 @@ function deriveFinalWorkspaceMembership(current, target, files) {
|
|
|
2228
2554
|
async function snapshotWorkspaceBase(root, base) {
|
|
2229
2555
|
assertSafeWorkspaceBase(base);
|
|
2230
2556
|
await inspectSafePath(root, base);
|
|
2231
|
-
const entries = await readdir2(
|
|
2557
|
+
const entries = await readdir2(join4(root, base), {
|
|
2232
2558
|
withFileTypes: true
|
|
2233
2559
|
}).catch((error) => {
|
|
2234
2560
|
if (isMissing2(error))
|
|
@@ -2270,8 +2596,8 @@ function isDirectWorkspaceManifest(base, path) {
|
|
|
2270
2596
|
const prefix = `${base}/`;
|
|
2271
2597
|
if (!path.startsWith(prefix))
|
|
2272
2598
|
return false;
|
|
2273
|
-
const
|
|
2274
|
-
const segments =
|
|
2599
|
+
const relative4 = path.slice(prefix.length);
|
|
2600
|
+
const segments = relative4.split("/");
|
|
2275
2601
|
return segments.length === 2 && segments[0]?.length > 0 && segments[1] === "package.json";
|
|
2276
2602
|
}
|
|
2277
2603
|
function isMissing2(error) {
|
|
@@ -2478,7 +2804,7 @@ var supplierWorkspaceCopies = [
|
|
|
2478
2804
|
var supplierWorkspacePaths = ["packages/license-sdk"];
|
|
2479
2805
|
async function prepareCustomerDockerfiles(root) {
|
|
2480
2806
|
await Promise.all(["apps/server/Dockerfile", webDockerfilePath].map(async (path) => {
|
|
2481
|
-
const absolutePath =
|
|
2807
|
+
const absolutePath = join5(root, path);
|
|
2482
2808
|
const source = await readFile3(absolutePath, "utf8");
|
|
2483
2809
|
await writeFile2(absolutePath, rewriteCustomerDockerfile(source));
|
|
2484
2810
|
}));
|
|
@@ -2487,7 +2813,7 @@ async function prepareCustomerDockerfiles(root) {
|
|
|
2487
2813
|
requireAnchors: true
|
|
2488
2814
|
});
|
|
2489
2815
|
if (plan.changed && plan.content !== undefined) {
|
|
2490
|
-
await writeFile2(
|
|
2816
|
+
await writeFile2(join5(root, target.dockerfilePath), plan.content);
|
|
2491
2817
|
}
|
|
2492
2818
|
}
|
|
2493
2819
|
}
|
|
@@ -2502,7 +2828,7 @@ function rewriteCustomerDockerfile(source) {
|
|
|
2502
2828
|
|
|
2503
2829
|
// src/code-quality.ts
|
|
2504
2830
|
import { readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
2505
|
-
import { join as
|
|
2831
|
+
import { join as join6 } from "path";
|
|
2506
2832
|
var oxcStarterPolicy = [
|
|
2507
2833
|
"- \u751F\u6210\u65F6\u9ED8\u8BA4\u9884\u88C5 Oxlint\u3001Oxfmt\u3001lint-staged \u4E0E Husky\u3002",
|
|
2508
2834
|
"- \u63D0\u4EA4\u524D\u81EA\u52A8\u683C\u5F0F\u5316\u6682\u5B58\u6587\u4EF6\uFF1Blint\u3001typecheck \u548C test \u4FDD\u7559\u4E3A\u663E\u5F0F\u547D\u4EE4\u3002",
|
|
@@ -2511,7 +2837,7 @@ var oxcStarterPolicy = [
|
|
|
2511
2837
|
`);
|
|
2512
2838
|
var noCodeQualityPolicy = "- \u672C\u9879\u76EE\u751F\u6210\u65F6\u672A\u5F15\u5165 lint \u6216 format \u5DE5\u5177\uFF1B\u9879\u76EE\u6240\u6709\u8005\u53EF\u6309\u56E2\u961F\u9700\u8981\u81EA\u884C\u9009\u62E9\u3002";
|
|
2513
2839
|
async function reflectCodeQualityChoice(targetDirectory, includeOxc) {
|
|
2514
|
-
const path =
|
|
2840
|
+
const path = join6(targetDirectory, "AGENTS.md");
|
|
2515
2841
|
const source = await readFile4(path, "utf8");
|
|
2516
2842
|
if (includeOxc)
|
|
2517
2843
|
return;
|
|
@@ -2523,18 +2849,18 @@ async function reflectCodeQualityChoice(targetDirectory, includeOxc) {
|
|
|
2523
2849
|
|
|
2524
2850
|
// src/license-files.ts
|
|
2525
2851
|
import { mkdir, readFile as readFile5, rm as rm2, writeFile as writeFile4 } from "fs/promises";
|
|
2526
|
-
import { dirname as
|
|
2852
|
+
import { dirname as dirname4, join as join7, resolve as resolve4 } from "path";
|
|
2527
2853
|
import { fileURLToPath } from "url";
|
|
2528
|
-
var packageRoot = resolve4(
|
|
2854
|
+
var packageRoot = resolve4(dirname4(fileURLToPath(import.meta.url)), "..");
|
|
2529
2855
|
var apacheLicensePath = resolve4(packageRoot, "LICENSE");
|
|
2530
2856
|
var windyLicensePath = ".windy/licenses/WINDY-APACHE-2.0.txt";
|
|
2531
2857
|
async function applyWindyBaseLicense(targetDirectory) {
|
|
2532
|
-
const target =
|
|
2533
|
-
await mkdir(
|
|
2858
|
+
const target = join7(targetDirectory, windyLicensePath);
|
|
2859
|
+
await mkdir(dirname4(target), { recursive: true });
|
|
2534
2860
|
await writeFile4(target, await readFile5(apacheLicensePath));
|
|
2535
2861
|
}
|
|
2536
2862
|
async function applyProjectLicense(targetDirectory, license, holder, year = new Date().getFullYear()) {
|
|
2537
|
-
const target =
|
|
2863
|
+
const target = join7(targetDirectory, "LICENSE");
|
|
2538
2864
|
if (license === "UNLICENSED") {
|
|
2539
2865
|
await rm2(target, { force: true });
|
|
2540
2866
|
return;
|
|
@@ -2577,7 +2903,7 @@ SOFTWARE.
|
|
|
2577
2903
|
|
|
2578
2904
|
// src/module-materializer.ts
|
|
2579
2905
|
import { lstat as lstat3, readFile as readFile6, readdir as readdir3, rm as rm3, writeFile as writeFile5 } from "fs/promises";
|
|
2580
|
-
import { basename as
|
|
2906
|
+
import { basename as basename4, extname, join as join8, relative as relative4, sep as sep3 } from "path";
|
|
2581
2907
|
var textExtensions = new Set([
|
|
2582
2908
|
".css",
|
|
2583
2909
|
".html",
|
|
@@ -2613,7 +2939,7 @@ async function materializeSelectedModules(targetDirectory, selectedNames) {
|
|
|
2613
2939
|
...manifest.documentation,
|
|
2614
2940
|
...manifest.schemaFiles
|
|
2615
2941
|
]));
|
|
2616
|
-
await Promise.all([...new Set(removedRoots)].map((path) => rm3(
|
|
2942
|
+
await Promise.all([...new Set(removedRoots)].map((path) => rm3(join8(targetDirectory, path), { recursive: true, force: true })));
|
|
2617
2943
|
await pruneWorkspaceReferences(targetDirectory, removedPackageNames, removedRoots);
|
|
2618
2944
|
}
|
|
2619
2945
|
function collapseRemovalRoots(paths) {
|
|
@@ -2628,7 +2954,7 @@ function collapseRemovalRoots(paths) {
|
|
|
2628
2954
|
}
|
|
2629
2955
|
async function stripModuleBlocks(root, selected) {
|
|
2630
2956
|
for (const path of await collectFiles2(root)) {
|
|
2631
|
-
if (
|
|
2957
|
+
if (basename4(path) !== "Dockerfile" && !textExtensions.has(extname(path))) {
|
|
2632
2958
|
continue;
|
|
2633
2959
|
}
|
|
2634
2960
|
const source = await readFile6(path, "utf8");
|
|
@@ -2668,7 +2994,7 @@ async function readRemovedPackageNames(root, roots) {
|
|
|
2668
2994
|
const names = new Set;
|
|
2669
2995
|
for (const packageRoot2 of roots) {
|
|
2670
2996
|
try {
|
|
2671
|
-
const value = JSON.parse(await readFile6(
|
|
2997
|
+
const value = JSON.parse(await readFile6(join8(root, packageRoot2, "package.json"), "utf8"));
|
|
2672
2998
|
if (value.name)
|
|
2673
2999
|
names.add(value.name);
|
|
2674
3000
|
} catch (error) {
|
|
@@ -2680,7 +3006,7 @@ async function readRemovedPackageNames(root, roots) {
|
|
|
2680
3006
|
}
|
|
2681
3007
|
async function pruneWorkspaceReferences(root, removedPackages, removedRoots) {
|
|
2682
3008
|
for (const path of await collectFiles2(root)) {
|
|
2683
|
-
if (
|
|
3009
|
+
if (basename4(path) === "package.json") {
|
|
2684
3010
|
const value = JSON.parse(await readFile6(path, "utf8"));
|
|
2685
3011
|
let changed = false;
|
|
2686
3012
|
for (const section of ["dependencies", "devDependencies"]) {
|
|
@@ -2697,7 +3023,7 @@ async function pruneWorkspaceReferences(root, removedPackages, removedRoots) {
|
|
|
2697
3023
|
`);
|
|
2698
3024
|
continue;
|
|
2699
3025
|
}
|
|
2700
|
-
if (
|
|
3026
|
+
if (basename4(path) !== "Dockerfile")
|
|
2701
3027
|
continue;
|
|
2702
3028
|
const source = await readFile6(path, "utf8");
|
|
2703
3029
|
const output = source.split(`
|
|
@@ -2711,7 +3037,7 @@ async function pruneDatabaseArtifacts(root, tableNames, statementTokens) {
|
|
|
2711
3037
|
if (!tableNames.length && !statementTokens.length)
|
|
2712
3038
|
return;
|
|
2713
3039
|
const tablePatterns = tableNames.map((name) => new RegExp(`(?:"${escapeRegExp(name)}"|\\b${escapeRegExp(name)}\\b)`));
|
|
2714
|
-
const drizzleRoot =
|
|
3040
|
+
const drizzleRoot = join8(root, "packages/database/drizzle");
|
|
2715
3041
|
try {
|
|
2716
3042
|
for (const path of await collectFiles2(drizzleRoot)) {
|
|
2717
3043
|
if (path.endsWith(".sql")) {
|
|
@@ -2754,7 +3080,7 @@ async function collectFiles2(root) {
|
|
|
2754
3080
|
for (const name of (await readdir3(directory)).sort()) {
|
|
2755
3081
|
if ([".git", "node_modules", "dist"].includes(name))
|
|
2756
3082
|
continue;
|
|
2757
|
-
const path =
|
|
3083
|
+
const path = join8(directory, name);
|
|
2758
3084
|
const metadata = await lstat3(path);
|
|
2759
3085
|
if (metadata.isSymbolicLink())
|
|
2760
3086
|
continue;
|
|
@@ -2766,7 +3092,7 @@ async function collectFiles2(root) {
|
|
|
2766
3092
|
}
|
|
2767
3093
|
}
|
|
2768
3094
|
function relativePath(root, path) {
|
|
2769
|
-
return
|
|
3095
|
+
return relative4(root, path).split(sep3).join("/");
|
|
2770
3096
|
}
|
|
2771
3097
|
function escapeRegExp(value) {
|
|
2772
3098
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -3280,7 +3606,7 @@ License \u7B7E\u53D1\u4E2D\u5FC3\u3001\u72EC\u7ACB\u7B7E\u540D\u670D\u52A1\u3001
|
|
|
3280
3606
|
- \u90E8\u7F72\u671F\u6A21\u5757\u7BA1\u7406\uFF1A[\u6A21\u5757\u751F\u547D\u5468\u671F](./development/module-lifecycle.md)\u3002
|
|
3281
3607
|
- \u4E1A\u52A1\u6A21\u5757\u5F00\u53D1\uFF1A[windy-business-module Skill](../.agents/skills/windy-business-module/SKILL.md)\u3002
|
|
3282
3608
|
${includeStorage ? "- \u5927\u62A5\u544A\u5BFC\u5165\uFF1A[\u53D7\u6CBB\u7406\u7684\u5927\u62A5\u544A\u6682\u5B58](./architecture/report-staging.md)\u3002" : ""}
|
|
3283
|
-
${includeOfflineLicense ? "- License \u6D88\u8D39\u7AEF\uFF1A[\u79BB\u7EBF\u6FC0\u6D3B\u4E0E\u5B89\u88C5\u534F\u8BAE](./license/license-offline-activation-code.md)\uFF1B\u8FD0\u884C\u65F6\u80FD\u529B\u7531 npm \u4F9D\u8D56 `@southwind-ai/license` \u63D0\u4F9B\u3002" : ""}
|
|
3609
|
+
${includeOfflineLicense ? "- License \u6D88\u8D39\u7AEF\uFF1A[\u79BB\u7EBF\u6FC0\u6D3B\u4E0E\u5B89\u88C5\u534F\u8BAE](./license/license-offline-activation-code.md)\u4E0E[\u624B\u673A\u626B\u7801\u914D\u5BF9\u6FC0\u6D3B](./license/license-pairing-activation.md)\uFF1B\u8FD0\u884C\u65F6\u80FD\u529B\u7531 npm \u4F9D\u8D56 `@southwind-ai/license` \u63D0\u4F9B\u3002" : ""}
|
|
3284
3610
|
- \u8FD0\u7EF4\uFF1A[\u53EF\u89C2\u6D4B\u6027](./operations/observability.md)${includeOperations ? " \u4E0E [\u8FD0\u7EF4\u603B\u89C8](./platform/operations-overview.md)" : ""}\u3002
|
|
3285
3611
|
- \u4EA4\u4ED8\uFF1A[\u6309 registry digest \u4E0E OCI blob \u5DEE\u91CF\u53D1\u5E03](./operations/incremental-delivery.md)\u3002
|
|
3286
3612
|
${includeAgent ? "- Agent\u3001\u591A\u6A21\u6001 Runtime \u4E0E MCP\uFF1A[Agent Runtime \u63A5\u5165](./platform/agent-runtime.md)\u3001[Document AI Runtime](./platform/document-ai-runtime.md)\u3001[Speech AI Runtime](./platform/speech-ai-runtime.md)\u3001[\u53D7\u63A7\u5DE5\u5177](./platform/agent-tools.md)\u4E0E[MCP \u4E1A\u52A1\u80FD\u529B](./architecture/mcp-business-capabilities.md)\u3002" : ""}
|
|
@@ -3338,6 +3664,10 @@ Drizzle migration\uFF0C\u518D\u542F\u52A8 Server \u4E0E Web\uFF1B\u4E0D\u8981\u8
|
|
|
3338
3664
|
BuildKit \u4E2D\u7684 Bun \u5305\u4E0B\u8F7D\u7F13\u5B58\uFF0C\u53EA\u4E0B\u8F7D\u65B0\u589E\u6216\u53D1\u751F\u53D8\u5316\u7684\u4F9D\u8D56\uFF1B\u51B7\u5B89\u88C5\u6BCF 15 \u79D2\u8F93\u51FA\u4E00\u6B21
|
|
3339
3665
|
\u4E0D\u542B registry \u5730\u5740\u6216\u51ED\u636E\u7684\u8FDB\u5EA6\u5FC3\u8DF3\u3002
|
|
3340
3666
|
|
|
3667
|
+
Windows 10/11 \u53EF\u5728\u539F\u751F PowerShell \u4E2D\u914D\u5408 Docker Desktop \u76F4\u63A5\u8FD0\u884C \`bun run dev\` \u4E0E
|
|
3668
|
+
\`bun run dev:build\`\uFF0C\u4E0D\u9700\u8981 WSL\u3002Windows \u662F\u672C\u5730\u5F00\u53D1\u5BBF\u4E3B\uFF1B\u751F\u4EA7\u4EA4\u4ED8\u4ECD\u4F7F\u7528 Linux
|
|
3669
|
+
amd64 \u5BB9\u5668\u3002
|
|
3670
|
+
|
|
3341
3671
|
| \u670D\u52A1 | \u5730\u5740 |
|
|
3342
3672
|
| ---- | ---- |
|
|
3343
3673
|
| Web | http://localhost:18746 |
|
|
@@ -3480,7 +3810,8 @@ browser-safe \`./admin\` \u4E0E project-owned \u7684
|
|
|
3480
3810
|
\`apps/web/src/app/web-composition.ts\` \u88C5\u914D\u9875\u9762\uFF0C\u4E0D\u590D\u5236\u7B2C\u4E8C\u4EFD Feature\u3001Permission
|
|
3481
3811
|
\u6216\u8DEF\u7531\u6E05\u5355\u3002\u6574\u4E2A \`apps/web/src\` \u4E0E\u6574\u4E2A \`apps/server/src/app\` \u90FD\u662F
|
|
3482
3812
|
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
|
|
3813
|
+
\`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
|
|
3814
|
+
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
3815
|
|
|
3485
3816
|
\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
3817
|
\`windy update\` \u4E0E \`windy module list/enable/disable\`\u3002\u5F53\u524D\u5185\u7F6E\u6A21\u5757\u4ECD\u4F9D\u8D56
|
|
@@ -3514,7 +3845,8 @@ ${includeOxc ? "\u63D0\u4EA4\u65F6 Husky \u4F1A\u901A\u8FC7 lint-staged \u4E0E O
|
|
|
3514
3845
|
\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
3846
|
\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
3847
|
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\
|
|
3848
|
+
\`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
|
|
3849
|
+
\u4EFB\u4F55\u51B2\u7A81\u90FD\u4F1A\u5728\u5199\u5165\u524D\u4E2D\u6B62\uFF0C\u6A21\u5757\u542F\u505C\u5728\u4EA4\u4E92
|
|
3518
3850
|
\u7EC8\u7AEF\u786E\u8BA4\uFF1BCI\u3001Agent \u6216\u5176\u5B83\u975E TTY \u73AF\u5883\u5FC5\u987B\u663E\u5F0F\u4F20\u5165 \`--yes\`\u3002
|
|
3519
3851
|
\u65E0\u5E76\u53D1\u53D8\u5316\u7684\u9A8C\u8BC1\u5931\u8D25\u4F1A\u81EA\u52A8\u56DE\u6EDA\uFF1B\u4E2D\u65AD\u6062\u590D\u4F7F\u7528
|
|
3520
3852
|
\`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,10 +4026,13 @@ var templateDocumentationFiles = [
|
|
|
3694
4026
|
"docs/development/custom-error-pages.md",
|
|
3695
4027
|
"docs/development/custom-login-page.md",
|
|
3696
4028
|
"docs/development/module-lifecycle.md",
|
|
4029
|
+
"docs/development/ui-component-gallery.md",
|
|
3697
4030
|
"docs/license/license-offline-activation-code.md",
|
|
4031
|
+
"docs/license/license-pairing-activation.md",
|
|
3698
4032
|
"docs/operations/observability.md",
|
|
3699
4033
|
"docs/operations/incremental-delivery.md",
|
|
3700
4034
|
"docs/platform/agent-run-attestation.md",
|
|
4035
|
+
"docs/platform/agent-supervisor-output-contract.md",
|
|
3701
4036
|
"docs/platform/agent-tools.md",
|
|
3702
4037
|
"docs/platform/agent-runtime.md",
|
|
3703
4038
|
"docs/platform/agent-runtime-observability.md",
|
|
@@ -3759,11 +4094,11 @@ function isExcludedTemplateName(name) {
|
|
|
3759
4094
|
// src/provenance.ts
|
|
3760
4095
|
import { createHash as createHash2 } from "crypto";
|
|
3761
4096
|
import { mkdir as mkdir2, readFile as readFile7, writeFile as writeFile6 } from "fs/promises";
|
|
3762
|
-
import { join as
|
|
4097
|
+
import { join as join9 } from "path";
|
|
3763
4098
|
var templateMetadataFile = ".windy-template.json";
|
|
3764
4099
|
var generationMetadataFile = ".windy/generation.json";
|
|
3765
4100
|
async function readTemplateMetadata(sourceRoot) {
|
|
3766
|
-
const path =
|
|
4101
|
+
const path = join9(sourceRoot, templateMetadataFile);
|
|
3767
4102
|
const parsed = JSON.parse(await readFile7(path, "utf8"));
|
|
3768
4103
|
if (!isTemplateMetadata(parsed)) {
|
|
3769
4104
|
throw new Error("create-windy \u6A21\u677F\u6765\u6E90\u5143\u6570\u636E\u65E0\u6548");
|
|
@@ -3774,7 +4109,7 @@ async function readGenerationProvenance(targetDirectory) {
|
|
|
3774
4109
|
return (await readGenerationProvenanceSnapshot(targetDirectory)).provenance;
|
|
3775
4110
|
}
|
|
3776
4111
|
async function readGenerationProvenanceSnapshot(targetDirectory) {
|
|
3777
|
-
const path =
|
|
4112
|
+
const path = join9(targetDirectory, generationMetadataFile);
|
|
3778
4113
|
const content = await readFile7(path);
|
|
3779
4114
|
return {
|
|
3780
4115
|
content,
|
|
@@ -3815,8 +4150,8 @@ async function writeGenerationProvenance(targetDirectory, metadata, profile, sel
|
|
|
3815
4150
|
includeOxc
|
|
3816
4151
|
}
|
|
3817
4152
|
};
|
|
3818
|
-
const path =
|
|
3819
|
-
await mkdir2(
|
|
4153
|
+
const path = join9(targetDirectory, generationMetadataFile);
|
|
4154
|
+
await mkdir2(join9(path, ".."), { recursive: true });
|
|
3820
4155
|
await writeFile6(path, `${JSON.stringify(provenance, null, 2)}
|
|
3821
4156
|
`);
|
|
3822
4157
|
}
|
|
@@ -3843,7 +4178,7 @@ function isModuleVersion(value) {
|
|
|
3843
4178
|
|
|
3844
4179
|
// src/registry-dependencies.ts
|
|
3845
4180
|
import { lstat as lstat4, readFile as readFile8, readdir as readdir4, writeFile as writeFile7 } from "fs/promises";
|
|
3846
|
-
import { basename as
|
|
4181
|
+
import { basename as basename5, extname as extname2, join as join10 } from "path";
|
|
3847
4182
|
var dependencySections = [
|
|
3848
4183
|
"dependencies",
|
|
3849
4184
|
"devDependencies",
|
|
@@ -3867,7 +4202,7 @@ async function materializeRegistryDependencies(root, dependencies) {
|
|
|
3867
4202
|
for (const path of await collectFiles3(root)) {
|
|
3868
4203
|
if (!replaceableExtensions.has(extname2(path)))
|
|
3869
4204
|
continue;
|
|
3870
|
-
if (
|
|
4205
|
+
if (basename5(path) === "package.json") {
|
|
3871
4206
|
await rewritePackageJson(path, dependencies);
|
|
3872
4207
|
continue;
|
|
3873
4208
|
}
|
|
@@ -3904,7 +4239,7 @@ async function collectFiles3(root) {
|
|
|
3904
4239
|
for (const name of (await readdir4(directory)).sort()) {
|
|
3905
4240
|
if ([".git", "node_modules", "dist"].includes(name))
|
|
3906
4241
|
continue;
|
|
3907
|
-
const path =
|
|
4242
|
+
const path = join10(directory, name);
|
|
3908
4243
|
const metadata = await lstat4(path);
|
|
3909
4244
|
if (metadata.isSymbolicLink())
|
|
3910
4245
|
continue;
|
|
@@ -3919,10 +4254,10 @@ async function collectFiles3(root) {
|
|
|
3919
4254
|
// src/project-module-registry.ts
|
|
3920
4255
|
import { createHash as createHash3 } from "crypto";
|
|
3921
4256
|
import { readFile as readFile9, writeFile as writeFile8 } from "fs/promises";
|
|
3922
|
-
import { join as
|
|
4257
|
+
import { join as join11 } from "path";
|
|
3923
4258
|
var projectModuleRegistryPath = "windy.modules.json";
|
|
3924
4259
|
async function readProjectModuleRegistrySnapshot(projectDirectory, installedNames) {
|
|
3925
|
-
const path =
|
|
4260
|
+
const path = join11(projectDirectory, projectModuleRegistryPath);
|
|
3926
4261
|
let content;
|
|
3927
4262
|
try {
|
|
3928
4263
|
content = await readFile9(path);
|
|
@@ -3975,7 +4310,7 @@ async function writeInitialProjectModuleRegistry(targetDirectory, selectedNames)
|
|
|
3975
4310
|
config: {}
|
|
3976
4311
|
})));
|
|
3977
4312
|
const registry = { schemaVersion: 1, modules };
|
|
3978
|
-
await writeFile8(
|
|
4313
|
+
await writeFile8(join11(targetDirectory, projectModuleRegistryPath), `${JSON.stringify(registry, null, 2)}
|
|
3979
4314
|
`);
|
|
3980
4315
|
}
|
|
3981
4316
|
function assertRegistryMatchesInstalled(registry, installedNames) {
|
|
@@ -4031,29 +4366,29 @@ async function generateProject(input) {
|
|
|
4031
4366
|
const selectedModules = input.selectedModules ?? templateMetadata.modules.filter(({ name }) => requestedIncludeExample || name !== "work-order").map(({ name }) => name);
|
|
4032
4367
|
const includeExample = selectedModules.includes("work-order");
|
|
4033
4368
|
for (const relativePath2 of generationTemplatePaths(true, includeOxc)) {
|
|
4034
|
-
await copyTree(await resolveTemplateSource(input.sourceRoot, relativePath2),
|
|
4369
|
+
await copyTree(await resolveTemplateSource(input.sourceRoot, relativePath2), join12(input.targetDirectory, relativePath2));
|
|
4035
4370
|
}
|
|
4036
4371
|
await materializeSelectedModules(input.targetDirectory, selectedModules);
|
|
4037
4372
|
await materializeRegistryDependencies(input.targetDirectory, selectedModuleManifests(selectedModules).flatMap(({ registryDependencies }) => registryDependencies));
|
|
4038
|
-
const packagePath =
|
|
4373
|
+
const packagePath = join12(input.targetDirectory, "package.json");
|
|
4039
4374
|
const packageJson = JSON.parse(await readFile10(packagePath, "utf8"));
|
|
4040
4375
|
await writeFile9(packagePath, `${JSON.stringify(createStarterPackage(packageJson, input.projectName, includeOxc, projectLicense, selectedModules, templateMetadata.generatorVersion), null, 2)}
|
|
4041
4376
|
`);
|
|
4042
|
-
await writeFile9(
|
|
4043
|
-
await writeFile9(
|
|
4044
|
-
await writeFile9(
|
|
4045
|
-
await writeFile9(
|
|
4377
|
+
await writeFile9(join12(input.targetDirectory, "docker-compose.yml"), starterComposeFor(selectedModules.includes("system.agent"), selectedModules.includes("system.search"), selectedModules.includes("system.storage")));
|
|
4378
|
+
await writeFile9(join12(input.targetDirectory, ".env.example"), environmentExample(includeExample, selectedModules.includes("system.agent"), selectedModules.includes("system.search"), selectedModules.includes("system.storage")));
|
|
4379
|
+
await writeFile9(join12(input.targetDirectory, "README.md"), starterReadme(input.projectName, includeExample, includeOxc, projectLicense, selectedModules));
|
|
4380
|
+
await writeFile9(join12(input.targetDirectory, "docs/README.md"), starterDocsReadme(selectedModules.includes("system.license"), selectedModules.includes("system.agent"), selectedModules.includes("system.operations"), selectedModules.includes("system.storage")));
|
|
4046
4381
|
await reflectCodeQualityChoice(input.targetDirectory, includeOxc);
|
|
4047
4382
|
await applyWindyBaseLicense(input.targetDirectory);
|
|
4048
4383
|
await applyProjectLicense(input.targetDirectory, projectLicense, input.licenseHolder);
|
|
4049
4384
|
await prepareCustomerDockerfiles(input.targetDirectory);
|
|
4050
4385
|
await writeGenerationProvenance(input.targetDirectory, templateMetadata, input.profile ?? starterProfile.key, selectedModules, includeOxc, projectLicense);
|
|
4051
4386
|
await writeInitialProjectModuleRegistry(input.targetDirectory, selectedModules);
|
|
4052
|
-
await rm4(
|
|
4387
|
+
await rm4(join12(input.targetDirectory, "bun.lock"), { force: true });
|
|
4053
4388
|
await writeManagedFilesManifest(input.targetDirectory, templateMetadata.generatorVersion);
|
|
4054
4389
|
}
|
|
4055
4390
|
async function resolveTemplateSource(sourceRoot, relativePath2) {
|
|
4056
|
-
const source =
|
|
4391
|
+
const source = join12(sourceRoot, relativePath2);
|
|
4057
4392
|
try {
|
|
4058
4393
|
await lstat5(source);
|
|
4059
4394
|
return source;
|
|
@@ -4064,12 +4399,12 @@ async function resolveTemplateSource(sourceRoot, relativePath2) {
|
|
|
4064
4399
|
const alias = npmTemplateAliases[relativePath2];
|
|
4065
4400
|
if (!alias)
|
|
4066
4401
|
return source;
|
|
4067
|
-
return
|
|
4402
|
+
return join12(sourceRoot, alias);
|
|
4068
4403
|
}
|
|
4069
4404
|
async function assertGeneratedProjectIsClean(targetDirectory) {
|
|
4070
4405
|
const violations = [];
|
|
4071
4406
|
await walk(targetDirectory, async (path) => {
|
|
4072
|
-
const name =
|
|
4407
|
+
const name = basename6(path);
|
|
4073
4408
|
const extension = extname3(name).toLowerCase();
|
|
4074
4409
|
if (isExcludedTemplateName(name) || excludedRuntimeFiles.has(name) || [".key", ".pem", ".p12", ".pfx"].includes(extension)) {
|
|
4075
4410
|
violations.push(path.slice(targetDirectory.length + 1));
|
|
@@ -4100,17 +4435,17 @@ async function assertTargetAvailable(targetDirectory) {
|
|
|
4100
4435
|
}
|
|
4101
4436
|
async function copyTree(source, target) {
|
|
4102
4437
|
const metadata = await lstat5(source);
|
|
4103
|
-
const name =
|
|
4438
|
+
const name = basename6(source);
|
|
4104
4439
|
if (shouldExclude(name) || metadata.isSymbolicLink())
|
|
4105
4440
|
return;
|
|
4106
4441
|
if (metadata.isDirectory()) {
|
|
4107
4442
|
await mkdir3(target, { recursive: true });
|
|
4108
4443
|
for (const child of await readdir5(source)) {
|
|
4109
|
-
await copyTree(
|
|
4444
|
+
await copyTree(join12(source, child), join12(target, child));
|
|
4110
4445
|
}
|
|
4111
4446
|
return;
|
|
4112
4447
|
}
|
|
4113
|
-
await mkdir3(
|
|
4448
|
+
await mkdir3(join12(target, ".."), { recursive: true });
|
|
4114
4449
|
await copyFile(source, target);
|
|
4115
4450
|
}
|
|
4116
4451
|
function shouldExclude(name) {
|
|
@@ -4118,7 +4453,7 @@ function shouldExclude(name) {
|
|
|
4118
4453
|
}
|
|
4119
4454
|
async function walk(directory, visit) {
|
|
4120
4455
|
for (const name of await readdir5(directory)) {
|
|
4121
|
-
const path =
|
|
4456
|
+
const path = join12(directory, name);
|
|
4122
4457
|
await visit(path);
|
|
4123
4458
|
if ((await lstat5(path)).isDirectory())
|
|
4124
4459
|
await walk(path, visit);
|
|
@@ -4130,10 +4465,10 @@ function isMissing5(error) {
|
|
|
4130
4465
|
|
|
4131
4466
|
// src/template-root.ts
|
|
4132
4467
|
import { access } from "fs/promises";
|
|
4133
|
-
import { dirname as
|
|
4468
|
+
import { dirname as dirname5, resolve as resolve5 } from "path";
|
|
4134
4469
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4135
4470
|
async function resolveTemplateRoot() {
|
|
4136
|
-
const currentDirectory =
|
|
4471
|
+
const currentDirectory = dirname5(fileURLToPath2(import.meta.url));
|
|
4137
4472
|
const templateRoot = resolve5(currentDirectory, "../template");
|
|
4138
4473
|
try {
|
|
4139
4474
|
await access(resolve5(templateRoot, "package.json"));
|
|
@@ -5975,7 +6310,7 @@ import { resolve as resolve8 } from "path";
|
|
|
5975
6310
|
|
|
5976
6311
|
// src/update/doctor.ts
|
|
5977
6312
|
import { readFile as readFile11 } from "fs/promises";
|
|
5978
|
-
import { join as
|
|
6313
|
+
import { join as join16 } from "path";
|
|
5979
6314
|
|
|
5980
6315
|
// src/update/process.ts
|
|
5981
6316
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -6028,10 +6363,10 @@ function withoutParentGitRepository(source) {
|
|
|
6028
6363
|
}
|
|
6029
6364
|
|
|
6030
6365
|
// src/update/transaction-cas.ts
|
|
6031
|
-
import { basename as
|
|
6366
|
+
import { basename as basename8, dirname as dirname7 } from "path";
|
|
6032
6367
|
|
|
6033
6368
|
// src/update/transaction-native-cas.ts
|
|
6034
|
-
import { ptr as
|
|
6369
|
+
import { ptr as ptr3, read as read3, dlopen as dlopen4, FFIType as FFIType4 } from "bun:ffi";
|
|
6035
6370
|
|
|
6036
6371
|
// src/update/transaction-native-cas-config.ts
|
|
6037
6372
|
function nativeRenameConfiguration(platform) {
|
|
@@ -6056,19 +6391,19 @@ function nativeRenameConfiguration(platform) {
|
|
|
6056
6391
|
|
|
6057
6392
|
// src/update/transaction-native-cas.ts
|
|
6058
6393
|
var renameSignature = {
|
|
6059
|
-
args: [
|
|
6060
|
-
returns:
|
|
6394
|
+
args: [FFIType4.i32, FFIType4.ptr, FFIType4.i32, FFIType4.ptr, FFIType4.i32],
|
|
6395
|
+
returns: FFIType4.i32
|
|
6061
6396
|
};
|
|
6062
6397
|
var linuxSymbols = {
|
|
6063
6398
|
renameat2: renameSignature,
|
|
6064
|
-
__errno_location: { args: [], returns:
|
|
6399
|
+
__errno_location: { args: [], returns: FFIType4.ptr }
|
|
6065
6400
|
};
|
|
6066
6401
|
var darwinSymbols = {
|
|
6067
6402
|
renameatx_np: renameSignature,
|
|
6068
|
-
__error: { args: [], returns:
|
|
6403
|
+
__error: { args: [], returns: FFIType4.ptr }
|
|
6069
6404
|
};
|
|
6070
|
-
var getLinuxLibc = createLazyLibcLoader((candidate) =>
|
|
6071
|
-
var getDarwinLibc = createLazyLibcLoader((candidate) =>
|
|
6405
|
+
var getLinuxLibc = createLazyLibcLoader((candidate) => dlopen4(candidate, linuxSymbols), "\u5F53\u524D\u5E73\u53F0\u65E0\u6CD5\u52A0\u8F7D renameat2\uFF0C\u4E8B\u52A1 CAS \u5B89\u5168\u5173\u95ED");
|
|
6406
|
+
var getDarwinLibc = createLazyLibcLoader((candidate) => dlopen4(candidate, darwinSymbols), "\u5F53\u524D\u5E73\u53F0\u65E0\u6CD5\u52A0\u8F7D renameatx_np\uFF0C\u4E8B\u52A1 CAS \u5B89\u5168\u5173\u95ED");
|
|
6072
6407
|
function exchangeAt(parent, left, right, rollback = false) {
|
|
6073
6408
|
atomicRename(parent, left, right, "exchange");
|
|
6074
6409
|
syncMutatedDirectory(rollback ? "rename-exchange-back" : "rename-exchange", parent.fd);
|
|
@@ -6078,10 +6413,18 @@ function moveNoReplaceAt(parent, source, target) {
|
|
|
6078
6413
|
syncMutatedDirectory("rename-noreplace", parent.fd);
|
|
6079
6414
|
}
|
|
6080
6415
|
function atomicRename(parent, source, target, operation) {
|
|
6416
|
+
if (process.platform === "win32") {
|
|
6417
|
+
if (operation === "exchange") {
|
|
6418
|
+
windowsExchangeAt(parent, source, target);
|
|
6419
|
+
} else {
|
|
6420
|
+
windowsMoveNoReplaceAt(parent, source, target);
|
|
6421
|
+
}
|
|
6422
|
+
return;
|
|
6423
|
+
}
|
|
6081
6424
|
const configuration = nativeRenameConfiguration(process.platform);
|
|
6082
6425
|
if (process.platform === "linux") {
|
|
6083
6426
|
const libc = getLinuxLibc();
|
|
6084
|
-
const result = libc.symbols.renameat2(parent.fd,
|
|
6427
|
+
const result = libc.symbols.renameat2(parent.fd, ptr3(cString2(source)), parent.fd, ptr3(cString2(target)), operation === "exchange" ? configuration.exchangeFlag : configuration.noReplaceFlag);
|
|
6085
6428
|
if (result < 0) {
|
|
6086
6429
|
throw linuxError(`renameat2 ${source} -> ${target}`);
|
|
6087
6430
|
}
|
|
@@ -6089,7 +6432,7 @@ function atomicRename(parent, source, target, operation) {
|
|
|
6089
6432
|
}
|
|
6090
6433
|
if (process.platform === "darwin") {
|
|
6091
6434
|
const libc = getDarwinLibc();
|
|
6092
|
-
const result = libc.symbols.renameatx_np(parent.fd,
|
|
6435
|
+
const result = libc.symbols.renameatx_np(parent.fd, ptr3(cString2(source)), parent.fd, ptr3(cString2(target)), operation === "exchange" ? configuration.exchangeFlag : configuration.noReplaceFlag);
|
|
6093
6436
|
if (result < 0) {
|
|
6094
6437
|
throw darwinError(`renameatx_np ${source} -> ${target}`);
|
|
6095
6438
|
}
|
|
@@ -6122,18 +6465,18 @@ function cString2(value) {
|
|
|
6122
6465
|
}
|
|
6123
6466
|
|
|
6124
6467
|
// src/update/transaction-cas-proof.ts
|
|
6125
|
-
import { closeSync as
|
|
6468
|
+
import { closeSync as closeSync6, constants as constants5, fstatSync as fstatSync4, readSync } from "fs";
|
|
6126
6469
|
function openFileProof(parent) {
|
|
6127
|
-
const fd = openFileAt(parent,
|
|
6470
|
+
const fd = openFileAt(parent, constants5.O_RDONLY | constants5.O_NOFOLLOW);
|
|
6128
6471
|
try {
|
|
6129
6472
|
const identity = identityOf(fd);
|
|
6130
6473
|
return {
|
|
6131
6474
|
fd,
|
|
6132
6475
|
...identity,
|
|
6133
|
-
close: () =>
|
|
6476
|
+
close: () => closeSync6(fd)
|
|
6134
6477
|
};
|
|
6135
6478
|
} catch (error) {
|
|
6136
|
-
|
|
6479
|
+
closeSync6(fd);
|
|
6137
6480
|
throw error;
|
|
6138
6481
|
}
|
|
6139
6482
|
}
|
|
@@ -6151,7 +6494,7 @@ function assertProofPayload(proof, content, mode) {
|
|
|
6151
6494
|
function pathMatchesProof(parent, proof) {
|
|
6152
6495
|
let fd;
|
|
6153
6496
|
try {
|
|
6154
|
-
fd = openFileAt(parent,
|
|
6497
|
+
fd = openFileAt(parent, constants5.O_RDONLY | constants5.O_NOFOLLOW);
|
|
6155
6498
|
} catch {
|
|
6156
6499
|
return false;
|
|
6157
6500
|
}
|
|
@@ -6159,7 +6502,7 @@ function pathMatchesProof(parent, proof) {
|
|
|
6159
6502
|
const identity = identityOf(fd);
|
|
6160
6503
|
return identity.device === proof.device && identity.inode === proof.inode;
|
|
6161
6504
|
} finally {
|
|
6162
|
-
|
|
6505
|
+
closeSync6(fd);
|
|
6163
6506
|
}
|
|
6164
6507
|
}
|
|
6165
6508
|
function pathMatchesExpectedProof(parent, proof, expected, expectedMode) {
|
|
@@ -6180,7 +6523,7 @@ function modeOfProof(proof) {
|
|
|
6180
6523
|
return inspectProof(proof).mode;
|
|
6181
6524
|
}
|
|
6182
6525
|
function inspectProof(proof) {
|
|
6183
|
-
const stat2 =
|
|
6526
|
+
const stat2 = fstatSync4(proof.fd, { bigint: true });
|
|
6184
6527
|
if (!stat2.isFile())
|
|
6185
6528
|
throw new Error("\u4E8B\u52A1\u76EE\u6807\u4E0D\u662F\u666E\u901A\u6587\u4EF6");
|
|
6186
6529
|
if (stat2.dev !== proof.device || stat2.ino !== proof.inode) {
|
|
@@ -6197,7 +6540,7 @@ function inspectProof(proof) {
|
|
|
6197
6540
|
throw new Error("\u4E8B\u52A1\u76EE\u6807\u8BFB\u53D6\u63D0\u524D\u7ED3\u675F");
|
|
6198
6541
|
offset += count;
|
|
6199
6542
|
}
|
|
6200
|
-
const after =
|
|
6543
|
+
const after = fstatSync4(proof.fd, { bigint: true });
|
|
6201
6544
|
if (after.dev !== stat2.dev || after.ino !== stat2.ino || after.size !== stat2.size || after.mtimeNs !== stat2.mtimeNs || after.ctimeNs !== stat2.ctimeNs || after.mode !== stat2.mode) {
|
|
6202
6545
|
throw new Error("\u4E8B\u52A1\u76EE\u6807\u5728\u8BC1\u660E\u671F\u95F4\u53D1\u751F\u53D8\u5316");
|
|
6203
6546
|
}
|
|
@@ -6207,7 +6550,7 @@ function inspectProof(proof) {
|
|
|
6207
6550
|
};
|
|
6208
6551
|
}
|
|
6209
6552
|
function identityOf(fd) {
|
|
6210
|
-
const stat2 =
|
|
6553
|
+
const stat2 = fstatSync4(fd, { bigint: true });
|
|
6211
6554
|
if (!stat2.isFile())
|
|
6212
6555
|
throw new Error("\u4E8B\u52A1\u76EE\u6807\u4E0D\u662F\u666E\u901A\u6587\u4EF6");
|
|
6213
6556
|
return { device: stat2.dev, inode: stat2.ino };
|
|
@@ -6328,11 +6671,218 @@ function isBackupEntry(value) {
|
|
|
6328
6671
|
return typeof entry.path === "string" && typeof entry.existed === "boolean" && (entry.mode === undefined || Number.isInteger(entry.mode) && entry.mode >= 0 && entry.mode <= 511);
|
|
6329
6672
|
}
|
|
6330
6673
|
|
|
6674
|
+
// src/update/transaction-cas-windows.ts
|
|
6675
|
+
import { basename as basename7, dirname as dirname6 } from "path";
|
|
6676
|
+
import { closeSync as closeSync7, constants as constants6, fstatSync as fstatSync5, readSync as readSync2 } from "fs";
|
|
6677
|
+
async function windowsAnchoredCompareAndReplace(input) {
|
|
6678
|
+
assertSameDirectory(input.path, input.temporaryPath);
|
|
6679
|
+
const parent = await openAnchoredParent(input.root, input.path, true, input.parentMode);
|
|
6680
|
+
const temporaryName = basename7(input.temporaryPath);
|
|
6681
|
+
let ownsTemporary = false;
|
|
6682
|
+
let exchanged = false;
|
|
6683
|
+
let containsUnknownProjectBytes = false;
|
|
6684
|
+
try {
|
|
6685
|
+
const targetSnapshot = input.expected.kind === "hash" ? snapshot(parent) : undefined;
|
|
6686
|
+
const requestedMode = input.mode ?? targetSnapshot?.mode ?? 384;
|
|
6687
|
+
writeExclusiveAt(withLeaf(parent, temporaryName), input.content, requestedMode);
|
|
6688
|
+
ownsTemporary = true;
|
|
6689
|
+
const desiredSnapshot = snapshot(withLeaf(parent, temporaryName));
|
|
6690
|
+
if (!matchesPayload(desiredSnapshot, input.content))
|
|
6691
|
+
throw casError(input.path);
|
|
6692
|
+
await input.hooks?.beforeAtomicRename?.();
|
|
6693
|
+
if (input.expected.kind === "missing") {
|
|
6694
|
+
publishMissing(parent, temporaryName, input, desiredSnapshot);
|
|
6695
|
+
await input.hooks?.afterAtomicRenameBeforeInspect?.();
|
|
6696
|
+
ownsTemporary = pathMatchesPayload(withLeaf(parent, temporaryName), desiredSnapshot, input.content);
|
|
6697
|
+
containsUnknownProjectBytes = !ownsTemporary;
|
|
6698
|
+
if (!ownsTemporary)
|
|
6699
|
+
throw casError(input.path, input.temporaryPath);
|
|
6700
|
+
return;
|
|
6701
|
+
}
|
|
6702
|
+
if (!targetSnapshot || !pathMatches(parent, targetSnapshot) || !matchesExpected(targetSnapshot, input.expected) || !pathMatches(withLeaf(parent, temporaryName), desiredSnapshot) || !matchesPayload(desiredSnapshot, input.content)) {
|
|
6703
|
+
throw casError(input.path);
|
|
6704
|
+
}
|
|
6705
|
+
exchangeAt(parent, temporaryName, parent.leaf);
|
|
6706
|
+
exchanged = true;
|
|
6707
|
+
ownsTemporary = false;
|
|
6708
|
+
containsUnknownProjectBytes = true;
|
|
6709
|
+
await input.hooks?.afterExchangeBeforeProof?.();
|
|
6710
|
+
if (!pathMatches(withLeaf(parent, temporaryName), targetSnapshot) || !matchesExpected(targetSnapshot, input.expected) || !pathMatches(parent, desiredSnapshot) || !matchesPayload(desiredSnapshot, input.content)) {
|
|
6711
|
+
await rollbackExchange(parent, temporaryName, input, targetSnapshot);
|
|
6712
|
+
exchanged = false;
|
|
6713
|
+
ownsTemporary = pathMatchesPayload(withLeaf(parent, temporaryName), desiredSnapshot, input.content);
|
|
6714
|
+
containsUnknownProjectBytes = !ownsTemporary;
|
|
6715
|
+
throw casError(input.path, ownsTemporary ? undefined : input.temporaryPath);
|
|
6716
|
+
}
|
|
6717
|
+
await input.hooks?.afterAtomicRenameBeforeInspect?.();
|
|
6718
|
+
ownsTemporary = pathMatches(withLeaf(parent, temporaryName), targetSnapshot) && matchesExpected(targetSnapshot, input.expected);
|
|
6719
|
+
containsUnknownProjectBytes = !ownsTemporary;
|
|
6720
|
+
if (!ownsTemporary)
|
|
6721
|
+
throw casError(input.path, input.temporaryPath);
|
|
6722
|
+
} catch (error) {
|
|
6723
|
+
if (error instanceof TransactionCasError)
|
|
6724
|
+
throw error;
|
|
6725
|
+
if (exchanged || containsUnknownProjectBytes) {
|
|
6726
|
+
throw casError(input.path, input.temporaryPath, error);
|
|
6727
|
+
}
|
|
6728
|
+
if (hasFsCode5(error, "ENOENT") || hasFsCode5(error, "EEXIST")) {
|
|
6729
|
+
throw casError(input.path);
|
|
6730
|
+
}
|
|
6731
|
+
throw error;
|
|
6732
|
+
} finally {
|
|
6733
|
+
if (ownsTemporary)
|
|
6734
|
+
removeTemporary(parent, temporaryName);
|
|
6735
|
+
await parent.close();
|
|
6736
|
+
}
|
|
6737
|
+
}
|
|
6738
|
+
async function windowsAnchoredCompareAndRemove(input) {
|
|
6739
|
+
assertSameDirectory(input.path, input.quarantinePath);
|
|
6740
|
+
if (input.expected.kind === "missing")
|
|
6741
|
+
return;
|
|
6742
|
+
const parent = await openAnchoredParent(input.root, input.path, false);
|
|
6743
|
+
const quarantineName = basename7(input.quarantinePath);
|
|
6744
|
+
let ownsQuarantine = false;
|
|
6745
|
+
try {
|
|
6746
|
+
const targetSnapshot = snapshot(parent);
|
|
6747
|
+
await input.hooks?.beforeAtomicRename?.();
|
|
6748
|
+
if (!pathMatches(parent, targetSnapshot) || !matchesExpected(targetSnapshot, input.expected)) {
|
|
6749
|
+
throw casError(input.path);
|
|
6750
|
+
}
|
|
6751
|
+
moveNoReplaceAt(parent, parent.leaf, quarantineName);
|
|
6752
|
+
ownsQuarantine = true;
|
|
6753
|
+
if (!pathMatches(withLeaf(parent, quarantineName), targetSnapshot) || !matchesExpected(targetSnapshot, input.expected)) {
|
|
6754
|
+
throw casError(input.path, input.quarantinePath);
|
|
6755
|
+
}
|
|
6756
|
+
await input.hooks?.afterAtomicRenameBeforeInspect?.();
|
|
6757
|
+
if (pathMatches(withLeaf(parent, quarantineName), targetSnapshot) && matchesExpected(targetSnapshot, input.expected)) {
|
|
6758
|
+
removeTemporary(parent, quarantineName);
|
|
6759
|
+
ownsQuarantine = false;
|
|
6760
|
+
return;
|
|
6761
|
+
}
|
|
6762
|
+
throw casError(input.path, input.quarantinePath);
|
|
6763
|
+
} catch (error) {
|
|
6764
|
+
if (error instanceof TransactionCasError)
|
|
6765
|
+
throw error;
|
|
6766
|
+
if (ownsQuarantine)
|
|
6767
|
+
throw casError(input.path, input.quarantinePath, error);
|
|
6768
|
+
if (hasFsCode5(error, "ENOENT") || hasFsCode5(error, "EEXIST")) {
|
|
6769
|
+
throw casError(input.path);
|
|
6770
|
+
}
|
|
6771
|
+
throw error;
|
|
6772
|
+
} finally {
|
|
6773
|
+
await parent.close();
|
|
6774
|
+
}
|
|
6775
|
+
}
|
|
6776
|
+
function publishMissing(parent, temporaryName, input, desiredSnapshot) {
|
|
6777
|
+
if (!pathMatches(withLeaf(parent, temporaryName), desiredSnapshot) || !matchesPayload(desiredSnapshot, input.content)) {
|
|
6778
|
+
throw casError(input.path);
|
|
6779
|
+
}
|
|
6780
|
+
try {
|
|
6781
|
+
linkAt(parent, temporaryName, parent.leaf);
|
|
6782
|
+
} catch (error) {
|
|
6783
|
+
if (hasFsCode5(error, "EEXIST"))
|
|
6784
|
+
throw casError(input.path);
|
|
6785
|
+
throw error;
|
|
6786
|
+
}
|
|
6787
|
+
if (!pathMatches(parent, desiredSnapshot) || !matchesPayload(desiredSnapshot, input.content)) {
|
|
6788
|
+
throw casError(input.path, input.temporaryPath);
|
|
6789
|
+
}
|
|
6790
|
+
}
|
|
6791
|
+
async function rollbackExchange(parent, temporaryName, input, targetSnapshot) {
|
|
6792
|
+
if (!pathMatches(withLeaf(parent, temporaryName), targetSnapshot) || !matchesExpected(targetSnapshot, input.expected)) {
|
|
6793
|
+
throw casError(input.path, input.temporaryPath);
|
|
6794
|
+
}
|
|
6795
|
+
await input.hooks?.beforeExchangeRollback?.();
|
|
6796
|
+
if (!pathMatches(withLeaf(parent, temporaryName), targetSnapshot) || !matchesExpected(targetSnapshot, input.expected)) {
|
|
6797
|
+
throw casError(input.path, input.temporaryPath);
|
|
6798
|
+
}
|
|
6799
|
+
exchangeAt(parent, temporaryName, parent.leaf, true);
|
|
6800
|
+
await input.hooks?.afterExchangeRollbackBeforeCleanup?.();
|
|
6801
|
+
}
|
|
6802
|
+
function snapshot(parent) {
|
|
6803
|
+
const fd = openFileAt(parent, constants6.O_RDONLY);
|
|
6804
|
+
try {
|
|
6805
|
+
const before = fstatSync5(fd, { bigint: true });
|
|
6806
|
+
if (!before.isFile())
|
|
6807
|
+
throw new Error("\u4E8B\u52A1\u76EE\u6807\u4E0D\u662F\u666E\u901A\u6587\u4EF6");
|
|
6808
|
+
if (before.size > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
6809
|
+
throw new Error("\u4E8B\u52A1\u76EE\u6807\u8FC7\u5927\uFF0C\u65E0\u6CD5\u5B89\u5168\u9A8C\u8BC1");
|
|
6810
|
+
}
|
|
6811
|
+
const content = Buffer.alloc(Number(before.size));
|
|
6812
|
+
let offset = 0;
|
|
6813
|
+
while (offset < content.length) {
|
|
6814
|
+
const count = readSync2(fd, content, offset, content.length - offset, offset);
|
|
6815
|
+
if (!count)
|
|
6816
|
+
throw new Error("\u4E8B\u52A1\u76EE\u6807\u8BFB\u53D6\u63D0\u524D\u7ED3\u675F");
|
|
6817
|
+
offset += count;
|
|
6818
|
+
}
|
|
6819
|
+
const after = fstatSync5(fd, { bigint: true });
|
|
6820
|
+
if (after.dev !== before.dev || after.ino !== before.ino || after.size !== before.size || after.mtimeNs !== before.mtimeNs || after.ctimeNs !== before.ctimeNs) {
|
|
6821
|
+
throw new Error("\u4E8B\u52A1\u76EE\u6807\u5728\u8BC1\u660E\u671F\u95F4\u53D1\u751F\u53D8\u5316");
|
|
6822
|
+
}
|
|
6823
|
+
return {
|
|
6824
|
+
device: before.dev,
|
|
6825
|
+
inode: before.ino,
|
|
6826
|
+
hash: hashContent(content),
|
|
6827
|
+
mode: Number(before.mode & 0o777n)
|
|
6828
|
+
};
|
|
6829
|
+
} finally {
|
|
6830
|
+
closeSync7(fd);
|
|
6831
|
+
}
|
|
6832
|
+
}
|
|
6833
|
+
function pathMatches(parent, expected) {
|
|
6834
|
+
try {
|
|
6835
|
+
const current = snapshot(parent);
|
|
6836
|
+
return current.device === expected.device && current.inode === expected.inode && current.hash === expected.hash;
|
|
6837
|
+
} catch {
|
|
6838
|
+
return false;
|
|
6839
|
+
}
|
|
6840
|
+
}
|
|
6841
|
+
function pathMatchesPayload(parent, expected, content) {
|
|
6842
|
+
try {
|
|
6843
|
+
const current = snapshot(parent);
|
|
6844
|
+
return current.device === expected.device && current.inode === expected.inode && current.hash === hashContent(content);
|
|
6845
|
+
} catch {
|
|
6846
|
+
return false;
|
|
6847
|
+
}
|
|
6848
|
+
}
|
|
6849
|
+
function matchesExpected(snapshot2, expected) {
|
|
6850
|
+
return expected.kind === "hash" && snapshot2.hash === expected.value;
|
|
6851
|
+
}
|
|
6852
|
+
function matchesPayload(snapshot2, content) {
|
|
6853
|
+
return snapshot2.hash === hashContent(content);
|
|
6854
|
+
}
|
|
6855
|
+
function removeTemporary(parent, name) {
|
|
6856
|
+
try {
|
|
6857
|
+
unlinkAt(withLeaf(parent, name));
|
|
6858
|
+
} catch (error) {
|
|
6859
|
+
if (!hasFsCode5(error, "ENOENT"))
|
|
6860
|
+
throw error;
|
|
6861
|
+
}
|
|
6862
|
+
}
|
|
6863
|
+
function withLeaf(parent, leaf) {
|
|
6864
|
+
return { ...parent, leaf };
|
|
6865
|
+
}
|
|
6866
|
+
function assertSameDirectory(path2, temporaryPath) {
|
|
6867
|
+
if (dirname6(path2) !== dirname6(temporaryPath)) {
|
|
6868
|
+
throw new Error("\u4E8B\u52A1 CAS \u4E34\u65F6\u6587\u4EF6\u5FC5\u987B\u4E0E\u76EE\u6807\u4F4D\u4E8E\u540C\u4E00\u76EE\u5F55");
|
|
6869
|
+
}
|
|
6870
|
+
}
|
|
6871
|
+
function casError(path2, artifactPath, cause) {
|
|
6872
|
+
return new TransactionCasError(`\u8BA1\u5212\u540E\u5DF2\u53D8\u5316\uFF1A${path2}`, path2, artifactPath ? [{ path: path2, artifactPath }] : [], { cause });
|
|
6873
|
+
}
|
|
6874
|
+
function hasFsCode5(error, code) {
|
|
6875
|
+
return error instanceof Error && "code" in error && error.code === code;
|
|
6876
|
+
}
|
|
6877
|
+
|
|
6331
6878
|
// src/update/transaction-cas.ts
|
|
6332
6879
|
async function anchoredCompareAndReplace(input) {
|
|
6333
|
-
|
|
6880
|
+
if (process.platform === "win32") {
|
|
6881
|
+
return windowsAnchoredCompareAndReplace(input);
|
|
6882
|
+
}
|
|
6883
|
+
assertSameDirectory2(input.path, input.temporaryPath);
|
|
6334
6884
|
const parent = await openAnchoredParent(input.root, input.path, true, input.parentMode);
|
|
6335
|
-
const temporaryName =
|
|
6885
|
+
const temporaryName = basename8(input.temporaryPath);
|
|
6336
6886
|
let ownsTemporary = false;
|
|
6337
6887
|
let exchanged = false;
|
|
6338
6888
|
let containsUnknownProjectBytes = false;
|
|
@@ -6343,103 +6893,106 @@ async function anchoredCompareAndReplace(input) {
|
|
|
6343
6893
|
targetProof = openFileProof(parent);
|
|
6344
6894
|
}
|
|
6345
6895
|
const mode = input.mode ?? (targetProof ? modeOfProof(targetProof) : 384);
|
|
6346
|
-
writeExclusiveAt(
|
|
6896
|
+
writeExclusiveAt(withLeaf2(parent, temporaryName), input.content, mode);
|
|
6347
6897
|
ownsTemporary = true;
|
|
6348
|
-
desiredProof = openFileProof(
|
|
6898
|
+
desiredProof = openFileProof(withLeaf2(parent, temporaryName));
|
|
6349
6899
|
await input.hooks?.beforeAtomicRename?.();
|
|
6350
6900
|
if (input.expected.kind === "missing") {
|
|
6351
|
-
await
|
|
6352
|
-
ownsTemporary = pathMatchesPayloadProof(
|
|
6901
|
+
await publishMissing2(parent, temporaryName, input, desiredProof, mode);
|
|
6902
|
+
ownsTemporary = pathMatchesPayloadProof(withLeaf2(parent, temporaryName), desiredProof, input.content, mode);
|
|
6353
6903
|
containsUnknownProjectBytes = !ownsTemporary;
|
|
6354
6904
|
if (!ownsTemporary) {
|
|
6355
|
-
throw
|
|
6905
|
+
throw casError2(input.path, input.temporaryPath);
|
|
6356
6906
|
}
|
|
6357
6907
|
return;
|
|
6358
6908
|
}
|
|
6359
|
-
if (!targetProof || !pathMatchesProof(parent, targetProof) || !assertProofMatches(targetProof, input.expected, input.expectedMode) || !pathMatchesProof(
|
|
6360
|
-
throw
|
|
6909
|
+
if (!targetProof || !pathMatchesProof(parent, targetProof) || !assertProofMatches(targetProof, input.expected, input.expectedMode) || !pathMatchesProof(withLeaf2(parent, temporaryName), desiredProof) || !assertProofPayload(desiredProof, input.content, mode)) {
|
|
6910
|
+
throw casError2(input.path);
|
|
6361
6911
|
}
|
|
6362
6912
|
exchangeAt(parent, temporaryName, parent.leaf);
|
|
6363
6913
|
exchanged = true;
|
|
6364
6914
|
ownsTemporary = false;
|
|
6365
6915
|
containsUnknownProjectBytes = true;
|
|
6366
6916
|
await input.hooks?.afterExchangeBeforeProof?.();
|
|
6367
|
-
const proofValid = pathMatchesProof(
|
|
6917
|
+
const proofValid = pathMatchesProof(withLeaf2(parent, temporaryName), targetProof) && assertProofMatches(targetProof, input.expected, input.expectedMode) && pathMatchesProof(parent, desiredProof) && assertProofPayload(desiredProof, input.content, mode);
|
|
6368
6918
|
if (!proofValid) {
|
|
6369
|
-
await
|
|
6919
|
+
await rollbackExchange2(parent, temporaryName, input, targetProof);
|
|
6370
6920
|
exchanged = false;
|
|
6371
|
-
ownsTemporary = pathMatchesPayloadProof(
|
|
6921
|
+
ownsTemporary = pathMatchesPayloadProof(withLeaf2(parent, temporaryName), desiredProof, input.content, mode);
|
|
6372
6922
|
containsUnknownProjectBytes = !ownsTemporary;
|
|
6373
|
-
throw
|
|
6923
|
+
throw casError2(input.path, ownsTemporary ? undefined : input.temporaryPath);
|
|
6374
6924
|
}
|
|
6375
6925
|
await input.hooks?.afterAtomicRenameBeforeInspect?.();
|
|
6376
|
-
ownsTemporary = pathMatchesExpectedProof(
|
|
6926
|
+
ownsTemporary = pathMatchesExpectedProof(withLeaf2(parent, temporaryName), targetProof, input.expected, input.expectedMode);
|
|
6377
6927
|
containsUnknownProjectBytes = !ownsTemporary;
|
|
6378
6928
|
if (!ownsTemporary) {
|
|
6379
|
-
throw
|
|
6929
|
+
throw casError2(input.path, input.temporaryPath);
|
|
6380
6930
|
}
|
|
6381
6931
|
} catch (error) {
|
|
6382
6932
|
if (error instanceof TransactionCasError)
|
|
6383
6933
|
throw error;
|
|
6384
6934
|
if (exchanged) {
|
|
6385
|
-
throw
|
|
6935
|
+
throw casError2(input.path, input.temporaryPath, error);
|
|
6386
6936
|
}
|
|
6387
6937
|
if (containsUnknownProjectBytes) {
|
|
6388
|
-
throw
|
|
6938
|
+
throw casError2(input.path, input.temporaryPath, error);
|
|
6389
6939
|
}
|
|
6390
|
-
if (
|
|
6391
|
-
throw
|
|
6940
|
+
if (hasFsCode4(error, "ENOENT") || hasFsCode4(error, "EEXIST") || hasFsCode4(error, "ELOOP") || hasFsCode4(error, "ENOTDIR")) {
|
|
6941
|
+
throw casError2(input.path);
|
|
6392
6942
|
}
|
|
6393
6943
|
throw error;
|
|
6394
6944
|
} finally {
|
|
6395
6945
|
if (ownsTemporary)
|
|
6396
|
-
|
|
6946
|
+
removeTemporary2(parent, temporaryName);
|
|
6397
6947
|
desiredProof?.close();
|
|
6398
6948
|
targetProof?.close();
|
|
6399
6949
|
await parent.close();
|
|
6400
6950
|
}
|
|
6401
6951
|
}
|
|
6402
6952
|
async function anchoredCompareAndRemove(input) {
|
|
6403
|
-
|
|
6953
|
+
if (process.platform === "win32") {
|
|
6954
|
+
return windowsAnchoredCompareAndRemove(input);
|
|
6955
|
+
}
|
|
6956
|
+
assertSameDirectory2(input.path, input.quarantinePath);
|
|
6404
6957
|
if (input.expected.kind === "missing")
|
|
6405
6958
|
return;
|
|
6406
6959
|
let parent;
|
|
6407
6960
|
try {
|
|
6408
6961
|
parent = await openAnchoredParent(input.root, input.path, false);
|
|
6409
6962
|
} catch (error) {
|
|
6410
|
-
if (
|
|
6411
|
-
throw
|
|
6963
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
6964
|
+
throw casError2(input.path);
|
|
6412
6965
|
throw error;
|
|
6413
6966
|
}
|
|
6414
|
-
const quarantineName =
|
|
6967
|
+
const quarantineName = basename8(input.quarantinePath);
|
|
6415
6968
|
let ownsQuarantine = false;
|
|
6416
6969
|
let targetProof;
|
|
6417
6970
|
try {
|
|
6418
6971
|
targetProof = openFileProof(parent);
|
|
6419
6972
|
await input.hooks?.beforeAtomicRename?.();
|
|
6420
6973
|
if (!pathMatchesProof(parent, targetProof) || !assertProofMatches(targetProof, input.expected, input.expectedMode)) {
|
|
6421
|
-
throw
|
|
6974
|
+
throw casError2(input.path);
|
|
6422
6975
|
}
|
|
6423
6976
|
moveNoReplaceAt(parent, parent.leaf, quarantineName);
|
|
6424
6977
|
ownsQuarantine = true;
|
|
6425
|
-
if (!pathMatchesProof(
|
|
6426
|
-
throw
|
|
6978
|
+
if (!pathMatchesProof(withLeaf2(parent, quarantineName), targetProof) || !assertProofMatches(targetProof, input.expected, input.expectedMode)) {
|
|
6979
|
+
throw casError2(input.path, input.quarantinePath);
|
|
6427
6980
|
}
|
|
6428
6981
|
await input.hooks?.afterAtomicRenameBeforeInspect?.();
|
|
6429
|
-
if (pathMatchesExpectedProof(
|
|
6430
|
-
|
|
6982
|
+
if (pathMatchesExpectedProof(withLeaf2(parent, quarantineName), targetProof, input.expected, input.expectedMode)) {
|
|
6983
|
+
removeTemporary2(parent, quarantineName);
|
|
6431
6984
|
ownsQuarantine = false;
|
|
6432
6985
|
return;
|
|
6433
6986
|
}
|
|
6434
|
-
throw
|
|
6987
|
+
throw casError2(input.path, input.quarantinePath);
|
|
6435
6988
|
} catch (error) {
|
|
6436
6989
|
if (error instanceof TransactionCasError)
|
|
6437
6990
|
throw error;
|
|
6438
6991
|
if (ownsQuarantine) {
|
|
6439
|
-
throw
|
|
6992
|
+
throw casError2(input.path, input.quarantinePath, error);
|
|
6440
6993
|
}
|
|
6441
|
-
if (
|
|
6442
|
-
throw
|
|
6994
|
+
if (hasFsCode4(error, "ENOENT") || hasFsCode4(error, "EEXIST")) {
|
|
6995
|
+
throw casError2(input.path);
|
|
6443
6996
|
}
|
|
6444
6997
|
throw error;
|
|
6445
6998
|
} finally {
|
|
@@ -6455,8 +7008,8 @@ async function linearizeExpectation(input) {
|
|
|
6455
7008
|
content = readFileAt(parent);
|
|
6456
7009
|
} catch (error) {
|
|
6457
7010
|
await parent.close();
|
|
6458
|
-
if (
|
|
6459
|
-
throw
|
|
7011
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
7012
|
+
throw casError2(input.path);
|
|
6460
7013
|
throw error;
|
|
6461
7014
|
}
|
|
6462
7015
|
await parent.close();
|
|
@@ -6468,61 +7021,61 @@ async function linearizeExpectation(input) {
|
|
|
6468
7021
|
}
|
|
6469
7022
|
throw new Error(`\u7F3A\u5931\u8DEF\u5F84\u5FC5\u987B\u7531\u5199\u5165\u6216\u5220\u9664 CAS \u63D0\u4F9B\u7EBF\u6027\u5316\u8BC1\u636E\uFF1A${input.path}`);
|
|
6470
7023
|
}
|
|
6471
|
-
async function
|
|
6472
|
-
if (!pathMatchesProof(
|
|
6473
|
-
throw
|
|
7024
|
+
async function publishMissing2(parent, temporaryName, input, desiredProof, mode) {
|
|
7025
|
+
if (!pathMatchesProof(withLeaf2(parent, temporaryName), desiredProof) || !assertProofPayload(desiredProof, input.content, mode)) {
|
|
7026
|
+
throw casError2(input.path);
|
|
6474
7027
|
}
|
|
6475
7028
|
try {
|
|
6476
7029
|
linkAt(parent, temporaryName, parent.leaf);
|
|
6477
7030
|
} catch (error) {
|
|
6478
|
-
if (
|
|
6479
|
-
throw
|
|
7031
|
+
if (hasFsCode4(error, "EEXIST"))
|
|
7032
|
+
throw casError2(input.path);
|
|
6480
7033
|
throw error;
|
|
6481
7034
|
}
|
|
6482
7035
|
if (!pathMatchesProof(parent, desiredProof) || !assertProofPayload(desiredProof, input.content, mode)) {
|
|
6483
|
-
throw
|
|
7036
|
+
throw casError2(input.path, input.temporaryPath);
|
|
6484
7037
|
}
|
|
6485
7038
|
await input.hooks?.afterAtomicRenameBeforeInspect?.();
|
|
6486
7039
|
}
|
|
6487
|
-
async function
|
|
6488
|
-
if (!pathMatchesProof(
|
|
6489
|
-
throw
|
|
7040
|
+
async function rollbackExchange2(parent, temporaryName, input, targetProof) {
|
|
7041
|
+
if (!pathMatchesProof(withLeaf2(parent, temporaryName), targetProof) || !assertProofMatches(targetProof, input.expected, input.expectedMode)) {
|
|
7042
|
+
throw casError2(input.path, input.temporaryPath);
|
|
6490
7043
|
}
|
|
6491
7044
|
await input.hooks?.beforeExchangeRollback?.();
|
|
6492
|
-
if (!pathMatchesProof(
|
|
6493
|
-
throw
|
|
7045
|
+
if (!pathMatchesProof(withLeaf2(parent, temporaryName), targetProof) || !assertProofMatches(targetProof, input.expected, input.expectedMode)) {
|
|
7046
|
+
throw casError2(input.path, input.temporaryPath);
|
|
6494
7047
|
}
|
|
6495
7048
|
exchangeAt(parent, temporaryName, parent.leaf, true);
|
|
6496
7049
|
await input.hooks?.afterExchangeRollbackBeforeCleanup?.();
|
|
6497
7050
|
}
|
|
6498
|
-
function
|
|
7051
|
+
function removeTemporary2(parent, name) {
|
|
6499
7052
|
try {
|
|
6500
|
-
unlinkAt(
|
|
7053
|
+
unlinkAt(withLeaf2(parent, name));
|
|
6501
7054
|
} catch (error) {
|
|
6502
|
-
if (!
|
|
7055
|
+
if (!hasFsCode4(error, "ENOENT"))
|
|
6503
7056
|
throw error;
|
|
6504
7057
|
}
|
|
6505
7058
|
}
|
|
6506
|
-
function
|
|
7059
|
+
function withLeaf2(parent, leaf) {
|
|
6507
7060
|
return { ...parent, leaf };
|
|
6508
7061
|
}
|
|
6509
|
-
function
|
|
6510
|
-
if (
|
|
7062
|
+
function assertSameDirectory2(path2, temporaryPath) {
|
|
7063
|
+
if (dirname7(path2) !== dirname7(temporaryPath)) {
|
|
6511
7064
|
throw new Error("\u4E8B\u52A1 CAS \u4E34\u65F6\u6587\u4EF6\u5FC5\u987B\u4E0E\u76EE\u6807\u4F4D\u4E8E\u540C\u4E00\u76EE\u5F55");
|
|
6512
7065
|
}
|
|
6513
7066
|
}
|
|
6514
|
-
function
|
|
7067
|
+
function casError2(path2, artifactPath, cause) {
|
|
6515
7068
|
return new TransactionCasError(`\u8BA1\u5212\u540E\u5DF2\u53D8\u5316\uFF1A${path2}`, path2, artifactPath ? [{ path: path2, artifactPath }] : [], { cause });
|
|
6516
7069
|
}
|
|
6517
7070
|
|
|
6518
7071
|
// src/update/transaction-runtime.ts
|
|
6519
7072
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
6520
|
-
import { join as
|
|
7073
|
+
import { join as join14 } from "path";
|
|
6521
7074
|
|
|
6522
7075
|
// src/update/transaction-state-temporaries.ts
|
|
6523
7076
|
import { randomUUID } from "crypto";
|
|
6524
7077
|
import { readdir as readdir7 } from "fs/promises";
|
|
6525
|
-
import { join as
|
|
7078
|
+
import { join as join13 } from "path";
|
|
6526
7079
|
function serializeTransactionState(state) {
|
|
6527
7080
|
return `${JSON.stringify(state, null, 2)}
|
|
6528
7081
|
`;
|
|
@@ -6638,8 +7191,8 @@ function stateTemporaryName(identity, cleanup) {
|
|
|
6638
7191
|
return `${prefix}.${identity.kind}.${identity.ownerToken}.${identity.nonce}.tmp`;
|
|
6639
7192
|
}
|
|
6640
7193
|
async function listWindyDirectory(root) {
|
|
6641
|
-
return readdir7(
|
|
6642
|
-
if (
|
|
7194
|
+
return readdir7(join13(root, ".windy")).catch((error) => {
|
|
7195
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
6643
7196
|
return [];
|
|
6644
7197
|
throw error;
|
|
6645
7198
|
});
|
|
@@ -6672,7 +7225,7 @@ function createTransactionState(root, updateId, entries, manifestHash) {
|
|
|
6672
7225
|
return {
|
|
6673
7226
|
schemaVersion: 1,
|
|
6674
7227
|
updateId,
|
|
6675
|
-
backupDirectory:
|
|
7228
|
+
backupDirectory: join14(root, backupRelativePath(updateId)),
|
|
6676
7229
|
entries,
|
|
6677
7230
|
ownerToken: randomUUID2(),
|
|
6678
7231
|
phase: "claiming",
|
|
@@ -6691,7 +7244,7 @@ async function claimTransactionState(root, state, hooks) {
|
|
|
6691
7244
|
expected: { kind: "missing" }
|
|
6692
7245
|
});
|
|
6693
7246
|
} catch (error) {
|
|
6694
|
-
if (
|
|
7247
|
+
if (hasFsCode4(error, "EEXIST") || error instanceof TransactionCasError) {
|
|
6695
7248
|
throw new Error("\u68C0\u6D4B\u5230\u672A\u5B8C\u6210\u66F4\u65B0\uFF0C\u8BF7\u5148\u8FD0\u884C bun run windy doctor --repair", { cause: error });
|
|
6696
7249
|
}
|
|
6697
7250
|
throw error;
|
|
@@ -6731,7 +7284,7 @@ async function backupEntriesToDisk(root, backupPath, entries, afterEntry) {
|
|
|
6731
7284
|
if (entry.mode !== undefined && await safeFileMode(root, entry.path) !== entry.mode) {
|
|
6732
7285
|
throw new TransactionCasError(`\u5F85\u5907\u4EFD\u6587\u4EF6 mode \u5DF2\u53D8\u5316\uFF1A${entry.path}`, entry.path);
|
|
6733
7286
|
}
|
|
6734
|
-
await writeExclusive(root,
|
|
7287
|
+
await writeExclusive(root, join14(backupPath, "files", entry.path), content, undefined, entry.mode);
|
|
6735
7288
|
await afterEntry?.();
|
|
6736
7289
|
}
|
|
6737
7290
|
}
|
|
@@ -7039,8 +7592,8 @@ async function removeOwnedResidue(root, evidence, hash, mode) {
|
|
|
7039
7592
|
}
|
|
7040
7593
|
|
|
7041
7594
|
// src/update/transaction-recovery-files.ts
|
|
7042
|
-
import { join as
|
|
7043
|
-
function
|
|
7595
|
+
import { join as join15 } from "path";
|
|
7596
|
+
function matchesExpected2(actualHash, actualMode, expected, expectedMode) {
|
|
7044
7597
|
return expected.kind === "missing" ? actualHash === undefined : actualHash === expected.value && (expectedMode === undefined || actualMode === expectedMode);
|
|
7045
7598
|
}
|
|
7046
7599
|
async function readRecoveryBackups(root, backupPath, state, preserved) {
|
|
@@ -7051,7 +7604,7 @@ async function readRecoveryBackups(root, backupPath, state, preserved) {
|
|
|
7051
7604
|
await inspectSafePath(root, entry.path);
|
|
7052
7605
|
if (!entry.existed)
|
|
7053
7606
|
continue;
|
|
7054
|
-
const backupFile =
|
|
7607
|
+
const backupFile = join15(backupPath, "files", entry.path);
|
|
7055
7608
|
const content = await readSafeOptional(root, backupFile);
|
|
7056
7609
|
if (!content)
|
|
7057
7610
|
throw new Error(`\u4E8B\u52A1\u5907\u4EFD\u7F3A\u5931\uFF1A${entry.path}`);
|
|
@@ -7065,7 +7618,7 @@ async function readRecoveryBackups(root, backupPath, state, preserved) {
|
|
|
7065
7618
|
async function assertRestoredEntries(root, state, backups) {
|
|
7066
7619
|
for (const entry of state.entries) {
|
|
7067
7620
|
const expected = entry.existed ? { kind: "hash", value: hashContent(backups.get(entry.path)) } : { kind: "missing" };
|
|
7068
|
-
if (!
|
|
7621
|
+
if (!matchesExpected2(await hashSafePath(root, entry.path), await safeFileMode(root, entry.path), expected, entry.mode)) {
|
|
7069
7622
|
throw new Error(`\u4E8B\u52A1\u8DEF\u5F84\u5C1A\u672A\u771F\u5B9E\u6062\u590D\uFF1A${entry.path}`);
|
|
7070
7623
|
}
|
|
7071
7624
|
const evidence = state.recoveryEvidence?.find(({ path: path2 }) => path2 === entry.path);
|
|
@@ -7088,8 +7641,8 @@ async function unresolvedPreservePaths(root, backupPath, state) {
|
|
|
7088
7641
|
const actualHash = await hashSafePath(root, path2);
|
|
7089
7642
|
const actualMode = await safeFileMode(root, path2);
|
|
7090
7643
|
const mutation = state.mutationEvidence?.find((evidence) => evidence.path === path2);
|
|
7091
|
-
const matchesBackup =
|
|
7092
|
-
const matchesOutcome = Boolean(mutation?.linearized && mutation.outcome &&
|
|
7644
|
+
const matchesBackup = matchesExpected2(actualHash, actualMode, backup, entry.mode);
|
|
7645
|
+
const matchesOutcome = Boolean(mutation?.linearized && mutation.outcome && matchesExpected2(actualHash, actualMode, mutation.outcome, mutation.outcomeMode));
|
|
7093
7646
|
const hasConflictArtifact = state.conflictArtifacts?.some((artifact) => artifact.path === path2) ?? false;
|
|
7094
7647
|
if (!matchesBackup && (!matchesOutcome || hasConflictArtifact)) {
|
|
7095
7648
|
unresolved.push(path2);
|
|
@@ -7161,7 +7714,7 @@ async function restoreUpdateState(projectDirectory, state, options) {
|
|
|
7161
7714
|
const actualHash = await hashSafePath(root, entry.path);
|
|
7162
7715
|
if (current.phase === "committing") {
|
|
7163
7716
|
const expected = current.expectations?.find(({ path: path2 }) => path2 === entry.path);
|
|
7164
|
-
if (!expected || !
|
|
7717
|
+
if (!expected || !matchesExpected2(actualHash, await safeFileMode(root, entry.path), expected.expected, expected.mode)) {
|
|
7165
7718
|
newlyPreserved.push(entry.path);
|
|
7166
7719
|
} else {
|
|
7167
7720
|
recoveryExpectations.set(entry.path, expected);
|
|
@@ -7171,9 +7724,9 @@ async function restoreUpdateState(projectDirectory, state, options) {
|
|
|
7171
7724
|
const evidence = current.mutationEvidence?.find(({ path: path2 }) => path2 === entry.path);
|
|
7172
7725
|
if (!evidence) {
|
|
7173
7726
|
newlyPreserved.push(entry.path);
|
|
7174
|
-
} else if (
|
|
7727
|
+
} else if (matchesExpected2(actualHash, await safeFileMode(root, entry.path), evidence.before, evidence.beforeMode)) {
|
|
7175
7728
|
continue;
|
|
7176
|
-
} else if (evidence.outcome &&
|
|
7729
|
+
} else if (evidence.outcome && matchesExpected2(actualHash, await safeFileMode(root, entry.path), evidence.outcome, evidence.outcomeMode)) {
|
|
7177
7730
|
recoveryExpectations.set(entry.path, {
|
|
7178
7731
|
expected: evidence.outcome,
|
|
7179
7732
|
mode: evidence.outcomeMode
|
|
@@ -7682,7 +8235,7 @@ async function diagnoseProject(projectDirectory, repair = false) {
|
|
|
7682
8235
|
if (file.ownership === "project-owned")
|
|
7683
8236
|
continue;
|
|
7684
8237
|
try {
|
|
7685
|
-
const changed = hashContent(await readFile11(
|
|
8238
|
+
const changed = hashContent(await readFile11(join16(projectDirectory, file.path))) !== file.hash;
|
|
7686
8239
|
if (!changed)
|
|
7687
8240
|
continue;
|
|
7688
8241
|
modifiedManagedFiles.push(file.path);
|
|
@@ -7727,6 +8280,16 @@ var recipes = [
|
|
|
7727
8280
|
id: "starter-0.6.7-to-0.6.8",
|
|
7728
8281
|
from: "0.6.7",
|
|
7729
8282
|
to: "0.6.8"
|
|
8283
|
+
},
|
|
8284
|
+
{
|
|
8285
|
+
id: "starter-0.6.8-to-0.6.9",
|
|
8286
|
+
from: "0.6.8",
|
|
8287
|
+
to: "0.6.9"
|
|
8288
|
+
},
|
|
8289
|
+
{
|
|
8290
|
+
id: "starter-0.6.9-to-0.6.10",
|
|
8291
|
+
from: "0.6.9",
|
|
8292
|
+
to: "0.6.10"
|
|
7730
8293
|
}
|
|
7731
8294
|
];
|
|
7732
8295
|
function resolveRecipeChain(sourceVersion, targetVersion) {
|
|
@@ -7773,17 +8336,17 @@ function parseVersion2(version) {
|
|
|
7773
8336
|
|
|
7774
8337
|
// src/update/updater.ts
|
|
7775
8338
|
import { readFile as readFile23, rm as rm8 } from "fs/promises";
|
|
7776
|
-
import { join as
|
|
8339
|
+
import { join as join28 } from "path";
|
|
7777
8340
|
|
|
7778
8341
|
// src/update/artifacts.ts
|
|
7779
8342
|
import { mkdtemp, readFile as readFile14 } from "fs/promises";
|
|
7780
8343
|
import { tmpdir } from "os";
|
|
7781
|
-
import { basename as
|
|
8344
|
+
import { basename as basename10, join as join19 } from "path";
|
|
7782
8345
|
|
|
7783
8346
|
// src/update/published-artifacts.ts
|
|
7784
8347
|
import { createHash as createHash4 } from "crypto";
|
|
7785
8348
|
import { mkdir as mkdir6, readFile as readFile12, writeFile as writeFile10 } from "fs/promises";
|
|
7786
|
-
import { basename as
|
|
8349
|
+
import { basename as basename9, join as join17 } from "path";
|
|
7787
8350
|
|
|
7788
8351
|
// src/update/safe-archive.ts
|
|
7789
8352
|
import { mkdir as mkdir5 } from "fs/promises";
|
|
@@ -7835,17 +8398,17 @@ async function downloadPublicArtifact(temporaryRoot, label, version, expectedInt
|
|
|
7835
8398
|
}
|
|
7836
8399
|
const archive = await readBoundedResponse(response, `create-windy@${version} artifact `);
|
|
7837
8400
|
verifyArchive(metadata, archive);
|
|
7838
|
-
const destination =
|
|
7839
|
-
const archivePath =
|
|
8401
|
+
const destination = join17(temporaryRoot, `${label}-artifact`);
|
|
8402
|
+
const archivePath = join17(temporaryRoot, `${label}.tgz`);
|
|
7840
8403
|
await writeFile10(archivePath, archive);
|
|
7841
8404
|
await extractSafeTarArchive({
|
|
7842
8405
|
archivePath,
|
|
7843
8406
|
destination,
|
|
7844
8407
|
cwd: temporaryRoot
|
|
7845
8408
|
});
|
|
7846
|
-
const packageRoot2 =
|
|
7847
|
-
const packageJson = JSON.parse(await readFile12(
|
|
7848
|
-
const template = await readTemplateMetadata(
|
|
8409
|
+
const packageRoot2 = join17(destination, "package");
|
|
8410
|
+
const packageJson = JSON.parse(await readFile12(join17(packageRoot2, "package.json"), "utf8"));
|
|
8411
|
+
const template = await readTemplateMetadata(join17(packageRoot2, "template"));
|
|
7849
8412
|
if (packageJson.name !== "create-windy" || packageJson.version !== version || template.generatorVersion !== version) {
|
|
7850
8413
|
throw new Error(`create-windy@${version} \u5305\u8EAB\u4EFD\u6216\u6A21\u677F\u5143\u6570\u636E\u4E0D\u4E00\u81F4`);
|
|
7851
8414
|
}
|
|
@@ -7977,10 +8540,10 @@ function verifyArchive(metadata, archive) {
|
|
|
7977
8540
|
}
|
|
7978
8541
|
}
|
|
7979
8542
|
async function generatePublicArtifactProject(temporaryRoot, label, projectName, packageRoot2, provenance) {
|
|
7980
|
-
const parent =
|
|
8543
|
+
const parent = join17(temporaryRoot, label);
|
|
7981
8544
|
await mkdir6(parent, { recursive: true });
|
|
7982
8545
|
const args = [
|
|
7983
|
-
|
|
8546
|
+
join17(packageRoot2, "dist/cli.js"),
|
|
7984
8547
|
projectName,
|
|
7985
8548
|
"--yes",
|
|
7986
8549
|
"--skip-install",
|
|
@@ -8000,7 +8563,7 @@ async function generatePublicArtifactProject(temporaryRoot, label, projectName,
|
|
|
8000
8563
|
}
|
|
8001
8564
|
}
|
|
8002
8565
|
await assertProcess("bun", args, parent);
|
|
8003
|
-
return
|
|
8566
|
+
return join17(parent, projectName);
|
|
8004
8567
|
}
|
|
8005
8568
|
|
|
8006
8569
|
// src/module-history.ts
|
|
@@ -8011,15 +8574,15 @@ import {
|
|
|
8011
8574
|
readFile as readFile13,
|
|
8012
8575
|
writeFile as writeFile11
|
|
8013
8576
|
} from "fs/promises";
|
|
8014
|
-
import { dirname as
|
|
8577
|
+
import { dirname as dirname8, join as join18, relative as relative5, sep as sep4 } from "path";
|
|
8015
8578
|
async function archiveRemovedModuleMigrations(input) {
|
|
8016
8579
|
await assertExistingHistoryIntegrity(input.projectDirectory);
|
|
8017
|
-
let changed = await copyMigrationTree(input.projectDirectory, ".windy/module-history",
|
|
8580
|
+
let changed = await copyMigrationTree(input.projectDirectory, ".windy/module-history", join18(input.targetDirectory, ".windy/module-history"));
|
|
8018
8581
|
const target = new Set(input.targetModules);
|
|
8019
8582
|
const removed = moduleDistributionCatalog.filter(({ name }) => input.sourceModules.includes(name) && !target.has(name));
|
|
8020
8583
|
for (const manifest of removed) {
|
|
8021
8584
|
for (const root of manifest.migrationRoots) {
|
|
8022
|
-
changed = await copyMigrationTree(input.projectDirectory, root,
|
|
8585
|
+
changed = await copyMigrationTree(input.projectDirectory, root, join18(input.targetDirectory, ".windy/module-history", manifest.name, root)) || changed;
|
|
8023
8586
|
}
|
|
8024
8587
|
}
|
|
8025
8588
|
if (changed) {
|
|
@@ -8027,7 +8590,7 @@ async function archiveRemovedModuleMigrations(input) {
|
|
|
8027
8590
|
}
|
|
8028
8591
|
}
|
|
8029
8592
|
async function assertExistingHistoryIntegrity(projectDirectory) {
|
|
8030
|
-
const historyRoot =
|
|
8593
|
+
const historyRoot = join18(projectDirectory, ".windy/module-history");
|
|
8031
8594
|
const metadata = await readOptionalMetadata(historyRoot);
|
|
8032
8595
|
if (!metadata)
|
|
8033
8596
|
return;
|
|
@@ -8037,7 +8600,7 @@ async function assertExistingHistoryIntegrity(projectDirectory) {
|
|
|
8037
8600
|
const manifest = await readManagedFilesManifest(projectDirectory);
|
|
8038
8601
|
const expected = new Map(manifest.files.map((entry) => [entry.path, entry]));
|
|
8039
8602
|
for (const path2 of await collectRegularFiles(historyRoot)) {
|
|
8040
|
-
const relativePath2 =
|
|
8603
|
+
const relativePath2 = relative5(projectDirectory, path2).split(sep4).join("/");
|
|
8041
8604
|
const entry = expected.get(relativePath2);
|
|
8042
8605
|
if (!entry || isMissingManagedFile(entry)) {
|
|
8043
8606
|
throw new Error(`\u6A21\u5757 migration \u5386\u53F2\u672A\u767B\u8BB0\u5230\u53D7\u7BA1\u6E05\u5355\uFF1A${relativePath2}`);
|
|
@@ -8048,7 +8611,7 @@ async function assertExistingHistoryIntegrity(projectDirectory) {
|
|
|
8048
8611
|
}
|
|
8049
8612
|
}
|
|
8050
8613
|
async function copyMigrationTree(projectRoot, relativeRoot, targetRoot) {
|
|
8051
|
-
const sourceRoot =
|
|
8614
|
+
const sourceRoot = join18(projectRoot, relativeRoot);
|
|
8052
8615
|
const rootMetadata = await readOptionalMetadata(sourceRoot);
|
|
8053
8616
|
if (!rootMetadata)
|
|
8054
8617
|
return false;
|
|
@@ -8056,8 +8619,8 @@ async function copyMigrationTree(projectRoot, relativeRoot, targetRoot) {
|
|
|
8056
8619
|
throw new Error(`\u6A21\u5757 migration \u6839\u76EE\u5F55\u65E0\u6548\uFF1A${relativeRoot}`);
|
|
8057
8620
|
}
|
|
8058
8621
|
for (const source of await collectRegularFiles(sourceRoot)) {
|
|
8059
|
-
const target =
|
|
8060
|
-
await mkdir7(
|
|
8622
|
+
const target = join18(targetRoot, relative5(sourceRoot, source).split(sep4).join("/"));
|
|
8623
|
+
await mkdir7(dirname8(target), { recursive: true });
|
|
8061
8624
|
await writeFile11(target, await readFile13(source));
|
|
8062
8625
|
}
|
|
8063
8626
|
return true;
|
|
@@ -8068,7 +8631,7 @@ async function collectRegularFiles(root) {
|
|
|
8068
8631
|
return files.sort();
|
|
8069
8632
|
async function visit(directory) {
|
|
8070
8633
|
for (const name of (await readdir8(directory)).sort()) {
|
|
8071
|
-
const path2 =
|
|
8634
|
+
const path2 = join18(directory, name);
|
|
8072
8635
|
const metadata = await lstat6(path2);
|
|
8073
8636
|
if (metadata.isSymbolicLink()) {
|
|
8074
8637
|
throw new Error(`\u6A21\u5757 migration \u4E0D\u5141\u8BB8\u7B26\u53F7\u94FE\u63A5\uFF1A${path2}`);
|
|
@@ -8098,10 +8661,10 @@ class PublishedArtifactProvider {
|
|
|
8098
8661
|
this.#fetch = fetcher;
|
|
8099
8662
|
}
|
|
8100
8663
|
async prepare(projectDirectory, provenance, targetModules) {
|
|
8101
|
-
const temporaryRoot = await mkdtemp(
|
|
8664
|
+
const temporaryRoot = await mkdtemp(join19(tmpdir(), "windy-update-"));
|
|
8102
8665
|
const projectName = await readProjectName2(projectDirectory);
|
|
8103
|
-
const baseDirectory =
|
|
8104
|
-
const targetDirectory =
|
|
8666
|
+
const baseDirectory = join19(temporaryRoot, "base", projectName);
|
|
8667
|
+
const targetDirectory = join19(temporaryRoot, "target", projectName);
|
|
8105
8668
|
const baseArtifact = await downloadPublicArtifact(temporaryRoot, "base", provenance.generatorVersion, undefined, this.#fetch);
|
|
8106
8669
|
if (baseArtifact.identity.templateCommit !== provenance.templateCommit) {
|
|
8107
8670
|
throw new Error("Project Lock \u4E0E\u6765\u6E90 registry artifact \u7684 template commit \u4E0D\u4E00\u81F4");
|
|
@@ -8129,13 +8692,13 @@ class PublishedArtifactProvider {
|
|
|
8129
8692
|
}
|
|
8130
8693
|
}
|
|
8131
8694
|
async function readProjectName2(projectDirectory) {
|
|
8132
|
-
const source = JSON.parse(await readFile14(
|
|
8133
|
-
return source.name ||
|
|
8695
|
+
const source = JSON.parse(await readFile14(join19(projectDirectory, "package.json"), "utf8"));
|
|
8696
|
+
return source.name || basename10(projectDirectory);
|
|
8134
8697
|
}
|
|
8135
8698
|
|
|
8136
8699
|
// src/update/planner.ts
|
|
8137
8700
|
import { readFile as readFile21 } from "fs/promises";
|
|
8138
|
-
import { dirname as
|
|
8701
|
+
import { dirname as dirname9, join as join26 } from "path";
|
|
8139
8702
|
|
|
8140
8703
|
// src/update/docker-copy-update-plan.ts
|
|
8141
8704
|
async function deriveDockerfilePlans(files, snapshots, paths, targetWorkspaceManifests) {
|
|
@@ -8224,15 +8787,15 @@ function matchesWorkspace(pattern, directory) {
|
|
|
8224
8787
|
|
|
8225
8788
|
// src/update/migration-reconciler.ts
|
|
8226
8789
|
import { readFile as readFile18 } from "fs/promises";
|
|
8227
|
-
import { join as
|
|
8790
|
+
import { join as join22 } from "path";
|
|
8228
8791
|
|
|
8229
8792
|
// src/update/migration-adoption.ts
|
|
8230
8793
|
import { readFile as readFile17 } from "fs/promises";
|
|
8231
|
-
import { join as
|
|
8794
|
+
import { join as join21 } from "path";
|
|
8232
8795
|
|
|
8233
8796
|
// src/update/migration-project-file.ts
|
|
8234
8797
|
import { readFile as readFile15 } from "fs/promises";
|
|
8235
|
-
import { join as
|
|
8798
|
+
import { join as join20 } from "path";
|
|
8236
8799
|
async function readProjectJson(input, path2) {
|
|
8237
8800
|
const content = await readProjectFile(input, path2);
|
|
8238
8801
|
if (!content) {
|
|
@@ -8248,7 +8811,7 @@ async function readProjectFile(input, path2) {
|
|
|
8248
8811
|
}
|
|
8249
8812
|
let content;
|
|
8250
8813
|
try {
|
|
8251
|
-
content = await readFile15(
|
|
8814
|
+
content = await readFile15(join20(input.projectDirectory, path2));
|
|
8252
8815
|
} catch (error) {
|
|
8253
8816
|
if (!isMissingFileError(error))
|
|
8254
8817
|
throw error;
|
|
@@ -8389,10 +8952,10 @@ async function inspectPreexistingMigrationAdoptions(input) {
|
|
|
8389
8952
|
projectBeforeBytes,
|
|
8390
8953
|
projectAfterBytes
|
|
8391
8954
|
] = await Promise.all([
|
|
8392
|
-
readFile17(
|
|
8955
|
+
readFile17(join21(input.targetDirectory, `${drizzleRoot}/${candidate.tag}.sql`)),
|
|
8393
8956
|
readProjectFile(input, projectSqlPath),
|
|
8394
|
-
readJson(
|
|
8395
|
-
readJson(
|
|
8957
|
+
readJson(join21(input.targetDirectory, snapshotPath(previousTarget.tag))),
|
|
8958
|
+
readJson(join21(input.targetDirectory, snapshotPath(candidate.tag))),
|
|
8396
8959
|
readProjectFile(input, snapshotPath(previousProject.tag)),
|
|
8397
8960
|
readProjectFile(input, projectSnapshotPath)
|
|
8398
8961
|
]);
|
|
@@ -8519,13 +9082,13 @@ async function reconcileDrizzleMigrations(input) {
|
|
|
8519
9082
|
const tag = `${prefix}_${name}`;
|
|
8520
9083
|
const sqlPath = `${drizzleRoot}/${tag}.sql`;
|
|
8521
9084
|
const snapshotPath2 = `${drizzleRoot}/meta/${prefix}_snapshot.json`;
|
|
8522
|
-
const sql = await readFile18(
|
|
9085
|
+
const sql = await readFile18(join22(input.targetDirectory, `${drizzleRoot}/${addition.tag}.sql`));
|
|
8523
9086
|
merged.id = targetAfter.id;
|
|
8524
9087
|
merged.prevId = currentSnapshot.id;
|
|
8525
|
-
const
|
|
9088
|
+
const snapshot2 = encodeJson(merged);
|
|
8526
9089
|
contentOverrides.set(sqlPath, sql);
|
|
8527
|
-
contentOverrides.set(snapshotPath2,
|
|
8528
|
-
files.push(managedEntry(sqlPath, sql), managedEntry(snapshotPath2,
|
|
9090
|
+
contentOverrides.set(snapshotPath2, snapshot2);
|
|
9091
|
+
files.push(managedEntry(sqlPath, sql), managedEntry(snapshotPath2, snapshot2));
|
|
8529
9092
|
previousWhen = Math.max(previousWhen + 1, addition.when);
|
|
8530
9093
|
mergedJournal.entries.push({
|
|
8531
9094
|
...addition,
|
|
@@ -8566,9 +9129,9 @@ function unchanged(targetManifest) {
|
|
|
8566
9129
|
async function readJournals(input) {
|
|
8567
9130
|
try {
|
|
8568
9131
|
const [base, project, target] = await Promise.all([
|
|
8569
|
-
readJson(
|
|
9132
|
+
readJson(join22(input.baseDirectory, journalPath)),
|
|
8570
9133
|
readProjectJson(input, journalPath),
|
|
8571
|
-
readJson(
|
|
9134
|
+
readJson(join22(input.targetDirectory, journalPath))
|
|
8572
9135
|
]);
|
|
8573
9136
|
return { base, project, target };
|
|
8574
9137
|
} catch (error) {
|
|
@@ -8599,17 +9162,17 @@ async function readLatestSnapshot(input, journal) {
|
|
|
8599
9162
|
return JSON.parse(new TextDecoder().decode(content));
|
|
8600
9163
|
}
|
|
8601
9164
|
async function readSnapshot(root, tag) {
|
|
8602
|
-
return await readJson(
|
|
9165
|
+
return await readJson(join22(root, snapshotPath(tag)));
|
|
8603
9166
|
}
|
|
8604
9167
|
|
|
8605
9168
|
// src/update/planner-file.ts
|
|
8606
9169
|
import { readFile as readFile19 } from "fs/promises";
|
|
8607
|
-
import { join as
|
|
9170
|
+
import { join as join24 } from "path";
|
|
8608
9171
|
|
|
8609
9172
|
// src/update/merge.ts
|
|
8610
9173
|
import { mkdtemp as mkdtemp2, rm as rm6, writeFile as writeFile12 } from "fs/promises";
|
|
8611
9174
|
import { tmpdir as tmpdir2 } from "os";
|
|
8612
|
-
import { join as
|
|
9175
|
+
import { join as join23 } from "path";
|
|
8613
9176
|
|
|
8614
9177
|
// src/update/merge-convergent-additions.ts
|
|
8615
9178
|
async function reconcileConvergentAdditions(input) {
|
|
@@ -8751,11 +9314,11 @@ function sameLines(left, right) {
|
|
|
8751
9314
|
|
|
8752
9315
|
// src/update/merge.ts
|
|
8753
9316
|
async function mergeTextFile(base, ours, theirs) {
|
|
8754
|
-
const root = await mkdtemp2(
|
|
9317
|
+
const root = await mkdtemp2(join23(tmpdir2(), "windy-merge-"));
|
|
8755
9318
|
try {
|
|
8756
|
-
const oursPath =
|
|
8757
|
-
const basePath =
|
|
8758
|
-
const theirsPath =
|
|
9319
|
+
const oursPath = join23(root, "ours");
|
|
9320
|
+
const basePath = join23(root, "base");
|
|
9321
|
+
const theirsPath = join23(root, "theirs");
|
|
8759
9322
|
await Promise.all([
|
|
8760
9323
|
writeFile12(oursPath, ours),
|
|
8761
9324
|
writeFile12(basePath, base),
|
|
@@ -9088,15 +9651,133 @@ function conflict(path2, reason, expectedProjectContent) {
|
|
|
9088
9651
|
};
|
|
9089
9652
|
}
|
|
9090
9653
|
|
|
9654
|
+
// src/update/recipe-project-owned.ts
|
|
9655
|
+
var managedPathsByRecipe = {
|
|
9656
|
+
"starter-0.6.8-to-0.6.9": [
|
|
9657
|
+
"apps/web/src/router/index.ts",
|
|
9658
|
+
"apps/web/src/router/platform-admin-route-bindings.ts"
|
|
9659
|
+
]
|
|
9660
|
+
};
|
|
9661
|
+
function recipeManagedProjectOwnedPaths(recipes2) {
|
|
9662
|
+
return new Set(recipes2.flatMap((recipe) => managedPathsByRecipe[recipe] ?? []));
|
|
9663
|
+
}
|
|
9664
|
+
async function planRecipeProjectOwned(input) {
|
|
9665
|
+
if (!input.ours) {
|
|
9666
|
+
return conflict2(input, "\u7248\u672C recipe \u6240\u9700\u7684\u9879\u76EE\u951A\u70B9\u7F3A\u5931");
|
|
9667
|
+
}
|
|
9668
|
+
const source = new TextDecoder().decode(input.ours);
|
|
9669
|
+
const transformed = transformProjectAdminAnchor(input.path, source);
|
|
9670
|
+
if ("error" in transformed)
|
|
9671
|
+
return conflict2(input, transformed.error);
|
|
9672
|
+
if (transformed.content === source) {
|
|
9673
|
+
return preserve(input, "\u5DF2\u5305\u542B\u7248\u672C recipe \u76EE\u6807\u5185\u5BB9");
|
|
9674
|
+
}
|
|
9675
|
+
return update(input, new TextEncoder().encode(transformed.content));
|
|
9676
|
+
}
|
|
9677
|
+
function transformProjectAdminAnchor(path2, source) {
|
|
9678
|
+
if (path2 === "apps/web/src/router/index.ts") {
|
|
9679
|
+
return addComponentPageLoader(source);
|
|
9680
|
+
}
|
|
9681
|
+
if (path2 === "apps/web/src/router/platform-admin-route-bindings.ts") {
|
|
9682
|
+
return addComponentRouteBinding(source);
|
|
9683
|
+
}
|
|
9684
|
+
return { error: `\u7248\u672C recipe \u672A\u767B\u8BB0\u9879\u76EE\u951A\u70B9\uFF1A${path2}` };
|
|
9685
|
+
}
|
|
9686
|
+
function addComponentPageLoader(source) {
|
|
9687
|
+
if (/^\s*"ui-components"\s*:/m.test(source))
|
|
9688
|
+
return { content: source };
|
|
9689
|
+
const declaration = source.indexOf("const platformAdminPageComponents");
|
|
9690
|
+
const start = source.indexOf("= {", declaration);
|
|
9691
|
+
const end = source.indexOf(`
|
|
9692
|
+
};`, start);
|
|
9693
|
+
if (declaration < 0 || start < 0 || end < 0) {
|
|
9694
|
+
return { error: "\u627E\u4E0D\u5230 platformAdminPageComponents \u9879\u76EE\u951A\u70B9" };
|
|
9695
|
+
}
|
|
9696
|
+
const block = source.slice(start, end);
|
|
9697
|
+
const profiles = [...block.matchAll(/^(\s*)profile:\s*.*,$/gm)];
|
|
9698
|
+
if (profiles.length !== 1) {
|
|
9699
|
+
return { error: "platformAdminPageComponents profile \u951A\u70B9\u4E0D\u552F\u4E00" };
|
|
9700
|
+
}
|
|
9701
|
+
const profile = profiles[0];
|
|
9702
|
+
const insertion = `${profile[0]}
|
|
9703
|
+
${profile[1]}"ui-components": () => import("@/pages/ui/UiComponentPage.vue"),`;
|
|
9704
|
+
return {
|
|
9705
|
+
content: source.slice(0, start) + block.replace(profile[0], insertion) + source.slice(end)
|
|
9706
|
+
};
|
|
9707
|
+
}
|
|
9708
|
+
function addComponentRouteBinding(source) {
|
|
9709
|
+
const unionStart = source.indexOf("export type PlatformAdminPageKey =");
|
|
9710
|
+
const interfaceStart = source.indexOf("export interface PlatformAdminRouteBinding", unionStart);
|
|
9711
|
+
if (unionStart < 0 || interfaceStart < 0) {
|
|
9712
|
+
return { error: "\u627E\u4E0D\u5230 PlatformAdminPageKey \u9879\u76EE\u951A\u70B9" };
|
|
9713
|
+
}
|
|
9714
|
+
let content = source;
|
|
9715
|
+
const union = content.slice(unionStart, interfaceStart);
|
|
9716
|
+
if (!union.includes('"ui-components"')) {
|
|
9717
|
+
const semicolon = content.lastIndexOf(";", interfaceStart);
|
|
9718
|
+
if (semicolon < unionStart) {
|
|
9719
|
+
return { error: "PlatformAdminPageKey \u7ED3\u675F\u951A\u70B9\u7F3A\u5931" };
|
|
9720
|
+
}
|
|
9721
|
+
content = `${content.slice(0, semicolon)}
|
|
9722
|
+
| "ui-components"${content.slice(semicolon)}`;
|
|
9723
|
+
}
|
|
9724
|
+
if (content.includes('routeKey: "system.ui-components"')) {
|
|
9725
|
+
return { content };
|
|
9726
|
+
}
|
|
9727
|
+
const features = [
|
|
9728
|
+
...content.matchAll(/^(\s*)\{ routeKey: "system\.feature", page: "resource", resourceKey: "features" \},$/gm)
|
|
9729
|
+
];
|
|
9730
|
+
if (features.length !== 1) {
|
|
9731
|
+
return { error: "system.feature Admin Route \u951A\u70B9\u4E0D\u552F\u4E00" };
|
|
9732
|
+
}
|
|
9733
|
+
const feature = features[0];
|
|
9734
|
+
return {
|
|
9735
|
+
content: content.replace(feature[0], `${feature[0]}
|
|
9736
|
+
${feature[1]}{ routeKey: "system.ui-components", page: "ui-components" },`)
|
|
9737
|
+
};
|
|
9738
|
+
}
|
|
9739
|
+
function preserve(input, reason) {
|
|
9740
|
+
return {
|
|
9741
|
+
path: input.path,
|
|
9742
|
+
ownership: "project-owned",
|
|
9743
|
+
action: "preserve",
|
|
9744
|
+
reason,
|
|
9745
|
+
expectedProjectContent: input.expected
|
|
9746
|
+
};
|
|
9747
|
+
}
|
|
9748
|
+
function update(input, content) {
|
|
9749
|
+
return {
|
|
9750
|
+
path: input.path,
|
|
9751
|
+
ownership: "project-owned",
|
|
9752
|
+
action: "update",
|
|
9753
|
+
reason: "\u7248\u672C recipe \u66F4\u65B0\u9879\u76EE Admin \u6269\u5C55\u951A\u70B9",
|
|
9754
|
+
expectedProjectContent: input.expected,
|
|
9755
|
+
content
|
|
9756
|
+
};
|
|
9757
|
+
}
|
|
9758
|
+
function conflict2(input, message) {
|
|
9759
|
+
return {
|
|
9760
|
+
path: input.path,
|
|
9761
|
+
ownership: "project-owned",
|
|
9762
|
+
action: "preserve",
|
|
9763
|
+
reason: "\u5BA2\u6237\u5DF2\u4FEE\u6539",
|
|
9764
|
+
expectedProjectContent: input.expected,
|
|
9765
|
+
conflict: message
|
|
9766
|
+
};
|
|
9767
|
+
}
|
|
9768
|
+
|
|
9091
9769
|
// src/update/planner-file.ts
|
|
9092
|
-
async function planFile(path2, baseRoot, targetRoot, source, target, ours, provenance, targetContentOverride, manageGeneratedProjectOwned = false, forcePlatformBaseline = false) {
|
|
9770
|
+
async function planFile(path2, baseRoot, targetRoot, source, target, ours, provenance, targetContentOverride, manageGeneratedProjectOwned = false, forcePlatformBaseline = false, manageRecipeProjectOwned = false) {
|
|
9093
9771
|
const [base, theirs] = await Promise.all([
|
|
9094
|
-
readOptional(
|
|
9095
|
-
targetContentOverride ? Promise.resolve(targetContentOverride) : readOptional(
|
|
9772
|
+
readOptional(join24(baseRoot, path2)),
|
|
9773
|
+
targetContentOverride ? Promise.resolve(targetContentOverride) : readOptional(join24(targetRoot, path2))
|
|
9096
9774
|
]);
|
|
9097
9775
|
const ownership = source?.ownership ?? target?.ownership ?? classifyOwnership(path2);
|
|
9098
9776
|
const expected = expectationForSnapshot(ours);
|
|
9099
9777
|
if (ownership === "project-owned") {
|
|
9778
|
+
if (manageRecipeProjectOwned) {
|
|
9779
|
+
return planRecipeProjectOwned({ path: path2, ours, expected });
|
|
9780
|
+
}
|
|
9100
9781
|
if (manageGeneratedProjectOwned) {
|
|
9101
9782
|
return planGeneratedProjectOwned(path2, source, target, ours, theirs, expected);
|
|
9102
9783
|
}
|
|
@@ -9104,26 +9785,26 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
|
|
|
9104
9785
|
}
|
|
9105
9786
|
if (path2.startsWith("packages/database/drizzle/") && path2.endsWith(".sql")) {
|
|
9106
9787
|
if (source && !target) {
|
|
9107
|
-
return
|
|
9788
|
+
return conflict3(path2, ownership, "\u5DF2\u53D1\u5E03 migration \u4E0D\u53EF\u5220\u9664", expected);
|
|
9108
9789
|
}
|
|
9109
9790
|
if (source && target && source.hash !== target.hash) {
|
|
9110
|
-
return
|
|
9791
|
+
return conflict3(path2, ownership, "\u5DF2\u53D1\u5E03 migration \u4E0D\u53EF\u6539\u5199\uFF0C\u53EA\u80FD\u8FFD\u52A0\u65B0\u6587\u4EF6", expected);
|
|
9111
9792
|
}
|
|
9112
9793
|
}
|
|
9113
9794
|
if (!source && target) {
|
|
9114
9795
|
if (!ours) {
|
|
9115
9796
|
return readyPlannedFile(path2, ownership, "create", "\u76EE\u6807\u7248\u672C\u65B0\u589E", expected, theirs);
|
|
9116
9797
|
}
|
|
9117
|
-
return theirs && hashContent(ours) === target.hash ? readyPlannedFile(path2, ownership, "preserve", "\u5DF2\u5305\u542B\u76EE\u6807\u5185\u5BB9", expected) :
|
|
9798
|
+
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);
|
|
9118
9799
|
}
|
|
9119
9800
|
if (source && !target) {
|
|
9120
9801
|
if (!ours) {
|
|
9121
9802
|
return readyPlannedFile(path2, ownership, "preserve", "\u9879\u76EE\u5DF2\u5220\u9664", expected);
|
|
9122
9803
|
}
|
|
9123
|
-
return hashContent(ours) === source.hash ? readyPlannedFile(path2, ownership, "delete", "\u76EE\u6807\u7248\u672C\u5220\u9664", expected) :
|
|
9804
|
+
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);
|
|
9124
9805
|
}
|
|
9125
9806
|
if (!source || !target || !ours || !theirs) {
|
|
9126
|
-
return
|
|
9807
|
+
return conflict3(path2, ownership, "\u6587\u4EF6\u72B6\u6001\u4E0D\u5B8C\u6574\uFF0C\u4E0D\u80FD\u5B89\u5168\u63A8\u65AD", expected);
|
|
9127
9808
|
}
|
|
9128
9809
|
const oursChanged = hashContent(ours) !== source.hash;
|
|
9129
9810
|
const sourceArtifactHash = artifactHashOf(source);
|
|
@@ -9137,7 +9818,7 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
|
|
|
9137
9818
|
});
|
|
9138
9819
|
if (forceTargetBaseline && path2.endsWith("package.json") && base) {
|
|
9139
9820
|
const merged = mergePackageJson(base, ours, theirs);
|
|
9140
|
-
return merged.content ? readyPlannedFile(path2, ownership, "update", "package.json \u5B57\u6BB5\u7EA7\u5408\u5E76", expected, merged.content) :
|
|
9821
|
+
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);
|
|
9141
9822
|
}
|
|
9142
9823
|
if (forceTargetBaseline) {
|
|
9143
9824
|
return readyPlannedFile(path2, ownership, "update", "\u5F3A\u5236\u91C7\u7528\u76EE\u6807\u5E73\u53F0\u57FA\u7EBF", expected, theirs);
|
|
@@ -9147,11 +9828,11 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
|
|
|
9147
9828
|
}
|
|
9148
9829
|
if (targetChanged && path2.endsWith("package.json") && base) {
|
|
9149
9830
|
const merged = mergePackageJson(base, ours, theirs);
|
|
9150
|
-
return merged.content ? readyPlannedFile(path2, ownership, "update", "package.json \u5B57\u6BB5\u7EA7\u5408\u5E76", expected, merged.content) :
|
|
9831
|
+
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);
|
|
9151
9832
|
}
|
|
9152
9833
|
if (!oursChanged && targetChanged && adoptedProjectDelta && base) {
|
|
9153
9834
|
const merged = await mergeTextFile(base, ours, theirs);
|
|
9154
|
-
return merged.content ? readyPlannedFile(path2, ownership, "update", "\u4E09\u65B9\u5408\u5E76\u5DF2\u91C7\u7EB3\u9879\u76EE\u589E\u91CF", expected, merged.content) :
|
|
9835
|
+
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);
|
|
9155
9836
|
}
|
|
9156
9837
|
if (!oursChanged) {
|
|
9157
9838
|
return readyPlannedFile(path2, ownership, "update", "\u4EC5 Windy \u4FEE\u6539", expected, theirs);
|
|
@@ -9164,9 +9845,9 @@ async function planFile(path2, baseRoot, targetRoot, source, target, ours, prove
|
|
|
9164
9845
|
}
|
|
9165
9846
|
if (base) {
|
|
9166
9847
|
const merged = await mergeTextFile(base, ours, theirs);
|
|
9167
|
-
return merged.content ? readyPlannedFile(path2, ownership, "update", "\u4E09\u65B9\u5408\u5E76", expected, merged.content) :
|
|
9848
|
+
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);
|
|
9168
9849
|
}
|
|
9169
|
-
return
|
|
9850
|
+
return conflict3(path2, ownership, "\u5BA2\u6237\u548C Windy \u5747\u5DF2\u4FEE\u6539", expected);
|
|
9170
9851
|
}
|
|
9171
9852
|
function shouldForcePlatformBaseline(input) {
|
|
9172
9853
|
return input.forcePlatformBaseline && !input.oursChanged && input.base !== undefined && hashContent(input.base) !== input.sourceArtifactHash;
|
|
@@ -9187,7 +9868,7 @@ function readyPlannedFile(path2, ownership, action, reason, expectedProjectConte
|
|
|
9187
9868
|
function expectationForSnapshot(content) {
|
|
9188
9869
|
return content ? { kind: "hash", value: hashContent(content) } : { kind: "missing" };
|
|
9189
9870
|
}
|
|
9190
|
-
function
|
|
9871
|
+
function conflict3(path2, ownership, reason, expectedProjectContent) {
|
|
9191
9872
|
return {
|
|
9192
9873
|
path: path2,
|
|
9193
9874
|
ownership,
|
|
@@ -9252,26 +9933,26 @@ function hasExistingSourceForTest(path2, sourcePaths) {
|
|
|
9252
9933
|
|
|
9253
9934
|
// src/update/planner-snapshots.ts
|
|
9254
9935
|
import { readFile as readFile20, stat as stat2 } from "fs/promises";
|
|
9255
|
-
import { join as
|
|
9936
|
+
import { join as join25 } from "path";
|
|
9256
9937
|
async function snapshotProjectFiles(project, paths, seed) {
|
|
9257
9938
|
const snapshots = new Map(seed);
|
|
9258
9939
|
await Promise.all([...paths].filter((path2) => !snapshots.has(path2)).map(async (path2) => {
|
|
9259
|
-
snapshots.set(path2, await readOptional2(
|
|
9940
|
+
snapshots.set(path2, await readOptional2(join25(project, path2)));
|
|
9260
9941
|
}));
|
|
9261
9942
|
return snapshots;
|
|
9262
9943
|
}
|
|
9263
9944
|
async function snapshotProjectModes(project, paths) {
|
|
9264
|
-
return new Map(await Promise.all([...paths].map(async (path2) => [path2, await readModeOptional(
|
|
9945
|
+
return new Map(await Promise.all([...paths].map(async (path2) => [path2, await readModeOptional(join25(project, path2))])));
|
|
9265
9946
|
}
|
|
9266
9947
|
async function assertPlanSnapshots(project, expectations) {
|
|
9267
9948
|
const changed = [];
|
|
9268
9949
|
for (const expectation2 of expectations) {
|
|
9269
|
-
const actual = expectationForSnapshot(await readOptional2(
|
|
9950
|
+
const actual = expectationForSnapshot(await readOptional2(join25(project, expectation2.path)));
|
|
9270
9951
|
if (JSON.stringify(actual) !== JSON.stringify(expectation2.expected)) {
|
|
9271
9952
|
changed.push(expectation2.path);
|
|
9272
9953
|
continue;
|
|
9273
9954
|
}
|
|
9274
|
-
if ("mode" in expectation2 && await readModeOptional(
|
|
9955
|
+
if ("mode" in expectation2 && await readModeOptional(join25(project, expectation2.path)) !== expectation2.mode) {
|
|
9275
9956
|
changed.push(expectation2.path);
|
|
9276
9957
|
}
|
|
9277
9958
|
}
|
|
@@ -9347,7 +10028,7 @@ var oxcManagedPaths = new Set([
|
|
|
9347
10028
|
]);
|
|
9348
10029
|
async function createUpdatePlan(request, artifacts, dependencies = {}) {
|
|
9349
10030
|
await assertProjectReadyForUpdate(request.projectDirectory);
|
|
9350
|
-
const manifestPath =
|
|
10031
|
+
const manifestPath = join26(request.projectDirectory, ".windy/files.json");
|
|
9351
10032
|
const expectedManifestHash = hashContent(await readFile21(manifestPath));
|
|
9352
10033
|
const generationSnapshot = await readGenerationProvenanceSnapshot(request.projectDirectory);
|
|
9353
10034
|
const provenance = generationSnapshot.provenance;
|
|
@@ -9361,6 +10042,7 @@ async function createUpdatePlan(request, artifacts, dependencies = {}) {
|
|
|
9361
10042
|
const versionRecipes = (dependencies.resolveVersionRecipes ?? resolveRecipeChain)(provenance.windyVersion, targetVersion);
|
|
9362
10043
|
const moduleRecipes = resolveModuleRecipeIds(request);
|
|
9363
10044
|
const recipes2 = [...versionRecipes.map(({ id }) => id), ...moduleRecipes];
|
|
10045
|
+
const recipeProjectOwnedPaths = recipeManagedProjectOwnedPaths(recipes2);
|
|
9364
10046
|
const [rawSourceManifest, rawTargetManifest] = await Promise.all([
|
|
9365
10047
|
readManagedFilesManifest(request.projectDirectory),
|
|
9366
10048
|
readManagedFilesManifest(artifactSet.targetDirectory)
|
|
@@ -9394,8 +10076,8 @@ async function createUpdatePlan(request, artifacts, dependencies = {}) {
|
|
|
9394
10076
|
const paths = new Set([...sourceEntries.keys(), ...targetEntries.keys()]);
|
|
9395
10077
|
for (const path2 of paths) {
|
|
9396
10078
|
if (!projectSnapshots.has(path2)) {
|
|
9397
|
-
projectSnapshots.set(path2, await readOptional2(
|
|
9398
|
-
projectModes.set(path2, await readModeOptional(
|
|
10079
|
+
projectSnapshots.set(path2, await readOptional2(join26(request.projectDirectory, path2)));
|
|
10080
|
+
projectModes.set(path2, await readModeOptional(join26(request.projectDirectory, path2)));
|
|
9399
10081
|
}
|
|
9400
10082
|
}
|
|
9401
10083
|
const files = await planFiles({
|
|
@@ -9407,7 +10089,8 @@ async function createUpdatePlan(request, artifacts, dependencies = {}) {
|
|
|
9407
10089
|
artifactSet,
|
|
9408
10090
|
provenance,
|
|
9409
10091
|
manageGeneratedProjectOwned: request.targetModules !== undefined,
|
|
9410
|
-
forcePlatformBaseline: request.forcePlatformBaseline === true
|
|
10092
|
+
forcePlatformBaseline: request.forcePlatformBaseline === true,
|
|
10093
|
+
recipeProjectOwnedPaths
|
|
9411
10094
|
});
|
|
9412
10095
|
preserveTestsForExistingProjectOwnedSources(files, sourceEntries);
|
|
9413
10096
|
await deriveDockerfilePlans(files, projectSnapshots, new Set([
|
|
@@ -9418,10 +10101,10 @@ async function createUpdatePlan(request, artifacts, dependencies = {}) {
|
|
|
9418
10101
|
for (const file of files) {
|
|
9419
10102
|
file.expectedProjectMode = projectModes.get(file.path);
|
|
9420
10103
|
if (file.action === "create" || file.action === "update") {
|
|
9421
|
-
file.mode = file.expectedProjectMode ?? await readModeOptional(
|
|
10104
|
+
file.mode = file.expectedProjectMode ?? await readModeOptional(join26(artifactSet.targetDirectory, file.path));
|
|
9422
10105
|
}
|
|
9423
10106
|
if (file.action === "create") {
|
|
9424
|
-
file.parentMode = await readSourceParentMode(
|
|
10107
|
+
file.parentMode = await readSourceParentMode(join26(artifactSet.targetDirectory, dirname9(file.path)));
|
|
9425
10108
|
}
|
|
9426
10109
|
}
|
|
9427
10110
|
const plannedPaths = new Set(files.map(({ path: path2 }) => path2));
|
|
@@ -9486,7 +10169,7 @@ async function planFiles(input) {
|
|
|
9486
10169
|
} else if (forcedContent) {
|
|
9487
10170
|
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));
|
|
9488
10171
|
} else {
|
|
9489
|
-
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));
|
|
10172
|
+
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)));
|
|
9490
10173
|
}
|
|
9491
10174
|
}
|
|
9492
10175
|
return files;
|
|
@@ -9568,7 +10251,7 @@ function frozenManifestHash(file, finalizedHashes) {
|
|
|
9568
10251
|
// src/update/format-stabilizer.ts
|
|
9569
10252
|
import { mkdir as mkdir8, mkdtemp as mkdtemp3, readFile as readFile22, rm as rm7, writeFile as writeFile13 } from "fs/promises";
|
|
9570
10253
|
import { tmpdir as tmpdir3 } from "os";
|
|
9571
|
-
import { dirname as
|
|
10254
|
+
import { dirname as dirname10, extname as extname4, join as join27, resolve as resolve6, sep as sep5 } from "path";
|
|
9572
10255
|
var formattedExtensions = new Set([
|
|
9573
10256
|
".cjs",
|
|
9574
10257
|
".css",
|
|
@@ -9607,7 +10290,7 @@ async function stabilizeManagedContent(result2, execute, writeProjectFile) {
|
|
|
9607
10290
|
}
|
|
9608
10291
|
}
|
|
9609
10292
|
inputs.set(".windy/generation.json", new TextEncoder().encode(generationContent));
|
|
9610
|
-
const temporaryRoot = await mkdtemp3(
|
|
10293
|
+
const temporaryRoot = await mkdtemp3(join27(tmpdir3(), "windy-update-format-"));
|
|
9611
10294
|
try {
|
|
9612
10295
|
const stagedPaths = await stageInputs(temporaryRoot, inputs);
|
|
9613
10296
|
for (let offset = 0;offset < stagedPaths.length; offset += 80) {
|
|
@@ -9615,7 +10298,7 @@ async function stabilizeManagedContent(result2, execute, writeProjectFile) {
|
|
|
9615
10298
|
"x",
|
|
9616
10299
|
"oxfmt",
|
|
9617
10300
|
"--write",
|
|
9618
|
-
`--config=${
|
|
10301
|
+
`--config=${join27(result2.plan.projectDirectory, ".oxfmtrc.json")}`,
|
|
9619
10302
|
...stagedPaths.slice(offset, offset + 80)
|
|
9620
10303
|
], result2.plan.projectDirectory);
|
|
9621
10304
|
}
|
|
@@ -9648,7 +10331,7 @@ async function stageInputs(temporaryRoot, inputs) {
|
|
|
9648
10331
|
const paths = [];
|
|
9649
10332
|
for (const [path2, content] of inputs) {
|
|
9650
10333
|
const target = safeTemporaryPath(temporaryRoot, path2);
|
|
9651
|
-
await mkdir8(
|
|
10334
|
+
await mkdir8(dirname10(target), { recursive: true });
|
|
9652
10335
|
await writeFile13(target, content);
|
|
9653
10336
|
paths.push(target);
|
|
9654
10337
|
}
|
|
@@ -9776,7 +10459,7 @@ class DefaultStarterUpdater {
|
|
|
9776
10459
|
const plannedPaths = new Set(result2.plan.files.map(({ path: path2 }) => path2));
|
|
9777
10460
|
replaceExpectations(result2, verificationSnapshot.filter(({ path: path2 }) => !metadataPaths2.has(path2) && !plannedPaths.has(path2)));
|
|
9778
10461
|
verificationExpectationsFrozen = true;
|
|
9779
|
-
const packageJson = JSON.parse(await readFile23(
|
|
10462
|
+
const packageJson = JSON.parse(await readFile23(join28(result2.plan.projectDirectory, "package.json"), "utf8"));
|
|
9780
10463
|
for (const name of ["lint", "typecheck", "test", "build"]) {
|
|
9781
10464
|
if (!packageJson.scripts?.[name]) {
|
|
9782
10465
|
steps.push({ name: `bun run ${name}`, status: "skipped" });
|
|
@@ -10007,9 +10690,9 @@ function assertEnabledConflicts(target, catalog) {
|
|
|
10007
10690
|
for (const [name, enabled] of target) {
|
|
10008
10691
|
if (!enabled)
|
|
10009
10692
|
continue;
|
|
10010
|
-
const
|
|
10011
|
-
if (
|
|
10012
|
-
throw new Error(`\u6A21\u5757\u51B2\u7A81\uFF1A${name} \u4E0E ${
|
|
10693
|
+
const conflict4 = catalog.get(name).conflicts.find((candidate) => target.get(candidate));
|
|
10694
|
+
if (conflict4)
|
|
10695
|
+
throw new Error(`\u6A21\u5757\u51B2\u7A81\uFF1A${name} \u4E0E ${conflict4}`);
|
|
10013
10696
|
}
|
|
10014
10697
|
}
|
|
10015
10698
|
function assertCompatible(version, range, name) {
|
|
@@ -10024,7 +10707,7 @@ function reconcileProjectModuleRegistryPlan(plan, current, lifecycle) {
|
|
|
10024
10707
|
if (!registryFile) {
|
|
10025
10708
|
throw new Error("\u6A21\u5757\u751F\u547D\u5468\u671F\u8BA1\u5212\u7F3A\u5C11 project-owned \u88C5\u914D\u9009\u62E9");
|
|
10026
10709
|
}
|
|
10027
|
-
plan.conflicts = plan.conflicts.filter((
|
|
10710
|
+
plan.conflicts = plan.conflicts.filter((conflict4) => !conflict4.startsWith(`${projectModuleRegistryPath}\uFF1A`));
|
|
10028
10711
|
delete registryFile.conflict;
|
|
10029
10712
|
if (lifecycle.action === "update") {
|
|
10030
10713
|
registryFile.action = "preserve";
|
|
@@ -10454,8 +11137,8 @@ function printModulePlan(plan, log) {
|
|
|
10454
11137
|
for (const file of changed) {
|
|
10455
11138
|
log(` ${file.action.padEnd(6)} ${file.path}\uFF08${file.reason}\uFF09`);
|
|
10456
11139
|
}
|
|
10457
|
-
for (const
|
|
10458
|
-
log(` conflict ${
|
|
11140
|
+
for (const conflict4 of plan.conflicts)
|
|
11141
|
+
log(` conflict ${conflict4}`);
|
|
10459
11142
|
}
|
|
10460
11143
|
function hasChanges(lifecycle) {
|
|
10461
11144
|
return lifecycle.addedModules.length > 0 || lifecycle.updatedModules.length > 0 || lifecycle.removedModules.length > 0;
|
|
@@ -10627,8 +11310,8 @@ function printPlan(plan) {
|
|
|
10627
11310
|
console.log(`\u8BA1\u5212\u6539\u52A8\uFF1A${changed.length} \u4E2A\u6587\u4EF6\uFF1B\u51B2\u7A81\uFF1A${plan.conflicts.length}`);
|
|
10628
11311
|
for (const file of changed)
|
|
10629
11312
|
console.log(` ${file.action.padEnd(6)} ${file.path}\uFF08${file.reason}\uFF09`);
|
|
10630
|
-
for (const
|
|
10631
|
-
console.log(` conflict ${
|
|
11313
|
+
for (const conflict4 of plan.conflicts)
|
|
11314
|
+
console.log(` conflict ${conflict4}`);
|
|
10632
11315
|
if (plan.detachedToolchain)
|
|
10633
11316
|
console.log("Oxc\uFF1A\u68C0\u6D4B\u5230\u5BA2\u6237\u63A5\u7BA1\uFF0C\u76F8\u5173\u914D\u7F6E\u4FDD\u6301\u4E0D\u53D8");
|
|
10634
11317
|
}
|
|
@@ -10715,11 +11398,11 @@ import {
|
|
|
10715
11398
|
rm as rm11,
|
|
10716
11399
|
writeFile as writeFile14
|
|
10717
11400
|
} from "fs/promises";
|
|
10718
|
-
import { dirname as
|
|
11401
|
+
import { dirname as dirname11, join as join29, relative as relative7 } from "path";
|
|
10719
11402
|
|
|
10720
11403
|
// src/module-schema/config.ts
|
|
10721
11404
|
import { readFile as readFile24 } from "fs/promises";
|
|
10722
|
-
import { isAbsolute as isAbsolute2, relative as
|
|
11405
|
+
import { isAbsolute as isAbsolute2, relative as relative6, resolve as resolve9 } from "path";
|
|
10723
11406
|
async function readModuleSchemaLineageConfig(projectDirectory, configPath) {
|
|
10724
11407
|
const absolutePath = resolveProjectPath(projectDirectory, configPath);
|
|
10725
11408
|
const parsed = JSON.parse(await readFile24(absolutePath, "utf8"));
|
|
@@ -10737,7 +11420,7 @@ function resolveProjectPath(projectDirectory, path2) {
|
|
|
10737
11420
|
if (isAbsolute2(path2))
|
|
10738
11421
|
throw new Error(`\u8DEF\u5F84\u5FC5\u987B\u76F8\u5BF9\u9879\u76EE\u6839\u76EE\u5F55\uFF1A${path2}`);
|
|
10739
11422
|
const resolved = resolve9(projectDirectory, path2);
|
|
10740
|
-
const projectRelative =
|
|
11423
|
+
const projectRelative = relative6(projectDirectory, resolved);
|
|
10741
11424
|
if (projectRelative.startsWith("..") || isAbsolute2(projectRelative)) {
|
|
10742
11425
|
throw new Error(`\u8DEF\u5F84\u8D8A\u51FA\u9879\u76EE\u6839\u76EE\u5F55\uFF1A${path2}`);
|
|
10743
11426
|
}
|
|
@@ -10856,17 +11539,17 @@ async function handoffModuleSchemaLineages(options) {
|
|
|
10856
11539
|
async function stageModuleLineages(project, temporaryRoot, config, execute) {
|
|
10857
11540
|
const outputs = [];
|
|
10858
11541
|
for (const [index, module2] of config.modules.entries()) {
|
|
10859
|
-
const output =
|
|
11542
|
+
const output = join29(temporaryRoot, `module-${index}`);
|
|
10860
11543
|
await mkdir9(output, { recursive: true });
|
|
10861
|
-
const generatedConfig =
|
|
10862
|
-
await writeDrizzleConfig(generatedConfig, project, module2.schema,
|
|
11544
|
+
const generatedConfig = join29(temporaryRoot, `module-${index}.config.ts`);
|
|
11545
|
+
await writeDrizzleConfig(generatedConfig, project, module2.schema, relative7(temporaryRoot, output));
|
|
10863
11546
|
await execute(generatedConfig, temporaryRoot);
|
|
10864
11547
|
const sqlFiles = await listSqlFiles(output);
|
|
10865
11548
|
if (sqlFiles.length !== 1) {
|
|
10866
11549
|
throw new Error(`${module2.key} baseline \u5FC5\u987B\u6070\u597D\u751F\u6210\u4E00\u4E2A migration`);
|
|
10867
11550
|
}
|
|
10868
|
-
await writeFile14(
|
|
10869
|
-
await writeFile14(
|
|
11551
|
+
await writeFile14(join29(output, sqlFiles[0]), metadataOnlySql("module"));
|
|
11552
|
+
await writeFile14(join29(output, "lineage.json"), `${JSON.stringify({
|
|
10870
11553
|
schemaVersion: 1,
|
|
10871
11554
|
moduleKey: module2.key,
|
|
10872
11555
|
schema: module2.schema,
|
|
@@ -10880,17 +11563,17 @@ async function stageModuleLineages(project, temporaryRoot, config, execute) {
|
|
|
10880
11563
|
}
|
|
10881
11564
|
async function stagePlatformLineage(project, temporaryRoot, config, execute) {
|
|
10882
11565
|
const source = resolveProjectPath(project, config.platform.out);
|
|
10883
|
-
const output =
|
|
11566
|
+
const output = join29(temporaryRoot, "platform");
|
|
10884
11567
|
await cp(source, output, { recursive: true });
|
|
10885
11568
|
const before = new Set(await listSqlFiles(output));
|
|
10886
|
-
const generatedConfig =
|
|
10887
|
-
await writeDrizzleConfig(generatedConfig, project, config.platform.schema,
|
|
11569
|
+
const generatedConfig = join29(temporaryRoot, "platform.config.ts");
|
|
11570
|
+
await writeDrizzleConfig(generatedConfig, project, config.platform.schema, relative7(temporaryRoot, output));
|
|
10888
11571
|
await execute(generatedConfig, temporaryRoot);
|
|
10889
11572
|
const created = (await listSqlFiles(output)).filter((path2) => !before.has(path2));
|
|
10890
11573
|
if (created.length !== 1) {
|
|
10891
11574
|
throw new Error("\u5E73\u53F0 lineage handoff \u5FC5\u987B\u6070\u597D\u751F\u6210\u4E00\u4E2A migration");
|
|
10892
11575
|
}
|
|
10893
|
-
const sqlPath =
|
|
11576
|
+
const sqlPath = join29(output, created[0]);
|
|
10894
11577
|
const allowed = config.modules.flatMap(({ legacyPlatformTables }) => legacyPlatformTables);
|
|
10895
11578
|
validatePlatformHandoffSql(await readFile25(sqlPath, "utf8"), allowed);
|
|
10896
11579
|
await writeFile14(sqlPath, metadataOnlySql("platform"));
|
|
@@ -10898,7 +11581,7 @@ async function stagePlatformLineage(project, temporaryRoot, config, execute) {
|
|
|
10898
11581
|
}
|
|
10899
11582
|
async function installStagedLineages(project, temporaryRoot, config, stagedModules, stagedPlatform) {
|
|
10900
11583
|
const platform = resolveProjectPath(project, config.platform.out);
|
|
10901
|
-
const backup =
|
|
11584
|
+
const backup = join29(temporaryRoot, "platform-backup");
|
|
10902
11585
|
const installed = [];
|
|
10903
11586
|
await rename2(platform, backup);
|
|
10904
11587
|
try {
|
|
@@ -10908,7 +11591,7 @@ async function installStagedLineages(project, temporaryRoot, config, stagedModul
|
|
|
10908
11591
|
if (await exists(output)) {
|
|
10909
11592
|
throw new Error(`${module2.key} lineage \u8F93\u51FA\u5DF2\u5B58\u5728\uFF0C\u7981\u6B62\u8986\u76D6`);
|
|
10910
11593
|
}
|
|
10911
|
-
await mkdir9(
|
|
11594
|
+
await mkdir9(dirname11(output), { recursive: true });
|
|
10912
11595
|
await rename2(stagedModules[index], output);
|
|
10913
11596
|
installed.push(output);
|
|
10914
11597
|
}
|
|
@@ -10945,9 +11628,9 @@ async function validateSchemaSources(project, config) {
|
|
|
10945
11628
|
}
|
|
10946
11629
|
}
|
|
10947
11630
|
async function createTemporaryRoot(project) {
|
|
10948
|
-
const windy =
|
|
11631
|
+
const windy = join29(project, ".windy");
|
|
10949
11632
|
await mkdir9(windy, { recursive: true });
|
|
10950
|
-
return await mkdtemp4(
|
|
11633
|
+
return await mkdtemp4(join29(windy, "module-schema-handoff-"));
|
|
10951
11634
|
}
|
|
10952
11635
|
async function listSqlFiles(root) {
|
|
10953
11636
|
return (await readdir9(root)).filter((path2) => path2.endsWith(".sql")).sort();
|