mirror of
https://github.com/earendil-works/pi.git
synced 2026-10-02 00:35:27 +08:00
feat: build with TypeScript 7 and run sources with plain node
Replace the tsgo native preview with typescript@7.0.2 and port the check scripts to the TS 7 API. Target ES2024, drop useDefineForClassFields: false and unused decorator options, and enable verbatimModuleSyntax. Replace tsx with node plus the source resolver hook, passed to --import as a file URL. closes #9965
This commit is contained in:
+4
-2
@@ -23,7 +23,7 @@ for arg in "$@"; do
|
||||
cat <<'USAGE'
|
||||
Usage: ./mini-test.sh [--dist] [--fresh] [--stop] [mini args...]
|
||||
|
||||
--dist run built output with plain node instead of tsx on sources
|
||||
--dist run built output instead of sources
|
||||
--fresh stop the detached session server first, so it picks up your changes
|
||||
--stop stop the detached session server and exit
|
||||
|
||||
@@ -43,4 +43,6 @@ if [[ "$USE_DIST" == "true" ]]; then
|
||||
exec node "$MINI_DIST" ${ARGS[@]+"${ARGS[@]}"}
|
||||
fi
|
||||
|
||||
exec "$SCRIPT_DIR/node_modules/.bin/tsx" --tsconfig "$SCRIPT_DIR/tsconfig.json" "$MINI_SRC" ${ARGS[@]+"${ARGS[@]}"}
|
||||
# --import takes a module specifier, so pass the resolver as a file URL (raw paths break on #, ?, %).
|
||||
RESOLVER_URL="$(node -p 'require("node:url").pathToFileURL(process.argv[1]).href' "$SCRIPT_DIR/packages/coding-agent/src/experimental/source-resolver.ts")"
|
||||
exec node --import "$RESOLVER_URL" "$MINI_SRC" ${ARGS[@]+"${ARGS[@]}"}
|
||||
|
||||
Generated
+301
-81
@@ -20,12 +20,10 @@
|
||||
"@anthropic-ai/sandbox-runtime": "0.0.26",
|
||||
"@biomejs/biome": "2.3.5",
|
||||
"@types/node": "22.19.19",
|
||||
"@typescript/native-preview": "7.0.0-dev.20260120.1",
|
||||
"esbuild": "0.28.2",
|
||||
"husky": "9.1.7",
|
||||
"shx": "0.4.0",
|
||||
"tsx": "4.22.1",
|
||||
"typescript": "5.9.3"
|
||||
"typescript": "7.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.19.0"
|
||||
@@ -1835,29 +1833,27 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript/native-preview": {
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-nnEf37C9ue7OBRnF2zmV/OCBmV5Y7T/K4mCHa+nxgiXcF/1w8sA0cgdFl+gHQ0mysqUJ+Bu5btAMeWgpLyjrgg==",
|
||||
"node_modules/@typescript/typescript-aix-ppc64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz",
|
||||
"integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsgo": "bin/tsgo.js"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260120.1",
|
||||
"@typescript/native-preview-darwin-x64": "7.0.0-dev.20260120.1",
|
||||
"@typescript/native-preview-linux-arm": "7.0.0-dev.20260120.1",
|
||||
"@typescript/native-preview-linux-arm64": "7.0.0-dev.20260120.1",
|
||||
"@typescript/native-preview-linux-x64": "7.0.0-dev.20260120.1",
|
||||
"@typescript/native-preview-win32-arm64": "7.0.0-dev.20260120.1",
|
||||
"@typescript/native-preview-win32-x64": "7.0.0-dev.20260120.1"
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-darwin-arm64": {
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-r3pWFuR2H7mn6ScwpH5jJljKQqKto0npVuJSk6pRwFwexpTyxOGmJTZJ1V0AWiisaNxU2+CNAqWFJSJYIE/QTg==",
|
||||
"node_modules/@typescript/typescript-darwin-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1866,12 +1862,15 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-darwin-x64": {
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-cuC1+wLbUP+Ip2UT94G134fqRdp5w3b3dhcCO6/FQ4yXxvRNyv/WK+upHBUFDaeSOeHgDTyO9/QFYUWwC4If1A==",
|
||||
"node_modules/@typescript/typescript-darwin-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1880,12 +1879,49 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-linux-arm": {
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-vN6OYVySol/kQZjJGmAzd6L30SyVlCgmCXS8WjUYtE5clN0YrzQHop16RK29fYZHMxpkOniVBtRPxUYQANZBlQ==",
|
||||
"node_modules/@typescript/typescript-freebsd-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-freebsd-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-arm": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz",
|
||||
"integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1894,12 +1930,15 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-linux-arm64": {
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-zZGvEGY7wcHYefMZ87KNmvjN3NLIhsCMHEpHZiGCS3khKf+8z6ZsanrzCjOTodvL01VPyBzHxV1EtkSxAcLiQg==",
|
||||
"node_modules/@typescript/typescript-linux-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1908,12 +1947,100 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-linux-x64": {
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-JBfNhWd/asd5MDeS3VgRvE24pGKBkmvLub6tsux6ypr+Yhy+o0WaAEzVpmlRYZUqss2ai5tvOu4dzPBXzZAtFw==",
|
||||
"node_modules/@typescript/typescript-linux-loong64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz",
|
||||
"integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-mips64el": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz",
|
||||
"integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-ppc64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz",
|
||||
"integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-riscv64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz",
|
||||
"integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-s390x": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz",
|
||||
"integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-linux-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1922,12 +2049,100 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-win32-arm64": {
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-tTndRtYCq2xwgE0VkTi9ACNiJaV43+PqvBqCxk8ceYi3X36Ve+CCnwlZfZJ4k9NxZthtrAwF/kUmpC9iIYbq1w==",
|
||||
"node_modules/@typescript/typescript-netbsd-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-netbsd-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-openbsd-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-openbsd-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-sunos-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/typescript-win32-arm64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz",
|
||||
"integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1936,12 +2151,15 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview-win32-x64": {
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20260120.1.tgz",
|
||||
"integrity": "sha512-oZia7hFL6k9pVepfonuPI86Jmyz6WlJKR57tWCDwRNmpA7odxuTq1PbvcYgy1z4+wHF1nnKKJY0PMAiq6ac18w==",
|
||||
"node_modules/@typescript/typescript-win32-x64": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz",
|
||||
"integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1950,7 +2168,10 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest-evals/core": {
|
||||
"version": "0.15.0",
|
||||
@@ -4860,25 +5081,6 @@
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/tsx": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.1.tgz",
|
||||
"integrity": "sha512-TvncJykhxAzFCk0VQZKBTClall4Pm7qXDSodb6uxi8QFa8X8mT6ABjxxsQ2opDRYxG7AzcRWXaFtruz5HJKuWg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "~0.28.0"
|
||||
},
|
||||
"bin": {
|
||||
"tsx": "dist/cli.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.3"
|
||||
}
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
@@ -4905,17 +5107,38 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz",
|
||||
"integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
"tsc": "bin/tsc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
"node": ">=16.20.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@typescript/typescript-aix-ppc64": "7.0.2",
|
||||
"@typescript/typescript-darwin-arm64": "7.0.2",
|
||||
"@typescript/typescript-darwin-x64": "7.0.2",
|
||||
"@typescript/typescript-freebsd-arm64": "7.0.2",
|
||||
"@typescript/typescript-freebsd-x64": "7.0.2",
|
||||
"@typescript/typescript-linux-arm": "7.0.2",
|
||||
"@typescript/typescript-linux-arm64": "7.0.2",
|
||||
"@typescript/typescript-linux-loong64": "7.0.2",
|
||||
"@typescript/typescript-linux-mips64el": "7.0.2",
|
||||
"@typescript/typescript-linux-ppc64": "7.0.2",
|
||||
"@typescript/typescript-linux-riscv64": "7.0.2",
|
||||
"@typescript/typescript-linux-s390x": "7.0.2",
|
||||
"@typescript/typescript-linux-x64": "7.0.2",
|
||||
"@typescript/typescript-netbsd-arm64": "7.0.2",
|
||||
"@typescript/typescript-netbsd-x64": "7.0.2",
|
||||
"@typescript/typescript-openbsd-arm64": "7.0.2",
|
||||
"@typescript/typescript-openbsd-x64": "7.0.2",
|
||||
"@typescript/typescript-sunos-x64": "7.0.2",
|
||||
"@typescript/typescript-win32-arm64": "7.0.2",
|
||||
"@typescript/typescript-win32-x64": "7.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
@@ -5294,7 +5517,6 @@
|
||||
"devDependencies": {
|
||||
"@types/node": "22.19.19",
|
||||
"@vitest/coverage-v8": "4.1.9",
|
||||
"typescript": "5.9.3",
|
||||
"vitest": "4.1.9"
|
||||
},
|
||||
"engines": {
|
||||
@@ -5429,7 +5651,6 @@
|
||||
"@types/semver": "7.7.1",
|
||||
"marked": "18.0.11",
|
||||
"shx": "0.4.0",
|
||||
"typescript": "5.9.3",
|
||||
"vitest": "4.1.9"
|
||||
},
|
||||
"engines": {
|
||||
@@ -5541,7 +5762,6 @@
|
||||
"@vitest-evals/core": "0.15.0",
|
||||
"autoevals": "0.3.0",
|
||||
"shx": "0.4.0",
|
||||
"typescript": "5.9.3",
|
||||
"vitest": "4.1.9",
|
||||
"vitest-evals": "0.15.0"
|
||||
}
|
||||
|
||||
+2
-4
@@ -18,7 +18,7 @@
|
||||
"build:native:darwin": "npm --prefix packages/tui run build:native:darwin",
|
||||
"build:native:linux": "npm --prefix packages/tui run build:native:linux",
|
||||
"build:native:win32": "npm --prefix packages/tui run build:native:win32",
|
||||
"check": "biome check --write --error-on-warnings . && npm run check:pinned-deps && npm run check:runtime-deps && npm run check:ts-imports && npm run check:entry-graphs && npm run check:shrinkwrap && npm run check:install-lock:coding-agent && tsgo --noEmit && npm run check:browser-smoke",
|
||||
"check": "biome check --write --error-on-warnings . && npm run check:pinned-deps && npm run check:runtime-deps && npm run check:ts-imports && npm run check:entry-graphs && npm run check:shrinkwrap && npm run check:install-lock:coding-agent && tsc --noEmit && npm run check:browser-smoke",
|
||||
"check:browser-smoke": "node scripts/check-browser-smoke.mjs",
|
||||
"check:pinned-deps": "node scripts/check-pinned-deps.mjs",
|
||||
"check:runtime-deps": "node scripts/check-runtime-deps.mjs",
|
||||
@@ -58,12 +58,10 @@
|
||||
"@anthropic-ai/sandbox-runtime": "0.0.26",
|
||||
"@biomejs/biome": "2.3.5",
|
||||
"@types/node": "22.19.19",
|
||||
"@typescript/native-preview": "7.0.0-dev.20260120.1",
|
||||
"esbuild": "0.28.2",
|
||||
"husky": "9.1.7",
|
||||
"shx": "0.4.0",
|
||||
"tsx": "4.22.1",
|
||||
"typescript": "5.9.3"
|
||||
"typescript": "7.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.19.0"
|
||||
|
||||
@@ -20,15 +20,16 @@ interface AllocationProfileResult {
|
||||
const execFileAsync = promisify(execFile);
|
||||
const packageRoot = fileURLToPath(new URL("../..", import.meta.url));
|
||||
const workerPath = fileURLToPath(new URL("./allocation-profile-worker.ts", import.meta.url));
|
||||
const tsconfigPath = fileURLToPath(new URL("../tsconfig.json", import.meta.url));
|
||||
// Resolve workspace packages to their sources, matching the root tsconfig paths.
|
||||
const sourceResolverUrl = new URL("../../../coding-agent/src/experimental/source-resolver.ts", import.meta.url).href;
|
||||
const results: AllocationProfileResult[] = [];
|
||||
|
||||
for (const target of storageBenchmarkTargets) {
|
||||
for (const dataset of STORAGE_BENCHMARK_DATASETS) {
|
||||
const { stdout } = await execFileAsync(
|
||||
process.execPath,
|
||||
["--import", "tsx", workerPath, target.name, dataset.name],
|
||||
{ cwd: packageRoot, env: { ...process.env, TSX_TSCONFIG_PATH: tsconfigPath } },
|
||||
["--import", sourceResolverUrl, workerPath, target.name, dataset.name],
|
||||
{ cwd: packageRoot },
|
||||
);
|
||||
results.push(JSON.parse(stdout) as AllocationProfileResult);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ interface LoadedFootprintResult {
|
||||
const execFileAsync = promisify(execFile);
|
||||
const packageRoot = fileURLToPath(new URL("../..", import.meta.url));
|
||||
const workerPath = fileURLToPath(new URL("./loaded-footprint-worker.ts", import.meta.url));
|
||||
const tsconfigPath = fileURLToPath(new URL("../tsconfig.json", import.meta.url));
|
||||
// Resolve workspace packages to their sources, matching the root tsconfig paths.
|
||||
const sourceResolverUrl = new URL("../../../coding-agent/src/experimental/source-resolver.ts", import.meta.url).href;
|
||||
const results: LoadedFootprintResult[] = [];
|
||||
|
||||
for (const target of storageBenchmarkTargets) {
|
||||
@@ -26,12 +27,12 @@ for (const target of storageBenchmarkTargets) {
|
||||
[
|
||||
"--expose-gc",
|
||||
"--import",
|
||||
"tsx",
|
||||
sourceResolverUrl,
|
||||
workerPath,
|
||||
target.name,
|
||||
dataset.name,
|
||||
],
|
||||
{ cwd: packageRoot, env: { ...process.env, TSX_TSCONFIG_PATH: tsconfigPath } },
|
||||
{ cwd: packageRoot },
|
||||
);
|
||||
results.push(JSON.parse(stdout) as LoadedFootprintResult);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "../../..",
|
||||
"noEmit": true,
|
||||
"paths": {
|
||||
"@earendil-works/pi-ai": ["packages/ai/src/index.ts"],
|
||||
"@earendil-works/pi-ai/*": ["packages/ai/src/*"]
|
||||
"@earendil-works/pi-ai": ["../../ai/src/index.ts"],
|
||||
"@earendil-works/pi-ai/*": ["../../ai/src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["./**/*.ts", "../src/**/*.ts"]
|
||||
|
||||
@@ -48,10 +48,10 @@
|
||||
"clean": "shx rm -rf dist",
|
||||
"generate-telemetry-docs": "node scripts/generate-telemetry-docs.ts",
|
||||
"check:telemetry-docs": "node scripts/generate-telemetry-docs.ts --check",
|
||||
"build": "tsgo -p tsconfig.build.json",
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"bench:session:timing": "vitest bench --config vitest.benchmark.config.ts",
|
||||
"bench:session:memory": "tsx --tsconfig benchmark/tsconfig.json benchmark/session/loaded-footprint.ts",
|
||||
"bench:session:allocations": "tsx --tsconfig benchmark/tsconfig.json benchmark/session/allocation-profile.ts",
|
||||
"bench:session:memory": "node --import ../coding-agent/src/experimental/source-resolver.ts benchmark/session/loaded-footprint.ts",
|
||||
"bench:session:allocations": "node --import ../coding-agent/src/experimental/source-resolver.ts benchmark/session/allocation-profile.ts",
|
||||
"test": "vitest --run",
|
||||
"test:harness": "vitest --run --config vitest.harness.config.ts",
|
||||
"test:session:conformance": "vitest --run --config vitest.harness.config.ts test/harness/memory-conformance.test.ts",
|
||||
@@ -87,7 +87,6 @@
|
||||
"devDependencies": {
|
||||
"@types/node": "22.19.19",
|
||||
"@vitest/coverage-v8": "4.1.9",
|
||||
"typescript": "5.9.3",
|
||||
"vitest": "4.1.9"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
"generate-model-catalog": "node scripts/generate-models.ts --strict --json-only --json-output ../../.artifacts/model-catalog",
|
||||
"check:model-data": "node scripts/check-model-data.ts",
|
||||
"build": "npm run generate-models && npm run build:offline",
|
||||
"build:offline": "npm run check:model-data && tsgo -p tsconfig.build.json && shx rm -rf dist/providers/data && shx cp -r src/providers/data dist/providers/data",
|
||||
"build:offline": "npm run check:model-data && tsc -p tsconfig.build.json && shx rm -rf dist/providers/data && shx cp -r src/providers/data dist/providers/data",
|
||||
"test": "vitest --run",
|
||||
"prepublishOnly": "npm run clean && npm run build"
|
||||
},
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"build": "tsgo -p tsconfig.build.json",
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"test": "vitest --run",
|
||||
"prepublishOnly": "npm run clean && npm run build"
|
||||
},
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"build": "tsgo -p tsconfig.build.json",
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"test": "vitest --run",
|
||||
"typecheck": "tsgo -p tsconfig.test.json",
|
||||
"typecheck": "tsc -p tsconfig.test.json",
|
||||
"prepublishOnly": "npm run clean && npm run build"
|
||||
},
|
||||
"keywords": [
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
- Added the `provider_stream_event` extension event for observing parsed provider events before normalization, with an opt-in `/debug-provider` example viewer ([#9784](https://github.com/earendil-works/pi/issues/9784)).
|
||||
- Added a show/hide toggle (`H`) in HTML exports for custom messages marked `display: false`. Messages remain hidden by default and can also be revealed from the sidebar ([#8896](https://github.com/earendil-works/pi/issues/8896)).
|
||||
|
||||
### Changed
|
||||
|
||||
- Switched the build from the TypeScript native preview to TypeScript 7.0 with an ES2024 target, and replaced `tsx` with Node's built-in type stripping for running from source ([#9965](https://github.com/earendil-works/pi/issues/9965)).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed X11 clipboard text being misidentified as an image when the clipboard owner accepts unadvertised image targets ([#9786](https://github.com/earendil-works/pi/issues/9786)).
|
||||
|
||||
@@ -9,7 +9,7 @@ Example code for the pi-coding-agent SDK, process integration, and extensions.
|
||||
Build the coding-agent package before running it from a repository checkout:
|
||||
|
||||
```bash
|
||||
npx tsx examples/rpc-client.ts "Explain this repository"
|
||||
node examples/rpc-client.ts "Explain this repository"
|
||||
```
|
||||
|
||||
## Directories
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
/**
|
||||
* Test script for GitLab Duo extension
|
||||
* Run: npx tsx test.ts [model-id] [--thinking]
|
||||
* Run: node test.ts [model-id] [--thinking]
|
||||
*
|
||||
* Examples:
|
||||
* npx tsx test.ts # Test default (claude-sonnet-4-5-20250929)
|
||||
* npx tsx test.ts gpt-5-codex # Test GPT-5 Codex
|
||||
* npx tsx test.ts claude-sonnet-4-5-20250929 --thinking
|
||||
* node test.ts # Test default (claude-sonnet-4-5-20250929)
|
||||
* node test.ts gpt-5-codex # Test GPT-5 Codex
|
||||
* node test.ts claude-sonnet-4-5-20250929 --thinking
|
||||
*/
|
||||
|
||||
import { type Api, type Context, type Model, registerApiProvider, streamSimple } from "@earendil-works/pi-ai/compat";
|
||||
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
||||
import { readFileSync } from "fs";
|
||||
import { getAgentDir } from "packages/coding-agent/src/config.js";
|
||||
import { join } from "path";
|
||||
import { MODELS, streamGitLabDuo } from "./index.ts";
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Run one prompt through a Pi RPC child process.
|
||||
*
|
||||
* Build the coding-agent package first, then run:
|
||||
* npx tsx examples/rpc-client.ts "Explain this repository"
|
||||
* node examples/rpc-client.ts "Explain this repository"
|
||||
*/
|
||||
|
||||
import { dirname, join } from "node:path";
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Demonstrates how to build a custom UI on top of the RPC protocol,
|
||||
* including handling extension UI requests (select, confirm, input, editor).
|
||||
*
|
||||
* Usage: npx tsx examples/rpc-extension-ui.ts
|
||||
* Usage: node examples/rpc-extension-ui.ts
|
||||
*
|
||||
* Slash commands:
|
||||
* /select - demo select dialog
|
||||
|
||||
@@ -26,7 +26,7 @@ The runtime example shows how to build a recreate function that closes over proc
|
||||
|
||||
```bash
|
||||
cd packages/coding-agent
|
||||
npx tsx examples/sdk/01-minimal.ts
|
||||
node examples/sdk/01-minimal.ts
|
||||
```
|
||||
|
||||
## Quick Reference
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"build": "npm run build:unbundled && node ../../scripts/build-coding-agent-bundle.mjs",
|
||||
"build:unbundled": "tsgo -p tsconfig.build.json && shx chmod +x dist/cli.js dist/rpc-entry.js && npm run copy-assets",
|
||||
"build:unbundled": "tsc -p tsconfig.build.json && shx chmod +x dist/cli.js dist/rpc-entry.js && npm run copy-assets",
|
||||
"build:binary": "npm --prefix ../tui run build && npm --prefix ../telemetry run build && npm --prefix ../ai run build && npm --prefix ../agent run build && npm --prefix ../protocol run build && npm --prefix ../client run build && npm run build && bun build --compile --no-compile-autoload-bunfig ./src/bun/cli.ts ./src/utils/image-resize-worker.ts --outfile dist/pi && npm run copy-binary-assets",
|
||||
"copy-assets": "shx mkdir -p dist/modes/interactive/theme && shx cp src/modes/interactive/theme/*.json dist/modes/interactive/theme/ && shx mkdir -p dist/modes/interactive/assets && shx cp src/modes/interactive/assets/*.png dist/modes/interactive/assets/ && shx mkdir -p dist/core/export-html/vendor && shx cp src/core/export-html/template.html src/core/export-html/template.css src/core/export-html/template.js dist/core/export-html/ && shx cp src/core/export-html/vendor/*.js dist/core/export-html/vendor/",
|
||||
"copy-binary-assets": "shx cp package.json dist/ && shx cp README.md dist/ && shx cp CHANGELOG.md dist/ && shx mkdir -p dist/theme && shx cp src/modes/interactive/theme/*.json dist/theme/ && shx mkdir -p dist/assets && shx cp src/modes/interactive/assets/*.png dist/assets/ && shx mkdir -p dist/export-html/vendor && shx cp src/core/export-html/template.html dist/export-html/ && shx cp src/core/export-html/vendor/*.js dist/export-html/vendor/ && shx cp -r docs dist/ && shx cp -r examples dist/ && shx cp ../../node_modules/@silvia-odwyer/photon-node/photon_rs_bg.wasm dist/",
|
||||
@@ -83,7 +83,6 @@
|
||||
"@types/semver": "7.7.1",
|
||||
"marked": "18.0.11",
|
||||
"shx": "0.4.0",
|
||||
"typescript": "5.9.3",
|
||||
"vitest": "4.1.9"
|
||||
},
|
||||
"keywords": [
|
||||
|
||||
@@ -366,7 +366,7 @@ export function getUpdateInstruction(packageName: string): string {
|
||||
/**
|
||||
* Get the base directory for resolving package assets (themes, package.json, README.md, CHANGELOG.md).
|
||||
* - For Bun binary: returns the directory containing the executable
|
||||
* - For Node.js and tsx: returns the package root containing package.json
|
||||
* - For Node.js: returns the package root containing package.json
|
||||
* - Ignores Bun binary metadata copied into dist/ when the package root is available
|
||||
*/
|
||||
export function findNodePackageDir(startDir: string): string {
|
||||
@@ -404,7 +404,7 @@ export function getPackageDir(): string {
|
||||
* Get path to built-in themes directory (shipped with package)
|
||||
* - For Bun binary: theme/ next to executable
|
||||
* - For Node.js (dist/): dist/modes/interactive/theme/
|
||||
* - For tsx (src/): src/modes/interactive/theme/
|
||||
* - For source (src/): src/modes/interactive/theme/
|
||||
*/
|
||||
export function getThemesDir(): string {
|
||||
if (isBunBinary) {
|
||||
@@ -420,7 +420,7 @@ export function getThemesDir(): string {
|
||||
* Get path to HTML export template directory (shipped with package)
|
||||
* - For Bun binary: export-html/ next to executable
|
||||
* - For Node.js (dist/): dist/core/export-html/
|
||||
* - For tsx (src/): src/core/export-html/
|
||||
* - For source (src/): src/core/export-html/
|
||||
*/
|
||||
export function getExportTemplateDir(): string {
|
||||
if (isBunBinary) {
|
||||
@@ -460,7 +460,7 @@ export function getChangelogPath(): string {
|
||||
* Get path to built-in interactive assets directory.
|
||||
* - For Bun binary: assets/ next to executable
|
||||
* - For Node.js (dist/): dist/modes/interactive/assets/
|
||||
* - For tsx (src/): src/modes/interactive/assets/
|
||||
* - For source (src/): src/modes/interactive/assets/
|
||||
*/
|
||||
export function getInteractiveAssetsDir(): string {
|
||||
if (isBunBinary) {
|
||||
|
||||
@@ -10,8 +10,8 @@ storage. Command failures and Pico events are folded into the view, so rendering
|
||||
result side channel.
|
||||
|
||||
```bash
|
||||
./node_modules/.bin/tsx --tsconfig tsconfig.json packages/coding-agent/src/experimental/micro/main.ts
|
||||
./node_modules/.bin/tsx --tsconfig tsconfig.json packages/coding-agent/src/experimental/micro/main.ts --continue
|
||||
node --import ./packages/coding-agent/src/experimental/source-resolver.ts packages/coding-agent/src/experimental/micro/main.ts
|
||||
node --import ./packages/coding-agent/src/experimental/source-resolver.ts packages/coding-agent/src/experimental/micro/main.ts --continue
|
||||
```
|
||||
|
||||
New sessions default to `openai-codex/gpt-5.6-sol`. `--continue` keeps the session's stored model and
|
||||
|
||||
@@ -8,7 +8,7 @@ an RPC-shaped presentation actually needs from it.
|
||||
node packages/coding-agent/src/experimental/mini/main.ts [--continue]
|
||||
|
||||
# while the harness is changing under us, run from source instead of built dist:
|
||||
./node_modules/.bin/tsx --tsconfig tsconfig.json packages/coding-agent/src/experimental/mini/main.ts
|
||||
node --import ./packages/coding-agent/src/experimental/source-resolver.ts packages/coding-agent/src/experimental/mini/main.ts
|
||||
```
|
||||
|
||||
`--continue` attaches to the newest session for the current directory. Starting `mini` twice attaches
|
||||
|
||||
@@ -47,8 +47,9 @@ export function spawnInternalProcess(
|
||||
throw new Error("A compiled Bun executable cannot launch an external internal-process entrypoint");
|
||||
}
|
||||
const entryUrl = defaultEntryUrl(role, options.entryUrl);
|
||||
// --import takes a module specifier; a raw path breaks on Windows drives and on `#`, `?`, or `%` in the path.
|
||||
const sourceRuntimeArgs = import.meta.url.endsWith(".ts")
|
||||
? ["--import", fileURLToPath(new URL("source-resolver.ts", import.meta.url))]
|
||||
? ["--import", new URL("source-resolver.ts", import.meta.url).href]
|
||||
: [];
|
||||
const child = spawn(
|
||||
process.execPath,
|
||||
|
||||
@@ -740,12 +740,12 @@ export function getDefaultTheme(): string {
|
||||
// Global Theme Instance
|
||||
// ============================================================================
|
||||
|
||||
// Use globalThis to share theme across module loaders (tsx + jiti in dev mode)
|
||||
// Use globalThis to share theme across module loaders (node + jiti in dev mode)
|
||||
const THEME_KEY = Symbol.for("@earendil-works/pi-coding-agent:theme");
|
||||
const THEME_KEY_OLD = Symbol.for("@mariozechner/pi-coding-agent:theme");
|
||||
|
||||
// Export theme as a getter that reads from globalThis
|
||||
// This ensures all module instances (tsx, jiti) see the same theme
|
||||
// This ensures all module instances (node, jiti) see the same theme
|
||||
export const theme: Theme = new Proxy({} as Theme, {
|
||||
get(_target, prop) {
|
||||
const t = (globalThis as Record<symbol, Theme>)[THEME_KEY];
|
||||
|
||||
@@ -2,10 +2,12 @@ import { spawnSync } from "node:child_process";
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, resolve } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { VERSION } from "../src/config.ts";
|
||||
|
||||
const sourceResolverPath = resolve(__dirname, "../src/experimental/source-resolver.ts");
|
||||
// --import takes a module specifier, not a filesystem path.
|
||||
const sourceResolverUrl = pathToFileURL(resolve(__dirname, "../src/experimental/source-resolver.ts")).href;
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
afterEach(() => {
|
||||
@@ -19,7 +21,7 @@ function runEntry(entry: string, experimental: boolean) {
|
||||
process.execPath,
|
||||
[
|
||||
"--import",
|
||||
sourceResolverPath,
|
||||
sourceResolverUrl,
|
||||
resolve(__dirname, "../src", entry),
|
||||
"server",
|
||||
"--server-id",
|
||||
|
||||
@@ -7,7 +7,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
/**
|
||||
* Interactive example of using coding-agent via RpcClient.
|
||||
* Usage: npx tsx test/rpc-example.ts
|
||||
* Usage: node test/rpc-example.ts
|
||||
*/
|
||||
|
||||
async function main() {
|
||||
|
||||
@@ -2,11 +2,13 @@ import { spawn } from "node:child_process";
|
||||
import { mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, resolve } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { ENV_AGENT_DIR } from "../src/config.ts";
|
||||
|
||||
const cliPath = resolve(__dirname, "../src/cli.ts");
|
||||
const sourceResolverPath = resolve(__dirname, "../src/experimental/source-resolver.ts");
|
||||
// --import takes a module specifier, not a filesystem path.
|
||||
const sourceResolverUrl = pathToFileURL(resolve(__dirname, "../src/experimental/source-resolver.ts")).href;
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
afterEach(() => {
|
||||
@@ -24,7 +26,7 @@ function createTempDir(): string {
|
||||
async function runCli(args: string[], cwd: string, agentDir: string): Promise<{ code: number | null; stderr: string }> {
|
||||
let stderr = "";
|
||||
const code = await new Promise<number | null>((resolvePromise, reject) => {
|
||||
const child = spawn(process.execPath, ["--import", sourceResolverPath, cliPath, ...args], {
|
||||
const child = spawn(process.execPath, ["--import", sourceResolverUrl, cliPath, ...args], {
|
||||
cwd,
|
||||
env: {
|
||||
...process.env,
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, resolve } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import type { Args } from "../src/cli/args.ts";
|
||||
import { ENV_AGENT_DIR } from "../src/config.ts";
|
||||
@@ -19,7 +20,8 @@ import { SettingsManager } from "../src/core/settings-manager.ts";
|
||||
import { createSessionManager } from "../src/main.ts";
|
||||
|
||||
const cliPath = resolve(__dirname, "../src/cli.ts");
|
||||
const sourceResolverPath = resolve(__dirname, "../src/experimental/source-resolver.ts");
|
||||
// --import takes a module specifier, not a filesystem path.
|
||||
const sourceResolverUrl = pathToFileURL(resolve(__dirname, "../src/experimental/source-resolver.ts")).href;
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
afterEach(() => {
|
||||
@@ -64,7 +66,7 @@ async function runCli(args: string[]): Promise<{ code: number | null; agentDir:
|
||||
mkdirSync(projectDir, { recursive: true });
|
||||
|
||||
const code = await new Promise<number | null>((resolvePromise, reject) => {
|
||||
const child = spawn(process.execPath, ["--import", sourceResolverPath, cliPath, ...args], {
|
||||
const child = spawn(process.execPath, ["--import", sourceResolverUrl, cliPath, ...args], {
|
||||
cwd: projectDir,
|
||||
env: {
|
||||
...process.env,
|
||||
|
||||
@@ -2,11 +2,13 @@ import { spawn } from "node:child_process";
|
||||
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, resolve } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { ENV_AGENT_DIR } from "../src/config.ts";
|
||||
|
||||
const cliPath = resolve(__dirname, "../src/cli.ts");
|
||||
const sourceResolverPath = resolve(__dirname, "../src/experimental/source-resolver.ts");
|
||||
// --import takes a module specifier, not a filesystem path.
|
||||
const sourceResolverUrl = pathToFileURL(resolve(__dirname, "../src/experimental/source-resolver.ts")).href;
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
afterEach(() => {
|
||||
@@ -66,7 +68,7 @@ function readSessionInfoNames(sessionFile: string): string[] {
|
||||
|
||||
async function runCli(args: string[], dirs: CliDirs): Promise<CliResult> {
|
||||
let stderr = "";
|
||||
const child = spawn(process.execPath, ["--import", sourceResolverPath, cliPath, ...args], {
|
||||
const child = spawn(process.execPath, ["--import", sourceResolverUrl, cliPath, ...args], {
|
||||
cwd: dirs.projectDir,
|
||||
env: {
|
||||
...process.env,
|
||||
|
||||
@@ -2,12 +2,14 @@ import { spawn } from "node:child_process";
|
||||
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, resolve } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { ENV_AGENT_DIR } from "../src/config.ts";
|
||||
import { allowNetwork } from "./test-network-env.ts";
|
||||
|
||||
const cliPath = resolve(__dirname, "../src/cli.ts");
|
||||
const sourceResolverPath = resolve(__dirname, "../src/experimental/source-resolver.ts");
|
||||
// --import takes a module specifier, not a filesystem path.
|
||||
const sourceResolverUrl = pathToFileURL(resolve(__dirname, "../src/experimental/source-resolver.ts")).href;
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
@@ -60,7 +62,7 @@ async function runCli(args: string[]): Promise<{ stdout: string; stderr: string;
|
||||
);
|
||||
|
||||
return await new Promise((resolvePromise, reject) => {
|
||||
const child = spawn(process.execPath, ["--import", sourceResolverPath, cliPath, ...args], {
|
||||
const child = spawn(process.execPath, ["--import", sourceResolverUrl, cliPath, ...args], {
|
||||
cwd: projectDir,
|
||||
env: {
|
||||
...process.env,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Debug script to reproduce streaming rendering issues.
|
||||
* Uses real fixture data that caused the bug.
|
||||
* Run with: npx tsx test/streaming-render-debug.ts
|
||||
* Run with: node --import ./src/experimental/source-resolver.ts test/streaming-render-debug.ts
|
||||
*/
|
||||
|
||||
import type { AssistantMessage } from "@earendil-works/pi-ai";
|
||||
|
||||
@@ -242,8 +242,11 @@ if (cmd === "contrast") {
|
||||
} else if (cmd === "light" || cmd === "dark") {
|
||||
cmdTheme(cmd);
|
||||
} else {
|
||||
console.log("Usage:");
|
||||
console.log(" npx tsx test-theme-colors.ts light|dark Test built-in theme");
|
||||
console.log(" npx tsx test-theme-colors.ts contrast 4.5 Compute colors at ratio");
|
||||
console.log(" npx tsx test-theme-colors.ts test file.json Test any JSON file");
|
||||
console.log("Usage (from packages/coding-agent):");
|
||||
console.log(" node --import ./src/experimental/source-resolver.ts test/test-theme-colors.ts <command>");
|
||||
console.log("");
|
||||
console.log("Commands:");
|
||||
console.log(" light|dark Test built-in theme");
|
||||
console.log(" contrast 4.5 Compute colors at ratio");
|
||||
console.log(" test file.json Test any JSON file");
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"build": "tsgo -p tsconfig.build.json",
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"test": "vitest --run",
|
||||
"bench:storage": "vitest bench --config vitest.benchmark.config.ts",
|
||||
"bench:storage:memory": "node --conditions=source --experimental-strip-types test/storage-memory.ts",
|
||||
|
||||
@@ -11,14 +11,13 @@
|
||||
"test": "vitest run --config vitest.test.config.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoevals": "0.3.0",
|
||||
"@earendil-works/pi-ai": "^0.87.1",
|
||||
"@earendil-works/pi-coding-agent": "^0.87.1",
|
||||
"@types/node": "22.19.19",
|
||||
"@vitest-evals/core": "0.15.0",
|
||||
"autoevals": "0.3.0",
|
||||
"shx": "0.4.0",
|
||||
"typescript": "5.9.3",
|
||||
"vitest-evals": "0.15.0",
|
||||
"vitest": "4.1.9"
|
||||
"vitest": "4.1.9",
|
||||
"vitest-evals": "0.15.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"build": "tsgo -p tsconfig.build.json",
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"test": "vitest --run",
|
||||
"prepublishOnly": "npm run clean && npm run build"
|
||||
},
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"dev": "tsgo -p tsconfig.build.json --watch --preserveWatchOutput",
|
||||
"build": "tsgo -p tsconfig.build.json",
|
||||
"dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput",
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"test": "vitest --run",
|
||||
"typecheck": "tsgo -p tsconfig.test.json",
|
||||
"typecheck": "tsc -p tsconfig.test.json",
|
||||
"prepublishOnly": "npm run clean && npm run build"
|
||||
},
|
||||
"keywords": [
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "node -e \"import('node:fs/promises').then(fs=>fs.rm('dist',{recursive:true,force:true}))\"",
|
||||
"build": "tsgo -p tsconfig.build.json && node scripts/copy-migrations.mjs",
|
||||
"build": "tsc -p tsconfig.build.json && node scripts/copy-migrations.mjs",
|
||||
"bench:session:timing": "vitest bench --config vitest.benchmark.config.ts",
|
||||
"test": "vitest --run",
|
||||
"coverage": "vitest --run --coverage",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"build": "tsgo -p tsconfig.build.json",
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"test": "vitest --run",
|
||||
"prepublishOnly": "npm run clean && npm run build"
|
||||
},
|
||||
|
||||
@@ -920,7 +920,7 @@ See `test/chat-simple.ts` for a complete chat interface example with:
|
||||
|
||||
Run it:
|
||||
```bash
|
||||
npx tsx test/chat-simple.ts
|
||||
node test/chat-simple.ts
|
||||
```
|
||||
|
||||
## Development
|
||||
@@ -933,7 +933,7 @@ npm install
|
||||
npm run check
|
||||
|
||||
# Run the demo
|
||||
npx tsx test/chat-simple.ts
|
||||
node test/chat-simple.ts
|
||||
```
|
||||
|
||||
### Debug logging
|
||||
@@ -941,5 +941,5 @@ npx tsx test/chat-simple.ts
|
||||
Set `PI_TUI_WRITE_LOG` to capture the raw ANSI stream written to stdout.
|
||||
|
||||
```bash
|
||||
PI_TUI_WRITE_LOG=/tmp/tui-ansi.log npx tsx test/chat-simple.ts
|
||||
PI_TUI_WRITE_LOG=/tmp/tui-ansi.log node test/chat-simple.ts
|
||||
```
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"build": "tsgo -p tsconfig.build.json",
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"build:native:darwin": "native/darwin/build.sh",
|
||||
"build:native:linux": "native/linux/build.sh",
|
||||
"build:native:win32": "node native/win32/build.mjs",
|
||||
|
||||
@@ -17,7 +17,7 @@ try {
|
||||
imageBuffer = readFileSync(testImagePath);
|
||||
} catch (_e) {
|
||||
console.error(`Failed to load image: ${testImagePath}`);
|
||||
console.error("Usage: npx tsx test/image-test.ts [path-to-image.png]");
|
||||
console.error("Usage: node test/image-test.ts [path-to-image.png]");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
* TUI viewport overwrite repro
|
||||
*
|
||||
* Place this file at: packages/tui/test/viewport-overwrite-repro.ts
|
||||
* Run from repo root: npx tsx packages/tui/test/viewport-overwrite-repro.ts
|
||||
* Run from repo root: node packages/tui/test/viewport-overwrite-repro.ts
|
||||
*
|
||||
* For reliable repro, run in a small terminal (8-12 rows) or a tmux session:
|
||||
* tmux new-session -d -s tui-bug -x 80 -y 12
|
||||
* tmux send-keys -t tui-bug "npx tsx packages/tui/test/viewport-overwrite-repro.ts" Enter
|
||||
* tmux send-keys -t tui-bug "node packages/tui/test/viewport-overwrite-repro.ts" Enter
|
||||
* tmux attach -t tui-bug
|
||||
*
|
||||
* Expected behavior:
|
||||
|
||||
+3
-6
@@ -58,13 +58,10 @@ if ($noEnv) {
|
||||
Write-Host "Running without API keys..."
|
||||
}
|
||||
|
||||
$tsxBin = Join-Path $scriptDir "node_modules/.bin/tsx.cmd"
|
||||
if (-not (Test-Path -LiteralPath $tsxBin)) {
|
||||
throw "tsx not found at $tsxBin. Run npm install from the repo root first."
|
||||
}
|
||||
|
||||
# --import takes a module specifier, so pass the resolver as a file URL (Windows paths are not specifiers).
|
||||
$resolverUrl = ([System.Uri](Join-Path $scriptDir "packages/coding-agent/src/experimental/source-resolver.ts")).AbsoluteUri
|
||||
$cliPath = Join-Path $scriptDir "packages/coding-agent/src/cli.ts"
|
||||
& $tsxBin $cliPath @forwardArgs
|
||||
& node --import $resolverUrl $cliPath @forwardArgs
|
||||
$exitCode = $LASTEXITCODE
|
||||
if ($exitCode -ne 0) {
|
||||
exit $exitCode
|
||||
|
||||
+3
-1
@@ -54,4 +54,6 @@ if [[ "$NO_ENV" == "true" ]]; then
|
||||
echo "Running without API keys..."
|
||||
fi
|
||||
|
||||
"$SCRIPT_DIR/node_modules/.bin/tsx" --tsconfig "$SCRIPT_DIR/tsconfig.json" "$SCRIPT_DIR/packages/coding-agent/src/experimental/cli.ts" ${ARGS[@]+"${ARGS[@]}"}
|
||||
# --import takes a module specifier, so pass the resolver as a file URL (raw paths break on #, ?, %).
|
||||
RESOLVER_URL="$(node -p 'require("node:url").pathToFileURL(process.argv[1]).href' "$SCRIPT_DIR/packages/coding-agent/src/experimental/source-resolver.ts")"
|
||||
node --import "$RESOLVER_URL" "$SCRIPT_DIR/packages/coding-agent/src/experimental/cli.ts" ${ARGS[@]+"${ARGS[@]}"}
|
||||
|
||||
@@ -3,9 +3,24 @@
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { isBuiltin } from "node:module";
|
||||
import { isAbsolute, join, relative, resolve } from "node:path";
|
||||
import ts from "typescript";
|
||||
import { SyntaxKind } from "typescript/unstable/ast";
|
||||
import {
|
||||
isCallExpression,
|
||||
isExportDeclaration,
|
||||
isIdentifier,
|
||||
isImportDeclaration,
|
||||
isNamedExports,
|
||||
isNamedImports,
|
||||
isNoSubstitutionTemplateLiteral,
|
||||
isPropertyAccessExpression,
|
||||
isStringLiteral,
|
||||
} from "typescript/unstable/ast/is";
|
||||
import { API } from "typescript/unstable/sync";
|
||||
import { getPublicWorkspacePackages } from "./release-packages.mjs";
|
||||
|
||||
// Packages without tsconfig.build.json are checked against a synthetic config.
|
||||
const fallbackConfigName = "tsconfig.runtime-deps-fallback.json";
|
||||
const fallbackConfig = JSON.stringify({ include: ["src/**/*"] });
|
||||
const failures = [];
|
||||
|
||||
function checkSource(source, manifest) {
|
||||
@@ -18,7 +33,7 @@ function checkSource(source, manifest) {
|
||||
]);
|
||||
|
||||
function checkSpecifier(node) {
|
||||
if (!node || !ts.isStringLiteralLike(node)) return;
|
||||
if (!node || !(isStringLiteral(node) || isNoSubstitutionTemplateLiteral(node))) return;
|
||||
const specifier = node.text;
|
||||
if (specifier.startsWith(".") || specifier.startsWith("/") || isBuiltin(specifier)) return;
|
||||
const name = specifier.split("/").slice(0, specifier.startsWith("@") ? 2 : 1).join("/");
|
||||
@@ -28,62 +43,87 @@ function checkSource(source, manifest) {
|
||||
}
|
||||
|
||||
function visit(node) {
|
||||
if (ts.isImportDeclaration(node)) {
|
||||
if (isImportDeclaration(node)) {
|
||||
const clause = node.importClause;
|
||||
const bindings = clause?.namedBindings;
|
||||
if (
|
||||
!clause ||
|
||||
(!clause.isTypeOnly &&
|
||||
(clause.name || !bindings || !ts.isNamedImports(bindings) ||
|
||||
bindings.elements.length === 0 || bindings.elements.some((element) => !element.isTypeOnly)))
|
||||
(clause.phaseModifier !== SyntaxKind.TypeKeyword &&
|
||||
(clause.name ||
|
||||
!bindings ||
|
||||
!isNamedImports(bindings) ||
|
||||
bindings.elements.length === 0 ||
|
||||
bindings.elements.some((element) => !element.isTypeOnly)))
|
||||
) {
|
||||
checkSpecifier(node.moduleSpecifier);
|
||||
}
|
||||
} else if (ts.isExportDeclaration(node) && !node.isTypeOnly) {
|
||||
} else if (isExportDeclaration(node) && !node.isTypeOnly) {
|
||||
const clause = node.exportClause;
|
||||
if (!clause || !ts.isNamedExports(clause) || clause.elements.length === 0 || clause.elements.some((element) => !element.isTypeOnly)) {
|
||||
if (
|
||||
!clause ||
|
||||
!isNamedExports(clause) ||
|
||||
clause.elements.length === 0 ||
|
||||
clause.elements.some((element) => !element.isTypeOnly)
|
||||
) {
|
||||
checkSpecifier(node.moduleSpecifier);
|
||||
}
|
||||
} else if (
|
||||
ts.isCallExpression(node) &&
|
||||
(node.expression.kind === ts.SyntaxKind.ImportKeyword ||
|
||||
(ts.isIdentifier(node.expression) && node.expression.text === "require") ||
|
||||
(ts.isPropertyAccessExpression(node.expression) && node.expression.getText(source) === "require.resolve"))
|
||||
isCallExpression(node) &&
|
||||
(node.expression.kind === SyntaxKind.ImportKeyword ||
|
||||
(isIdentifier(node.expression) && node.expression.text === "require") ||
|
||||
(isPropertyAccessExpression(node.expression) && node.expression.getText(source) === "require.resolve"))
|
||||
) {
|
||||
checkSpecifier(node.arguments[0]);
|
||||
}
|
||||
ts.forEachChild(node, visit);
|
||||
node.forEachChild(visit);
|
||||
}
|
||||
visit(source);
|
||||
}
|
||||
|
||||
for (const { directory } of getPublicWorkspacePackages()) {
|
||||
const sourceDirectory = resolve(directory, "src");
|
||||
if (!existsSync(sourceDirectory)) continue;
|
||||
const manifest = JSON.parse(readFileSync(join(directory, "package.json"), "utf8"));
|
||||
const configPath = join(directory, "tsconfig.build.json");
|
||||
const config = existsSync(configPath)
|
||||
? ts.readConfigFile(configPath, ts.sys.readFile)
|
||||
: { config: { include: ["src/**/*"] } };
|
||||
if (config.error) throw new Error(ts.flattenDiagnosticMessageText(config.error.messageText, "\n"));
|
||||
const parsed = ts.parseJsonConfigFileContent(config.config, ts.sys, resolve(directory));
|
||||
if (parsed.errors.length > 0) {
|
||||
throw new Error(parsed.errors.map((error) => ts.flattenDiagnosticMessageText(error.messageText, "\n")).join("\n"));
|
||||
}
|
||||
const roots = new Set(parsed.fileNames.map((file) => resolve(file)));
|
||||
const program = ts.createProgram(parsed.fileNames, parsed.options);
|
||||
for (const source of program.getSourceFiles()) {
|
||||
if (source.isDeclarationFile || source.fileName.endsWith(".json")) continue;
|
||||
const path = relative(sourceDirectory, resolve(source.fileName));
|
||||
const packages = getPublicWorkspacePackages()
|
||||
.map(({ directory }) => ({ directory, sourceDirectory: resolve(directory, "src") }))
|
||||
.filter(({ sourceDirectory }) => existsSync(sourceDirectory))
|
||||
.map(({ directory, sourceDirectory }) => {
|
||||
const configPath = resolve(directory, "tsconfig.build.json");
|
||||
return {
|
||||
sourceDirectory,
|
||||
manifest: JSON.parse(readFileSync(join(directory, "package.json"), "utf8")),
|
||||
configPath: existsSync(configPath) ? configPath : resolve(directory, fallbackConfigName),
|
||||
};
|
||||
});
|
||||
|
||||
const fallbackConfigs = new Set(
|
||||
packages.map(({ configPath }) => configPath).filter((path) => path.endsWith(fallbackConfigName)),
|
||||
);
|
||||
const api = new API({
|
||||
cwd: process.cwd(),
|
||||
fs: {
|
||||
fileExists: (fileName) => (fallbackConfigs.has(resolve(fileName)) ? true : undefined),
|
||||
readFile: (fileName) => (fallbackConfigs.has(resolve(fileName)) ? fallbackConfig : undefined),
|
||||
},
|
||||
});
|
||||
try {
|
||||
const snapshot = api.updateSnapshot({ openProjects: packages.map(({ configPath }) => configPath) });
|
||||
for (const { sourceDirectory, manifest, configPath } of packages) {
|
||||
const project = snapshot.getProject(configPath);
|
||||
const diagnostics = project.program.getConfigFileParsingDiagnostics();
|
||||
if (diagnostics.length > 0) throw new Error(diagnostics.map((diagnostic) => diagnostic.text).join("\n"));
|
||||
const roots = new Set(project.rootFiles.map((file) => resolve(file)));
|
||||
for (const fileName of project.program.getSourceFileNames()) {
|
||||
if (fileName.endsWith(".d.ts") || fileName.endsWith(".json")) continue;
|
||||
const path = relative(sourceDirectory, resolve(fileName));
|
||||
if (path.startsWith("..") || isAbsolute(path)) continue;
|
||||
// TypeScript's exclude only filters roots: imports can pull excluded files
|
||||
// back into the build. Reject that too, including type-only imports.
|
||||
if (!roots.has(resolve(source.fileName))) {
|
||||
failures.push(`${source.fileName} is excluded from ${manifest.name}'s build but imported by it`);
|
||||
if (!roots.has(resolve(fileName))) {
|
||||
failures.push(`${fileName} is excluded from ${manifest.name}'s build but imported by it`);
|
||||
}
|
||||
checkSource(source, manifest);
|
||||
checkSource(project.program.getSourceFile(fileName), manifest);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
api.close();
|
||||
}
|
||||
|
||||
if (failures.length > 0) {
|
||||
console.error("Undeclared runtime imports in public packages:");
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
import { readdirSync, readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import ts from "typescript";
|
||||
import { readdirSync } from "node:fs";
|
||||
import { join, relative, resolve } from "node:path";
|
||||
import { SyntaxKind } from "typescript/unstable/ast";
|
||||
import {
|
||||
isCallExpression,
|
||||
isExportDeclaration,
|
||||
isImportDeclaration,
|
||||
isImportTypeNode,
|
||||
isLiteralTypeNode,
|
||||
isNoSubstitutionTemplateLiteral,
|
||||
isStringLiteral,
|
||||
} from "typescript/unstable/ast/is";
|
||||
import { API } from "typescript/unstable/sync";
|
||||
|
||||
const ignoredDirectories = new Set([".git", "coverage", "dist", "node_modules"]);
|
||||
const files = [];
|
||||
@@ -20,13 +30,17 @@ function collectTypescriptFiles(directory) {
|
||||
}
|
||||
}
|
||||
|
||||
function isStringLiteralLike(node) {
|
||||
return node !== undefined && (isStringLiteral(node) || isNoSubstitutionTemplateLiteral(node));
|
||||
}
|
||||
|
||||
function isRelativeJavaScriptSpecifier(specifier) {
|
||||
return /^\.\.?\//.test(specifier) && /\.js(?:[?#].*)?$/.test(specifier);
|
||||
}
|
||||
|
||||
function getImportTypeSpecifier(node) {
|
||||
if (!ts.isLiteralTypeNode(node.argument)) return undefined;
|
||||
if (!ts.isStringLiteralLike(node.argument.literal)) return undefined;
|
||||
if (!isLiteralTypeNode(node.argument)) return undefined;
|
||||
if (!isStringLiteralLike(node.argument.literal)) return undefined;
|
||||
return node.argument.literal;
|
||||
}
|
||||
|
||||
@@ -34,38 +48,55 @@ const failures = [];
|
||||
|
||||
collectTypescriptFiles(".");
|
||||
|
||||
// Parse every file through one synthetic project. noResolve keeps the program to exactly these files.
|
||||
const configPath = resolve("tsconfig.check-ts-relative-imports.json");
|
||||
const config = JSON.stringify({
|
||||
compilerOptions: { noResolve: true, noLib: true, types: [] },
|
||||
files: files.map((file) => resolve(file)),
|
||||
});
|
||||
const api = new API({
|
||||
cwd: process.cwd(),
|
||||
fs: {
|
||||
fileExists: (fileName) => (resolve(fileName) === configPath ? true : undefined),
|
||||
readFile: (fileName) => (resolve(fileName) === configPath ? config : undefined),
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
const program = api.updateSnapshot({ openProjects: [configPath] }).getProject(configPath).program;
|
||||
for (const file of files.sort()) {
|
||||
const sourceText = readFileSync(file, "utf8");
|
||||
const sourceFile = ts.createSourceFile(file, sourceText, ts.ScriptTarget.Latest, true);
|
||||
const sourceFile = program.getSourceFile(resolve(file));
|
||||
|
||||
function checkSpecifier(node) {
|
||||
if (!isRelativeJavaScriptSpecifier(node.text)) return;
|
||||
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
||||
failures.push(`${file}:${line + 1}:${character + 1}: ${node.text}`);
|
||||
failures.push(`${relative(".", file)}:${line + 1}:${character + 1}: ${node.text}`);
|
||||
}
|
||||
|
||||
function visit(node) {
|
||||
if (ts.isImportDeclaration(node) && ts.isStringLiteralLike(node.moduleSpecifier)) {
|
||||
if (isImportDeclaration(node) && isStringLiteralLike(node.moduleSpecifier)) {
|
||||
checkSpecifier(node.moduleSpecifier);
|
||||
} else if (ts.isExportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteralLike(node.moduleSpecifier)) {
|
||||
} else if (isExportDeclaration(node) && isStringLiteralLike(node.moduleSpecifier)) {
|
||||
checkSpecifier(node.moduleSpecifier);
|
||||
} else if (
|
||||
ts.isCallExpression(node) &&
|
||||
node.expression.kind === ts.SyntaxKind.ImportKeyword &&
|
||||
node.arguments[0] &&
|
||||
ts.isStringLiteralLike(node.arguments[0])
|
||||
isCallExpression(node) &&
|
||||
node.expression.kind === SyntaxKind.ImportKeyword &&
|
||||
isStringLiteralLike(node.arguments[0])
|
||||
) {
|
||||
checkSpecifier(node.arguments[0]);
|
||||
} else if (ts.isImportTypeNode(node)) {
|
||||
} else if (isImportTypeNode(node)) {
|
||||
const specifier = getImportTypeSpecifier(node);
|
||||
if (specifier) checkSpecifier(specifier);
|
||||
}
|
||||
|
||||
ts.forEachChild(node, visit);
|
||||
node.forEachChild(visit);
|
||||
}
|
||||
|
||||
visit(sourceFile);
|
||||
}
|
||||
} finally {
|
||||
api.close();
|
||||
}
|
||||
|
||||
if (failures.length > 0) {
|
||||
console.error("Relative .js imports are not allowed in non-declaration .ts files:");
|
||||
|
||||
+3
-5
@@ -1,10 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"target": "ES2024",
|
||||
"module": "Node16",
|
||||
"lib": ["ES2022"],
|
||||
"lib": ["ES2024"],
|
||||
"strict": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
@@ -17,9 +18,6 @@
|
||||
"resolveJsonModule": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"rewriteRelativeImportExtensions": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"useDefineForClassFields": false,
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"paths": {
|
||||
"*": ["./*"],
|
||||
"@earendil-works/chord": ["./packages/chord/src/index.ts"],
|
||||
"@earendil-works/chord/bundler": ["./packages/chord/src/bundler.ts"],
|
||||
"@earendil-works/chord/context": ["./packages/chord/src/context/index.ts"],
|
||||
|
||||
Reference in New Issue
Block a user