create-windy 0.6.9 → 0.6.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/cli.js +865 -305
- package/package.json +1 -1
- package/template/.windy-template.json +3 -3
- package/template/README.md +4 -0
- package/template/apps/agent-server/src/southwind_agent_server/contracts.py +2 -0
- package/template/apps/agent-server/src/southwind_agent_server/report_presenter.py +19 -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_report_routes.py +86 -0
- package/template/apps/agent-server/tests/test_report_store.py +62 -1
- 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/ai-runtime-report/remote-parser.ts +10 -0
- package/template/apps/server/src/ai-runtime-report/service.test.ts +1 -0
- 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/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/pages/license/LicensePage.vue +8 -0
- package/template/apps/web/src/pages/system/AiRuntimePage.vue +3 -1
- package/template/apps/web/src/pages/system/components/ai-runtime/AiRuntimeFilters.vue +43 -31
- package/template/apps/web/src/pages/system/components/ai-runtime/AiRuntimeFilters.webtest.ts +15 -4
- package/template/apps/web/src/pages/system/components/ai-runtime/AiRuntimeModelUsageList.vue +48 -0
- package/template/apps/web/src/pages/system/components/ai-runtime/AiRuntimeModelUsageList.webtest.ts +32 -0
- package/template/apps/web/src/pages/system/components/ai-runtime/AiRuntimeRunDetailDialog.vue +2 -1
- package/template/apps/web/src/pages/system/components/ai-runtime/AiRuntimeRunDetailDialog.webtest.ts +70 -0
- package/template/apps/web/src/pages/system/components/ai-runtime/AiRuntimeRunTable.vue +29 -2
- package/template/apps/web/src/pages/system/components/ai-runtime/AiRuntimeRunTable.webtest.ts +56 -0
- package/template/apps/web/src/services/ai-runtime-api.ts +7 -10
- package/template/apps/web/src/services/ai-runtime-api.webtest.ts +115 -2
- 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/license/license-pairing-activation.md +67 -0
- package/template/docs/operations/incremental-delivery.md +6 -6
- package/template/docs/platform/agent-runtime-observability.md +6 -0
- package/template/docs/platform/agent-supervisor-output-contract.md +97 -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-ui-catalog.ts +5 -1
- 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-license-pairing.test.ts +44 -0
- package/template/packages/modules/src/system-module-catalog.ts +8 -18
- 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 +2 -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/template/packages/shared/package.json +1 -1
- package/template/packages/shared/src/ai-runtime-report.ts +19 -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 |
|
|
@@ -3698,9 +4028,11 @@ var templateDocumentationFiles = [
|
|
|
3698
4028
|
"docs/development/module-lifecycle.md",
|
|
3699
4029
|
"docs/development/ui-component-gallery.md",
|
|
3700
4030
|
"docs/license/license-offline-activation-code.md",
|
|
4031
|
+
"docs/license/license-pairing-activation.md",
|
|
3701
4032
|
"docs/operations/observability.md",
|
|
3702
4033
|
"docs/operations/incremental-delivery.md",
|
|
3703
4034
|
"docs/platform/agent-run-attestation.md",
|
|
4035
|
+
"docs/platform/agent-supervisor-output-contract.md",
|
|
3704
4036
|
"docs/platform/agent-tools.md",
|
|
3705
4037
|
"docs/platform/agent-runtime.md",
|
|
3706
4038
|
"docs/platform/agent-runtime-observability.md",
|
|
@@ -3762,11 +4094,11 @@ function isExcludedTemplateName(name) {
|
|
|
3762
4094
|
// src/provenance.ts
|
|
3763
4095
|
import { createHash as createHash2 } from "crypto";
|
|
3764
4096
|
import { mkdir as mkdir2, readFile as readFile7, writeFile as writeFile6 } from "fs/promises";
|
|
3765
|
-
import { join as
|
|
4097
|
+
import { join as join9 } from "path";
|
|
3766
4098
|
var templateMetadataFile = ".windy-template.json";
|
|
3767
4099
|
var generationMetadataFile = ".windy/generation.json";
|
|
3768
4100
|
async function readTemplateMetadata(sourceRoot) {
|
|
3769
|
-
const path =
|
|
4101
|
+
const path = join9(sourceRoot, templateMetadataFile);
|
|
3770
4102
|
const parsed = JSON.parse(await readFile7(path, "utf8"));
|
|
3771
4103
|
if (!isTemplateMetadata(parsed)) {
|
|
3772
4104
|
throw new Error("create-windy \u6A21\u677F\u6765\u6E90\u5143\u6570\u636E\u65E0\u6548");
|
|
@@ -3777,7 +4109,7 @@ async function readGenerationProvenance(targetDirectory) {
|
|
|
3777
4109
|
return (await readGenerationProvenanceSnapshot(targetDirectory)).provenance;
|
|
3778
4110
|
}
|
|
3779
4111
|
async function readGenerationProvenanceSnapshot(targetDirectory) {
|
|
3780
|
-
const path =
|
|
4112
|
+
const path = join9(targetDirectory, generationMetadataFile);
|
|
3781
4113
|
const content = await readFile7(path);
|
|
3782
4114
|
return {
|
|
3783
4115
|
content,
|
|
@@ -3818,8 +4150,8 @@ async function writeGenerationProvenance(targetDirectory, metadata, profile, sel
|
|
|
3818
4150
|
includeOxc
|
|
3819
4151
|
}
|
|
3820
4152
|
};
|
|
3821
|
-
const path =
|
|
3822
|
-
await mkdir2(
|
|
4153
|
+
const path = join9(targetDirectory, generationMetadataFile);
|
|
4154
|
+
await mkdir2(join9(path, ".."), { recursive: true });
|
|
3823
4155
|
await writeFile6(path, `${JSON.stringify(provenance, null, 2)}
|
|
3824
4156
|
`);
|
|
3825
4157
|
}
|
|
@@ -3846,7 +4178,7 @@ function isModuleVersion(value) {
|
|
|
3846
4178
|
|
|
3847
4179
|
// src/registry-dependencies.ts
|
|
3848
4180
|
import { lstat as lstat4, readFile as readFile8, readdir as readdir4, writeFile as writeFile7 } from "fs/promises";
|
|
3849
|
-
import { basename as
|
|
4181
|
+
import { basename as basename5, extname as extname2, join as join10 } from "path";
|
|
3850
4182
|
var dependencySections = [
|
|
3851
4183
|
"dependencies",
|
|
3852
4184
|
"devDependencies",
|
|
@@ -3870,7 +4202,7 @@ async function materializeRegistryDependencies(root, dependencies) {
|
|
|
3870
4202
|
for (const path of await collectFiles3(root)) {
|
|
3871
4203
|
if (!replaceableExtensions.has(extname2(path)))
|
|
3872
4204
|
continue;
|
|
3873
|
-
if (
|
|
4205
|
+
if (basename5(path) === "package.json") {
|
|
3874
4206
|
await rewritePackageJson(path, dependencies);
|
|
3875
4207
|
continue;
|
|
3876
4208
|
}
|
|
@@ -3907,7 +4239,7 @@ async function collectFiles3(root) {
|
|
|
3907
4239
|
for (const name of (await readdir4(directory)).sort()) {
|
|
3908
4240
|
if ([".git", "node_modules", "dist"].includes(name))
|
|
3909
4241
|
continue;
|
|
3910
|
-
const path =
|
|
4242
|
+
const path = join10(directory, name);
|
|
3911
4243
|
const metadata = await lstat4(path);
|
|
3912
4244
|
if (metadata.isSymbolicLink())
|
|
3913
4245
|
continue;
|
|
@@ -3922,10 +4254,10 @@ async function collectFiles3(root) {
|
|
|
3922
4254
|
// src/project-module-registry.ts
|
|
3923
4255
|
import { createHash as createHash3 } from "crypto";
|
|
3924
4256
|
import { readFile as readFile9, writeFile as writeFile8 } from "fs/promises";
|
|
3925
|
-
import { join as
|
|
4257
|
+
import { join as join11 } from "path";
|
|
3926
4258
|
var projectModuleRegistryPath = "windy.modules.json";
|
|
3927
4259
|
async function readProjectModuleRegistrySnapshot(projectDirectory, installedNames) {
|
|
3928
|
-
const path =
|
|
4260
|
+
const path = join11(projectDirectory, projectModuleRegistryPath);
|
|
3929
4261
|
let content;
|
|
3930
4262
|
try {
|
|
3931
4263
|
content = await readFile9(path);
|
|
@@ -3978,7 +4310,7 @@ async function writeInitialProjectModuleRegistry(targetDirectory, selectedNames)
|
|
|
3978
4310
|
config: {}
|
|
3979
4311
|
})));
|
|
3980
4312
|
const registry = { schemaVersion: 1, modules };
|
|
3981
|
-
await writeFile8(
|
|
4313
|
+
await writeFile8(join11(targetDirectory, projectModuleRegistryPath), `${JSON.stringify(registry, null, 2)}
|
|
3982
4314
|
`);
|
|
3983
4315
|
}
|
|
3984
4316
|
function assertRegistryMatchesInstalled(registry, installedNames) {
|
|
@@ -4034,29 +4366,29 @@ async function generateProject(input) {
|
|
|
4034
4366
|
const selectedModules = input.selectedModules ?? templateMetadata.modules.filter(({ name }) => requestedIncludeExample || name !== "work-order").map(({ name }) => name);
|
|
4035
4367
|
const includeExample = selectedModules.includes("work-order");
|
|
4036
4368
|
for (const relativePath2 of generationTemplatePaths(true, includeOxc)) {
|
|
4037
|
-
await copyTree(await resolveTemplateSource(input.sourceRoot, relativePath2),
|
|
4369
|
+
await copyTree(await resolveTemplateSource(input.sourceRoot, relativePath2), join12(input.targetDirectory, relativePath2));
|
|
4038
4370
|
}
|
|
4039
4371
|
await materializeSelectedModules(input.targetDirectory, selectedModules);
|
|
4040
4372
|
await materializeRegistryDependencies(input.targetDirectory, selectedModuleManifests(selectedModules).flatMap(({ registryDependencies }) => registryDependencies));
|
|
4041
|
-
const packagePath =
|
|
4373
|
+
const packagePath = join12(input.targetDirectory, "package.json");
|
|
4042
4374
|
const packageJson = JSON.parse(await readFile10(packagePath, "utf8"));
|
|
4043
4375
|
await writeFile9(packagePath, `${JSON.stringify(createStarterPackage(packageJson, input.projectName, includeOxc, projectLicense, selectedModules, templateMetadata.generatorVersion), null, 2)}
|
|
4044
4376
|
`);
|
|
4045
|
-
await writeFile9(
|
|
4046
|
-
await writeFile9(
|
|
4047
|
-
await writeFile9(
|
|
4048
|
-
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")));
|
|
4049
4381
|
await reflectCodeQualityChoice(input.targetDirectory, includeOxc);
|
|
4050
4382
|
await applyWindyBaseLicense(input.targetDirectory);
|
|
4051
4383
|
await applyProjectLicense(input.targetDirectory, projectLicense, input.licenseHolder);
|
|
4052
4384
|
await prepareCustomerDockerfiles(input.targetDirectory);
|
|
4053
4385
|
await writeGenerationProvenance(input.targetDirectory, templateMetadata, input.profile ?? starterProfile.key, selectedModules, includeOxc, projectLicense);
|
|
4054
4386
|
await writeInitialProjectModuleRegistry(input.targetDirectory, selectedModules);
|
|
4055
|
-
await rm4(
|
|
4387
|
+
await rm4(join12(input.targetDirectory, "bun.lock"), { force: true });
|
|
4056
4388
|
await writeManagedFilesManifest(input.targetDirectory, templateMetadata.generatorVersion);
|
|
4057
4389
|
}
|
|
4058
4390
|
async function resolveTemplateSource(sourceRoot, relativePath2) {
|
|
4059
|
-
const source =
|
|
4391
|
+
const source = join12(sourceRoot, relativePath2);
|
|
4060
4392
|
try {
|
|
4061
4393
|
await lstat5(source);
|
|
4062
4394
|
return source;
|
|
@@ -4067,12 +4399,12 @@ async function resolveTemplateSource(sourceRoot, relativePath2) {
|
|
|
4067
4399
|
const alias = npmTemplateAliases[relativePath2];
|
|
4068
4400
|
if (!alias)
|
|
4069
4401
|
return source;
|
|
4070
|
-
return
|
|
4402
|
+
return join12(sourceRoot, alias);
|
|
4071
4403
|
}
|
|
4072
4404
|
async function assertGeneratedProjectIsClean(targetDirectory) {
|
|
4073
4405
|
const violations = [];
|
|
4074
4406
|
await walk(targetDirectory, async (path) => {
|
|
4075
|
-
const name =
|
|
4407
|
+
const name = basename6(path);
|
|
4076
4408
|
const extension = extname3(name).toLowerCase();
|
|
4077
4409
|
if (isExcludedTemplateName(name) || excludedRuntimeFiles.has(name) || [".key", ".pem", ".p12", ".pfx"].includes(extension)) {
|
|
4078
4410
|
violations.push(path.slice(targetDirectory.length + 1));
|
|
@@ -4103,17 +4435,17 @@ async function assertTargetAvailable(targetDirectory) {
|
|
|
4103
4435
|
}
|
|
4104
4436
|
async function copyTree(source, target) {
|
|
4105
4437
|
const metadata = await lstat5(source);
|
|
4106
|
-
const name =
|
|
4438
|
+
const name = basename6(source);
|
|
4107
4439
|
if (shouldExclude(name) || metadata.isSymbolicLink())
|
|
4108
4440
|
return;
|
|
4109
4441
|
if (metadata.isDirectory()) {
|
|
4110
4442
|
await mkdir3(target, { recursive: true });
|
|
4111
4443
|
for (const child of await readdir5(source)) {
|
|
4112
|
-
await copyTree(
|
|
4444
|
+
await copyTree(join12(source, child), join12(target, child));
|
|
4113
4445
|
}
|
|
4114
4446
|
return;
|
|
4115
4447
|
}
|
|
4116
|
-
await mkdir3(
|
|
4448
|
+
await mkdir3(join12(target, ".."), { recursive: true });
|
|
4117
4449
|
await copyFile(source, target);
|
|
4118
4450
|
}
|
|
4119
4451
|
function shouldExclude(name) {
|
|
@@ -4121,7 +4453,7 @@ function shouldExclude(name) {
|
|
|
4121
4453
|
}
|
|
4122
4454
|
async function walk(directory, visit) {
|
|
4123
4455
|
for (const name of await readdir5(directory)) {
|
|
4124
|
-
const path =
|
|
4456
|
+
const path = join12(directory, name);
|
|
4125
4457
|
await visit(path);
|
|
4126
4458
|
if ((await lstat5(path)).isDirectory())
|
|
4127
4459
|
await walk(path, visit);
|
|
@@ -4133,10 +4465,10 @@ function isMissing5(error) {
|
|
|
4133
4465
|
|
|
4134
4466
|
// src/template-root.ts
|
|
4135
4467
|
import { access } from "fs/promises";
|
|
4136
|
-
import { dirname as
|
|
4468
|
+
import { dirname as dirname5, resolve as resolve5 } from "path";
|
|
4137
4469
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4138
4470
|
async function resolveTemplateRoot() {
|
|
4139
|
-
const currentDirectory =
|
|
4471
|
+
const currentDirectory = dirname5(fileURLToPath2(import.meta.url));
|
|
4140
4472
|
const templateRoot = resolve5(currentDirectory, "../template");
|
|
4141
4473
|
try {
|
|
4142
4474
|
await access(resolve5(templateRoot, "package.json"));
|
|
@@ -5978,7 +6310,7 @@ import { resolve as resolve8 } from "path";
|
|
|
5978
6310
|
|
|
5979
6311
|
// src/update/doctor.ts
|
|
5980
6312
|
import { readFile as readFile11 } from "fs/promises";
|
|
5981
|
-
import { join as
|
|
6313
|
+
import { join as join16 } from "path";
|
|
5982
6314
|
|
|
5983
6315
|
// src/update/process.ts
|
|
5984
6316
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -6031,10 +6363,10 @@ function withoutParentGitRepository(source) {
|
|
|
6031
6363
|
}
|
|
6032
6364
|
|
|
6033
6365
|
// src/update/transaction-cas.ts
|
|
6034
|
-
import { basename as
|
|
6366
|
+
import { basename as basename8, dirname as dirname7 } from "path";
|
|
6035
6367
|
|
|
6036
6368
|
// src/update/transaction-native-cas.ts
|
|
6037
|
-
import { ptr as
|
|
6369
|
+
import { ptr as ptr3, read as read3, dlopen as dlopen4, FFIType as FFIType4 } from "bun:ffi";
|
|
6038
6370
|
|
|
6039
6371
|
// src/update/transaction-native-cas-config.ts
|
|
6040
6372
|
function nativeRenameConfiguration(platform) {
|
|
@@ -6059,19 +6391,19 @@ function nativeRenameConfiguration(platform) {
|
|
|
6059
6391
|
|
|
6060
6392
|
// src/update/transaction-native-cas.ts
|
|
6061
6393
|
var renameSignature = {
|
|
6062
|
-
args: [
|
|
6063
|
-
returns:
|
|
6394
|
+
args: [FFIType4.i32, FFIType4.ptr, FFIType4.i32, FFIType4.ptr, FFIType4.i32],
|
|
6395
|
+
returns: FFIType4.i32
|
|
6064
6396
|
};
|
|
6065
6397
|
var linuxSymbols = {
|
|
6066
6398
|
renameat2: renameSignature,
|
|
6067
|
-
__errno_location: { args: [], returns:
|
|
6399
|
+
__errno_location: { args: [], returns: FFIType4.ptr }
|
|
6068
6400
|
};
|
|
6069
6401
|
var darwinSymbols = {
|
|
6070
6402
|
renameatx_np: renameSignature,
|
|
6071
|
-
__error: { args: [], returns:
|
|
6403
|
+
__error: { args: [], returns: FFIType4.ptr }
|
|
6072
6404
|
};
|
|
6073
|
-
var getLinuxLibc = createLazyLibcLoader((candidate) =>
|
|
6074
|
-
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");
|
|
6075
6407
|
function exchangeAt(parent, left, right, rollback = false) {
|
|
6076
6408
|
atomicRename(parent, left, right, "exchange");
|
|
6077
6409
|
syncMutatedDirectory(rollback ? "rename-exchange-back" : "rename-exchange", parent.fd);
|
|
@@ -6081,10 +6413,18 @@ function moveNoReplaceAt(parent, source, target) {
|
|
|
6081
6413
|
syncMutatedDirectory("rename-noreplace", parent.fd);
|
|
6082
6414
|
}
|
|
6083
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
|
+
}
|
|
6084
6424
|
const configuration = nativeRenameConfiguration(process.platform);
|
|
6085
6425
|
if (process.platform === "linux") {
|
|
6086
6426
|
const libc = getLinuxLibc();
|
|
6087
|
-
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);
|
|
6088
6428
|
if (result < 0) {
|
|
6089
6429
|
throw linuxError(`renameat2 ${source} -> ${target}`);
|
|
6090
6430
|
}
|
|
@@ -6092,7 +6432,7 @@ function atomicRename(parent, source, target, operation) {
|
|
|
6092
6432
|
}
|
|
6093
6433
|
if (process.platform === "darwin") {
|
|
6094
6434
|
const libc = getDarwinLibc();
|
|
6095
|
-
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);
|
|
6096
6436
|
if (result < 0) {
|
|
6097
6437
|
throw darwinError(`renameatx_np ${source} -> ${target}`);
|
|
6098
6438
|
}
|
|
@@ -6125,18 +6465,18 @@ function cString2(value) {
|
|
|
6125
6465
|
}
|
|
6126
6466
|
|
|
6127
6467
|
// src/update/transaction-cas-proof.ts
|
|
6128
|
-
import { closeSync as
|
|
6468
|
+
import { closeSync as closeSync6, constants as constants5, fstatSync as fstatSync4, readSync } from "fs";
|
|
6129
6469
|
function openFileProof(parent) {
|
|
6130
|
-
const fd = openFileAt(parent,
|
|
6470
|
+
const fd = openFileAt(parent, constants5.O_RDONLY | constants5.O_NOFOLLOW);
|
|
6131
6471
|
try {
|
|
6132
6472
|
const identity = identityOf(fd);
|
|
6133
6473
|
return {
|
|
6134
6474
|
fd,
|
|
6135
6475
|
...identity,
|
|
6136
|
-
close: () =>
|
|
6476
|
+
close: () => closeSync6(fd)
|
|
6137
6477
|
};
|
|
6138
6478
|
} catch (error) {
|
|
6139
|
-
|
|
6479
|
+
closeSync6(fd);
|
|
6140
6480
|
throw error;
|
|
6141
6481
|
}
|
|
6142
6482
|
}
|
|
@@ -6154,7 +6494,7 @@ function assertProofPayload(proof, content, mode) {
|
|
|
6154
6494
|
function pathMatchesProof(parent, proof) {
|
|
6155
6495
|
let fd;
|
|
6156
6496
|
try {
|
|
6157
|
-
fd = openFileAt(parent,
|
|
6497
|
+
fd = openFileAt(parent, constants5.O_RDONLY | constants5.O_NOFOLLOW);
|
|
6158
6498
|
} catch {
|
|
6159
6499
|
return false;
|
|
6160
6500
|
}
|
|
@@ -6162,7 +6502,7 @@ function pathMatchesProof(parent, proof) {
|
|
|
6162
6502
|
const identity = identityOf(fd);
|
|
6163
6503
|
return identity.device === proof.device && identity.inode === proof.inode;
|
|
6164
6504
|
} finally {
|
|
6165
|
-
|
|
6505
|
+
closeSync6(fd);
|
|
6166
6506
|
}
|
|
6167
6507
|
}
|
|
6168
6508
|
function pathMatchesExpectedProof(parent, proof, expected, expectedMode) {
|
|
@@ -6183,7 +6523,7 @@ function modeOfProof(proof) {
|
|
|
6183
6523
|
return inspectProof(proof).mode;
|
|
6184
6524
|
}
|
|
6185
6525
|
function inspectProof(proof) {
|
|
6186
|
-
const stat2 =
|
|
6526
|
+
const stat2 = fstatSync4(proof.fd, { bigint: true });
|
|
6187
6527
|
if (!stat2.isFile())
|
|
6188
6528
|
throw new Error("\u4E8B\u52A1\u76EE\u6807\u4E0D\u662F\u666E\u901A\u6587\u4EF6");
|
|
6189
6529
|
if (stat2.dev !== proof.device || stat2.ino !== proof.inode) {
|
|
@@ -6200,7 +6540,7 @@ function inspectProof(proof) {
|
|
|
6200
6540
|
throw new Error("\u4E8B\u52A1\u76EE\u6807\u8BFB\u53D6\u63D0\u524D\u7ED3\u675F");
|
|
6201
6541
|
offset += count;
|
|
6202
6542
|
}
|
|
6203
|
-
const after =
|
|
6543
|
+
const after = fstatSync4(proof.fd, { bigint: true });
|
|
6204
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) {
|
|
6205
6545
|
throw new Error("\u4E8B\u52A1\u76EE\u6807\u5728\u8BC1\u660E\u671F\u95F4\u53D1\u751F\u53D8\u5316");
|
|
6206
6546
|
}
|
|
@@ -6210,7 +6550,7 @@ function inspectProof(proof) {
|
|
|
6210
6550
|
};
|
|
6211
6551
|
}
|
|
6212
6552
|
function identityOf(fd) {
|
|
6213
|
-
const stat2 =
|
|
6553
|
+
const stat2 = fstatSync4(fd, { bigint: true });
|
|
6214
6554
|
if (!stat2.isFile())
|
|
6215
6555
|
throw new Error("\u4E8B\u52A1\u76EE\u6807\u4E0D\u662F\u666E\u901A\u6587\u4EF6");
|
|
6216
6556
|
return { device: stat2.dev, inode: stat2.ino };
|
|
@@ -6331,11 +6671,218 @@ function isBackupEntry(value) {
|
|
|
6331
6671
|
return typeof entry.path === "string" && typeof entry.existed === "boolean" && (entry.mode === undefined || Number.isInteger(entry.mode) && entry.mode >= 0 && entry.mode <= 511);
|
|
6332
6672
|
}
|
|
6333
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
|
+
|
|
6334
6878
|
// src/update/transaction-cas.ts
|
|
6335
6879
|
async function anchoredCompareAndReplace(input) {
|
|
6336
|
-
|
|
6880
|
+
if (process.platform === "win32") {
|
|
6881
|
+
return windowsAnchoredCompareAndReplace(input);
|
|
6882
|
+
}
|
|
6883
|
+
assertSameDirectory2(input.path, input.temporaryPath);
|
|
6337
6884
|
const parent = await openAnchoredParent(input.root, input.path, true, input.parentMode);
|
|
6338
|
-
const temporaryName =
|
|
6885
|
+
const temporaryName = basename8(input.temporaryPath);
|
|
6339
6886
|
let ownsTemporary = false;
|
|
6340
6887
|
let exchanged = false;
|
|
6341
6888
|
let containsUnknownProjectBytes = false;
|
|
@@ -6346,103 +6893,106 @@ async function anchoredCompareAndReplace(input) {
|
|
|
6346
6893
|
targetProof = openFileProof(parent);
|
|
6347
6894
|
}
|
|
6348
6895
|
const mode = input.mode ?? (targetProof ? modeOfProof(targetProof) : 384);
|
|
6349
|
-
writeExclusiveAt(
|
|
6896
|
+
writeExclusiveAt(withLeaf2(parent, temporaryName), input.content, mode);
|
|
6350
6897
|
ownsTemporary = true;
|
|
6351
|
-
desiredProof = openFileProof(
|
|
6898
|
+
desiredProof = openFileProof(withLeaf2(parent, temporaryName));
|
|
6352
6899
|
await input.hooks?.beforeAtomicRename?.();
|
|
6353
6900
|
if (input.expected.kind === "missing") {
|
|
6354
|
-
await
|
|
6355
|
-
ownsTemporary = pathMatchesPayloadProof(
|
|
6901
|
+
await publishMissing2(parent, temporaryName, input, desiredProof, mode);
|
|
6902
|
+
ownsTemporary = pathMatchesPayloadProof(withLeaf2(parent, temporaryName), desiredProof, input.content, mode);
|
|
6356
6903
|
containsUnknownProjectBytes = !ownsTemporary;
|
|
6357
6904
|
if (!ownsTemporary) {
|
|
6358
|
-
throw
|
|
6905
|
+
throw casError2(input.path, input.temporaryPath);
|
|
6359
6906
|
}
|
|
6360
6907
|
return;
|
|
6361
6908
|
}
|
|
6362
|
-
if (!targetProof || !pathMatchesProof(parent, targetProof) || !assertProofMatches(targetProof, input.expected, input.expectedMode) || !pathMatchesProof(
|
|
6363
|
-
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);
|
|
6364
6911
|
}
|
|
6365
6912
|
exchangeAt(parent, temporaryName, parent.leaf);
|
|
6366
6913
|
exchanged = true;
|
|
6367
6914
|
ownsTemporary = false;
|
|
6368
6915
|
containsUnknownProjectBytes = true;
|
|
6369
6916
|
await input.hooks?.afterExchangeBeforeProof?.();
|
|
6370
|
-
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);
|
|
6371
6918
|
if (!proofValid) {
|
|
6372
|
-
await
|
|
6919
|
+
await rollbackExchange2(parent, temporaryName, input, targetProof);
|
|
6373
6920
|
exchanged = false;
|
|
6374
|
-
ownsTemporary = pathMatchesPayloadProof(
|
|
6921
|
+
ownsTemporary = pathMatchesPayloadProof(withLeaf2(parent, temporaryName), desiredProof, input.content, mode);
|
|
6375
6922
|
containsUnknownProjectBytes = !ownsTemporary;
|
|
6376
|
-
throw
|
|
6923
|
+
throw casError2(input.path, ownsTemporary ? undefined : input.temporaryPath);
|
|
6377
6924
|
}
|
|
6378
6925
|
await input.hooks?.afterAtomicRenameBeforeInspect?.();
|
|
6379
|
-
ownsTemporary = pathMatchesExpectedProof(
|
|
6926
|
+
ownsTemporary = pathMatchesExpectedProof(withLeaf2(parent, temporaryName), targetProof, input.expected, input.expectedMode);
|
|
6380
6927
|
containsUnknownProjectBytes = !ownsTemporary;
|
|
6381
6928
|
if (!ownsTemporary) {
|
|
6382
|
-
throw
|
|
6929
|
+
throw casError2(input.path, input.temporaryPath);
|
|
6383
6930
|
}
|
|
6384
6931
|
} catch (error) {
|
|
6385
6932
|
if (error instanceof TransactionCasError)
|
|
6386
6933
|
throw error;
|
|
6387
6934
|
if (exchanged) {
|
|
6388
|
-
throw
|
|
6935
|
+
throw casError2(input.path, input.temporaryPath, error);
|
|
6389
6936
|
}
|
|
6390
6937
|
if (containsUnknownProjectBytes) {
|
|
6391
|
-
throw
|
|
6938
|
+
throw casError2(input.path, input.temporaryPath, error);
|
|
6392
6939
|
}
|
|
6393
|
-
if (
|
|
6394
|
-
throw
|
|
6940
|
+
if (hasFsCode4(error, "ENOENT") || hasFsCode4(error, "EEXIST") || hasFsCode4(error, "ELOOP") || hasFsCode4(error, "ENOTDIR")) {
|
|
6941
|
+
throw casError2(input.path);
|
|
6395
6942
|
}
|
|
6396
6943
|
throw error;
|
|
6397
6944
|
} finally {
|
|
6398
6945
|
if (ownsTemporary)
|
|
6399
|
-
|
|
6946
|
+
removeTemporary2(parent, temporaryName);
|
|
6400
6947
|
desiredProof?.close();
|
|
6401
6948
|
targetProof?.close();
|
|
6402
6949
|
await parent.close();
|
|
6403
6950
|
}
|
|
6404
6951
|
}
|
|
6405
6952
|
async function anchoredCompareAndRemove(input) {
|
|
6406
|
-
|
|
6953
|
+
if (process.platform === "win32") {
|
|
6954
|
+
return windowsAnchoredCompareAndRemove(input);
|
|
6955
|
+
}
|
|
6956
|
+
assertSameDirectory2(input.path, input.quarantinePath);
|
|
6407
6957
|
if (input.expected.kind === "missing")
|
|
6408
6958
|
return;
|
|
6409
6959
|
let parent;
|
|
6410
6960
|
try {
|
|
6411
6961
|
parent = await openAnchoredParent(input.root, input.path, false);
|
|
6412
6962
|
} catch (error) {
|
|
6413
|
-
if (
|
|
6414
|
-
throw
|
|
6963
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
6964
|
+
throw casError2(input.path);
|
|
6415
6965
|
throw error;
|
|
6416
6966
|
}
|
|
6417
|
-
const quarantineName =
|
|
6967
|
+
const quarantineName = basename8(input.quarantinePath);
|
|
6418
6968
|
let ownsQuarantine = false;
|
|
6419
6969
|
let targetProof;
|
|
6420
6970
|
try {
|
|
6421
6971
|
targetProof = openFileProof(parent);
|
|
6422
6972
|
await input.hooks?.beforeAtomicRename?.();
|
|
6423
6973
|
if (!pathMatchesProof(parent, targetProof) || !assertProofMatches(targetProof, input.expected, input.expectedMode)) {
|
|
6424
|
-
throw
|
|
6974
|
+
throw casError2(input.path);
|
|
6425
6975
|
}
|
|
6426
6976
|
moveNoReplaceAt(parent, parent.leaf, quarantineName);
|
|
6427
6977
|
ownsQuarantine = true;
|
|
6428
|
-
if (!pathMatchesProof(
|
|
6429
|
-
throw
|
|
6978
|
+
if (!pathMatchesProof(withLeaf2(parent, quarantineName), targetProof) || !assertProofMatches(targetProof, input.expected, input.expectedMode)) {
|
|
6979
|
+
throw casError2(input.path, input.quarantinePath);
|
|
6430
6980
|
}
|
|
6431
6981
|
await input.hooks?.afterAtomicRenameBeforeInspect?.();
|
|
6432
|
-
if (pathMatchesExpectedProof(
|
|
6433
|
-
|
|
6982
|
+
if (pathMatchesExpectedProof(withLeaf2(parent, quarantineName), targetProof, input.expected, input.expectedMode)) {
|
|
6983
|
+
removeTemporary2(parent, quarantineName);
|
|
6434
6984
|
ownsQuarantine = false;
|
|
6435
6985
|
return;
|
|
6436
6986
|
}
|
|
6437
|
-
throw
|
|
6987
|
+
throw casError2(input.path, input.quarantinePath);
|
|
6438
6988
|
} catch (error) {
|
|
6439
6989
|
if (error instanceof TransactionCasError)
|
|
6440
6990
|
throw error;
|
|
6441
6991
|
if (ownsQuarantine) {
|
|
6442
|
-
throw
|
|
6992
|
+
throw casError2(input.path, input.quarantinePath, error);
|
|
6443
6993
|
}
|
|
6444
|
-
if (
|
|
6445
|
-
throw
|
|
6994
|
+
if (hasFsCode4(error, "ENOENT") || hasFsCode4(error, "EEXIST")) {
|
|
6995
|
+
throw casError2(input.path);
|
|
6446
6996
|
}
|
|
6447
6997
|
throw error;
|
|
6448
6998
|
} finally {
|
|
@@ -6458,8 +7008,8 @@ async function linearizeExpectation(input) {
|
|
|
6458
7008
|
content = readFileAt(parent);
|
|
6459
7009
|
} catch (error) {
|
|
6460
7010
|
await parent.close();
|
|
6461
|
-
if (
|
|
6462
|
-
throw
|
|
7011
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
7012
|
+
throw casError2(input.path);
|
|
6463
7013
|
throw error;
|
|
6464
7014
|
}
|
|
6465
7015
|
await parent.close();
|
|
@@ -6471,61 +7021,61 @@ async function linearizeExpectation(input) {
|
|
|
6471
7021
|
}
|
|
6472
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}`);
|
|
6473
7023
|
}
|
|
6474
|
-
async function
|
|
6475
|
-
if (!pathMatchesProof(
|
|
6476
|
-
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);
|
|
6477
7027
|
}
|
|
6478
7028
|
try {
|
|
6479
7029
|
linkAt(parent, temporaryName, parent.leaf);
|
|
6480
7030
|
} catch (error) {
|
|
6481
|
-
if (
|
|
6482
|
-
throw
|
|
7031
|
+
if (hasFsCode4(error, "EEXIST"))
|
|
7032
|
+
throw casError2(input.path);
|
|
6483
7033
|
throw error;
|
|
6484
7034
|
}
|
|
6485
7035
|
if (!pathMatchesProof(parent, desiredProof) || !assertProofPayload(desiredProof, input.content, mode)) {
|
|
6486
|
-
throw
|
|
7036
|
+
throw casError2(input.path, input.temporaryPath);
|
|
6487
7037
|
}
|
|
6488
7038
|
await input.hooks?.afterAtomicRenameBeforeInspect?.();
|
|
6489
7039
|
}
|
|
6490
|
-
async function
|
|
6491
|
-
if (!pathMatchesProof(
|
|
6492
|
-
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);
|
|
6493
7043
|
}
|
|
6494
7044
|
await input.hooks?.beforeExchangeRollback?.();
|
|
6495
|
-
if (!pathMatchesProof(
|
|
6496
|
-
throw
|
|
7045
|
+
if (!pathMatchesProof(withLeaf2(parent, temporaryName), targetProof) || !assertProofMatches(targetProof, input.expected, input.expectedMode)) {
|
|
7046
|
+
throw casError2(input.path, input.temporaryPath);
|
|
6497
7047
|
}
|
|
6498
7048
|
exchangeAt(parent, temporaryName, parent.leaf, true);
|
|
6499
7049
|
await input.hooks?.afterExchangeRollbackBeforeCleanup?.();
|
|
6500
7050
|
}
|
|
6501
|
-
function
|
|
7051
|
+
function removeTemporary2(parent, name) {
|
|
6502
7052
|
try {
|
|
6503
|
-
unlinkAt(
|
|
7053
|
+
unlinkAt(withLeaf2(parent, name));
|
|
6504
7054
|
} catch (error) {
|
|
6505
|
-
if (!
|
|
7055
|
+
if (!hasFsCode4(error, "ENOENT"))
|
|
6506
7056
|
throw error;
|
|
6507
7057
|
}
|
|
6508
7058
|
}
|
|
6509
|
-
function
|
|
7059
|
+
function withLeaf2(parent, leaf) {
|
|
6510
7060
|
return { ...parent, leaf };
|
|
6511
7061
|
}
|
|
6512
|
-
function
|
|
6513
|
-
if (
|
|
7062
|
+
function assertSameDirectory2(path2, temporaryPath) {
|
|
7063
|
+
if (dirname7(path2) !== dirname7(temporaryPath)) {
|
|
6514
7064
|
throw new Error("\u4E8B\u52A1 CAS \u4E34\u65F6\u6587\u4EF6\u5FC5\u987B\u4E0E\u76EE\u6807\u4F4D\u4E8E\u540C\u4E00\u76EE\u5F55");
|
|
6515
7065
|
}
|
|
6516
7066
|
}
|
|
6517
|
-
function
|
|
7067
|
+
function casError2(path2, artifactPath, cause) {
|
|
6518
7068
|
return new TransactionCasError(`\u8BA1\u5212\u540E\u5DF2\u53D8\u5316\uFF1A${path2}`, path2, artifactPath ? [{ path: path2, artifactPath }] : [], { cause });
|
|
6519
7069
|
}
|
|
6520
7070
|
|
|
6521
7071
|
// src/update/transaction-runtime.ts
|
|
6522
7072
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
6523
|
-
import { join as
|
|
7073
|
+
import { join as join14 } from "path";
|
|
6524
7074
|
|
|
6525
7075
|
// src/update/transaction-state-temporaries.ts
|
|
6526
7076
|
import { randomUUID } from "crypto";
|
|
6527
7077
|
import { readdir as readdir7 } from "fs/promises";
|
|
6528
|
-
import { join as
|
|
7078
|
+
import { join as join13 } from "path";
|
|
6529
7079
|
function serializeTransactionState(state) {
|
|
6530
7080
|
return `${JSON.stringify(state, null, 2)}
|
|
6531
7081
|
`;
|
|
@@ -6641,8 +7191,8 @@ function stateTemporaryName(identity, cleanup) {
|
|
|
6641
7191
|
return `${prefix}.${identity.kind}.${identity.ownerToken}.${identity.nonce}.tmp`;
|
|
6642
7192
|
}
|
|
6643
7193
|
async function listWindyDirectory(root) {
|
|
6644
|
-
return readdir7(
|
|
6645
|
-
if (
|
|
7194
|
+
return readdir7(join13(root, ".windy")).catch((error) => {
|
|
7195
|
+
if (hasFsCode4(error, "ENOENT"))
|
|
6646
7196
|
return [];
|
|
6647
7197
|
throw error;
|
|
6648
7198
|
});
|
|
@@ -6675,7 +7225,7 @@ function createTransactionState(root, updateId, entries, manifestHash) {
|
|
|
6675
7225
|
return {
|
|
6676
7226
|
schemaVersion: 1,
|
|
6677
7227
|
updateId,
|
|
6678
|
-
backupDirectory:
|
|
7228
|
+
backupDirectory: join14(root, backupRelativePath(updateId)),
|
|
6679
7229
|
entries,
|
|
6680
7230
|
ownerToken: randomUUID2(),
|
|
6681
7231
|
phase: "claiming",
|
|
@@ -6694,7 +7244,7 @@ async function claimTransactionState(root, state, hooks) {
|
|
|
6694
7244
|
expected: { kind: "missing" }
|
|
6695
7245
|
});
|
|
6696
7246
|
} catch (error) {
|
|
6697
|
-
if (
|
|
7247
|
+
if (hasFsCode4(error, "EEXIST") || error instanceof TransactionCasError) {
|
|
6698
7248
|
throw new Error("\u68C0\u6D4B\u5230\u672A\u5B8C\u6210\u66F4\u65B0\uFF0C\u8BF7\u5148\u8FD0\u884C bun run windy doctor --repair", { cause: error });
|
|
6699
7249
|
}
|
|
6700
7250
|
throw error;
|
|
@@ -6734,7 +7284,7 @@ async function backupEntriesToDisk(root, backupPath, entries, afterEntry) {
|
|
|
6734
7284
|
if (entry.mode !== undefined && await safeFileMode(root, entry.path) !== entry.mode) {
|
|
6735
7285
|
throw new TransactionCasError(`\u5F85\u5907\u4EFD\u6587\u4EF6 mode \u5DF2\u53D8\u5316\uFF1A${entry.path}`, entry.path);
|
|
6736
7286
|
}
|
|
6737
|
-
await writeExclusive(root,
|
|
7287
|
+
await writeExclusive(root, join14(backupPath, "files", entry.path), content, undefined, entry.mode);
|
|
6738
7288
|
await afterEntry?.();
|
|
6739
7289
|
}
|
|
6740
7290
|
}
|
|
@@ -7042,8 +7592,8 @@ async function removeOwnedResidue(root, evidence, hash, mode) {
|
|
|
7042
7592
|
}
|
|
7043
7593
|
|
|
7044
7594
|
// src/update/transaction-recovery-files.ts
|
|
7045
|
-
import { join as
|
|
7046
|
-
function
|
|
7595
|
+
import { join as join15 } from "path";
|
|
7596
|
+
function matchesExpected2(actualHash, actualMode, expected, expectedMode) {
|
|
7047
7597
|
return expected.kind === "missing" ? actualHash === undefined : actualHash === expected.value && (expectedMode === undefined || actualMode === expectedMode);
|
|
7048
7598
|
}
|
|
7049
7599
|
async function readRecoveryBackups(root, backupPath, state, preserved) {
|
|
@@ -7054,7 +7604,7 @@ async function readRecoveryBackups(root, backupPath, state, preserved) {
|
|
|
7054
7604
|
await inspectSafePath(root, entry.path);
|
|
7055
7605
|
if (!entry.existed)
|
|
7056
7606
|
continue;
|
|
7057
|
-
const backupFile =
|
|
7607
|
+
const backupFile = join15(backupPath, "files", entry.path);
|
|
7058
7608
|
const content = await readSafeOptional(root, backupFile);
|
|
7059
7609
|
if (!content)
|
|
7060
7610
|
throw new Error(`\u4E8B\u52A1\u5907\u4EFD\u7F3A\u5931\uFF1A${entry.path}`);
|
|
@@ -7068,7 +7618,7 @@ async function readRecoveryBackups(root, backupPath, state, preserved) {
|
|
|
7068
7618
|
async function assertRestoredEntries(root, state, backups) {
|
|
7069
7619
|
for (const entry of state.entries) {
|
|
7070
7620
|
const expected = entry.existed ? { kind: "hash", value: hashContent(backups.get(entry.path)) } : { kind: "missing" };
|
|
7071
|
-
if (!
|
|
7621
|
+
if (!matchesExpected2(await hashSafePath(root, entry.path), await safeFileMode(root, entry.path), expected, entry.mode)) {
|
|
7072
7622
|
throw new Error(`\u4E8B\u52A1\u8DEF\u5F84\u5C1A\u672A\u771F\u5B9E\u6062\u590D\uFF1A${entry.path}`);
|
|
7073
7623
|
}
|
|
7074
7624
|
const evidence = state.recoveryEvidence?.find(({ path: path2 }) => path2 === entry.path);
|
|
@@ -7091,8 +7641,8 @@ async function unresolvedPreservePaths(root, backupPath, state) {
|
|
|
7091
7641
|
const actualHash = await hashSafePath(root, path2);
|
|
7092
7642
|
const actualMode = await safeFileMode(root, path2);
|
|
7093
7643
|
const mutation = state.mutationEvidence?.find((evidence) => evidence.path === path2);
|
|
7094
|
-
const matchesBackup =
|
|
7095
|
-
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));
|
|
7096
7646
|
const hasConflictArtifact = state.conflictArtifacts?.some((artifact) => artifact.path === path2) ?? false;
|
|
7097
7647
|
if (!matchesBackup && (!matchesOutcome || hasConflictArtifact)) {
|
|
7098
7648
|
unresolved.push(path2);
|
|
@@ -7164,7 +7714,7 @@ async function restoreUpdateState(projectDirectory, state, options) {
|
|
|
7164
7714
|
const actualHash = await hashSafePath(root, entry.path);
|
|
7165
7715
|
if (current.phase === "committing") {
|
|
7166
7716
|
const expected = current.expectations?.find(({ path: path2 }) => path2 === entry.path);
|
|
7167
|
-
if (!expected || !
|
|
7717
|
+
if (!expected || !matchesExpected2(actualHash, await safeFileMode(root, entry.path), expected.expected, expected.mode)) {
|
|
7168
7718
|
newlyPreserved.push(entry.path);
|
|
7169
7719
|
} else {
|
|
7170
7720
|
recoveryExpectations.set(entry.path, expected);
|
|
@@ -7174,9 +7724,9 @@ async function restoreUpdateState(projectDirectory, state, options) {
|
|
|
7174
7724
|
const evidence = current.mutationEvidence?.find(({ path: path2 }) => path2 === entry.path);
|
|
7175
7725
|
if (!evidence) {
|
|
7176
7726
|
newlyPreserved.push(entry.path);
|
|
7177
|
-
} else if (
|
|
7727
|
+
} else if (matchesExpected2(actualHash, await safeFileMode(root, entry.path), evidence.before, evidence.beforeMode)) {
|
|
7178
7728
|
continue;
|
|
7179
|
-
} else if (evidence.outcome &&
|
|
7729
|
+
} else if (evidence.outcome && matchesExpected2(actualHash, await safeFileMode(root, entry.path), evidence.outcome, evidence.outcomeMode)) {
|
|
7180
7730
|
recoveryExpectations.set(entry.path, {
|
|
7181
7731
|
expected: evidence.outcome,
|
|
7182
7732
|
mode: evidence.outcomeMode
|
|
@@ -7685,7 +8235,7 @@ async function diagnoseProject(projectDirectory, repair = false) {
|
|
|
7685
8235
|
if (file.ownership === "project-owned")
|
|
7686
8236
|
continue;
|
|
7687
8237
|
try {
|
|
7688
|
-
const changed = hashContent(await readFile11(
|
|
8238
|
+
const changed = hashContent(await readFile11(join16(projectDirectory, file.path))) !== file.hash;
|
|
7689
8239
|
if (!changed)
|
|
7690
8240
|
continue;
|
|
7691
8241
|
modifiedManagedFiles.push(file.path);
|
|
@@ -7735,6 +8285,16 @@ var recipes = [
|
|
|
7735
8285
|
id: "starter-0.6.8-to-0.6.9",
|
|
7736
8286
|
from: "0.6.8",
|
|
7737
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"
|
|
8293
|
+
},
|
|
8294
|
+
{
|
|
8295
|
+
id: "starter-0.6.10-to-0.6.11",
|
|
8296
|
+
from: "0.6.10",
|
|
8297
|
+
to: "0.6.11"
|
|
7738
8298
|
}
|
|
7739
8299
|
];
|
|
7740
8300
|
function resolveRecipeChain(sourceVersion, targetVersion) {
|
|
@@ -7781,17 +8341,17 @@ function parseVersion2(version) {
|
|
|
7781
8341
|
|
|
7782
8342
|
// src/update/updater.ts
|
|
7783
8343
|
import { readFile as readFile23, rm as rm8 } from "fs/promises";
|
|
7784
|
-
import { join as
|
|
8344
|
+
import { join as join28 } from "path";
|
|
7785
8345
|
|
|
7786
8346
|
// src/update/artifacts.ts
|
|
7787
8347
|
import { mkdtemp, readFile as readFile14 } from "fs/promises";
|
|
7788
8348
|
import { tmpdir } from "os";
|
|
7789
|
-
import { basename as
|
|
8349
|
+
import { basename as basename10, join as join19 } from "path";
|
|
7790
8350
|
|
|
7791
8351
|
// src/update/published-artifacts.ts
|
|
7792
8352
|
import { createHash as createHash4 } from "crypto";
|
|
7793
8353
|
import { mkdir as mkdir6, readFile as readFile12, writeFile as writeFile10 } from "fs/promises";
|
|
7794
|
-
import { basename as
|
|
8354
|
+
import { basename as basename9, join as join17 } from "path";
|
|
7795
8355
|
|
|
7796
8356
|
// src/update/safe-archive.ts
|
|
7797
8357
|
import { mkdir as mkdir5 } from "fs/promises";
|
|
@@ -7843,17 +8403,17 @@ async function downloadPublicArtifact(temporaryRoot, label, version, expectedInt
|
|
|
7843
8403
|
}
|
|
7844
8404
|
const archive = await readBoundedResponse(response, `create-windy@${version} artifact `);
|
|
7845
8405
|
verifyArchive(metadata, archive);
|
|
7846
|
-
const destination =
|
|
7847
|
-
const archivePath =
|
|
8406
|
+
const destination = join17(temporaryRoot, `${label}-artifact`);
|
|
8407
|
+
const archivePath = join17(temporaryRoot, `${label}.tgz`);
|
|
7848
8408
|
await writeFile10(archivePath, archive);
|
|
7849
8409
|
await extractSafeTarArchive({
|
|
7850
8410
|
archivePath,
|
|
7851
8411
|
destination,
|
|
7852
8412
|
cwd: temporaryRoot
|
|
7853
8413
|
});
|
|
7854
|
-
const packageRoot2 =
|
|
7855
|
-
const packageJson = JSON.parse(await readFile12(
|
|
7856
|
-
const template = await readTemplateMetadata(
|
|
8414
|
+
const packageRoot2 = join17(destination, "package");
|
|
8415
|
+
const packageJson = JSON.parse(await readFile12(join17(packageRoot2, "package.json"), "utf8"));
|
|
8416
|
+
const template = await readTemplateMetadata(join17(packageRoot2, "template"));
|
|
7857
8417
|
if (packageJson.name !== "create-windy" || packageJson.version !== version || template.generatorVersion !== version) {
|
|
7858
8418
|
throw new Error(`create-windy@${version} \u5305\u8EAB\u4EFD\u6216\u6A21\u677F\u5143\u6570\u636E\u4E0D\u4E00\u81F4`);
|
|
7859
8419
|
}
|
|
@@ -7985,10 +8545,10 @@ function verifyArchive(metadata, archive) {
|
|
|
7985
8545
|
}
|
|
7986
8546
|
}
|
|
7987
8547
|
async function generatePublicArtifactProject(temporaryRoot, label, projectName, packageRoot2, provenance) {
|
|
7988
|
-
const parent =
|
|
8548
|
+
const parent = join17(temporaryRoot, label);
|
|
7989
8549
|
await mkdir6(parent, { recursive: true });
|
|
7990
8550
|
const args = [
|
|
7991
|
-
|
|
8551
|
+
join17(packageRoot2, "dist/cli.js"),
|
|
7992
8552
|
projectName,
|
|
7993
8553
|
"--yes",
|
|
7994
8554
|
"--skip-install",
|
|
@@ -8008,7 +8568,7 @@ async function generatePublicArtifactProject(temporaryRoot, label, projectName,
|
|
|
8008
8568
|
}
|
|
8009
8569
|
}
|
|
8010
8570
|
await assertProcess("bun", args, parent);
|
|
8011
|
-
return
|
|
8571
|
+
return join17(parent, projectName);
|
|
8012
8572
|
}
|
|
8013
8573
|
|
|
8014
8574
|
// src/module-history.ts
|
|
@@ -8019,15 +8579,15 @@ import {
|
|
|
8019
8579
|
readFile as readFile13,
|
|
8020
8580
|
writeFile as writeFile11
|
|
8021
8581
|
} from "fs/promises";
|
|
8022
|
-
import { dirname as
|
|
8582
|
+
import { dirname as dirname8, join as join18, relative as relative5, sep as sep4 } from "path";
|
|
8023
8583
|
async function archiveRemovedModuleMigrations(input) {
|
|
8024
8584
|
await assertExistingHistoryIntegrity(input.projectDirectory);
|
|
8025
|
-
let changed = await copyMigrationTree(input.projectDirectory, ".windy/module-history",
|
|
8585
|
+
let changed = await copyMigrationTree(input.projectDirectory, ".windy/module-history", join18(input.targetDirectory, ".windy/module-history"));
|
|
8026
8586
|
const target = new Set(input.targetModules);
|
|
8027
8587
|
const removed = moduleDistributionCatalog.filter(({ name }) => input.sourceModules.includes(name) && !target.has(name));
|
|
8028
8588
|
for (const manifest of removed) {
|
|
8029
8589
|
for (const root of manifest.migrationRoots) {
|
|
8030
|
-
changed = await copyMigrationTree(input.projectDirectory, root,
|
|
8590
|
+
changed = await copyMigrationTree(input.projectDirectory, root, join18(input.targetDirectory, ".windy/module-history", manifest.name, root)) || changed;
|
|
8031
8591
|
}
|
|
8032
8592
|
}
|
|
8033
8593
|
if (changed) {
|
|
@@ -8035,7 +8595,7 @@ async function archiveRemovedModuleMigrations(input) {
|
|
|
8035
8595
|
}
|
|
8036
8596
|
}
|
|
8037
8597
|
async function assertExistingHistoryIntegrity(projectDirectory) {
|
|
8038
|
-
const historyRoot =
|
|
8598
|
+
const historyRoot = join18(projectDirectory, ".windy/module-history");
|
|
8039
8599
|
const metadata = await readOptionalMetadata(historyRoot);
|
|
8040
8600
|
if (!metadata)
|
|
8041
8601
|
return;
|
|
@@ -8045,7 +8605,7 @@ async function assertExistingHistoryIntegrity(projectDirectory) {
|
|
|
8045
8605
|
const manifest = await readManagedFilesManifest(projectDirectory);
|
|
8046
8606
|
const expected = new Map(manifest.files.map((entry) => [entry.path, entry]));
|
|
8047
8607
|
for (const path2 of await collectRegularFiles(historyRoot)) {
|
|
8048
|
-
const relativePath2 =
|
|
8608
|
+
const relativePath2 = relative5(projectDirectory, path2).split(sep4).join("/");
|
|
8049
8609
|
const entry = expected.get(relativePath2);
|
|
8050
8610
|
if (!entry || isMissingManagedFile(entry)) {
|
|
8051
8611
|
throw new Error(`\u6A21\u5757 migration \u5386\u53F2\u672A\u767B\u8BB0\u5230\u53D7\u7BA1\u6E05\u5355\uFF1A${relativePath2}`);
|
|
@@ -8056,7 +8616,7 @@ async function assertExistingHistoryIntegrity(projectDirectory) {
|
|
|
8056
8616
|
}
|
|
8057
8617
|
}
|
|
8058
8618
|
async function copyMigrationTree(projectRoot, relativeRoot, targetRoot) {
|
|
8059
|
-
const sourceRoot =
|
|
8619
|
+
const sourceRoot = join18(projectRoot, relativeRoot);
|
|
8060
8620
|
const rootMetadata = await readOptionalMetadata(sourceRoot);
|
|
8061
8621
|
if (!rootMetadata)
|
|
8062
8622
|
return false;
|
|
@@ -8064,8 +8624,8 @@ async function copyMigrationTree(projectRoot, relativeRoot, targetRoot) {
|
|
|
8064
8624
|
throw new Error(`\u6A21\u5757 migration \u6839\u76EE\u5F55\u65E0\u6548\uFF1A${relativeRoot}`);
|
|
8065
8625
|
}
|
|
8066
8626
|
for (const source of await collectRegularFiles(sourceRoot)) {
|
|
8067
|
-
const target =
|
|
8068
|
-
await mkdir7(
|
|
8627
|
+
const target = join18(targetRoot, relative5(sourceRoot, source).split(sep4).join("/"));
|
|
8628
|
+
await mkdir7(dirname8(target), { recursive: true });
|
|
8069
8629
|
await writeFile11(target, await readFile13(source));
|
|
8070
8630
|
}
|
|
8071
8631
|
return true;
|
|
@@ -8076,7 +8636,7 @@ async function collectRegularFiles(root) {
|
|
|
8076
8636
|
return files.sort();
|
|
8077
8637
|
async function visit(directory) {
|
|
8078
8638
|
for (const name of (await readdir8(directory)).sort()) {
|
|
8079
|
-
const path2 =
|
|
8639
|
+
const path2 = join18(directory, name);
|
|
8080
8640
|
const metadata = await lstat6(path2);
|
|
8081
8641
|
if (metadata.isSymbolicLink()) {
|
|
8082
8642
|
throw new Error(`\u6A21\u5757 migration \u4E0D\u5141\u8BB8\u7B26\u53F7\u94FE\u63A5\uFF1A${path2}`);
|
|
@@ -8106,10 +8666,10 @@ class PublishedArtifactProvider {
|
|
|
8106
8666
|
this.#fetch = fetcher;
|
|
8107
8667
|
}
|
|
8108
8668
|
async prepare(projectDirectory, provenance, targetModules) {
|
|
8109
|
-
const temporaryRoot = await mkdtemp(
|
|
8669
|
+
const temporaryRoot = await mkdtemp(join19(tmpdir(), "windy-update-"));
|
|
8110
8670
|
const projectName = await readProjectName2(projectDirectory);
|
|
8111
|
-
const baseDirectory =
|
|
8112
|
-
const targetDirectory =
|
|
8671
|
+
const baseDirectory = join19(temporaryRoot, "base", projectName);
|
|
8672
|
+
const targetDirectory = join19(temporaryRoot, "target", projectName);
|
|
8113
8673
|
const baseArtifact = await downloadPublicArtifact(temporaryRoot, "base", provenance.generatorVersion, undefined, this.#fetch);
|
|
8114
8674
|
if (baseArtifact.identity.templateCommit !== provenance.templateCommit) {
|
|
8115
8675
|
throw new Error("Project Lock \u4E0E\u6765\u6E90 registry artifact \u7684 template commit \u4E0D\u4E00\u81F4");
|
|
@@ -8137,13 +8697,13 @@ class PublishedArtifactProvider {
|
|
|
8137
8697
|
}
|
|
8138
8698
|
}
|
|
8139
8699
|
async function readProjectName2(projectDirectory) {
|
|
8140
|
-
const source = JSON.parse(await readFile14(
|
|
8141
|
-
return source.name ||
|
|
8700
|
+
const source = JSON.parse(await readFile14(join19(projectDirectory, "package.json"), "utf8"));
|
|
8701
|
+
return source.name || basename10(projectDirectory);
|
|
8142
8702
|
}
|
|
8143
8703
|
|
|
8144
8704
|
// src/update/planner.ts
|
|
8145
8705
|
import { readFile as readFile21 } from "fs/promises";
|
|
8146
|
-
import { dirname as
|
|
8706
|
+
import { dirname as dirname9, join as join26 } from "path";
|
|
8147
8707
|
|
|
8148
8708
|
// src/update/docker-copy-update-plan.ts
|
|
8149
8709
|
async function deriveDockerfilePlans(files, snapshots, paths, targetWorkspaceManifests) {
|
|
@@ -8232,15 +8792,15 @@ function matchesWorkspace(pattern, directory) {
|
|
|
8232
8792
|
|
|
8233
8793
|
// src/update/migration-reconciler.ts
|
|
8234
8794
|
import { readFile as readFile18 } from "fs/promises";
|
|
8235
|
-
import { join as
|
|
8795
|
+
import { join as join22 } from "path";
|
|
8236
8796
|
|
|
8237
8797
|
// src/update/migration-adoption.ts
|
|
8238
8798
|
import { readFile as readFile17 } from "fs/promises";
|
|
8239
|
-
import { join as
|
|
8799
|
+
import { join as join21 } from "path";
|
|
8240
8800
|
|
|
8241
8801
|
// src/update/migration-project-file.ts
|
|
8242
8802
|
import { readFile as readFile15 } from "fs/promises";
|
|
8243
|
-
import { join as
|
|
8803
|
+
import { join as join20 } from "path";
|
|
8244
8804
|
async function readProjectJson(input, path2) {
|
|
8245
8805
|
const content = await readProjectFile(input, path2);
|
|
8246
8806
|
if (!content) {
|
|
@@ -8256,7 +8816,7 @@ async function readProjectFile(input, path2) {
|
|
|
8256
8816
|
}
|
|
8257
8817
|
let content;
|
|
8258
8818
|
try {
|
|
8259
|
-
content = await readFile15(
|
|
8819
|
+
content = await readFile15(join20(input.projectDirectory, path2));
|
|
8260
8820
|
} catch (error) {
|
|
8261
8821
|
if (!isMissingFileError(error))
|
|
8262
8822
|
throw error;
|
|
@@ -8397,10 +8957,10 @@ async function inspectPreexistingMigrationAdoptions(input) {
|
|
|
8397
8957
|
projectBeforeBytes,
|
|
8398
8958
|
projectAfterBytes
|
|
8399
8959
|
] = await Promise.all([
|
|
8400
|
-
readFile17(
|
|
8960
|
+
readFile17(join21(input.targetDirectory, `${drizzleRoot}/${candidate.tag}.sql`)),
|
|
8401
8961
|
readProjectFile(input, projectSqlPath),
|
|
8402
|
-
readJson(
|
|
8403
|
-
readJson(
|
|
8962
|
+
readJson(join21(input.targetDirectory, snapshotPath(previousTarget.tag))),
|
|
8963
|
+
readJson(join21(input.targetDirectory, snapshotPath(candidate.tag))),
|
|
8404
8964
|
readProjectFile(input, snapshotPath(previousProject.tag)),
|
|
8405
8965
|
readProjectFile(input, projectSnapshotPath)
|
|
8406
8966
|
]);
|
|
@@ -8527,13 +9087,13 @@ async function reconcileDrizzleMigrations(input) {
|
|
|
8527
9087
|
const tag = `${prefix}_${name}`;
|
|
8528
9088
|
const sqlPath = `${drizzleRoot}/${tag}.sql`;
|
|
8529
9089
|
const snapshotPath2 = `${drizzleRoot}/meta/${prefix}_snapshot.json`;
|
|
8530
|
-
const sql = await readFile18(
|
|
9090
|
+
const sql = await readFile18(join22(input.targetDirectory, `${drizzleRoot}/${addition.tag}.sql`));
|
|
8531
9091
|
merged.id = targetAfter.id;
|
|
8532
9092
|
merged.prevId = currentSnapshot.id;
|
|
8533
|
-
const
|
|
9093
|
+
const snapshot2 = encodeJson(merged);
|
|
8534
9094
|
contentOverrides.set(sqlPath, sql);
|
|
8535
|
-
contentOverrides.set(snapshotPath2,
|
|
8536
|
-
files.push(managedEntry(sqlPath, sql), managedEntry(snapshotPath2,
|
|
9095
|
+
contentOverrides.set(snapshotPath2, snapshot2);
|
|
9096
|
+
files.push(managedEntry(sqlPath, sql), managedEntry(snapshotPath2, snapshot2));
|
|
8537
9097
|
previousWhen = Math.max(previousWhen + 1, addition.when);
|
|
8538
9098
|
mergedJournal.entries.push({
|
|
8539
9099
|
...addition,
|
|
@@ -8574,9 +9134,9 @@ function unchanged(targetManifest) {
|
|
|
8574
9134
|
async function readJournals(input) {
|
|
8575
9135
|
try {
|
|
8576
9136
|
const [base, project, target] = await Promise.all([
|
|
8577
|
-
readJson(
|
|
9137
|
+
readJson(join22(input.baseDirectory, journalPath)),
|
|
8578
9138
|
readProjectJson(input, journalPath),
|
|
8579
|
-
readJson(
|
|
9139
|
+
readJson(join22(input.targetDirectory, journalPath))
|
|
8580
9140
|
]);
|
|
8581
9141
|
return { base, project, target };
|
|
8582
9142
|
} catch (error) {
|
|
@@ -8607,17 +9167,17 @@ async function readLatestSnapshot(input, journal) {
|
|
|
8607
9167
|
return JSON.parse(new TextDecoder().decode(content));
|
|
8608
9168
|
}
|
|
8609
9169
|
async function readSnapshot(root, tag) {
|
|
8610
|
-
return await readJson(
|
|
9170
|
+
return await readJson(join22(root, snapshotPath(tag)));
|
|
8611
9171
|
}
|
|
8612
9172
|
|
|
8613
9173
|
// src/update/planner-file.ts
|
|
8614
9174
|
import { readFile as readFile19 } from "fs/promises";
|
|
8615
|
-
import { join as
|
|
9175
|
+
import { join as join24 } from "path";
|
|
8616
9176
|
|
|
8617
9177
|
// src/update/merge.ts
|
|
8618
9178
|
import { mkdtemp as mkdtemp2, rm as rm6, writeFile as writeFile12 } from "fs/promises";
|
|
8619
9179
|
import { tmpdir as tmpdir2 } from "os";
|
|
8620
|
-
import { join as
|
|
9180
|
+
import { join as join23 } from "path";
|
|
8621
9181
|
|
|
8622
9182
|
// src/update/merge-convergent-additions.ts
|
|
8623
9183
|
async function reconcileConvergentAdditions(input) {
|
|
@@ -8759,11 +9319,11 @@ function sameLines(left, right) {
|
|
|
8759
9319
|
|
|
8760
9320
|
// src/update/merge.ts
|
|
8761
9321
|
async function mergeTextFile(base, ours, theirs) {
|
|
8762
|
-
const root = await mkdtemp2(
|
|
9322
|
+
const root = await mkdtemp2(join23(tmpdir2(), "windy-merge-"));
|
|
8763
9323
|
try {
|
|
8764
|
-
const oursPath =
|
|
8765
|
-
const basePath =
|
|
8766
|
-
const theirsPath =
|
|
9324
|
+
const oursPath = join23(root, "ours");
|
|
9325
|
+
const basePath = join23(root, "base");
|
|
9326
|
+
const theirsPath = join23(root, "theirs");
|
|
8767
9327
|
await Promise.all([
|
|
8768
9328
|
writeFile12(oursPath, ours),
|
|
8769
9329
|
writeFile12(basePath, base),
|
|
@@ -9214,8 +9774,8 @@ function conflict2(input, message) {
|
|
|
9214
9774
|
// src/update/planner-file.ts
|
|
9215
9775
|
async function planFile(path2, baseRoot, targetRoot, source, target, ours, provenance, targetContentOverride, manageGeneratedProjectOwned = false, forcePlatformBaseline = false, manageRecipeProjectOwned = false) {
|
|
9216
9776
|
const [base, theirs] = await Promise.all([
|
|
9217
|
-
readOptional(
|
|
9218
|
-
targetContentOverride ? Promise.resolve(targetContentOverride) : readOptional(
|
|
9777
|
+
readOptional(join24(baseRoot, path2)),
|
|
9778
|
+
targetContentOverride ? Promise.resolve(targetContentOverride) : readOptional(join24(targetRoot, path2))
|
|
9219
9779
|
]);
|
|
9220
9780
|
const ownership = source?.ownership ?? target?.ownership ?? classifyOwnership(path2);
|
|
9221
9781
|
const expected = expectationForSnapshot(ours);
|
|
@@ -9378,26 +9938,26 @@ function hasExistingSourceForTest(path2, sourcePaths) {
|
|
|
9378
9938
|
|
|
9379
9939
|
// src/update/planner-snapshots.ts
|
|
9380
9940
|
import { readFile as readFile20, stat as stat2 } from "fs/promises";
|
|
9381
|
-
import { join as
|
|
9941
|
+
import { join as join25 } from "path";
|
|
9382
9942
|
async function snapshotProjectFiles(project, paths, seed) {
|
|
9383
9943
|
const snapshots = new Map(seed);
|
|
9384
9944
|
await Promise.all([...paths].filter((path2) => !snapshots.has(path2)).map(async (path2) => {
|
|
9385
|
-
snapshots.set(path2, await readOptional2(
|
|
9945
|
+
snapshots.set(path2, await readOptional2(join25(project, path2)));
|
|
9386
9946
|
}));
|
|
9387
9947
|
return snapshots;
|
|
9388
9948
|
}
|
|
9389
9949
|
async function snapshotProjectModes(project, paths) {
|
|
9390
|
-
return new Map(await Promise.all([...paths].map(async (path2) => [path2, await readModeOptional(
|
|
9950
|
+
return new Map(await Promise.all([...paths].map(async (path2) => [path2, await readModeOptional(join25(project, path2))])));
|
|
9391
9951
|
}
|
|
9392
9952
|
async function assertPlanSnapshots(project, expectations) {
|
|
9393
9953
|
const changed = [];
|
|
9394
9954
|
for (const expectation2 of expectations) {
|
|
9395
|
-
const actual = expectationForSnapshot(await readOptional2(
|
|
9955
|
+
const actual = expectationForSnapshot(await readOptional2(join25(project, expectation2.path)));
|
|
9396
9956
|
if (JSON.stringify(actual) !== JSON.stringify(expectation2.expected)) {
|
|
9397
9957
|
changed.push(expectation2.path);
|
|
9398
9958
|
continue;
|
|
9399
9959
|
}
|
|
9400
|
-
if ("mode" in expectation2 && await readModeOptional(
|
|
9960
|
+
if ("mode" in expectation2 && await readModeOptional(join25(project, expectation2.path)) !== expectation2.mode) {
|
|
9401
9961
|
changed.push(expectation2.path);
|
|
9402
9962
|
}
|
|
9403
9963
|
}
|
|
@@ -9473,7 +10033,7 @@ var oxcManagedPaths = new Set([
|
|
|
9473
10033
|
]);
|
|
9474
10034
|
async function createUpdatePlan(request, artifacts, dependencies = {}) {
|
|
9475
10035
|
await assertProjectReadyForUpdate(request.projectDirectory);
|
|
9476
|
-
const manifestPath =
|
|
10036
|
+
const manifestPath = join26(request.projectDirectory, ".windy/files.json");
|
|
9477
10037
|
const expectedManifestHash = hashContent(await readFile21(manifestPath));
|
|
9478
10038
|
const generationSnapshot = await readGenerationProvenanceSnapshot(request.projectDirectory);
|
|
9479
10039
|
const provenance = generationSnapshot.provenance;
|
|
@@ -9521,8 +10081,8 @@ async function createUpdatePlan(request, artifacts, dependencies = {}) {
|
|
|
9521
10081
|
const paths = new Set([...sourceEntries.keys(), ...targetEntries.keys()]);
|
|
9522
10082
|
for (const path2 of paths) {
|
|
9523
10083
|
if (!projectSnapshots.has(path2)) {
|
|
9524
|
-
projectSnapshots.set(path2, await readOptional2(
|
|
9525
|
-
projectModes.set(path2, await readModeOptional(
|
|
10084
|
+
projectSnapshots.set(path2, await readOptional2(join26(request.projectDirectory, path2)));
|
|
10085
|
+
projectModes.set(path2, await readModeOptional(join26(request.projectDirectory, path2)));
|
|
9526
10086
|
}
|
|
9527
10087
|
}
|
|
9528
10088
|
const files = await planFiles({
|
|
@@ -9546,10 +10106,10 @@ async function createUpdatePlan(request, artifacts, dependencies = {}) {
|
|
|
9546
10106
|
for (const file of files) {
|
|
9547
10107
|
file.expectedProjectMode = projectModes.get(file.path);
|
|
9548
10108
|
if (file.action === "create" || file.action === "update") {
|
|
9549
|
-
file.mode = file.expectedProjectMode ?? await readModeOptional(
|
|
10109
|
+
file.mode = file.expectedProjectMode ?? await readModeOptional(join26(artifactSet.targetDirectory, file.path));
|
|
9550
10110
|
}
|
|
9551
10111
|
if (file.action === "create") {
|
|
9552
|
-
file.parentMode = await readSourceParentMode(
|
|
10112
|
+
file.parentMode = await readSourceParentMode(join26(artifactSet.targetDirectory, dirname9(file.path)));
|
|
9553
10113
|
}
|
|
9554
10114
|
}
|
|
9555
10115
|
const plannedPaths = new Set(files.map(({ path: path2 }) => path2));
|
|
@@ -9696,7 +10256,7 @@ function frozenManifestHash(file, finalizedHashes) {
|
|
|
9696
10256
|
// src/update/format-stabilizer.ts
|
|
9697
10257
|
import { mkdir as mkdir8, mkdtemp as mkdtemp3, readFile as readFile22, rm as rm7, writeFile as writeFile13 } from "fs/promises";
|
|
9698
10258
|
import { tmpdir as tmpdir3 } from "os";
|
|
9699
|
-
import { dirname as
|
|
10259
|
+
import { dirname as dirname10, extname as extname4, join as join27, resolve as resolve6, sep as sep5 } from "path";
|
|
9700
10260
|
var formattedExtensions = new Set([
|
|
9701
10261
|
".cjs",
|
|
9702
10262
|
".css",
|
|
@@ -9735,7 +10295,7 @@ async function stabilizeManagedContent(result2, execute, writeProjectFile) {
|
|
|
9735
10295
|
}
|
|
9736
10296
|
}
|
|
9737
10297
|
inputs.set(".windy/generation.json", new TextEncoder().encode(generationContent));
|
|
9738
|
-
const temporaryRoot = await mkdtemp3(
|
|
10298
|
+
const temporaryRoot = await mkdtemp3(join27(tmpdir3(), "windy-update-format-"));
|
|
9739
10299
|
try {
|
|
9740
10300
|
const stagedPaths = await stageInputs(temporaryRoot, inputs);
|
|
9741
10301
|
for (let offset = 0;offset < stagedPaths.length; offset += 80) {
|
|
@@ -9743,7 +10303,7 @@ async function stabilizeManagedContent(result2, execute, writeProjectFile) {
|
|
|
9743
10303
|
"x",
|
|
9744
10304
|
"oxfmt",
|
|
9745
10305
|
"--write",
|
|
9746
|
-
`--config=${
|
|
10306
|
+
`--config=${join27(result2.plan.projectDirectory, ".oxfmtrc.json")}`,
|
|
9747
10307
|
...stagedPaths.slice(offset, offset + 80)
|
|
9748
10308
|
], result2.plan.projectDirectory);
|
|
9749
10309
|
}
|
|
@@ -9776,7 +10336,7 @@ async function stageInputs(temporaryRoot, inputs) {
|
|
|
9776
10336
|
const paths = [];
|
|
9777
10337
|
for (const [path2, content] of inputs) {
|
|
9778
10338
|
const target = safeTemporaryPath(temporaryRoot, path2);
|
|
9779
|
-
await mkdir8(
|
|
10339
|
+
await mkdir8(dirname10(target), { recursive: true });
|
|
9780
10340
|
await writeFile13(target, content);
|
|
9781
10341
|
paths.push(target);
|
|
9782
10342
|
}
|
|
@@ -9904,7 +10464,7 @@ class DefaultStarterUpdater {
|
|
|
9904
10464
|
const plannedPaths = new Set(result2.plan.files.map(({ path: path2 }) => path2));
|
|
9905
10465
|
replaceExpectations(result2, verificationSnapshot.filter(({ path: path2 }) => !metadataPaths2.has(path2) && !plannedPaths.has(path2)));
|
|
9906
10466
|
verificationExpectationsFrozen = true;
|
|
9907
|
-
const packageJson = JSON.parse(await readFile23(
|
|
10467
|
+
const packageJson = JSON.parse(await readFile23(join28(result2.plan.projectDirectory, "package.json"), "utf8"));
|
|
9908
10468
|
for (const name of ["lint", "typecheck", "test", "build"]) {
|
|
9909
10469
|
if (!packageJson.scripts?.[name]) {
|
|
9910
10470
|
steps.push({ name: `bun run ${name}`, status: "skipped" });
|
|
@@ -10843,11 +11403,11 @@ import {
|
|
|
10843
11403
|
rm as rm11,
|
|
10844
11404
|
writeFile as writeFile14
|
|
10845
11405
|
} from "fs/promises";
|
|
10846
|
-
import { dirname as
|
|
11406
|
+
import { dirname as dirname11, join as join29, relative as relative7 } from "path";
|
|
10847
11407
|
|
|
10848
11408
|
// src/module-schema/config.ts
|
|
10849
11409
|
import { readFile as readFile24 } from "fs/promises";
|
|
10850
|
-
import { isAbsolute as isAbsolute2, relative as
|
|
11410
|
+
import { isAbsolute as isAbsolute2, relative as relative6, resolve as resolve9 } from "path";
|
|
10851
11411
|
async function readModuleSchemaLineageConfig(projectDirectory, configPath) {
|
|
10852
11412
|
const absolutePath = resolveProjectPath(projectDirectory, configPath);
|
|
10853
11413
|
const parsed = JSON.parse(await readFile24(absolutePath, "utf8"));
|
|
@@ -10865,7 +11425,7 @@ function resolveProjectPath(projectDirectory, path2) {
|
|
|
10865
11425
|
if (isAbsolute2(path2))
|
|
10866
11426
|
throw new Error(`\u8DEF\u5F84\u5FC5\u987B\u76F8\u5BF9\u9879\u76EE\u6839\u76EE\u5F55\uFF1A${path2}`);
|
|
10867
11427
|
const resolved = resolve9(projectDirectory, path2);
|
|
10868
|
-
const projectRelative =
|
|
11428
|
+
const projectRelative = relative6(projectDirectory, resolved);
|
|
10869
11429
|
if (projectRelative.startsWith("..") || isAbsolute2(projectRelative)) {
|
|
10870
11430
|
throw new Error(`\u8DEF\u5F84\u8D8A\u51FA\u9879\u76EE\u6839\u76EE\u5F55\uFF1A${path2}`);
|
|
10871
11431
|
}
|
|
@@ -10984,17 +11544,17 @@ async function handoffModuleSchemaLineages(options) {
|
|
|
10984
11544
|
async function stageModuleLineages(project, temporaryRoot, config, execute) {
|
|
10985
11545
|
const outputs = [];
|
|
10986
11546
|
for (const [index, module2] of config.modules.entries()) {
|
|
10987
|
-
const output =
|
|
11547
|
+
const output = join29(temporaryRoot, `module-${index}`);
|
|
10988
11548
|
await mkdir9(output, { recursive: true });
|
|
10989
|
-
const generatedConfig =
|
|
10990
|
-
await writeDrizzleConfig(generatedConfig, project, module2.schema,
|
|
11549
|
+
const generatedConfig = join29(temporaryRoot, `module-${index}.config.ts`);
|
|
11550
|
+
await writeDrizzleConfig(generatedConfig, project, module2.schema, relative7(temporaryRoot, output));
|
|
10991
11551
|
await execute(generatedConfig, temporaryRoot);
|
|
10992
11552
|
const sqlFiles = await listSqlFiles(output);
|
|
10993
11553
|
if (sqlFiles.length !== 1) {
|
|
10994
11554
|
throw new Error(`${module2.key} baseline \u5FC5\u987B\u6070\u597D\u751F\u6210\u4E00\u4E2A migration`);
|
|
10995
11555
|
}
|
|
10996
|
-
await writeFile14(
|
|
10997
|
-
await writeFile14(
|
|
11556
|
+
await writeFile14(join29(output, sqlFiles[0]), metadataOnlySql("module"));
|
|
11557
|
+
await writeFile14(join29(output, "lineage.json"), `${JSON.stringify({
|
|
10998
11558
|
schemaVersion: 1,
|
|
10999
11559
|
moduleKey: module2.key,
|
|
11000
11560
|
schema: module2.schema,
|
|
@@ -11008,17 +11568,17 @@ async function stageModuleLineages(project, temporaryRoot, config, execute) {
|
|
|
11008
11568
|
}
|
|
11009
11569
|
async function stagePlatformLineage(project, temporaryRoot, config, execute) {
|
|
11010
11570
|
const source = resolveProjectPath(project, config.platform.out);
|
|
11011
|
-
const output =
|
|
11571
|
+
const output = join29(temporaryRoot, "platform");
|
|
11012
11572
|
await cp(source, output, { recursive: true });
|
|
11013
11573
|
const before = new Set(await listSqlFiles(output));
|
|
11014
|
-
const generatedConfig =
|
|
11015
|
-
await writeDrizzleConfig(generatedConfig, project, config.platform.schema,
|
|
11574
|
+
const generatedConfig = join29(temporaryRoot, "platform.config.ts");
|
|
11575
|
+
await writeDrizzleConfig(generatedConfig, project, config.platform.schema, relative7(temporaryRoot, output));
|
|
11016
11576
|
await execute(generatedConfig, temporaryRoot);
|
|
11017
11577
|
const created = (await listSqlFiles(output)).filter((path2) => !before.has(path2));
|
|
11018
11578
|
if (created.length !== 1) {
|
|
11019
11579
|
throw new Error("\u5E73\u53F0 lineage handoff \u5FC5\u987B\u6070\u597D\u751F\u6210\u4E00\u4E2A migration");
|
|
11020
11580
|
}
|
|
11021
|
-
const sqlPath =
|
|
11581
|
+
const sqlPath = join29(output, created[0]);
|
|
11022
11582
|
const allowed = config.modules.flatMap(({ legacyPlatformTables }) => legacyPlatformTables);
|
|
11023
11583
|
validatePlatformHandoffSql(await readFile25(sqlPath, "utf8"), allowed);
|
|
11024
11584
|
await writeFile14(sqlPath, metadataOnlySql("platform"));
|
|
@@ -11026,7 +11586,7 @@ async function stagePlatformLineage(project, temporaryRoot, config, execute) {
|
|
|
11026
11586
|
}
|
|
11027
11587
|
async function installStagedLineages(project, temporaryRoot, config, stagedModules, stagedPlatform) {
|
|
11028
11588
|
const platform = resolveProjectPath(project, config.platform.out);
|
|
11029
|
-
const backup =
|
|
11589
|
+
const backup = join29(temporaryRoot, "platform-backup");
|
|
11030
11590
|
const installed = [];
|
|
11031
11591
|
await rename2(platform, backup);
|
|
11032
11592
|
try {
|
|
@@ -11036,7 +11596,7 @@ async function installStagedLineages(project, temporaryRoot, config, stagedModul
|
|
|
11036
11596
|
if (await exists(output)) {
|
|
11037
11597
|
throw new Error(`${module2.key} lineage \u8F93\u51FA\u5DF2\u5B58\u5728\uFF0C\u7981\u6B62\u8986\u76D6`);
|
|
11038
11598
|
}
|
|
11039
|
-
await mkdir9(
|
|
11599
|
+
await mkdir9(dirname11(output), { recursive: true });
|
|
11040
11600
|
await rename2(stagedModules[index], output);
|
|
11041
11601
|
installed.push(output);
|
|
11042
11602
|
}
|
|
@@ -11073,9 +11633,9 @@ async function validateSchemaSources(project, config) {
|
|
|
11073
11633
|
}
|
|
11074
11634
|
}
|
|
11075
11635
|
async function createTemporaryRoot(project) {
|
|
11076
|
-
const windy =
|
|
11636
|
+
const windy = join29(project, ".windy");
|
|
11077
11637
|
await mkdir9(windy, { recursive: true });
|
|
11078
|
-
return await mkdtemp4(
|
|
11638
|
+
return await mkdtemp4(join29(windy, "module-schema-handoff-"));
|
|
11079
11639
|
}
|
|
11080
11640
|
async function listSqlFiles(root) {
|
|
11081
11641
|
return (await readdir9(root)).filter((path2) => path2.endsWith(".sql")).sort();
|