refactor: migrated packages to internal utility modules and removed external dependencies

- Implemented in-house, zero-dependency utility modules in `pi-utils` covering DOM manipulation, markdown parsing, templating, browser automation helpers, and terminal buffers.
- Migrated packages across the repository to consume the new internal utilities and `omptype` schema validators instead of external dependencies.
- Removed multiple external runtime and development dependencies including Zod, Marked, LRU cache, Turndown, and Puppeteer browser packages.
This commit is contained in:
can1357
2026-08-05 13:39:09 +02:00
parent 1e492d6ff9
commit e9888367d1
284 changed files with 14662 additions and 2477 deletions
+10 -277
View File
@@ -47,7 +47,6 @@
"@oh-my-pi/pi-catalog": "catalog:",
"@oh-my-pi/pi-utils": "catalog:",
"@oh-my-pi/pi-wire": "catalog:",
"zod": "catalog:",
},
"devDependencies": {
"@bufbuild/protoc-gen-es": "catalog:",
@@ -69,7 +68,6 @@
"@bufbuild/protobuf": "catalog:",
"@oh-my-pi/omptype": "catalog:",
"@oh-my-pi/pi-utils": "catalog:",
"zod": "catalog:",
},
"devDependencies": {
"@oh-my-pi/pi-ai": "catalog:",
@@ -83,9 +81,7 @@
"omp": "src/cli.ts",
},
"dependencies": {
"@agentclientprotocol/sdk": "catalog:",
"@babel/parser": "catalog:",
"@mozilla/readability": "catalog:",
"@oh-my-pi/hashline": "catalog:",
"@oh-my-pi/omp-stats": "catalog:",
"@oh-my-pi/omptype": "catalog:",
@@ -109,25 +105,11 @@
"@opentelemetry/sdk-metrics": "catalog:",
"@opentelemetry/sdk-trace-base": "catalog:",
"@opentelemetry/sdk-trace-node": "catalog:",
"@puppeteer/browsers": "catalog:",
"@types/turndown": "catalog:",
"@xterm/headless": "catalog:",
"chalk": "catalog:",
"fast-xml-parser": "catalog:",
"handlebars": "catalog:",
"header-generator": "catalog:",
"linkedom": "catalog:",
"lru-cache": "catalog:",
"mammoth": "catalog:",
"mupdf": "catalog:",
"puppeteer-core": "catalog:",
"turndown": "catalog:",
"turndown-plugin-gfm": "catalog:",
"zod": "catalog:",
},
"devDependencies": {
"@types/bun": "catalog:",
"marked": "catalog:",
},
"optionalDependencies": {
"@huggingface/transformers": "catalog:",
@@ -138,9 +120,9 @@
"name": "@oh-my-pi/collab-web",
"version": "16.3.6",
"dependencies": {
"@oh-my-pi/pi-utils": "catalog:",
"@oh-my-pi/pi-wire": "catalog:",
"lucide-react": "catalog:",
"marked": "catalog:",
"react": "catalog:",
"react-dom": "catalog:",
},
@@ -155,7 +137,7 @@
"version": "17.2.9",
"dependencies": {
"@oh-my-pi/pi-natives": "catalog:",
"lru-cache": "catalog:",
"@oh-my-pi/pi-utils": "catalog:",
},
"devDependencies": {
"@types/bun": "catalog:",
@@ -205,7 +187,6 @@
"@oh-my-pi/pi-catalog": "catalog:",
"@oh-my-pi/pi-natives": "catalog:",
"@oh-my-pi/pi-utils": "catalog:",
"lru-cache": "catalog:",
},
"devDependencies": {
"@types/bun": "catalog:",
@@ -240,7 +221,6 @@
"@types/bun": "catalog:",
"arkregex": "0.0.8",
"arktype": "2.2.3",
"zod": "catalog:",
},
},
"packages/snapcompact": {
@@ -268,7 +248,6 @@
"@oh-my-pi/pi-utils": "catalog:",
"@tailwindcss/node": "catalog:",
"chart.js": "catalog:",
"date-fns": "catalog:",
"lucide-react": "catalog:",
"react": "catalog:",
"react-chartjs-2": "catalog:",
@@ -279,7 +258,6 @@
"@types/bun": "catalog:",
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
"linkedom": "catalog:",
"postcss": "catalog:",
},
},
@@ -289,11 +267,8 @@
"dependencies": {
"@oh-my-pi/pi-natives": "catalog:",
"@oh-my-pi/pi-utils": "catalog:",
"lru-cache": "catalog:",
"marked": "catalog:",
},
"devDependencies": {
"chalk": "catalog:",
"ghostty-web": "catalog:",
},
},
@@ -327,9 +302,6 @@
"version": "17.2.9",
"dependencies": {
"@oh-my-pi/pi-natives": "catalog:",
"handlebars": "catalog:",
"winston": "catalog:",
"winston-daily-rotate-file": "catalog:",
},
"devDependencies": {
"@types/bun": "catalog:",
@@ -361,13 +333,11 @@
"patchedDependencies": {
"puppeteer-core@25.3.0": "patches/puppeteer-core@25.3.0.patch",
"@ark/schema@0.56.2": "patches/@ark%2Fschema@0.56.2.patch",
"@agentclientprotocol/sdk@1.2.1": "patches/@agentclientprotocol%2Fsdk@1.2.1.patch",
},
"overrides": {
"@ark/schema": "0.56.2",
},
"catalog": {
"@agentclientprotocol/sdk": "1.2.1",
"@babel/generator": "^7.29.7",
"@babel/parser": "^7.29.7",
"@babel/traverse": "^7.29.7",
@@ -376,7 +346,6 @@
"@bufbuild/protobuf": "^2.12.1",
"@bufbuild/protoc-gen-es": "^2.12.1",
"@huggingface/transformers": "^4.2.0",
"@mozilla/readability": "^0.6.0",
"@napi-rs/cli": "3.7.2",
"@oh-my-pi/hashline": "17.2.9",
"@oh-my-pi/omp-stats": "17.2.9",
@@ -402,7 +371,6 @@
"@opentelemetry/sdk-metrics": "^2.9.0",
"@opentelemetry/sdk-trace-base": "^2.9.0",
"@opentelemetry/sdk-trace-node": "^2.9.0",
"@puppeteer/browsers": "^3.0.6",
"@tailwindcss/node": "^4.3.2",
"@tailwindcss/vite": "^4.3.2",
"@types/babel__generator": "^7.27.0",
@@ -410,25 +378,13 @@
"@types/bun": "^1.3.14",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@types/turndown": "5.0.6",
"@typescript/native-preview": "7.0.0-dev.20260707.2",
"@xterm/headless": "^6.0.0",
"chalk": "^5.6.2",
"chart.js": "^4.5.1",
"date-fns": "^4.4.0",
"diff": "^9.0.0",
"fast-xml-parser": "^5.9.3",
"fastembed": "2.1.0",
"fflate": "0.8.3",
"ghostty-web": "^0.4.0",
"handlebars": "^4.7.9",
"header-generator": "^2.1.82",
"linkedom": "^0.18.13",
"lint-staged": "^17.0.8",
"lru-cache": "11.5.2",
"lucide-react": "^1.24.0",
"mammoth": "^1.12.0",
"marked": "^18.0.6",
"mupdf": "^1.28.0",
"onnxruntime-node": "1.26.0",
"postcss": "^8.5.16",
@@ -441,18 +397,11 @@
"solid-js": "^1.9.14",
"tailwindcss": "^4.3.2",
"ts-morph": "^28.0.0",
"turndown": "7.2.4",
"turndown-plugin-gfm": "1.0.2",
"typescript": "^7.0.2",
"vite": "^8.1.4",
"vite-plugin-solid": "^2.11.12",
"winston": "^3.19.0",
"winston-daily-rotate-file": "5.0.0",
"zod": "^4",
},
"packages": {
"@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@1.2.1", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-jwYUdOQR7tc+Zfch53VL4JJyUNK/46q03uUTYb+PjECsmnNl94XFXOfYLJ8RBpMNidXd1rpOAVgb0vqD98xImA=="],
"@anush008/tokenizers": ["@anush008/tokenizers@0.0.0", "", { "optionalDependencies": { "@anush008/tokenizers-darwin-universal": "0.0.0", "@anush008/tokenizers-linux-x64-gnu": "0.0.0", "@anush008/tokenizers-win32-x64-msvc": "0.0.0" } }, "sha512-IQD9wkVReKAhsEAbDjh/0KrBGTEXelqZLpOBRDaIRvlzZ9sjmUP+gKbpvzyJnei2JHQiE8JAgj7YcNloINbGBw=="],
"@anush008/tokenizers-darwin-universal": ["@anush008/tokenizers-darwin-universal@0.0.0", "", { "os": "darwin" }, "sha512-SACpWEooTjFX89dFKRVUhivMxxcZRtA3nJGVepdLyrwTkQ1TZQ8581B5JoXp0TcTMHfgnDaagifvVoBiFEdNCQ=="],
@@ -529,10 +478,6 @@
"@bufbuild/protoplugin": ["@bufbuild/protoplugin@2.13.0", "", { "dependencies": { "@bufbuild/protobuf": "2.13.0", "@typescript/vfs": "^1.6.2", "typescript": "5.4.5" } }, "sha512-32eMChKaL/A8Hh5AfMmXSdnuyznN85uoEjoyWiWeRrvtQOtpqX/v1R9PDe0g9vMIgzznK9inMT3CUaal0kjLUQ=="],
"@colors/colors": ["@colors/colors@1.6.0", "", {}, "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA=="],
"@dabh/diagnostics": ["@dabh/diagnostics@2.0.8", "", { "dependencies": { "@so-ric/colorspace": "^1.1.6", "enabled": "2.0.x", "kuler": "^2.0.0" } }, "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q=="],
"@emnapi/core": ["@emnapi/core@1.9.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA=="],
"@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="],
@@ -649,10 +594,6 @@
"@kurkle/color": ["@kurkle/color@0.3.4", "", {}, "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w=="],
"@mixmark-io/domino": ["@mixmark-io/domino@2.2.0", "", {}, "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="],
"@mozilla/readability": ["@mozilla/readability@0.6.0", "", {}, "sha512-juG5VWh4qAivzTAeMzvY9xs9HY5rAcr2E4I7tiSSCokRFi7XIZCAu92ZkSTsIj1OPceCifL3cpfteP3pDT9/QQ=="],
"@napi-rs/cli": ["@napi-rs/cli@3.7.2", "", { "dependencies": { "@inquirer/prompts": "^8.5.2", "@napi-rs/cross-toolchain": "^1.0.3", "@napi-rs/wasm-tools": "^1.0.1", "@octokit/rest": "^22.0.1", "clipanion": "^4.0.0-rc.4", "colorette": "^2.0.20", "emnapi": "^1.11.1", "es-toolkit": "^1.47.0", "js-yaml": "^4.2.0", "obug": "^2.1.2", "semver": "^7.8.2", "typanion": "^3.14.0" }, "peerDependencies": { "@emnapi/runtime": "^1.7.1" }, "optionalPeers": ["@emnapi/runtime"], "bin": { "napi": "dist/cli.js", "napi-raw": "cli.mjs" } }, "sha512-shDW0Td/XZQpP04Yy+OsMt1ILMKGGkoLcy1zVAsSAK0fLfWm0Upgkmfs/NOV2ZhMQwkgpR3ZEdyHmTwgrUDQuA=="],
"@napi-rs/cross-toolchain": ["@napi-rs/cross-toolchain@1.0.3", "", { "dependencies": { "@napi-rs/lzma": "^1.4.5", "@napi-rs/tar": "^1.1.0", "debug": "^4.4.1" }, "peerDependencies": { "@napi-rs/cross-toolchain-arm64-target-aarch64": "^1.0.3", "@napi-rs/cross-toolchain-arm64-target-armv7": "^1.0.3", "@napi-rs/cross-toolchain-arm64-target-ppc64le": "^1.0.3", "@napi-rs/cross-toolchain-arm64-target-s390x": "^1.0.3", "@napi-rs/cross-toolchain-arm64-target-x86_64": "^1.0.3", "@napi-rs/cross-toolchain-x64-target-aarch64": "^1.0.3", "@napi-rs/cross-toolchain-x64-target-armv7": "^1.0.3", "@napi-rs/cross-toolchain-x64-target-ppc64le": "^1.0.3", "@napi-rs/cross-toolchain-x64-target-s390x": "^1.0.3", "@napi-rs/cross-toolchain-x64-target-x86_64": "^1.0.3" }, "optionalPeers": ["@napi-rs/cross-toolchain-arm64-target-aarch64", "@napi-rs/cross-toolchain-arm64-target-armv7", "@napi-rs/cross-toolchain-arm64-target-ppc64le", "@napi-rs/cross-toolchain-arm64-target-s390x", "@napi-rs/cross-toolchain-arm64-target-x86_64", "@napi-rs/cross-toolchain-x64-target-aarch64", "@napi-rs/cross-toolchain-x64-target-armv7", "@napi-rs/cross-toolchain-x64-target-ppc64le", "@napi-rs/cross-toolchain-x64-target-s390x", "@napi-rs/cross-toolchain-x64-target-x86_64"] }, "sha512-ENPfLe4937bsKVTDA6zdABx4pq9w0tHqRrJHyaGxgaPq03a2Bd1unD5XSKjXJjebsABJ+MjAv1A2OvCgK9yehg=="],
@@ -757,8 +698,6 @@
"@napi-rs/wasm-tools-win32-x64-msvc": ["@napi-rs/wasm-tools-win32-x64-msvc@1.1.0", "", { "os": "win32", "cpu": "x64" }, "sha512-bVVjuvhlyVX++3eJXfDR63cXdw1ay5QYac6iq0MKQw8wZARInTM+bXCtByDT4fzVFI3+7ZthYb/ERWRdBNIqgQ=="],
"@nodable/entities": ["@nodable/entities@3.0.0", "", {}, "sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw=="],
"@octokit/auth-token": ["@octokit/auth-token@6.0.0", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="],
"@octokit/core": ["@octokit/core@7.0.7", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.4", "@octokit/request": "^10.0.13", "@octokit/request-error": "^7.1.1", "@octokit/types": "^17.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-DcB0M3KFgr9ECI328lhBMVsyFT2DnmNucSBTqEN3exyNKUzkkpUSCHmTRcunF41Eou2TIQKW4seewri8ON9bSA=="],
@@ -909,10 +848,6 @@
"@sinclair/typebox": ["@sinclair/typebox@0.34.52", "", {}, "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw=="],
"@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="],
"@so-ric/colorspace": ["@so-ric/colorspace@1.1.6", "", { "dependencies": { "color": "^5.0.2", "text-hex": "1.0.x" } }, "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw=="],
"@tailwindcss/node": ["@tailwindcss/node@4.3.3", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.24.1", "jiti": "^2.7.0", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.3" } }, "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg=="],
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.3.3", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.3", "@tailwindcss/oxide-darwin-arm64": "4.3.3", "@tailwindcss/oxide-darwin-x64": "4.3.3", "@tailwindcss/oxide-freebsd-x64": "4.3.3", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", "@tailwindcss/oxide-linux-x64-musl": "4.3.3", "@tailwindcss/oxide-wasm32-wasi": "4.3.3", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" } }, "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA=="],
@@ -971,10 +906,6 @@
"@types/react-dom": ["@types/react-dom@19.2.4", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw=="],
"@types/triple-beam": ["@types/triple-beam@1.3.5", "", {}, "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="],
"@types/turndown": ["@types/turndown@5.0.6", "", {}, "sha512-ru00MoyeeouE5BX4gRL+6m/BsDfbRayOskWqUvh7CLGW+UXxHQItqALa38kKnOiZPqJrtzJUgAC2+F0rL1S4Pg=="],
"@typescript/analyze-trace": ["@typescript/analyze-trace@0.10.1", "", { "dependencies": { "chalk": "^4.1.2", "exit": "^0.1.2", "jsonparse": "^1.3.1", "jsonstream-next": "^3.0.0", "p-limit": "^3.1.0", "split2": "^3.2.2", "treeify": "^1.1.0", "yargs": "^16.2.0" }, "bin": { "analyze-trace": "bin/analyze-trace", "print-trace-types": "bin/print-trace-types", "simplify-trace-types": "bin/simplify-trace-types" } }, "sha512-RnlSOPh14QbopGCApgkSx5UBgGda5MX1cHqp2fsqfiDyCwGL/m1jaeB9fzu7didVS81LQqGZZuxFBcg8YU8EVw=="],
"@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260707.2", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260707.2", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260707.2", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260707.2", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260707.2", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260707.2", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260707.2", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260707.2" }, "bin": { "tsgo": "bin/tsgo" } }, "sha512-oUGp+Rep/hqMhPunyinsALUwSlzHINSxitifPiSaeqoKOKD2OlR9NE3TaPqwsl4NlGslsOSUXI1JotWQzpYCPg=="],
@@ -1035,42 +966,28 @@
"@typescript/vfs": ["@typescript/vfs@1.6.1", "", { "dependencies": { "debug": "^4.1.1" }, "peerDependencies": { "typescript": "*" } }, "sha512-JwoxboBh7Oz1v38tPbkrZ62ZXNHAk9bJ7c9x0eI5zBfBnBYGhURdbnh7Z4smN/MV48Y5OCcZb58n972UtbazsA=="],
"@xmldom/xmldom": ["@xmldom/xmldom@0.8.13", "", {}, "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw=="],
"@xterm/headless": ["@xterm/headless@6.0.0", "", {}, "sha512-5Yj1QINYCyzrZtf8OFIHi47iQtI+0qYFPHmouEfG8dHNxbZ9Tb9YGSuLcsEwj9Z+OL75GJqPyJbyoFer80a2Hw=="],
"adm-zip": ["adm-zip@0.5.18", "", {}, "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng=="],
"ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"anynum": ["anynum@1.0.1", "", {}, "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A=="],
"argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
"arkregex": ["arkregex@0.0.8", "", { "dependencies": { "@ark/util": "0.56.2" } }, "sha512-PJcx6G1kQTgLKPUbeYlYecDRaKq15AMSGVajlKFYWlPeJRQL+j3dKE6tyMs40HZ99djS1l9Vhl3ezAHy9JBIqQ=="],
"arktype": ["arktype@2.2.3", "", { "dependencies": { "@ark/schema": "0.56.2", "@ark/util": "0.56.2", "arkregex": "0.0.8" } }, "sha512-7W+0RLTUNJiBFIIZXwOQxSR8Z273IAd6IvqBeG9+gHnQKFsIx2C0iOtGTmMrPnlX4qLXyc5+ll7A0BIj9WrbTg=="],
"async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="],
"babel-plugin-jsx-dom-expressions": ["babel-plugin-jsx-dom-expressions@0.40.7", "", { "dependencies": { "@babel/helper-module-imports": "7.18.6", "@babel/plugin-syntax-jsx": "^7.18.6", "@babel/types": "^7.20.7", "html-entities": "2.3.3", "parse5": "^7.1.2" }, "peerDependencies": { "@babel/core": "^7.20.12" } }, "sha512-/O6JWUmjv03OI9lL2ry9bUjpD5S3PclM55RRJEyCdcFZ5W2SEA/59d+l2hNsk3gI6kiWRdRPdOtqZmsQzFN1pQ=="],
"babel-preset-solid": ["babel-preset-solid@1.9.12", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.6" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.12" }, "optionalPeers": ["solid-js"] }, "sha512-LLqnuKVDlKpyBlMPcH6qEvs/wmS9a+NczppxJ3ryS/c0O5IiSFOIBQi9GzyiGDSbcJpx4Gr87jyFTos1MyEuWg=="],
"balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.11.10", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-35JEvJ5/KKlbCHjMCsONI2w6HE88STjVdHk+C7d8LtcFxUjZR1KeLP9izofn2qs0KUxX5r4z73bwH/rd+JHacw=="],
"before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="],
"bluebird": ["bluebird@3.4.7", "", {}, "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA=="],
"boolbase": ["boolbase@2.0.0", "", {}, "sha512-DkVaaQHymRhpYEYo9x1oo7Q7B0Y6KJUsjm3c9eTyFDby4MHLBTwZ6ZDWBel5zrYxj1WsZgC5oLpiz+93MluXeA=="],
"boolean": ["boolean@3.2.0", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="],
"brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="],
@@ -1079,11 +996,9 @@
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"caniuse-lite": ["caniuse-lite@1.0.30001806", "", {}, "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw=="],
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"chardet": ["chardet@2.2.0", "", {}, "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA=="],
@@ -1105,28 +1020,16 @@
"code-block-writer": ["code-block-writer@13.0.3", "", {}, "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg=="],
"color": ["color@5.0.3", "", { "dependencies": { "color-convert": "^3.1.3", "color-string": "^2.1.3" } }, "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"color-string": ["color-string@2.1.4", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg=="],
"colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="],
"content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="],
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
"core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
"css-select": ["css-select@7.0.0", "", { "dependencies": { "boolbase": "^2.0.0", "css-what": "^8.0.0", "domhandler": "^6.0.1", "domutils": "^4.0.2", "nth-check": "^3.0.1" } }, "sha512-snmjEVXy+1LnwXdxhYvTMj1d9tOh4HxkA1YmoayVBeeyR2C14Pum7fcxJIm4SswYspVy866eYNwlH6xC3/VH5g=="],
"css-what": ["css-what@8.0.0", "", {}, "sha512-DH0Bqq3DNp5tdOReuNyAA+Ev4Y2GS5FMbZpeTLP6C4CDi0h5nL0BmUPChXw3o/qbHLDWHl49sbNqQVY7bMSDdw=="],
"cssom": ["cssom@0.5.0", "", {}, "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw=="],
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
"d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="],
@@ -1147,8 +1050,6 @@
"d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="],
"date-fns": ["date-fns@4.4.0", "", {}, "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w=="],
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="],
@@ -1163,31 +1064,15 @@
"diff": ["diff@9.0.0", "", {}, "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw=="],
"dingbat-to-unicode": ["dingbat-to-unicode@1.0.1", "", {}, "sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w=="],
"dom-serializer": ["dom-serializer@3.1.1", "", { "dependencies": { "domelementtype": "^3.0.0", "domhandler": "^6.0.0", "entities": "^8.0.0" } }, "sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw=="],
"domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="],
"domhandler": ["domhandler@6.0.1", "", { "dependencies": { "domelementtype": "^3.0.0" } }, "sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg=="],
"domutils": ["domutils@4.0.2", "", { "dependencies": { "dom-serializer": "^3.0.0", "domelementtype": "^3.0.0", "domhandler": "^6.0.0" } }, "sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA=="],
"dot-prop": ["dot-prop@6.0.1", "", { "dependencies": { "is-obj": "^2.0.0" } }, "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA=="],
"duck": ["duck@0.1.12", "", { "dependencies": { "underscore": "^1.13.1" } }, "sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg=="],
"electron-to-chromium": ["electron-to-chromium@1.5.399", "", {}, "sha512-lEcqhErbHjXRvd41rnWLpzbyU/IXfIYo7QwaFWmxGeLiLyY2TBCdHnWY88vB+p3ubnihRypDm66panXl7TylLA=="],
"emnapi": ["emnapi@1.11.3", "", { "peerDependencies": { "node-addon-api": ">= 6.1.0" }, "optionalPeers": ["node-addon-api"] }, "sha512-+/ZS90YK/rYfVOHtGLHkGffVsnmD/MAKaBHio+Y4XAtg75RLr4cveV/w0jTkUdLM1CcAlaRgG76mpIemWAlk0A=="],
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"enabled": ["enabled@2.0.0", "", {}, "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="],
"enhanced-resolve": ["enhanced-resolve@5.24.5", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A=="],
"entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
"entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
@@ -1209,22 +1094,12 @@
"fast-wrap-ansi": ["fast-wrap-ansi@0.2.2", "", { "dependencies": { "fast-string-width": "^3.0.2" } }, "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q=="],
"fast-xml-builder": ["fast-xml-builder@1.3.0", "", { "dependencies": { "path-expression-matcher": "^1.6.2", "xml-naming": "^0.3.0" } }, "sha512-F74cZEdCvuw9P41GAC3rod4X04jjWGM1JPEv/GWSqFTWLsdyMSBMBMlm9Hk3GLBgLBbdBNY8yee0pQh2RBVESQ=="],
"fast-xml-parser": ["fast-xml-parser@5.10.1", "", { "dependencies": { "@nodable/entities": "^3.0.0", "fast-xml-builder": "^1.2.0", "is-unsafe": "^2.0.0", "path-expression-matcher": "^1.6.2", "strnum": "^2.4.1", "xml-naming": "^0.3.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-IEMIf7298kXuZSRFoGfMYrl7is8LpavODgbNz1cwIudv7KwVFnuU+UsMporfq6PD6aXSlawZlARiA3UywCTfMw=="],
"fastembed": ["fastembed@2.1.0", "", { "dependencies": { "@anush008/tokenizers": "^0.0.0", "@huggingface/hub": "^2.7.1", "onnxruntime-node": "1.21.0", "progress": "^2.0.3", "tar": "^6.2.0" } }, "sha512-oQkpcRHBppJ3+a3w9dU0uytSY0N1cnEa/iVMc8AXEd+tvT529GekOEFhNviJy89R3lvQXF6cdIMTXHj1Gi00xQ=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"fecha": ["fecha@4.2.3", "", {}, "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="],
"file-stream-rotator": ["file-stream-rotator@0.6.1", "", { "dependencies": { "moment": "^2.29.1" } }, "sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ=="],
"flatbuffers": ["flatbuffers@25.9.23", "", {}, "sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ=="],
"fn.name": ["fn.name@1.1.0", "", {}, "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="],
"framer-motion": ["framer-motion@12.43.0", "", { "dependencies": { "motion-dom": "^12.43.0", "motion-utils": "^12.39.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-1eaL3RvR/kAlbG7UYcpMptEyzPoENO0c6w7ZnB3/hh2vSAz/6uGAFn6fdoqTBguNstf3MsFhJHsD/0DHiclG+g=="],
"fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="],
@@ -1233,8 +1108,6 @@
"gearhash-jit": ["gearhash-jit@1.0.2", "", {}, "sha512-UhzJL4KXSdqAKepy/tZwmi2Rcy0YMmtiC4DQS4SURCuIWdh8ECZtnXK2ePRMLigfB61hRKdLK/Vgg2bSw73izQ=="],
"generative-bayesian-network": ["generative-bayesian-network@2.1.87", "", { "dependencies": { "adm-zip": "^0.6.0", "tslib": "^2.4.0" } }, "sha512-Bd14uZSkGGef6gWsJp170xnTMxeMENcnkJega4UjFrgF0KHSG8IOYA5hgFVOIgWlfyYUy9B2qiLGvXsKR/TlYA=="],
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
@@ -1253,40 +1126,22 @@
"guid-typescript": ["guid-typescript@1.0.9", "", {}, "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ=="],
"handlebars": ["handlebars@4.7.9", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ=="],
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="],
"header-generator": ["header-generator@2.1.87", "", { "dependencies": { "browserslist": "^4.21.1", "generative-bayesian-network": "2.1.87", "ow": "^0.28.1", "tslib": "^2.4.0" } }, "sha512-J3MG508JWaH3UJtHlPM3xaOQ2Iqys8BiW07t6XehzP+HuvVX4MP4C2YztJKasDmB8R3yPwpBfyroOiEi4Ymn6Q=="],
"html-entities": ["html-entities@2.3.3", "", {}, "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA=="],
"html-escaper": ["html-escaper@3.0.3", "", {}, "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ=="],
"htmlparser2": ["htmlparser2@10.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "entities": "^7.0.1" } }, "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ=="],
"iconv-lite": ["iconv-lite@0.7.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ=="],
"immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="],
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
"internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="],
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
"is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="],
"is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
"is-unsafe": ["is-unsafe@2.0.0", "", {}, "sha512-2LdV822R+wmI86unXA93WCFpL6g+av8ynWk0nrHyJqGop5VoocYsSLFgN8jrfalT6iGeLNM4KXuVSsULP53kEA=="],
"is-what": ["is-what@4.1.16", "", {}, "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A=="],
"isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
"jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="],
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
@@ -1305,12 +1160,6 @@
"jsonstream-next": ["jsonstream-next@3.0.0", "", { "dependencies": { "jsonparse": "^1.2.0", "through2": "^4.0.2" }, "bin": { "jsonstream-next": "bin.js" } }, "sha512-aAi6oPhdt7BKyQn1SrIIGZBt0ukKuOUE1qV6kJ3GgioSOYzsRc8z9Hfr1BVmacA/jLe9nARfmgMGgn68BqIAgg=="],
"jszip": ["jszip@3.10.1", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g=="],
"kuler": ["kuler@2.0.0", "", {}, "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="],
"lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="],
"lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
@@ -1335,19 +1184,11 @@
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="],
"linkedom": ["linkedom@0.18.13", "", { "dependencies": { "css-select": "^7.0.0", "cssom": "^0.5.0", "html-escaper": "^3.0.3", "htmlparser2": "^10.1.0", "uhyphen": "^0.2.0" }, "peerDependencies": { "canvas": ">= 2" }, "optionalPeers": ["canvas"] }, "sha512-ES/o9qotMpzpN2MHs+Iq/JcVoOj8Fa5wiQYrTdFpvAnwXL0g66XHHUc9WUMk6nAlBtGsFQ24ne+SYnvnaQ2FSw=="],
"lint-staged": ["lint-staged@17.3.0", "", { "dependencies": { "picomatch": "^4.0.5", "string-argv": "^0.3.2", "tinyexec": "^1.2.4" }, "optionalDependencies": { "yaml": "^2.9.0" }, "bin": { "lint-staged": "bin/lint-staged.js" } }, "sha512-woZS3vNe3UKqBaLPvbLOtKRY4tLANpWQhom12MGWqC8Mh1lCOO+WgSwmX2amjJAqTY9BkXYW87fCUH5H9Ph6xw=="],
"lodash.isequal": ["lodash.isequal@4.5.0", "", {}, "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="],
"logform": ["logform@2.7.0", "", { "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ=="],
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
"lop": ["lop@0.4.2", "", { "dependencies": { "duck": "^0.1.12", "option": "~0.2.1", "underscore": "^1.13.1" } }, "sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw=="],
"lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="],
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"lucide-react": ["lucide-react@1.28.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-fARAFJULsGuDDydjp6+6blekG/sBIM29TerzLjc9bQUKAcEfrSc4ZQKb25KRz4OMKd87cZTb5dgq0w/T6KufVg=="],
@@ -1355,18 +1196,12 @@
"make-synchronized": ["make-synchronized@0.8.0", "", {}, "sha512-DZu4lwc0ffoFz581BSQa/BJl+1ZqIkoRQ+VejMlH0VrP4E86StAODnZujZ4sepumQj8rcP7wUnUBGM8Gu+zKUA=="],
"mammoth": ["mammoth@1.12.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.6", "argparse": "~1.0.3", "base64-js": "^1.5.1", "bluebird": "~3.4.0", "dingbat-to-unicode": "^1.0.1", "jszip": "^3.7.1", "lop": "^0.4.2", "path-is-absolute": "^1.0.0", "underscore": "^1.13.1", "xmlbuilder": "^10.0.0" }, "bin": { "mammoth": "bin/mammoth" } }, "sha512-cwnK1RIcRdDMi2HRx2EXGYlxqIEh0Oo3bLhorgnsVJi2UkbX1+jKxuBNR9PC5+JaX7EkmJxFPmo6mjLpqShI2w=="],
"marked": ["marked@18.0.7", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-iDVQ5ldaiKXn6b2JroX5kgRfmwgqolW7NpaEzTl1k/2Zh1njIEN9yniyLV/mOvWwtsE8OGgkjsCYvijuPk1dtA=="],
"matcher": ["matcher@4.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-S6x5wmcDmsDRRU/c2dkccDwQPXoFczc5+HpQ2lON8pnvHlnvHAHj5WlLVvw6n6vNyHuVugYrFohYxbS+pvFpKQ=="],
"merge-anything": ["merge-anything@5.1.7", "", { "dependencies": { "is-what": "^4.1.8" } }, "sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ=="],
"minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="],
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
"minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="],
"minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="],
@@ -1377,8 +1212,6 @@
"modern-tar": ["modern-tar@0.7.7", "", {}, "sha512-t9VmxaqrmANnEOBhpSDI6HD192Ge48k8vmWqQQL7hSFEqHEYwZbbsu49+aKLWZeRvFs3j1pMhXOqqF4kPlvjkQ=="],
"moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="],
"motion": ["motion@12.43.0", "", { "dependencies": { "framer-motion": "^12.43.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-BQgQbSa9Hn3/mtbib0MK53y6JSANa+YKUKlaYnWzAVDH424RYQ5LVpV3pNiWH00BA2z4ojsSdMzqT7g2FQwjuQ=="],
"motion-dom": ["motion-dom@12.43.0", "", { "dependencies": { "motion-utils": "^12.39.0" } }, "sha512-azKON4d9S65PEoFUiQTMTgPheEmzf2QngdRc50AKfJp9Q9mmcBVw22c8eMq9k8kxOFHdL7+WZY7N/5F/lwiDag=="],
@@ -1393,42 +1226,24 @@
"nanoid": ["nanoid@3.3.16", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q=="],
"neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="],
"node-releases": ["node-releases@2.0.51", "", {}, "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ=="],
"nth-check": ["nth-check@3.0.1", "", { "dependencies": { "boolbase": "^2.0.0" } }, "sha512-GX0gsdbGVCgnRgbeGaubfjpBXyYRWOOCVeYh08bSQvDZqxz5ndXs1OTfAt/h36G1xvI94YIspsI0sVFqAV9+RQ=="],
"object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="],
"object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="],
"obug": ["obug@2.1.4", "", {}, "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA=="],
"one-time": ["one-time@1.0.0", "", { "dependencies": { "fn.name": "1.x.x" } }, "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g=="],
"onnxruntime-common": ["onnxruntime-common@1.26.0", "", {}, "sha512-qVyMR4lcWgbkc4getFV+GQijsTnbg/siteoqcDwa3sI/LxbrMSNw4ePyvCq/ymdQaRomCA7YuWmhzsswxvymdw=="],
"onnxruntime-node": ["onnxruntime-node@1.26.0", "", { "dependencies": { "adm-zip": "^0.5.16", "global-agent": "^4.1.3", "onnxruntime-common": "1.26.0" }, "os": [ "linux", "win32", "darwin", ] }, "sha512-OHl6PiOEOqxaLHL0N9eFrbzS7IGmu3BtJNH3RTEnRAheCIkfc3gjcjl4sGcjp9C22ZC9YTquDOxSdT/stBQ6BQ=="],
"onnxruntime-web": ["onnxruntime-web@1.26.0-dev.20260416-b7804b056c", "", { "dependencies": { "flatbuffers": "^25.1.24", "guid-typescript": "^1.0.9", "long": "^5.2.3", "onnxruntime-common": "1.24.0-dev.20251116-b39e144322", "platform": "^1.3.6", "protobufjs": "^7.2.4" } }, "sha512-MD6Ss4GSpQBo6zqoJzyT9LRbKYs7x/JVN23FT24EcEvlqF4VuzPOeH6X38orZPKHQDbprn7K+SBpu0/mj2CQiw=="],
"option": ["option@0.2.4", "", {}, "sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A=="],
"ow": ["ow@0.28.2", "", { "dependencies": { "@sindresorhus/is": "^4.2.0", "callsites": "^3.1.0", "dot-prop": "^6.0.1", "lodash.isequal": "^4.5.0", "vali-date": "^1.0.0" } }, "sha512-dD4UpyBh/9m4X2NVjA+73/ZPBRF+uF4zIMFvvQsabMiEK8x41L3rQ8EENOi35kyyoaJwNxEeJcP6Fj1H4U409Q=="],
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
"pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="],
"parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="],
"path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="],
"path-expression-matcher": ["path-expression-matcher@1.6.2", "", {}, "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ=="],
"path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@4.0.5", "", {}, "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A=="],
@@ -1439,8 +1254,6 @@
"prettier": ["prettier@3.9.6", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g=="],
"process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
"progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="],
"protobufjs": ["protobufjs@7.6.5", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.5", "@protobufjs/eventemitter": "^1.1.1", "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", "long": "^5.3.2" } }, "sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw=="],
@@ -1467,9 +1280,7 @@
"rolldown": ["rolldown@1.2.1", "", { "dependencies": { "@oxc-project/types": "=0.142.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.2.1", "@rolldown/binding-darwin-arm64": "1.2.1", "@rolldown/binding-darwin-x64": "1.2.1", "@rolldown/binding-freebsd-x64": "1.2.1", "@rolldown/binding-linux-arm-gnueabihf": "1.2.1", "@rolldown/binding-linux-arm64-gnu": "1.2.1", "@rolldown/binding-linux-arm64-musl": "1.2.1", "@rolldown/binding-linux-ppc64-gnu": "1.2.1", "@rolldown/binding-linux-s390x-gnu": "1.2.1", "@rolldown/binding-linux-x64-gnu": "1.2.1", "@rolldown/binding-linux-x64-musl": "1.2.1", "@rolldown/binding-openharmony-arm64": "1.2.1", "@rolldown/binding-wasm32-wasi": "1.2.1", "@rolldown/binding-win32-arm64-msvc": "1.2.1", "@rolldown/binding-win32-x64-msvc": "1.2.1" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-4FKJhg8d3OiyQOA6Q1Q0hoFFpW9/OoX+VsHzpECsdsIZoOArrAK90gl59YK/Z+gnDel45bgJZK03ozH/9bCqEw=="],
"safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
"safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
@@ -1485,8 +1296,6 @@
"seroval-plugins": ["seroval-plugins@1.5.6", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-HXuLAX2pu/UByPpaeo/TaMfvMIi+1QqIoPJYCcAtU8QkVNwgR6MPlGuCQTErV1JwraaMbYaWVIBX7mppzGLATQ=="],
"setimmediate": ["setimmediate@1.0.5", "", {}, "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="],
"sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="],
"sherpa-onnx": ["sherpa-onnx@1.13.2", "", {}, "sha512-hheOLl4JlOzERco73u+1Q/LaNDdFChDe4r3+IlMYIO3wggBZrReHDSxWwRUIW+YLw3eLslyiXw/hfb75aOylEA=="],
@@ -1511,15 +1320,11 @@
"solid-refresh": ["solid-refresh@0.6.3", "", { "dependencies": { "@babel/generator": "^7.23.6", "@babel/helper-module-imports": "^7.22.15", "@babel/types": "^7.23.6" }, "peerDependencies": { "solid-js": "^1.3" } }, "sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA=="],
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"split2": ["split2@3.2.2", "", { "dependencies": { "readable-stream": "^3.0.0" } }, "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg=="],
"sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="],
"stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="],
"sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="],
"string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="],
@@ -1529,8 +1334,6 @@
"strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
"strnum": ["strnum@2.4.1", "", { "dependencies": { "anynum": "^1.0.1" } }, "sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg=="],
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"tailwind-merge": ["tailwind-merge@3.6.0", "", {}, "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w=="],
@@ -1541,8 +1344,6 @@
"tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
"text-hex": ["text-hex@1.0.0", "", {}, "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="],
"through2": ["through2@4.0.2", "", { "dependencies": { "readable-stream": "3" } }, "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw=="],
"tinyexec": ["tinyexec@1.3.0", "", {}, "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ=="],
@@ -1551,16 +1352,10 @@
"treeify": ["treeify@1.1.0", "", {}, "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A=="],
"triple-beam": ["triple-beam@1.4.1", "", {}, "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg=="],
"ts-morph": ["ts-morph@28.0.0", "", { "dependencies": { "@ts-morph/common": "~0.29.0", "code-block-writer": "^13.0.3" } }, "sha512-Wp3tnZ2bzwxyTZMtgWVzXDfm7lB1Drz+y9DmmYH/L702PQhPyVrp3pkou3yIz4qjS14GY9kcpmLiOOMvl8oG1g=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"turndown": ["turndown@7.2.4", "", { "dependencies": { "@mixmark-io/domino": "^2.2.0" } }, "sha512-I8yFsfRzmzK0WV1pNNOA4A7y4RDfFxPRxb3t+e3ui14qSGOxGtiSP6GjeX+Y6CHb7HYaFj7ECUD7VE5kQMZWGQ=="],
"turndown-plugin-gfm": ["turndown-plugin-gfm@1.0.2", "", {}, "sha512-vwz9tfvF7XN/jE0dGoBei3FXWuvll78ohzCZQuOb+ZjWrs3a0XhQVomJEb2Qh4VHTPNRO4GPZh0V7VRbiWwkRg=="],
"typanion": ["typanion@3.14.0", "", {}, "sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug=="],
"type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="],
@@ -1569,12 +1364,6 @@
"typescript": ["typescript@7.0.2", "", { "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" }, "bin": { "tsc": "bin/tsc" } }, "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA=="],
"uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="],
"uhyphen": ["uhyphen@0.2.0", "", {}, "sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA=="],
"underscore": ["underscore@1.13.8", "", {}, "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ=="],
"undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="],
"universal-user-agent": ["universal-user-agent@7.0.3", "", {}, "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A=="],
@@ -1583,8 +1372,6 @@
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
"vali-date": ["vali-date@1.0.0", "", {}, "sha512-sgECfZthyaCKW10N0fm27cg8HYTFK5qMWgypqkXMQ4Wbl/zZKx7xZICgcoxIIE+WFAP/MBL2EFwC/YvLxw3Zeg=="],
"vite": ["vite@8.2.0", "", { "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.5", "postcss": "^8.5.23", "rolldown": "~1.2.0", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.4.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-pn+CFpM0lwDeKwmOq1ZaBK/9sjorZcgqxki6MbY/jPEVd9vichIlmlD4HmQ5wdP5EgqQCFRaACBxMC7uEGc6lQ=="],
"vite-plugin-solid": ["vite-plugin-solid@2.11.14", "", { "dependencies": { "@babel/core": "^7.23.3", "@types/babel__core": "^7.20.4", "babel-preset-solid": "^1.8.4", "merge-anything": "^5.1.7", "solid-refresh": "^0.6.3", "vitefu": "^1.0.4" }, "peerDependencies": { "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.0.0 || ^7.0.0", "solid-js": "^1.7.2", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-7ZVBt8rpoyqmlwin2kRIUveaHoF6/kulY7gsnD+qFh4nS29V4OPAnw+ojoAspXIjObiL9o1xh9a/nTuYHm02Rw=="],
@@ -1593,22 +1380,10 @@
"webdriver-bidi-protocol": ["webdriver-bidi-protocol@0.4.2", "", {}, "sha512-VSV+fzfChirL3e7jay2yUC7B4HQCGtEWEg/MSSQbK+qWbqeGlRLlXTzPpYr3XGUvbpDHumWZBJxgesg4N7dbtA=="],
"winston": ["winston@3.19.0", "", { "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.8", "async": "^3.2.3", "is-stream": "^2.0.0", "logform": "^2.7.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", "winston-transport": "^4.9.0" } }, "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA=="],
"winston-daily-rotate-file": ["winston-daily-rotate-file@5.0.0", "", { "dependencies": { "file-stream-rotator": "^0.6.1", "object-hash": "^3.0.0", "triple-beam": "^1.4.1", "winston-transport": "^4.7.0" }, "peerDependencies": { "winston": "^3" } }, "sha512-JDjiXXkM5qvwY06733vf09I2wnMXpZEhxEVOSPenZMii+g7pcDcTBt2MRugnoi8BwVSuCT2jfRXBUy+n1Zz/Yw=="],
"winston-transport": ["winston-transport@4.9.0", "", { "dependencies": { "logform": "^2.7.0", "readable-stream": "^3.6.2", "triple-beam": "^1.3.0" } }, "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A=="],
"wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="],
"wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="],
"ws": ["ws@8.21.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw=="],
"xml-naming": ["xml-naming@0.3.0", "", {}, "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ=="],
"xmlbuilder": ["xmlbuilder@10.1.1", "", {}, "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg=="],
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
"yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
@@ -1621,14 +1396,12 @@
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
"zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="],
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"@ark/attest/prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
"@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@bufbuild/protoplugin/@typescript/vfs": ["@typescript/vfs@1.6.4", "", { "dependencies": { "debug": "^4.4.3" }, "peerDependencies": { "typescript": "*" } }, "sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ=="],
@@ -1703,62 +1476,30 @@
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"@typescript/analyze-trace/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"@typescript/analyze-trace/yargs": ["yargs@16.2.2", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w=="],
"babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="],
"chromium-bidi/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"cli-progress/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"cliui/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
"color/color-convert": ["color-convert@3.1.3", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg=="],
"color-string/color-name": ["color-name@2.1.1", "", {}, "sha512-p2FdgwVx1a9yWBHP2wI0VgShkDpgN4kZISkxdNipGBJWpa5G6b04OINlVWCyJj0JmfvcPrgqt95E9k8yvaOJFg=="],
"dom-serializer/domelementtype": ["domelementtype@3.0.0", "", {}, "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg=="],
"dom-serializer/entities": ["entities@8.0.0", "", {}, "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA=="],
"domhandler/domelementtype": ["domelementtype@3.0.0", "", {}, "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg=="],
"domutils/domelementtype": ["domelementtype@3.0.0", "", {}, "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg=="],
"fastembed/onnxruntime-node": ["onnxruntime-node@1.21.0", "", { "dependencies": { "global-agent": "^3.0.0", "onnxruntime-common": "1.21.0", "tar": "^7.0.1" }, "os": [ "linux", "win32", "darwin", ] }, "sha512-NeaCX6WW2L8cRCSqy3bInlo5ojjQqu2fD3D+9W5qb5irwxhEyWKXeH2vZ8W9r6VxaMPUan+4/7NDwZMtouZxEw=="],
"fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
"generative-bayesian-network/adm-zip": ["adm-zip@0.6.0", "", {}, "sha512-XleryMhbuksdKtofnWZ9Sk+4CUTbms4Mb/EU32SZwToAyZ5RgVos/ki8n+yr0LWHOGKuakbXTuuYNHLQjhddgg=="],
"htmlparser2/domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="],
"htmlparser2/domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="],
"js-yaml/argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
"jszip/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
"lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
"onnxruntime-web/onnxruntime-common": ["onnxruntime-common@1.24.0-dev.20251116-b39e144322", "", {}, "sha512-BOoomdHYmNRL5r4iQ4bMvsl2t0/hzVQ3OM3PHD0gxeXu1PmggqBv3puZicEUVOA3AtHHYmqZtjMj9FOfGrATTw=="],
"parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
"roarr/sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="],
"string_decoder/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"vite/lightningcss": ["lightningcss@1.33.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.33.0", "lightningcss-darwin-arm64": "1.33.0", "lightningcss-darwin-x64": "1.33.0", "lightningcss-freebsd-x64": "1.33.0", "lightningcss-linux-arm-gnueabihf": "1.33.0", "lightningcss-linux-arm64-gnu": "1.33.0", "lightningcss-linux-arm64-musl": "1.33.0", "lightningcss-linux-x64-gnu": "1.33.0", "lightningcss-linux-x64-musl": "1.33.0", "lightningcss-win32-arm64-msvc": "1.33.0", "lightningcss-win32-x64-msvc": "1.33.0" } }, "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA=="],
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
"wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
"@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"@huggingface/transformers/onnxruntime-node/global-agent": ["global-agent@3.0.0", "", { "dependencies": { "boolean": "^3.0.1", "es6-error": "^4.1.1", "matcher": "^3.0.0", "roarr": "^2.15.3", "semver": "^7.3.2", "serialize-error": "^7.0.1" } }, "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q=="],
"@huggingface/transformers/onnxruntime-node/onnxruntime-common": ["onnxruntime-common@1.24.3", "", {}, "sha512-GeuPZO6U/LBJXvwdaqHbuUmoXiEdeCjWi/EG7Y1HNnDwJYuk6WUbNXpF6luSUY8yASul3cmUlLGrCCL1ZgVXqA=="],
@@ -1785,18 +1526,12 @@
"cliui/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
"color/color-convert/color-name": ["color-name@2.1.1", "", {}, "sha512-p2FdgwVx1a9yWBHP2wI0VgShkDpgN4kZISkxdNipGBJWpa5G6b04OINlVWCyJj0JmfvcPrgqt95E9k8yvaOJFg=="],
"fastembed/onnxruntime-node/global-agent": ["global-agent@3.0.0", "", { "dependencies": { "boolean": "^3.0.1", "es6-error": "^4.1.1", "matcher": "^3.0.0", "roarr": "^2.15.3", "semver": "^7.3.2", "serialize-error": "^7.0.1" } }, "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q=="],
"fastembed/onnxruntime-node/onnxruntime-common": ["onnxruntime-common@1.21.0", "", {}, "sha512-Q632iLLrtCAVOTO65dh2+mNbQir/QNTVBG3h/QdZBpns7mZ0RYbLRBgGABPbpU9351AgYy7SJf1WaeVwMrBFPQ=="],
"fastembed/onnxruntime-node/tar": ["tar@7.5.22", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA=="],
"htmlparser2/domutils/dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="],
"jszip/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
"vite/lightningcss/lightningcss-android-arm64": ["lightningcss-android-arm64@1.33.0", "", { "os": "android", "cpu": "arm64" }, "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg=="],
"vite/lightningcss/lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.33.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg=="],
@@ -1845,8 +1580,6 @@
"fastembed/onnxruntime-node/tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
"htmlparser2/domutils/dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
"@huggingface/transformers/onnxruntime-node/global-agent/serialize-error/type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="],
"@typescript/analyze-trace/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
+4 -5
View File
@@ -44,8 +44,8 @@ Removed in the unified-flow refactor:
- `strict-mode.ts` (merged into `normalize.ts`).
- `sanitize-google.ts` and `normalize-cca.ts` (replaced by
`normalizeSchemaFor*` dispatchers).
- `StringEnum` helper — use `z.enum([...])` directly; Zod's emitted JSON
Schema is already wire-compatible with Google and other providers.
- `StringEnum` helper — use `type.enumerated(...)`; omptype emits
provider-compatible JSON Schema.
- `sanitizeSchemaFor{Google,CCA,MCP}` / `prepareSchemaForCCA` — renamed to
`normalizeSchemaFor{Google,CCA,MCP}`.
@@ -70,9 +70,8 @@ shared Google Claude path.
## Walk semantics
`normalizeSchema` first detoxifies serialized Zod-instance-shaped inputs, upgrades them to
JSON Schema 2020-12, dereferences the tree, then walks it with the option set
pinned by the dispatcher. Each node:
`normalizeSchema` upgrades inputs to JSON Schema 2020-12, dereferences the tree,
then walks it with the option set pinned by the dispatcher. Each node:
1. Renames `snake_case` combinator/property keys to camelCase
(`any_of` → `anyOf`, etc.; collisions follow python-genai
+1 -1
View File
@@ -132,7 +132,7 @@ Supported formats:
Behavior:
- Validates parsed data against a provided Zod schema.
- Validates parsed data against a provided omptype schema.
- Caches load result until `invalidate()`.
- Returns tri-state result via `tryLoad()`:
- `ok`
+5 -6
View File
@@ -70,8 +70,8 @@ const factory: CustomToolFactory = (pi) => ({
name: "repo_stats",
label: "Repo Stats",
description: "Counts tracked TypeScript files",
parameters: pi.arktype({
glob: "string?",
parameters: pi.zod.object({
glob: pi.zod.string().optional(),
}),
async execute(toolCallId, params, onUpdate, ctx, signal) {
@@ -109,7 +109,7 @@ const factory: CustomToolFactory = (pi) => ({
export default factory;
```
Parameter schemas may use ArkType (`pi.arktype`), Zod (`pi.zod`), or the legacy-compatible TypeBox shim (`pi.typebox`); ArkType is preferred for new tools. Schemas flow through the shared validation/wire pipeline.
Parameter schemas may use the Zod-compatible omptype builder (`pi.zod`), native omptype builder (`pi.arktype`), or legacy-compatible TypeBox shim (`pi.typebox`) and flow through the shared validation/wire pipeline.
Factory return type:
@@ -126,9 +126,8 @@ From `types.ts` and `loader.ts`:
- `ui`: UI context (can be no-op in headless modes)
- `hasUI`: `false` in non-interactive flows
- `logger`: shared file logger
- `arktype`: injected ArkType module (preferred for new schemas)
- `arktype`: injected omptype `type(...)` builder
- `typebox`: compatibility shim for legacy TypeBox-style schemas
- `zod`: injected `zod/v4` module
- `pi`: injected `@oh-my-pi/pi-coding-agent` exports
- `pushPendingAction(action)`: stage a preview action that is finalized by writing a plain-text reason to `xd://resolve` or `xd://reject`
@@ -142,7 +141,7 @@ The loader starts with a no-op UI context and requires host code to call `setUIC
execute(toolCallId, params, onUpdate, ctx, signal);
```
- `params` is statically typed from its ArkType, Zod, or TypeBox schema via `Static<TParams>`.
- `params` is statically typed from its omptype or TypeBox schema via `Static<TParams>`.
- Runtime argument validation happens before execution in the agent loop.
- `onUpdate` emits partial results for UI streaming.
- `ctx` includes `sessionManager`, `modelRegistry`, current `model`, `isIdle()`, `hasQueuedMessages()`, `abort()`, and optional `settings`, `fetch`, `localProtocolOptions`, and `autoApprove`.
+6 -6
View File
@@ -70,7 +70,7 @@ Important constraint from `loader.ts`:
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
export default function (pi: ExtensionAPI) {
const { z } = pi.zod;
const z = pi.zod;
pi.setLabel("Safety + Utilities");
@@ -132,9 +132,9 @@ In interactive mode, `input` handlers run before the built-in first-message auto
Also exposed:
- `pi.logger`
- `pi.arktype` (the ArkType `Type` runtime; this is not ArkType's `type(...)` schema builder)
- `pi.zod` (injected `zod/v4` module for Zod-authored tool parameter schemas)
- `pi.typebox` (zod-backed compatibility shim for legacy TypeBox-style schemas)
- `pi.arktype` (the omptype `type(...)` schema builder)
- `pi.zod` (Zod-compatible builder backed by omptype)
- `pi.typebox` (legacy TypeBox-compatible shim)
- `pi.pi` (package exports)
### Message delivery semantics
@@ -302,7 +302,7 @@ Current runtime note: `ExtensionRunner.emitResourcesDiscover(...)` is implemente
## Tool authoring details
`registerTool` uses `ToolDefinition` from `types.ts`. Its `parameters` field accepts ArkType or Zod schemas; the injected TypeBox compatibility shim remains available for legacy extensions.
`registerTool` uses `ToolDefinition` from `types.ts`. Its `parameters` field accepts omptype schemas; the injected TypeBox compatibility shim remains available for legacy extensions.
Current `execute` signature:
@@ -339,7 +339,7 @@ are already approved as, and delegation depth is guarded against accidental self
Template:
```ts
const { z } = pi.zod;
const z = pi.zod;
pi.registerTool({
name: "my_tool",
+1 -1
View File
@@ -48,7 +48,7 @@ The factory can:
- register slash commands via `pi.registerCommand(...)`
- register custom message renderers via `pi.registerMessageRenderer(...)`
- run shell commands via `pi.exec(...)` and log through `pi.logger`
- use injected `pi.zod`, the legacy-compatible `pi.typebox`, and package exports via `pi.pi`; `pi.arktype` is the ArkType `Type` runtime, not the `type(...)` schema builder
- use the injected Zod-compatible builder `pi.zod`, native omptype builder `pi.arktype`, legacy `pi.typebox`, and package exports via `pi.pi`
## Discovery and loading
+8 -25
View File
@@ -4,9 +4,6 @@ Internal schemas use **`@oh-my-pi/omptype`** — an ArkType-compatible validator
with a lazy JIT runtime (`packages/omptype`). Author types with
`import { type } from "@oh-my-pi/omptype"`.
> **Scope rule.** Zod stays supported at the **external boundary** — `Tool.parameters`
> accepts Zod _or_ omptype _or_ JSON Schema, and the public `pi.zod` extension API is
> untouched. Internal schemas use omptype.
## Why omptype (perf contract)
@@ -19,10 +16,9 @@ with a lazy JIT runtime (`packages/omptype`). Author types with
## The detection contract (don't break it)
`packages/ai/src/utils/schema/wire.ts` distinguishes the three schema kinds:
`packages/ai/src/utils/schema/wire.ts` distinguishes two schema kinds:
- **omptype** = a _callable function_ with `.toJsonSchema` and `.assert` methods (`isArkSchema`).
- **Zod** = a non-callable object carrying `_zod` + `.parse` (`isZodSchema`).
- **omptype** = a callable function with `.toJsonSchema` and `.assert` methods (`isArkSchema`).
- **JSON Schema** = a plain object.
At the provider boundary, `toolWireSchema()` calls `toJsonSchema()`, prunes
@@ -80,30 +76,17 @@ if (out instanceof type.errors) {
Note on `.or()` typing: schema and string operands infer precisely;
object-literal operands degrade — wrap them with `type({...})` first.
## Zod → omptype translation (for new code)
| Zod | omptype |
| ---------------------------------- | ----------------------------------------------------------- |
| `z.object({ a: ... })` | `type({ a: ... })` |
| `z.enum(["a","b"])` (static) | `"'a' \| 'b'"` |
| `z.enum(RUNTIME_ARRAY)` | `type.enumerated(...RUNTIME_ARRAY)` |
| `z.record(z.string(), z.number())` | `type({ "[string]": "number" })` |
| `.optional()` | optional key `{ "a?": "string" }` |
| `.strict()` / `.strip()` | `"+": "reject"` / `"+": "delete"` |
| `.refine(fn, msg)` | `.narrow((d, ctx) => fn(d) \|\| ctx.mustBe("<expect>"))` |
| `.transform(fn)` | `.pipe(fn)` |
| `.catch(fallback)` | `type("unknown").pipe(raw => { const out = inner(raw); return out instanceof type.errors ? FALLBACK : out; })` |
| `z.infer<typeof S>` | `typeof S.infer` |
## Adapters
For TypeBox-style or Zod-style authoring backed by the omptype runtime:
TypeBox-style and Zod-style authoring are backed by the omptype runtime:
```ts
import { Type, type Static } from "@oh-my-pi/omptype/typebox";
import { z } from "@oh-my-pi/omptype/zod";
const User = z.object({ name: z.string() });
type User = z.infer<typeof User>;
```
Both produce real omptype schemas (JIT validation, `toJsonSchema`, wire
detection). Use them for extension-facing surfaces; internal code authors
the string DSL directly.
These produce real omptype schemas with JIT validation and `toJsonSchema`.
Internal code authors the string DSL directly.
+1 -1
View File
@@ -364,7 +364,7 @@ Our fork has architectural decisions that differ from upstream. **Do not port th
| ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `jiti` for TypeScript loading | Native Bun `import()` |
| `pkg.pi` manifest field | `pkg.omp` preferred; fallback to `pkg.pi` remains |
| `StringEnum` from `pi-ai` | `Type.Enum` from the `pi.typebox` shim (or author the schema with `pi.zod`); `pi-ai` no longer exports `StringEnum` |
| `StringEnum` from `pi-ai` | `Type.Enum` from `pi.typebox`, or `pi.arktype.enumerated(...)`; `pi-ai` no longer exports `StringEnum` |
| `formatSize` from `pi-coding-agent` | `formatBytes` from `@oh-my-pi/pi-utils` |
| Upstream resource/package/settings managers as the native architecture | Capability-based discovery (`loadCapability(...)`), the `Settings` singleton, and `EventBus`; legacy extension imports of `DefaultResourceLoader`, `DefaultPackageManager`, and `SettingsManager` are compatibility shims in `legacy-pi-coding-agent-shim.ts`, not the native implementation |
+4 -2
View File
@@ -162,7 +162,9 @@ pi.registerCommand("my-cmd", {
## Registering tools
Tools are called by the LLM. Parameter definitions accept ArkType or Zod schemas; `pi.typebox` remains available as a compatibility shim for legacy TypeBox-style extensions. The following example uses the injected `zod/v4` module:
Tools are called by the LLM. Parameter definitions may use the injected
Zod-compatible omptype builder; `pi.arktype` and the legacy-compatible
`pi.typebox` are also available:
```ts
const z = pi.zod;
@@ -173,7 +175,7 @@ pi.registerTool({
description: "Full-text search through project notes",
parameters: z.object({
query: z.string().describe("Search query"),
limit: z.number().default(10).describe("Max results").optional(),
limit: z.number().default(10).optional().describe("Max results"),
}),
async execute(toolCallId, params, signal, onUpdate, ctx) {
if (signal?.aborted) {
+1 -1
View File
@@ -197,7 +197,7 @@ The tool returns one result per call; no streaming partial output is emitted fro
- Network
- CDP attach paths poll `http://127.0.0.1:<port>/json/version` or the supplied `cdp_url` `/json/version`.
- Headless/browser-attach sessions create CDP websocket connections.
- Headless first-use Chromium download uses `@puppeteer/browsers`.
- Headless first-use Chromium download uses the in-house `@oh-my-pi/pi-utils/browsers` installer.
- Loopback relay mode may start the machine-global `omp.browser.relay` daemon. The extension connects outbound to the relay, and Puppeteer connects to its CDP-compatible endpoint.
- User `page` / `tab` operations perform normal browser network traffic.
- Subprocesses / native bindings
+1 -1
View File
@@ -40,7 +40,7 @@ Sources: [`packages/omptype/README.md`](../packages/omptype/README.md), [`packag
- Package: public `@oh-my-pi/omptype`; install with `bun add @oh-my-pi/omptype`; requires Bun 1.3.14 or newer.
- Feature: callable ArkType-compatible schemas with cheap interpreted startup, lazy hot-path compilation, validation errors, defaults and morphs, and JSON Schema emission.
- Public surfaces: `@oh-my-pi/omptype` for native authoring, `@oh-my-pi/omptype/typebox` and `/zod` for compatibility builders, and `/ark` for the alias-free ArkType compatibility facade.
- Public surfaces: `@oh-my-pi/omptype` for native authoring, `/typebox` and `/zod` for compatibility builders, and `/ark` for the alias-free ArkType compatibility facade.
- Runtime behavior: schema calls return the validated value or `type.errors`; `.assert()` returns the value or throws; `.allows()` performs a boolean check.
- Limits: this is an intentionally focused compatibility surface rather than a complete implementation of every ArkType, TypeBox, or Zod API.
+2 -23
View File
@@ -6,8 +6,7 @@
"packageManager": "bun@1.3.14",
"patchedDependencies": {
"@ark/schema@0.56.2": "patches/@ark%2Fschema@0.56.2.patch",
"puppeteer-core@25.3.0": "patches/puppeteer-core@25.3.0.patch",
"@agentclientprotocol/sdk@1.2.1": "patches/@agentclientprotocol%2Fsdk@1.2.1.patch"
"puppeteer-core@25.3.0": "patches/puppeteer-core@25.3.0.patch"
},
"workspaces": {
"packages": [
@@ -15,7 +14,6 @@
"python/robomp/web"
],
"catalog": {
"@agentclientprotocol/sdk": "1.2.1",
"@babel/generator": "^7.29.7",
"@babel/parser": "^7.29.7",
"@babel/traverse": "^7.29.7",
@@ -24,7 +22,6 @@
"@bufbuild/protobuf": "^2.12.1",
"@bufbuild/protoc-gen-es": "^2.12.1",
"@huggingface/transformers": "^4.2.0",
"@mozilla/readability": "^0.6.0",
"@napi-rs/cli": "3.7.2",
"@oh-my-pi/hashline": "17.2.9",
"@oh-my-pi/omp-stats": "17.2.9",
@@ -50,7 +47,6 @@
"@opentelemetry/sdk-metrics": "^2.9.0",
"@opentelemetry/sdk-trace-base": "^2.9.0",
"@opentelemetry/sdk-trace-node": "^2.9.0",
"@puppeteer/browsers": "^3.0.6",
"@tailwindcss/node": "^4.3.2",
"@tailwindcss/vite": "^4.3.2",
"@types/babel__generator": "^7.27.0",
@@ -58,25 +54,13 @@
"@types/bun": "^1.3.14",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@types/turndown": "5.0.6",
"@typescript/native-preview": "7.0.0-dev.20260707.2",
"@xterm/headless": "^6.0.0",
"chalk": "^5.6.2",
"chart.js": "^4.5.1",
"date-fns": "^4.4.0",
"diff": "^9.0.0",
"fflate": "0.8.3",
"fastembed": "2.1.0",
"fast-xml-parser": "^5.9.3",
"ghostty-web": "^0.4.0",
"handlebars": "^4.7.9",
"header-generator": "^2.1.82",
"linkedom": "^0.18.13",
"lint-staged": "^17.0.8",
"lru-cache": "11.5.2",
"lucide-react": "^1.24.0",
"mammoth": "^1.12.0",
"marked": "^18.0.6",
"mupdf": "^1.28.0",
"onnxruntime-node": "1.26.0",
"postcss": "^8.5.16",
@@ -89,14 +73,9 @@
"solid-js": "^1.9.14",
"tailwindcss": "^4.3.2",
"ts-morph": "^28.0.0",
"turndown": "7.2.4",
"turndown-plugin-gfm": "1.0.2",
"typescript": "^7.0.2",
"vite": "^8.1.4",
"vite-plugin-solid": "^2.11.12",
"winston": "^3.19.0",
"winston-daily-rotate-file": "5.0.0",
"zod": "^4"
"vite-plugin-solid": "^2.11.12"
}
},
"overrides": {
+4 -4
View File
@@ -279,17 +279,17 @@ const agent = new Agent({
## Tools
Define tools using `AgentTool` with a Zod parameter schema (via `z` from `@oh-my-pi/pi-ai`).
Define tools using `AgentTool` with an omptype parameter schema.
```typescript
import { z } from "@oh-my-pi/pi-ai";
import { type } from "@oh-my-pi/omptype";
const readFileTool: AgentTool = {
name: "read_file",
label: "Read File", // For UI display
description: "Read a file's contents",
parameters: z.object({
path: z.string().describe("File path"),
parameters: type({
path: type("string").describe("File path"),
}),
execute: async (toolCallId, params, signal, onUpdate, context) => {
const content = await fs.readFile(params.path, "utf-8");
@@ -1,5 +1,6 @@
import { describe, expect, it, mock } from "bun:test";
import { type AssistantMessage, type Context, z } from "@oh-my-pi/pi-ai";
import { type } from "@oh-my-pi/omptype";
import type { AssistantMessage, Context } from "@oh-my-pi/pi-ai";
import { createMockModel } from "@oh-my-pi/pi-ai/providers/mock";
import { AssistantMessageEventStream } from "@oh-my-pi/pi-ai/utils/event-stream";
import { buildModel } from "@oh-my-pi/pi-catalog/build";
@@ -59,7 +60,7 @@ describe("Agent — buildSideRequestContext", () => {
name: "test_tool",
label: "Test Tool",
description: "a cool tool",
parameters: z.object({ arg: z.string() }) as unknown as AgentTool["parameters"],
parameters: type({ arg: type("string") }) as unknown as AgentTool["parameters"],
execute: async () => ({ content: [{ type: "text", text: "success" }], details: { value: "success" } }),
};
+11 -10
View File
@@ -1,6 +1,7 @@
import { describe, expect, it } from "bun:test";
import { type } from "@oh-my-pi/omptype";
import { Agent, AgentBusyError, type AgentEvent, type AgentTool, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
import { type SimpleStreamOptions, type ToolResultMessage, z } from "@oh-my-pi/pi-ai";
import type { SimpleStreamOptions, ToolResultMessage } from "@oh-my-pi/pi-ai";
import { createMockModel } from "@oh-my-pi/pi-ai/providers/mock";
import { kCursorExecResolved } from "@oh-my-pi/pi-ai/utils/block-symbols";
import { AssistantMessageEventStream } from "@oh-my-pi/pi-ai/utils/event-stream";
@@ -18,7 +19,7 @@ describe("Agent", () => {
});
it("classifies agent-authored steering as a parent steering message", async () => {
const toolSchema = z.object({ value: z.string() });
const toolSchema = type({ value: type("string") });
const executed: string[] = [];
let agent: Agent;
const tool: AgentTool<typeof toolSchema, { value: string }> = {
@@ -81,7 +82,7 @@ describe("Agent", () => {
});
it("classifies user-attributed custom steering as a queued user message", async () => {
const toolSchema = z.object({ value: z.string() });
const toolSchema = type({ value: type("string") });
const executed: string[] = [];
let agent: Agent;
const tool: AgentTool<typeof toolSchema, { value: string }> = {
@@ -165,7 +166,7 @@ describe("Agent", () => {
];
for (const scenario of cases) {
const toolSchema = z.object({ value: z.string() });
const toolSchema = type({ value: type("string") });
const executed: string[] = [];
let agent: Agent;
const tool: AgentTool<typeof toolSchema, { value: string }> = {
@@ -1036,7 +1037,7 @@ describe("Agent", () => {
});
it("prompt() refreshes tools and system prompt between same-turn model calls", async () => {
const toolSchema = z.object({ value: z.string() });
const toolSchema = type({ value: type("string") });
type Details = { value: string };
const betaTool: AgentTool<typeof toolSchema, Details> = {
@@ -1101,7 +1102,7 @@ describe("Agent", () => {
});
it("prompt() drops stale forced toolChoice after same-turn tool refresh", async () => {
const toolSchema = z.object({ value: z.string() });
const toolSchema = type({ value: type("string") });
type Details = { value: string };
const betaTool: AgentTool<typeof toolSchema, Details> = {
@@ -1159,7 +1160,7 @@ describe("Agent", () => {
});
it("drops queued forced toolChoice when the queued tool is not active", async () => {
const toolSchema = z.object({ value: z.string() });
const toolSchema = type({ value: type("string") });
type Details = { value: string };
const betaTool: AgentTool<typeof toolSchema, Details> = {
@@ -1191,7 +1192,7 @@ describe("Agent", () => {
});
it("re-reads thinking level for each model call within a run", async () => {
const toolSchema = z.object({ value: z.string() });
const toolSchema = type({ value: type("string") });
type Details = { value: string };
const alphaTool: AgentTool<typeof toolSchema, Details> = {
name: "alpha",
@@ -1252,7 +1253,7 @@ describe("Agent", () => {
});
it("re-reads disableReasoning for each model call within a run", async () => {
const toolSchema = z.object({ value: z.string() });
const toolSchema = type({ value: type("string") });
type Details = { value: string };
const alphaTool: AgentTool<typeof toolSchema, Details> = {
name: "alpha",
@@ -1344,7 +1345,7 @@ describe("Agent", () => {
});
it("re-reads cwd from cwdResolver for each model call within a run (a /move mid-run is seen)", async () => {
const toolSchema = z.object({ value: z.string() });
const toolSchema = type({ value: type("string") });
type Details = { value: string };
const alphaTool: AgentTool<typeof toolSchema, Details> = {
name: "alpha",
+3 -2
View File
@@ -1,10 +1,11 @@
import { afterEach, describe, expect, test, vi } from "bun:test";
import { type } from "@oh-my-pi/omptype";
import type { AgentMessage, AgentTool } from "@oh-my-pi/pi-agent-core";
import { generateHandoff, generateHandoffFromContext, renderHandoffPrompt } from "@oh-my-pi/pi-agent-core/compaction";
import { ThinkingLevel } from "@oh-my-pi/pi-agent-core/thinking";
import type { AssistantMessage, Model, ToolCall } from "@oh-my-pi/pi-ai";
import * as ai from "@oh-my-pi/pi-ai";
import { Effort, z } from "@oh-my-pi/pi-ai";
import { Effort } from "@oh-my-pi/pi-ai";
import { getBundledModel } from "@oh-my-pi/pi-catalog/models";
function createAssistantMessage(content: AssistantMessage["content"]): AssistantMessage {
@@ -36,7 +37,7 @@ function createAssistantError(errorStatus: number, errorMessage: string): Assist
};
}
const handoffToolSchema = z.object({ note: z.string().optional() });
const handoffToolSchema = type({ note: type("string").optional() });
function createHandoffTool(): AgentTool<typeof handoffToolSchema> {
return {
+6 -6
View File
@@ -6,6 +6,7 @@
* lifecycle hook dispatch.
*/
import { afterAll, afterEach, beforeAll, describe, expect, it } from "bun:test";
import { type } from "@oh-my-pi/omptype";
import { agentLoop } from "@oh-my-pi/pi-agent-core/agent-loop";
import {
type AgentTelemetryConfig,
@@ -23,7 +24,6 @@ import {
} from "@oh-my-pi/pi-agent-core/telemetry";
import type { AgentContext, AgentEvent, AgentLoopConfig, AgentMessage, AgentTool } from "@oh-my-pi/pi-agent-core/types";
import type { Message } from "@oh-my-pi/pi-ai";
import { z } from "@oh-my-pi/pi-ai";
import { createMockModel } from "@oh-my-pi/pi-ai/providers/mock";
import type { EventStream } from "@oh-my-pi/pi-ai/utils/event-stream";
import { context, SpanStatusCode, trace } from "@opentelemetry/api";
@@ -218,7 +218,7 @@ describe("agent-loop OTEL instrumentation", () => {
convertToLlm: identityConverter,
telemetry: {},
};
const alphaSchema = z.object({ value: z.string() });
const alphaSchema = type({ value: type("string") });
const alphaTool: AgentTool<typeof alphaSchema> = {
name: "alpha",
label: "Alpha",
@@ -263,7 +263,7 @@ describe("agent-loop OTEL instrumentation", () => {
convertToLlm: identityConverter,
telemetry: {},
};
const probeSchema = z.object({ value: z.string() });
const probeSchema = type({ value: type("string") });
const probeTool: AgentTool<typeof probeSchema> = {
name: "probe",
label: "Probe",
@@ -299,7 +299,7 @@ describe("agent-loop OTEL instrumentation", () => {
convertToLlm: identityConverter,
telemetry: {},
};
const failSchema = z.object({ value: z.string() });
const failSchema = type({ value: type("string") });
const failTool: AgentTool<typeof failSchema> = {
name: "fail",
label: "Fail",
@@ -694,7 +694,7 @@ describe("agent-loop OTEL instrumentation", () => {
onSpanEnd: ctx => ends.push(ctx),
},
};
const echoSchema = z.object({ value: z.string() });
const echoSchema = type({ value: type("string") });
const echoTool: AgentTool<typeof echoSchema> = {
name: "echo",
label: "Echo",
@@ -797,7 +797,7 @@ describe("agent-loop OTEL instrumentation", () => {
convertToLlm: identityConverter,
telemetry: cfg,
};
const echoSchema = z.object({ value: z.string() });
const echoSchema = type({ value: type("string") });
const tool: AgentTool<typeof echoSchema> = {
name: "echo",
label: "Echo",
+7 -7
View File
@@ -7,6 +7,7 @@
*/
import { describe, expect, it } from "bun:test";
import { type } from "@oh-my-pi/omptype";
import { agentLoop, agentLoopDetailed } from "@oh-my-pi/pi-agent-core/agent-loop";
import {
type AgentRunSummary,
@@ -18,7 +19,6 @@ import {
import { EXECUTE_TOOL_STATUS_ATTR, GenAIAttr, PiGenAIAggregateAttr } from "@oh-my-pi/pi-agent-core/telemetry";
import type { AgentEvent, AgentLoopConfig, AgentMessage, AgentTool } from "@oh-my-pi/pi-agent-core/types";
import type { AssistantMessage, Message } from "@oh-my-pi/pi-ai";
import { z } from "@oh-my-pi/pi-ai";
import { createMockModel } from "@oh-my-pi/pi-ai/providers/mock";
import type {
AttributeValue,
@@ -132,7 +132,7 @@ function buildTool(spec: TestTool): AgentTool {
name: spec.name,
label: spec.name,
description: `test tool ${spec.name}`,
parameters: z.object({ value: z.string().optional() }),
parameters: type({ value: type("string").optional() }),
intent: "omit",
execute: async () => {
if (spec.behavior === "throw") throw new Error(`${spec.name} boom`);
@@ -145,7 +145,7 @@ function buildTool(spec: TestTool): AgentTool {
name: spec.name,
label: spec.name,
description: `blocked tool ${spec.name}`,
parameters: z.object({ value: z.string().optional() }),
parameters: type({ value: type("string").optional() }),
intent: "omit",
execute: async () => ({ content: [{ type: "text", text: "should not run" }], details: {} }),
} satisfies AgentTool;
@@ -545,7 +545,7 @@ describe("skipped tools without spans", () => {
name: "fast",
label: "fast",
description: "fast",
parameters: z.object({ value: z.string().optional() }),
parameters: type({ value: type("string").optional() }),
intent: "omit",
execute: async () => {
fastDone = true;
@@ -556,7 +556,7 @@ describe("skipped tools without spans", () => {
name: "slow",
label: "slow",
description: "slow",
parameters: z.object({ value: z.string().optional() }),
parameters: type({ value: type("string").optional() }),
intent: "omit",
// concurrency: shared (default) — both run in parallel. Interruptible:
// queued steering hard-aborts only interruptible waits; non-interruptible
@@ -636,7 +636,7 @@ describe("regressions: agent loop telemetry/run summary", () => {
name: "fast",
label: "fast",
description: "fast",
parameters: z.object({ value: z.string().optional() }),
parameters: type({ value: type("string").optional() }),
intent: "omit",
concurrency: "exclusive",
execute: async () => {
@@ -762,7 +762,7 @@ describe("regressions: agent loop telemetry/run summary", () => {
name: "cyclic",
label: "cyclic",
description: "returns cyclic details",
parameters: z.object({ value: z.string().optional() }),
parameters: type({ value: type("string").optional() }),
intent: "omit",
execute: async () => ({
content: [{ type: "text", text: "ok" }],
+3
View File
@@ -2,6 +2,9 @@
## [Unreleased]
### Breaking Changes
- Removed the `zod` dependency and the `z`/`ZodType` re-exports; tool schemas are omptype `type()` schemas, with zod-style authoring still available via `@oh-my-pi/omptype/zod`
## [17.2.9] - 2026-08-05
### Fixed
+15 -19
View File
@@ -94,21 +94,18 @@ npm install @oh-my-pi/pi-ai
## Quick Start
```typescript
import { z, getModel, stream, complete, Context, Tool } from "@oh-my-pi/pi-ai";
import { getModel, stream, complete, Context, Tool, type } from "@oh-my-pi/pi-ai";
// Fully typed with auto-complete support for both providers and models
const model = getModel("openai", "gpt-4o-mini");
// Define tools with Zod schemas for type safety and validation
// Define tools with omptype schemas for type safety and validation
const tools: Tool[] = [
{
name: "get_time",
description: "Get the current time",
parameters: z.object({
timezone: z
.string()
.optional()
.describe("Optional timezone (e.g., America/New_York)"),
parameters: type({
"timezone?": type("string").describe("Optional timezone (e.g., America/New_York)"),
}),
},
];
@@ -221,31 +218,30 @@ for (const block of response.content) {
## Tools
Tools enable LLMs to interact with external systems. This library uses **Zod** schemas for type-safe tool definitions with automatic validation. Schemas are converted to JSON Schema for providers as needed.
Tools enable LLMs to interact with external systems. Omptype schemas provide type-safe definitions, runtime validation, and JSON Schema conversion for providers.
### Defining Tools
```typescript
import { z, Tool } from "@oh-my-pi/pi-ai";
import { type Tool, type } from "@oh-my-pi/pi-ai";
// Define tool parameters with Zod
const weatherTool: Tool = {
name: "get_weather",
description: "Get current weather for a location",
parameters: z.object({
location: z.string().describe("City name or coordinates"),
units: z.enum(["celsius", "fahrenheit"]).default("celsius"),
parameters: type({
location: type("string").describe("City name or coordinates"),
units: type.enumerated("celsius", "fahrenheit").default("celsius"),
}),
};
const bookMeetingTool: Tool = {
name: "book_meeting",
description: "Schedule a meeting",
parameters: z.object({
title: z.string().min(1),
startTime: z.string().describe("ISO 8601 date-time"),
endTime: z.string().describe("ISO 8601 date-time"),
attendees: z.array(z.email()).min(1),
parameters: type({
title: type("string").atLeastLength(1),
startTime: type("string").describe("ISO 8601 date-time"),
endTime: type("string").describe("ISO 8601 date-time"),
attendees: type("string.email").array().atLeastLength(1),
}),
};
```
@@ -345,7 +341,7 @@ for await (const event of s) {
### Validating Tool Arguments
When using `agentLoop`, tool arguments are automatically validated against your Zod parameter schemas before execution. If validation fails, the error is returned to the model as a tool result, allowing it to retry.
When using `agentLoop`, tool arguments are automatically validated against their omptype schemas before execution. Validation failures are returned to the model as tool results so it can retry.
When implementing your own tool execution loop with `stream()` or `complete()`, use `validateToolCall` to validate arguments before passing them to your tools:
+1 -2
View File
@@ -41,8 +41,7 @@
"@oh-my-pi/omptype": "catalog:",
"@oh-my-pi/pi-catalog": "catalog:",
"@oh-my-pi/pi-utils": "catalog:",
"@oh-my-pi/pi-wire": "catalog:",
"zod": "catalog:"
"@oh-my-pi/pi-wire": "catalog:"
},
"devDependencies": {
"@bufbuild/protoc-gen-es": "catalog:",
-1
View File
@@ -1,5 +1,4 @@
export { type Type, type } from "@oh-my-pi/omptype";
export { type ZodType, z } from "zod/v4";
export * from "./api-registry";
export type * from "./auth-broker";
export type { AuthGatewayBootOptions, ModelResolver } from "./auth-gateway/server";
+4 -11
View File
@@ -36,7 +36,6 @@ import type {
import type { Effort } from "@oh-my-pi/pi-catalog/effort";
import { isOpenAIModelId } from "@oh-my-pi/pi-catalog/identity/family";
import type { Api, FetchImpl, KnownApi, Model, Provider, ThinkingBudgets, Usage } from "@oh-my-pi/pi-catalog/types";
import type { ZodType, z } from "zod/v4";
import type { ApiKey } from "./auth-retry";
import type { BedrockOptions } from "./providers/amazon-bedrock";
import type { AnthropicOptions } from "./providers/anthropic";
@@ -1140,19 +1139,13 @@ export type TJsonSchema = Record<string, unknown>;
/**
* Schema type accepted by the {@link Tool} interface.
*
* Canonical authoring uses Zod or ArkType. Extension compat may supply a JSON
* Schema object (including TypeBox static schema objects).
* Canonical authoring uses ArkType. Extension compat may supply a JSON Schema
* object (including TypeBox static schema objects).
*/
export type TSchema = ZodType | Type | TJsonSchema;
export type TSchema = Type | TJsonSchema;
/** Resolve parameter types for tool execution / handlers. */
export type Static<S> = S extends ZodType
? z.infer<S>
: S extends Type
? S["infer"]
: S extends { static: infer T }
? T
: unknown;
export type Static<S> = S extends Type ? S["infer"] : S extends { static: infer T } ? T : unknown;
export interface ToolCallExample<TArgs = Record<string, unknown>> {
caption?: string;
-1
View File
@@ -12,4 +12,3 @@ export * from "./strict-tool-validation";
export * from "./types";
export * from "./typescript";
export * from "./wire";
export * from "./zod-decontaminate";
+1 -3
View File
@@ -24,7 +24,6 @@ import { isValidJsonSchema } from "./meta-validator";
import { type DescriptionSpillFormat, spillToDescription } from "./spill";
import { enter, epochNext, exit, once, stamp } from "./stamps";
import { isJsonObject, isJsonObjectEmpty, type JsonObject } from "./types";
import { decontaminateZodInstance } from "./zod-decontaminate";
export type ResidualSchemaIncompatibility = "type-array" | "type-null" | "nullable" | "combiners" | "not";
@@ -1069,8 +1068,7 @@ function hasResidualSchemaIncompatibilities(
}
export function normalizeSchema(value: unknown, options: NormalizeSchemaOptions): unknown {
const detoxified = decontaminateZodInstance(value);
const upgraded = upgradeJsonSchemaTo202012(detoxified);
const upgraded = upgradeJsonSchemaTo202012(value);
const dereferenced = dereferenceJsonSchema(upgraded);
let normalized = normalizeSchemaNode(dereferenced, {
...options,
+17 -144
View File
@@ -1,62 +1,21 @@
/**
* Compute the wire (JSON Schema) representation of a tool's parameters.
*
* Tools may author parameters in three shapes:
* 1. Zod (canonical) — converted to JSON Schema on demand.
* 2. ArkType — converted to JSON Schema via its native `toJsonSchema`.
* 3. TypeBox / plain JSON Schema (legacy + extension compat) — upgraded to
* draft 2020-12 without converting.
*
* All three are normalized at the boundary so providers and validators see the same
* JSON Schema dialect.
* Tools may author parameters as ArkType schemas or legacy TypeBox / plain JSON
* Schema documents. Both are normalized at the boundary so providers and
* validators see the same JSON Schema dialect.
*/
import type { Type } from "@oh-my-pi/omptype";
// We import the Zod *value* (z) for runtime APIs. Marker checks rely on the
// `_zod` symbol that every Zod v4 schema instance carries.
import { type ZodType, z } from "zod/v4";
import type { Tool, TSchema } from "../../types";
import { upgradeJsonSchemaTo202012 } from "./draft";
import { stamp } from "./stamps";
/**
* True when `value` is a live Zod schema instance.
*
* The check is stricter than "has a `_zod` property" because a JSON
* round-trip preserves the `_zod` key as a plain object and would otherwise
* fool the predicate — see issue #1101, where MCP servers ship
* `JSON.stringify(zodSchemaInstance)` as a tool's `inputSchema` and the
* resulting plain object then explodes `z.toJSONSchema` because the prototype
* (and every Zod parsing method) is gone.
*
* Live Zod instances always carry a `.parse` function on the prototype;
* impostors do not.
*/
export function isZodSchema(value: unknown): value is ZodType {
return (
typeof value === "object" &&
value !== null &&
// Zod v4 instances expose a `_zod` internal property with a `def` object.
// Tagging on this marker keeps the check stable across Zod minor versions.
// (`_zod` is part of Zod's documented internal contract used by introspection.)
// We avoid checking constructor name because Zod ships multiple variants
// (`ZodObject`, `ZodOptional`, etc.) and a tagged-union style check would
// have to enumerate them all.
"_zod" in value &&
typeof (value as { _zod?: { def?: unknown } })._zod === "object" &&
// Reject JSON-roundtripped objects that kept the `_zod` key but lost the
// prototype. Real instances have `.parse` on the prototype chain.
typeof (value as { parse?: unknown }).parse === "function"
);
}
/**
* True when `value` is a live ArkType schema instance.
*
* ArkType schemas are callable functions carrying `toJsonSchema`/`assert`
* methods. Zod v4 instances are non-callable objects (keyed off `_zod`), and
* raw JSON Schema is a plain object — the three are disjoint. We deliberately
* avoid the Standard Schema `~standard` marker because Zod v4 implements it too.
* methods, while raw JSON Schema is a plain object.
*/
export function isArkSchema(value: unknown): value is Type {
return (
@@ -149,41 +108,17 @@ function arkJsonAstToWire(value: unknown): unknown {
}
/** Symbol-stamped caches keyed by schema object identity. */
const kZodWireSchema = Symbol("pi.schema.zod.wire");
const kJsonWireSchema = Symbol("pi.schema.json.wire");
const kArkWireSchema = Symbol("pi.schema.ark.wire");
const kStrippedSchema = Symbol("pi.schema.descriptions.stripped");
/**
* Post-process Zod-emitted JSON Schema so it matches the wire shape providers
* already expect from TypeBox-authored tools:
*
* - Drop the `$schema` URL (providers parse the body, not the metadata).
* - Make fields with a `default` non-required (TypeBox/JSON-Schema semantics
* treat defaulted fields as optional; Zod inverts this and keeps them
* required at the input boundary, then materializes the default).
* - Strip the noisy safe-integer bounds Zod injects for `z.number().int()`.
*
* The empty-schema normalization (`{}` → `true`, see `normalizeEmptySchemas`)
* runs separately from `toolWireSchema` so both Zod and TypeBox tools get it.
*/
function postProcess(schema: Record<string, unknown>): Record<string, unknown> {
delete schema.$schema;
walk(schema, true);
normalizeArkPropertyComments(schema);
normalizeEmptySchemas(schema);
return schema;
}
function postProcessJsonSchema(schema: Record<string, unknown>): Record<string, unknown> {
walk(schema, false);
walk(schema);
normalizeArkPropertyComments(schema);
normalizeEmptySchemas(schema);
return schema;
}
const SAFE_INTEGER_MAX = Number.MAX_SAFE_INTEGER;
const SAFE_INTEGER_MIN = Number.MIN_SAFE_INTEGER;
const NULLABLE_SCALAR_TYPES = new Set(["string", "number", "integer", "boolean"]);
const SCHEMA_DEFINING_SIBLING_KEYS = new Set([
@@ -226,11 +161,6 @@ function isNullVariant(schema: Record<string, unknown>): boolean {
function isScalarVariant(schema: Record<string, unknown>): schema is Record<string, unknown> & { type: string } {
return typeof schema.type === "string" && NULLABLE_SCALAR_TYPES.has(schema.type);
}
function hasIntegerType(type: unknown): boolean {
return type === "integer" || (Array.isArray(type) && type.includes("integer"));
}
function copyNullableScalarConstraints(schema: Record<string, unknown>, scalarVariant: Record<string, unknown>): void {
for (const key in scalarVariant) {
if (key === "type" || key === "enum" || key === "const" || Object.hasOwn(schema, key)) continue;
@@ -455,9 +385,9 @@ function collapseConstUnionAnyOf(obj: Record<string, unknown>): void {
}
}
function walk(node: unknown, zodCleanup: boolean): void {
function walk(node: unknown): void {
if (Array.isArray(node)) {
for (const child of node) walk(child, zodCleanup);
for (const child of node) walk(child);
return;
}
if (!node || typeof node !== "object") return;
@@ -465,48 +395,16 @@ function walk(node: unknown, zodCleanup: boolean): void {
rewriteNullableScalarAnyOf(obj);
inferBareEnumScalarType(obj);
collapseConstUnionAnyOf(obj);
if (zodCleanup) {
// Drop noise injected for `z.number().int()`.
if (hasIntegerType(obj.type)) {
if (obj.minimum === SAFE_INTEGER_MIN) delete obj.minimum;
if (obj.maximum === SAFE_INTEGER_MAX) delete obj.maximum;
}
// Make defaulted properties non-required.
if (Array.isArray(obj.required) && obj.properties && typeof obj.properties === "object") {
const properties = obj.properties as Record<string, unknown>;
const required = obj.required as string[];
const filtered = required.filter(name => {
const propertySchema = properties[name];
if (!propertySchema || typeof propertySchema !== "object") return true;
return !("default" in (propertySchema as Record<string, unknown>));
});
if (filtered.length !== required.length) {
if (filtered.length === 0) {
delete obj.required;
} else {
obj.required = filtered;
}
}
}
}
for (const k in obj) walk(obj[k], zodCleanup);
for (const k in obj) walk(obj[k]);
}
/**
* Normalize `{}` (empty JSON Schema = `z.unknown()` / unconstrained value) to
* boolean `true` in every schema-valued position. JSON Schema draft 2020-12
* §4.3.1: `{}` and `true` are semantically equivalent ("any JSON value").
* Grammar-constrained samplers (llama.cpp, etc.) treat the object form as
* "generate an empty object" rather than "any JSON value", causing open-typed
* fields like `extra.title` (from `z.record(z.string(), z.unknown())`) to
* always emit `{}` instead of the intended string/number/etc. (issue #1179).
* Normalize `{}` (an unconstrained schema) to boolean `true` in every
* schema-valued position. JSON Schema draft 2020-12 §4.3.1 defines them as
* semantically equivalent. Grammar-constrained samplers often treat the object
* form as "generate an empty object" rather than "any JSON value".
*
* Mutates in place. Provider-agnostic — applied to every tool wire schema so
* Anthropic, Google, OpenAI, Ollama, Bedrock, and Cursor all see the
* normalized form, regardless of whether the source was Zod or TypeBox.
* Mutates in place and applies to every tool wire schema.
*/
export function normalizeEmptySchemas(node: unknown): void {
if (Array.isArray(node)) {
@@ -539,23 +437,10 @@ export function normalizeEmptySchemas(node: unknown): void {
for (const k in obj) normalizeEmptySchemas(obj[k]);
}
/** Convert a Zod schema into the JSON Schema shape providers consume. */
export function zodToWireSchema(schema: ZodType): Record<string, unknown> {
return stamp(schema, kZodWireSchema, s => {
// `target: "draft-2020-12"` matches what Anthropic's `input_schema` validator
// requires out of the box; our other provider sanitizers (OpenAI strict,
// Google, Anthropic CCA) already handle the superset structurally.
const raw = z.toJSONSchema(s, { target: "draft-2020-12" }) as Record<string, unknown>;
return postProcess(raw);
});
}
/**
* Recursively set `additionalProperties: false` on declared object nodes so the
* model-facing wire matches Zod's closed emission. Only nodes that declare
* `properties` and carry neither `additionalProperties` nor `patternProperties`
* are closed — open record/index nodes (which already carry one of those, e.g.
* `additionalProperties: true` after empty-schema normalization) stay open.
* model-facing wire is closed. Only nodes that declare `properties` and carry
* neither `additionalProperties` nor `patternProperties` are closed.
*
* Traverses only schema-valued positions via the shared traversal-key constants
* so it never descends into `default`/`examples`/`enum`/`const` instance data.
@@ -665,14 +550,6 @@ function pruneArkUndefinedUnionBranches(node: unknown): void {
/**
* Convert an ArkType schema into the JSON Schema shape providers consume.
*
* Mirrors {@link zodToWireSchema}: emit draft-2020-12, drop the `$schema`
* metadata, run the JSON-schema post-process (NOT the Zod-only cleanup), then
* close declared objects so the wire is `additionalProperties: false` like Zod.
*
* The `fallback` degrades any un-emittable node (a `.narrow()` predicate or a
* morph) to its underlying base schema instead of throwing — matching Zod,
* whose `.refine()`/`.transform()` likewise never appear in the wire schema.
*/
export function arkToWireSchema(schema: Type): Record<string, unknown> {
return stamp(schema, kArkWireSchema, s => {
@@ -687,16 +564,12 @@ export function arkToWireSchema(schema: Type): Record<string, unknown> {
/**
* Resolve a tool's parameters to a JSON Schema object suitable for sending
* over the wire. Zod schemas are converted (and cached); legacy TypeBox / raw
* JSON Schema parameters are upgraded to draft 2020-12 (and cached).
*
* Zod schemas also receive Zod-artifact cleanup; both branches normalize
* schema-valued positions and nullable scalar unions.
* over the wire. ArkType schemas are converted and cached; legacy TypeBox /
* raw JSON Schema parameters are upgraded to draft 2020-12 and cached.
*/
export function toolWireSchema(tool: Tool): Record<string, unknown> {
const params: TSchema = tool.parameters;
if (isArkSchema(params)) return arkToWireSchema(params);
if (isZodSchema(params)) return zodToWireSchema(params);
return stamp(params as Record<string, unknown>, kJsonWireSchema, p => {
const raw = isArkJsonAst(p) ? arkJsonAstToWire(p) : p;
const upgraded = upgradeJsonSchemaTo202012(raw) as Record<string, unknown>;
@@ -1,331 +0,0 @@
/**
* Defensive rewrite for nodes that look like `JSON.stringify(zodSchemaInstance)`
* output rather than JSON Schema. MCP servers using Zod 4 sometimes ship a
* serialised schema instance directly as a tool's `inputSchema`, because the
* fields Zod surfaces on its instances (`type`, `enum`, `options`, `def`) shadow
* (and clash with) JSON Schema keywords. The resulting payload is neither valid
* Zod nor valid JSON Schema 2020-12 and Anthropic's strict validator rejects
* the whole tool list.
*
* Symptoms we've observed (gitnexus_impact.direction):
* {
* def: { type: "enum", entries: { upstream: "upstream", ... } },
* type: "enum", // <- invalid `type` value
* enum: { upstream: "upstream", ... }, // <- `enum` MUST be an array
* options: ["upstream", "downstream"],
* }
*
* This module recognises the shape (`def.type === node.type` and `def.type` is
* a known Zod kind) and rewrites it to clean JSON Schema where deterministic.
* For Zod kinds we don't fully model, we strip the toxic siblings (`def`,
* `options`, object-shaped `enum`) and drop an invalid `type` so the remainder
* passes meta-schema validation as a permissive node.
*
* Pure / identity-preserving: returns the input reference when nothing changes.
*/
import { isJsonObject, type JsonObject } from "./types";
const VALID_JSON_SCHEMA_TYPES: Record<string, true> = {
string: true,
number: true,
integer: true,
boolean: true,
object: true,
array: true,
null: true,
};
/**
* Known Zod 4 schema kinds as surfaced on `_def.type` / `.type`. Matching this
* set (rather than just "has `def`") is what keeps us from rewriting legitimate
* JSON Schemas that happen to use `def` as a property name.
*/
const ZOD_KINDS: Record<string, true> = {
string: true,
number: true,
int: true,
boolean: true,
bigint: true,
null: true,
undefined: true,
void: true,
any: true,
unknown: true,
never: true,
date: true,
symbol: true,
nan: true,
enum: true,
literal: true,
object: true,
array: true,
tuple: true,
record: true,
map: true,
set: true,
union: true,
discriminatedUnion: true,
intersection: true,
lazy: true,
promise: true,
function: true,
file: true,
custom: true,
template_literal: true,
optional: true,
nullable: true,
default: true,
prefault: true,
catch: true,
pipe: true,
transform: true,
brand: true,
readonly: true,
success: true,
nonoptional: true,
};
const ZOD_SCALAR_TO_JSON_TYPE: Record<string, string> = {
string: "string",
number: "number",
int: "integer",
boolean: "boolean",
null: "null",
bigint: "string",
date: "string",
nan: "number",
};
const ZOD_NOISE_KEYS: Record<string, true> = {
def: true,
options: true,
_zod: true,
checks: true,
};
/**
* JSON Schema keywords where `null` is a legal value (literal payload positions).
* Anywhere else, a `null`-valued key is a meta-schema violation — Zod scalars
* leak `format: null`, `minLength: null`, etc. that we have to scrub.
*/
const KEYS_THAT_ACCEPT_NULL: Record<string, true> = {
default: true,
const: true,
examples: true,
};
function isZodLeak(node: JsonObject): boolean {
const def = node.def;
if (!isJsonObject(def)) return false;
const defType = def.type;
if (typeof defType !== "string" || !ZOD_KINDS[defType]) return false;
// Both surface and inner `.type` must agree — Zod always mirrors `_def.type`
// onto the instance, so this is a near-zero false-positive guard.
return node.type === defType;
}
function inferTypeFromValues(values: readonly unknown[]): string {
if (values.length === 0) return "string";
const first = values[0];
if (typeof first === "number") return Number.isInteger(first) ? "integer" : "number";
if (typeof first === "boolean") return "boolean";
if (first === null) return "null";
return "string";
}
function unwrapInnerSchema(def: JsonObject): unknown {
// Zod uses different fields depending on the wrapper:
// optional/nullable/readonly/brand/default → `innerType`
// pipe → `in` (or `out`)
// lazy → `getter` (a function — gone after JSON.stringify); fall back to {}
return def.innerType ?? def.in ?? def.out ?? def.schema ?? def.element ?? {};
}
function copyWithoutNoise(node: JsonObject): JsonObject {
const out: JsonObject = {};
for (const key in node) {
if (ZOD_NOISE_KEYS[key]) continue;
const value = node[key];
if (value === null && !KEYS_THAT_ACCEPT_NULL[key]) continue;
out[key] = value;
}
return out;
}
function rewriteZodNode(node: JsonObject, seen: WeakSet<object>): unknown {
const def = node.def as JsonObject;
const kind = def.type as string;
switch (kind) {
case "enum": {
// Prefer node.options (array form Zod exposes) → def.entries values →
// object-shaped node.enum values. All three carry the same data.
const optionsArray = Array.isArray(node.options) ? (node.options as unknown[]) : null;
const entries = isJsonObject(def.entries) ? Object.values(def.entries) : null;
const enumObj = isJsonObject(node.enum) ? Object.values(node.enum) : null;
const values = optionsArray ?? entries ?? enumObj ?? [];
return { type: inferTypeFromValues(values), enum: values };
}
case "literal": {
const values = Array.isArray(def.values) ? (def.values as unknown[]) : [];
if (values.length === 1) {
return { const: values[0] };
}
if (values.length > 1) {
return { type: inferTypeFromValues(values), enum: values };
}
return {};
}
case "union":
case "discriminatedUnion": {
const arms = Array.isArray(def.options)
? (def.options as unknown[])
: Array.isArray(node.options)
? (node.options as unknown[])
: [];
return { anyOf: arms.map(x => walk(x, seen)) };
}
case "intersection": {
return {
allOf: [walk(def.left, seen), walk(def.right, seen)],
};
}
case "array": {
return { type: "array", items: walk(def.element, seen) };
}
case "set": {
const element = def.valueType ?? def.element;
return { type: "array", uniqueItems: true, items: walk(element, seen) };
}
case "tuple": {
const items = Array.isArray(def.items) ? (def.items as unknown[]) : [];
const out: JsonObject = { type: "array", prefixItems: items.map(x => walk(x, seen)) };
const rest = def.rest;
if (rest != null) out.items = walk(rest, seen);
return out;
}
case "record":
case "map": {
return { type: "object", additionalProperties: walk(def.valueType, seen) };
}
case "object": {
const shape = isJsonObject(def.shape) ? def.shape : ({} as JsonObject);
const properties: JsonObject = {};
const required: string[] = [];
for (const key in shape) {
const inner = walk(shape[key], seen);
properties[key] = inner;
if (!isOptionalEntry(shape[key])) required.push(key);
}
const out: JsonObject = { type: "object", properties };
if (required.length > 0) out.required = required;
return out;
}
case "nonoptional":
case "optional":
case "nullable":
case "default":
case "prefault":
case "catch":
case "readonly":
case "brand":
case "lazy":
case "pipe":
case "transform": {
const inner = walk(unwrapInnerSchema(def), seen);
if (kind === "nullable" && isJsonObject(inner)) {
if (typeof inner.type === "string") {
return { ...inner, type: [inner.type, "null"] };
}
if (Array.isArray(inner.type)) {
return (inner.type as string[]).includes("null")
? inner
: { ...inner, type: [...(inner.type as string[]), "null"] };
}
// anyOf / allOf / $ref shapes — no scalar `type` field
return { anyOf: [inner, { type: "null" }] };
}
return inner;
}
default: {
// Best-effort: drop the noise, map the kind to a JSON Schema type if
// we know one, otherwise drop `type` so the node validates as
// permissive.
const cleaned = copyWithoutNoise(node);
const mapped = ZOD_SCALAR_TO_JSON_TYPE[kind];
if (mapped) {
cleaned.type = mapped;
} else if (typeof cleaned.type === "string" && !VALID_JSON_SCHEMA_TYPES[cleaned.type]) {
delete cleaned.type;
}
// Object-shaped `enum` survives as a noise field — remove if present.
if (cleaned.enum !== undefined && !Array.isArray(cleaned.enum)) {
delete cleaned.enum;
}
return cleaned;
}
}
}
function isOptionalEntry(value: unknown): boolean {
if (!isJsonObject(value)) return false;
if (!isZodLeak(value)) return false;
const kind = (value.def as JsonObject).type;
return kind === "optional" || kind === "default" || kind === "prefault";
}
/**
* Walks a JSON value and rewrites every Zod-instance-shaped node into clean
* JSON Schema 2020-12. Identity-preserving when no rewrite fires. Tolerates
* self-referential graphs — a revisited node returns as-is.
*/
export function decontaminateZodInstance(value: unknown): unknown {
return walk(value, new WeakSet());
}
function walk(value: unknown, seen: WeakSet<object>): unknown {
if (Array.isArray(value)) {
if (seen.has(value)) return value;
seen.add(value);
let changed = false;
const out = value.map(entry => {
const rewritten = walk(entry, seen);
if (rewritten !== entry) changed = true;
return rewritten;
});
return changed ? out : value;
}
if (!isJsonObject(value)) return value;
if (seen.has(value)) return value;
seen.add(value);
if (isZodLeak(value)) {
// Rewrite the node itself, then recurse into the rewrite so any nested
// Zod-instance children get cleaned in the same pass.
const rewritten = rewriteZodNode(value, seen);
return rewritten === value ? value : walk(rewritten, seen);
}
// Plain JSON Schema node: recurse into children, preserving identity when
// nothing under us changed.
let changed = false;
const out: JsonObject = {};
for (const key in value) {
const child = value[key];
const rewritten = walk(child, seen);
if (rewritten !== child) changed = true;
out[key] = rewritten;
}
return changed ? out : value;
}
+24 -153
View File
@@ -1,22 +1,10 @@
/**
* Tool-call argument validation pipeline.
*
* Tools may declare their parameters as either Zod schemas (canonical) or
* plain JSON Schema (legacy / extensions). This module is the single
* entrypoint the agent calls before dispatching a tool — it:
*
* 1. Builds (or fetches from cache) a `ValidationContext` for the tool —
* the Zod schema if available plus the equivalent wire JSON Schema, or
* just the JSON Schema for non-Zod tools.
* 2. Normalizes LLM quirks (null / "null" → omit-or-default substitution)
* against the JSON Schema before validation.
* 3. Validates with the Zod or JSON-Schema validator.
* 4. On failure, walks the resulting issues and coerces common LLM type
* drift (JSON-stringified values, boolean/number/string scalar drift),
* drops unrecognized keys, and retries up to `MAX_COERCION_PASSES` times.
* 5. Throws a formatted error if reconciliation fails; otherwise returns
* the parsed arguments with original unknown root fields preserved (so
* hallucinated top-level keys still surface to the caller).
* Tools may declare ArkType schemas or plain JSON Schema. This module builds a
* cached validation context, normalizes common LLM quirks against the wire
* schema, validates, performs conservative schema-directed coercions, and
* returns parsed arguments while preserving unknown root fields.
*
* The goal is to be conservative: every coercion is a structural rewrite that
* keeps the schema in charge of acceptance — we never invent values, only
@@ -25,8 +13,6 @@
import { type Type, type } from "@oh-my-pi/omptype";
import { structuredCloneJSON } from "@oh-my-pi/pi-utils";
import type { ZodType } from "zod/v4";
import type { $ZodIssue as ZodIssue } from "zod/v4/core";
import * as AIError from "../error";
import type { Tool, ToolCall } from "../types";
import { upgradeJsonSchemaTo202012 } from "./schema/draft";
@@ -36,7 +22,7 @@ import {
validateJsonSchemaValue,
} from "./schema/json-schema-validator";
import { stamp } from "./schema/stamps";
import { arkToWireSchema, isArkSchema, isZodSchema, zodToWireSchema } from "./schema/wire";
import { arkToWireSchema, isArkSchema } from "./schema/wire";
// ============================================================================
// Type Coercion Utilities
@@ -47,12 +33,8 @@ import { arkToWireSchema, isArkSchema, isZodSchema, zodToWireSchema } from "./sc
// `"[1, 2, 3]"`, a boolean as `"yes"` or `1`, or a string field as a structured
// object that should be embedded verbatim.
//
// Rather than rejecting these outright, we attempt automatic coercion:
// 1. Validate against the tool's schema (Zod, derived from TypeBox when the
// tool was authored with TypeBox).
// 2. For each type error, perform only the schema-directed rewrite that
// matches the expected type.
// 3. Re-validate the full argument object after each coercion pass.
// Rather than rejecting these outright, validate against the declared schema
// and perform only schema-directed rewrites for reported type errors.
//
// This is intentionally conservative: each rewrite is small and validation
// remains the source of truth for whether the result is accepted.
@@ -528,13 +510,11 @@ function tryParseJsonForTypes(value: string, expectedTypes: string[], depth = 0)
// JSON Pointer Utilities (RFC 6901)
// ============================================================================
//
// Internally we still address error locations using JSON Pointer syntax
// (e.g., `/foo/0/bar`). These utilities let coercion read and write values at
// those paths regardless of whether the original error came from Zod or
// from JSON-Schema-shaped normalization.
// Error locations use JSON Pointer syntax so coercion can read and write
// validator-reported paths uniformly.
// ============================================================================
/** Encode a structured Zod issue path as a JSON Pointer. */
/** Encode a structured issue path as a JSON Pointer. */
function pathToPointer(path: ReadonlyArray<PropertyKey>): string {
if (path.length === 0) return "";
return `/${path.map(seg => String(seg).replace(/~/g, "~0").replace(/\//g, "~1")).join("/")}`;
@@ -814,11 +794,8 @@ function normalizeOptionalNullsForSchema(
// with non-null unknown values are left intact so genuine schema mistakes
// still surface as validation errors.
//
// At the ROOT level we deliberately keep unknown null-valued keys intact:
// Zod-emitted wire schemas always set `additionalProperties: false`, but the
// post-validation `preserveUnknownRootFields` pass re-attaches root extras
// so callers can observe (and reject) hallucinated fields. Stripping here
// would erase the field before that snapshot, hiding the rejection signal.
// At the root level unknown null-valued keys stay intact; the
// post-validation `preserveUnknownRootFields` pass re-attaches root extras.
if (!isRoot && schemaObject.additionalProperties === false) {
const knownKeys = new Set(Object.keys(properties));
for (const key of Object.keys(nextValue)) {
@@ -1049,9 +1026,8 @@ function trimIdentifierStringLeaf(input: unknown): unknown {
/**
* Recursively strip trailing line terminators from string values whose property
* key matches {@link IDENTIFIER_STRING_KEYS}. Runs by property name only
* (schema-agnostic) so it fires uniformly across Zod, ArkType, and plain JSON
* Schema tools while preserving nested payloads under content-carrying keys.
* key matches {@link IDENTIFIER_STRING_KEYS}. Runs by property name only so it
* fires uniformly across ArkType and plain JSON Schema tools.
*/
function normalizeIdentifierStringWhitespace(value: unknown): { value: unknown; changed: boolean } {
if (Array.isArray(value)) {
@@ -1254,12 +1230,9 @@ function parsedArrayMatchesArrayBranch(schema: Record<string, unknown>, value: u
/**
* Pre-validation normalization: when a schema field accepts BOTH `string` and
* `array`, providers that double-serialize tool arguments (e.g. Z.AI / GLM)
* deliver array values as JSON-encoded strings like `'["a","b"]'`. Zod's
* `union([string, array])` happily accepts that string against the string
* branch, so the type-error driven coercion in {@link coerceArgsFromIssues}
* never fires, and downstream tools treat the literal `["a","b"]` as a path
* (silently producing zero matches or glob parse errors).
* `array`, providers that double-serialize tool arguments can deliver array
* values as JSON-encoded strings like `'["a","b"]'`. A string-or-array union
* accepts that value against the string branch before issue-driven coercion.
*
* Walk the schema; when both shapes are accepted AND the incoming value is a
* JSON-array-shaped string, substitute the parsed array only if it validates
@@ -1387,9 +1360,7 @@ function normalizeSingleStringField(schema: unknown, value: unknown): { value: u
return { value, changed: false };
}
// ============================================================================
// Zod issue → coercion bridge
// ============================================================================
// Validation issue → coercion bridge
interface FlatIssue {
keyword: "type" | "unrecognized" | "other";
@@ -1398,81 +1369,6 @@ interface FlatIssue {
unionBranch: boolean;
}
/**
* Translate the Zod expected-type marker into the JSON-Schema type name our
* coercion helpers already understand.
*/
function mapZodExpectedToJsonSchemaType(expected: unknown): string | null {
if (typeof expected !== "string") return null;
switch (expected) {
case "string":
case "number":
case "boolean":
case "array":
case "object":
case "null":
return expected;
case "record":
return "object";
case "int":
case "bigint":
return "integer";
case "nan":
return "number";
default:
return null;
}
}
/**
* Flatten Zod issues into a list of (path, expected-types) records suitable
* for the coercion pass. Recurses through `invalid_union` so each inner
* candidate produces independent coercion attempts.
*/
function flattenIssues(issues: ReadonlyArray<ZodIssue>): FlatIssue[] {
const out: FlatIssue[] = [];
const walk = (issue: ZodIssue, prefix: ReadonlyArray<PropertyKey>, unionBranch: boolean): void => {
const fullPath = prefix.length === 0 ? issue.path : [...prefix, ...issue.path];
if (issue.code === "invalid_type") {
const mapped = mapZodExpectedToJsonSchemaType((issue as { expected?: unknown }).expected);
if (mapped) {
out.push({ keyword: "type", instancePath: pathToPointer(fullPath), expectedTypes: [mapped], unionBranch });
return;
}
}
if (issue.code === "unrecognized_keys") {
const keys = (issue as { keys?: ReadonlyArray<string> }).keys ?? [];
for (const key of keys) {
out.push({
keyword: "unrecognized",
instancePath: pathToPointer([...fullPath, key]),
expectedTypes: [],
unionBranch,
});
}
return;
}
if (issue.code === "invalid_union") {
const inner = (issue as unknown as { errors?: ReadonlyArray<ReadonlyArray<ZodIssue>> }).errors;
if (inner) {
// A union-branch issue only competes with a sibling branch when it
// sits at the union node's own path. Issues whose own path is
// non-empty live on a deeper field that an already-identified
// branch owns, so the singleton-array repair should still apply.
for (const branch of inner) {
for (const child of branch) {
walk(child, fullPath, child.path.length === 0);
}
}
}
return;
}
out.push({ keyword: "other", instancePath: pathToPointer(fullPath), expectedTypes: [], unionBranch });
};
for (const issue of issues) walk(issue, [], false);
return out;
}
/**
* Repair issues raised by the validator before we surface them to the caller.
*
@@ -1482,11 +1378,9 @@ function flattenIssues(issues: ReadonlyArray<ZodIssue>): FlatIssue[] {
* accept boolean spellings, stringify non-null values for string fields,
* map booleans to numeric 0/1, and wrap singleton array values for non-union
* array expectations.
* - **unrecognized**: when a strict object received an extra key (Zod's
* `unrecognized_keys` or JSON Schema's `additionalProperties: false`),
* drop that key so re-validation succeeds. This effectively coerces every
* object schema to loose semantics recursively without rebuilding the
* underlying Zod tree.
* - **unrecognized**: when a closed object received an extra key
* (`additionalProperties: false`), drop that key so re-validation succeeds.
* This effectively coerces object schemas to loose semantics recursively.
*
* The function is safe and conservative:
* - Only processes "type" and "unrecognized" issues
@@ -1551,11 +1445,6 @@ function coerceArgsFromIssues(args: unknown, issues: FlatIssue[]): { value: unkn
// ============================================================================
type ValidationContext =
| {
kind: "zod";
zod: ZodType;
json: Record<string, unknown>;
}
| {
kind: "arktype";
ark: Type;
@@ -1577,8 +1466,6 @@ function getValidationContext(tool: Tool): ValidationContext {
return stamp(tool.parameters as object, kValidationContext, params =>
isArkSchema(params)
? { kind: "arktype", ark: params, json: arkToWireSchema(params) }
: isZodSchema(params)
? { kind: "zod", zod: params, json: zodToWireSchema(params) }
: { kind: "json", json: upgradeJsonSchemaTo202012(params) as Record<string, unknown> },
);
}
@@ -1621,18 +1508,6 @@ function formatIssuePath(path: ReadonlyArray<PropertyKey>): string {
}
function validateContext(ctx: ValidationContext, value: unknown): ContextValidationResult {
if (ctx.kind === "zod") {
const result = ctx.zod.safeParse(value);
if (result.success) {
return { success: true, value: preserveUnknownRootFields(value, result.data) };
}
return {
success: false,
flatIssues: flattenIssues(result.error.issues),
messages: result.error.issues.map(issue => ` - ${formatIssuePath(issue.path)}: ${issue.message}`),
};
}
if (ctx.kind === "arktype") {
const out = ctx.ark(value);
if (!(out instanceof type.errors)) {
@@ -1850,10 +1725,8 @@ function truncateArgsForError(value: unknown): unknown {
}
/**
* Validates tool call arguments against the tool's schema (Zod or plain JSON
* Schema). Applies LLM-quirk coercions (numeric strings, JSON-string
* containers, null/invalid-empty-string-for-optional, null-for-default) before
* declaring failure.
* Validates tool call arguments against an ArkType or plain JSON Schema schema.
* Applies conservative LLM-quirk normalization before declaring failure.
*
* @throws Error with a formatted message when validation cannot be reconciled.
*/
@@ -1916,9 +1789,7 @@ export function validateToolArguments(tool: Tool, toolCall: ToolCall): ToolCall[
}
// Then re-shape JSON-stringified arrays whose schema accepts both string
// and array (e.g. `paths: string | string[]`). Without this, zod accepts
// the literal `'["a","b"]'` as a string and downstream tools treat it as
// a single path with embedded glob brackets — silent zero results.
// and array. Otherwise downstream tools receive the encoded string.
const stringEncodedArrayNorm = normalizeStringEncodedArrayUnions(json, normalizedArgs);
if (stringEncodedArrayNorm.changed) {
normalizedArgs = stringEncodedArrayNorm.value;
@@ -2,6 +2,7 @@ import { afterAll, beforeAll, describe, expect, it } from "bun:test";
import * as fs from "node:fs/promises";
import * as os from "node:os";
import * as path from "node:path";
import { type } from "@oh-my-pi/omptype";
import { isContextOverflow } from "@oh-my-pi/pi-ai/error";
import {
buildGitLabDuoWorkflowApprovalStartRequest,
@@ -41,7 +42,6 @@ import type {
import { AssistantMessageEventStream } from "@oh-my-pi/pi-ai/utils/event-stream";
import { buildModel } from "@oh-my-pi/pi-catalog/build";
import { extractHttpStatusFromError } from "@oh-my-pi/pi-utils";
import { z } from "zod/v4";
beforeAll(() => configureCredentialRedaction(true));
afterAll(() => configureCredentialRedaction(false));
@@ -67,13 +67,13 @@ const context: Context = {
const editTool: Tool = {
name: "edit",
description: "Apply a hashline patch.",
parameters: z.object({ input: z.string() }),
parameters: type({ input: type("string") }),
};
const nativeTools: Tool[] = ["read", "write", "grep", "glob", "bash", "lsp", "todo"].map(name => ({
name,
description: `${name} native bridge`,
parameters: z.object({}),
parameters: type({}),
}));
function restoreOptionalEnv(name: string, value: string | undefined): void {
+3 -3
View File
@@ -1,13 +1,13 @@
import { describe, expect, it } from "bun:test";
import { type } from "@oh-my-pi/omptype";
import { complete } from "@oh-my-pi/pi-ai/stream";
import type { Api, AssistantMessage, Context, Message, Model, Tool, ToolResultMessage } from "@oh-my-pi/pi-ai/types";
import { getBundledModel } from "@oh-my-pi/pi-catalog/models";
import { z } from "zod/v4";
import { e2eApiKey } from "./oauth";
// Tool for testing
const weatherSchema = z.object({
location: z.string().describe("City name"),
const weatherSchema = type({
location: type("string").describe("City name"),
});
const weatherTool: Tool<typeof weatherSchema> = {
+3 -3
View File
@@ -1,11 +1,11 @@
import { describe, expect, it } from "bun:test";
import * as fs from "node:fs/promises";
import * as path from "node:path";
import { type } from "@oh-my-pi/omptype";
import type { Api, Context, Model, Tool, ToolResultMessage } from "@oh-my-pi/pi-ai";
import { complete } from "@oh-my-pi/pi-ai";
import type { OptionsForApi } from "@oh-my-pi/pi-ai/types";
import { getBundledModel } from "@oh-my-pi/pi-catalog/models";
import { z } from "zod/v4";
import { e2eApiKey, resolveApiKey } from "./oauth";
// Resolve OAuth tokens at module level (async, runs before tests)
@@ -38,7 +38,7 @@ async function handleToolWithImageResult<TApi extends Api>(model: Model<TApi>, o
const base64Image = imageBuffer.toBase64();
// Define a tool that returns only an image (no text)
const getImageSchema = z.object({});
const getImageSchema = type({});
const getImageTool: Tool<typeof getImageSchema> = {
name: "get_circle",
description: "Returns a circle image for visualization",
@@ -126,7 +126,7 @@ async function handleToolWithTextAndImageResult<TApi extends Api>(model: Model<T
const base64Image = imageBuffer.toBase64();
// Define a tool that returns both text and an image
const getImageSchema = z.object({});
const getImageSchema = type({});
const getImageTool: Tool<typeof getImageSchema> = {
name: "get_circle_with_description",
description: "Returns a circle image with a text description",
+4 -4
View File
@@ -1,4 +1,5 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "bun:test";
import { type } from "@oh-my-pi/omptype";
import { streamAzureOpenAIResponses } from "@oh-my-pi/pi-ai/providers/azure-openai-responses";
import { streamOpenAICodexResponses } from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
import { streamOpenAICompletions } from "@oh-my-pi/pi-ai/providers/openai-completions";
@@ -6,7 +7,6 @@ import { streamOpenAIResponses } from "@oh-my-pi/pi-ai/providers/openai-response
import type { Context, Model, Tool, ToolChoice } from "@oh-my-pi/pi-ai/types";
import { buildModel } from "@oh-my-pi/pi-catalog/build";
import * as piUtils from "@oh-my-pi/pi-utils";
import { z } from "zod/v4";
const TEST_INSTALLATION_ID = "00000000-0000-4000-8000-000000000001";
@@ -73,19 +73,19 @@ const codexModel: Model<"openai-codex-responses"> = buildModel({
const forkAgentTool: Tool = {
name: "fork_agent",
description: "Fork a subagent",
parameters: z.object({ prompt: z.string() }),
parameters: type({ prompt: type("string") }),
};
const searchTool: Tool = {
name: "dataforseo_search",
description: "Search via DataForSEO",
parameters: z.object({ query: z.string() }),
parameters: type({ query: type("string") }),
};
const todoTool: Tool = {
name: "todo",
description: "Manage a phased task list",
parameters: z.object({ ops: z.array(z.object({ op: z.string() })) }),
parameters: type({ ops: type.array(type({ op: type("string") })) }),
};
const absentTodoContext: Context = {
+2 -2
View File
@@ -1,9 +1,9 @@
import { afterAll, beforeAll, describe, expect, it } from "bun:test";
import { type } from "@oh-my-pi/omptype";
import { streamBedrock } from "@oh-my-pi/pi-ai/providers/amazon-bedrock";
import { crc32 } from "@oh-my-pi/pi-ai/providers/aws-eventstream";
import type { Context, FetchImpl, Model, Tool } from "@oh-my-pi/pi-ai/types";
import { buildModel } from "@oh-my-pi/pi-catalog/build";
import { z } from "zod/v4";
const originalSkipAuth = process.env.AWS_BEDROCK_SKIP_AUTH;
@@ -195,7 +195,7 @@ describe("issue #3124 — Bedrock /btw with tool history", () => {
const userTool: Tool = {
name: "__no_tools__",
description: "Caller-registered tool that collides with the sentinel name.",
parameters: z.object({ query: z.string() }),
parameters: type({ query: type("string") }),
};
const context: Context = {
messages: [{ role: "user", content: "Use my tool", timestamp: 0 }],
+3 -3
View File
@@ -1,9 +1,9 @@
import { describe, expect, it } from "bun:test";
import { type } from "@oh-my-pi/omptype";
import { streamOpenAICompletions } from "@oh-my-pi/pi-ai/providers/openai-completions";
import { streamOpenAIResponses } from "@oh-my-pi/pi-ai/providers/openai-responses";
import type { Context, Model, ModelSpec, Tool, ToolChoice } from "@oh-my-pi/pi-ai/types";
import { buildModel } from "@oh-my-pi/pi-catalog/build";
import { z } from "zod/v4";
interface ChatCompletionsPayload {
tool_choice?: unknown;
@@ -18,13 +18,13 @@ interface ResponsesPayload {
const resolveTool: Tool = {
name: "resolve",
description: "Apply or discard a pending preview",
parameters: z.object({ action: z.enum(["apply", "discard"]), reason: z.string() }),
parameters: type({ action: type.enumeration(["apply", "discard"]), reason: type("string") }),
};
const todoTool: Tool = {
name: "todo",
description: "Track work items",
parameters: z.object({ note: z.string() }),
parameters: type({ note: type("string") }),
};
const multiToolContext: Context = {
@@ -1,6 +1,6 @@
import { describe, expect, it } from "bun:test";
import { type } from "@oh-my-pi/omptype";
import { jsonSchemaToTypeScript, toolWireSchema } from "@oh-my-pi/pi-ai/utils/schema";
import { z } from "zod/v4";
describe("jsonSchemaToTypeScript", () => {
it("renders objects with optional markers and JSDoc descriptions", () => {
@@ -99,9 +99,9 @@ describe("jsonSchemaToTypeScript", () => {
});
it("converts a Zod schema through the wire pipeline", () => {
const parameters = z.object({
name: z.string().describe("the name"),
count: z.number().int().optional(),
const parameters = type({
name: type("string").describe("the name"),
count: type("number.integer").optional(),
});
const ts = jsonSchemaToTypeScript(toolWireSchema({ name: "t", description: "", parameters }));
expect(ts).toContain("/** the name */");
+9 -11
View File
@@ -3,7 +3,6 @@ import { type } from "@oh-my-pi/omptype";
import type { Tool } from "@oh-my-pi/pi-ai/types";
import { isArkSchema, toolWireSchema } from "@oh-my-pi/pi-ai/utils/schema";
import { validateToolArguments } from "@oh-my-pi/pi-ai/utils/validation";
import { z } from "zod/v4";
// ---------------------------------------------------------------------------
// Phase-1 parity gate: ArkType schemas must flow through the same wire-emission
@@ -36,8 +35,7 @@ describe("isArkSchema", () => {
expect(isArkSchema(type("string"))).toBe(true);
});
it("rejects Zod schemas, JSON Schema objects, and non-objects", () => {
expect(isArkSchema(z.object({ a: z.string() }))).toBe(false);
it("rejects JSON Schema objects and non-objects", () => {
expect(isArkSchema({ type: "object", properties: {} })).toBe(false);
expect(isArkSchema(null)).toBe(false);
expect(isArkSchema(undefined)).toBe(false);
@@ -75,10 +73,10 @@ describe("arkToWireSchema — emission", () => {
const zodTwin: Tool = {
name: "zod-plain",
description: "",
parameters: z.object({
name: z.string().describe("the display name"),
count: z.number().describe("how many items"),
nested: z.object({ inner: z.string().describe("inner value") }).describe("a nested object"),
parameters: type({
name: type("string").describe("the display name"),
count: type("number").describe("how many items"),
nested: type({ inner: type("string").describe("inner value") }).describe("a nested object"),
}),
};
// Normalize key + array ordering (semantically irrelevant to JSON Schema).
@@ -160,10 +158,10 @@ describe("validateToolArguments — ArkType contracts", () => {
const zodTwin: Tool = {
name: "zod-plain",
description: "",
parameters: z.object({
name: z.string(),
count: z.number(),
nested: z.object({ inner: z.string() }),
parameters: type({
name: type("string"),
count: type("number"),
nested: type({ inner: type("string") }),
}),
};
const zodResult = validateToolArguments(zodTwin, {
+2 -84
View File
@@ -461,91 +461,9 @@ describe("normalizeSchemaForMCP", () => {
});
});
// Regression: issue #1101. Some MCP servers ship `JSON.stringify(zodSchema)`
// directly as a tool's `inputSchema`. Zod 4 surfaces `.type`, `.enum`,
// `.options`, and `.def` on every schema instance — those keys collide with
// JSON Schema keywords, producing payloads that fail Anthropic's strict
// JSON Schema 2020-12 validator (`"type":"enum"`, `"enum":{...}` as object).
// `normalizeSchemaForMCP` must rewrite the offending nodes into clean JSON
// Schema so the tool list still ships.
it("rewrites a Zod-enum instance leaked as inputSchema", () => {
const leaked = {
def: { type: "enum", entries: { upstream: "upstream", downstream: "downstream" } },
type: "enum",
enum: { upstream: "upstream", downstream: "downstream" },
options: ["upstream", "downstream"],
};
expect(normalizeSchemaForMCP(leaked)).toEqual({
type: "string",
enum: ["upstream", "downstream"],
});
});
it("rewrites a numeric Zod-enum (integer values keep integer type)", () => {
const leaked = {
def: { type: "enum", entries: { ONE: 1, TWO: 2 } },
type: "enum",
enum: { ONE: 1, TWO: 2 },
options: [1, 2],
};
expect(normalizeSchemaForMCP(leaked)).toEqual({
type: "integer",
enum: [1, 2],
});
});
it("rewrites a Zod-literal instance to a single-element enum", () => {
const leaked = {
def: { type: "literal", values: ["only"] },
type: "literal",
values: ["only"],
};
// Decontamination emits `{const:"only"}`; downstream normalizer collapses
// it to the equivalent enum form. End-to-end contract is what callers see.
expect(normalizeSchemaForMCP(leaked)).toEqual({ type: "string", enum: ["only"] });
});
it("rewrites a Zod-union of literals (downstream collapses anyOf-of-consts to enum)", () => {
const leaked = {
def: {
type: "union",
options: [
{ def: { type: "literal", values: ["on"] }, type: "literal", values: ["on"] },
{ def: { type: "literal", values: ["off"] }, type: "literal", values: ["off"] },
],
},
type: "union",
};
expect(normalizeSchemaForMCP(leaked)).toEqual({
type: "string",
enum: ["on", "off"],
});
});
it("strips null-valued JSON Schema keywords that Zod scalars leak (format: null, minLength: null)", () => {
const leaked = {
def: { type: "string", checks: [] },
type: "string",
format: null,
minLength: null,
maxLength: null,
};
expect(normalizeSchemaForMCP(leaked)).toEqual({ type: "string" });
});
it("drops invalid `type` for unmodelled Zod kinds so the residue stays valid", () => {
const leaked = {
def: { type: "any" },
type: "any",
description: "anything",
};
expect(normalizeSchemaForMCP(leaked)).toEqual({ description: "anything" });
});
it("leaves a genuine JSON Schema that happens to have a `def` property alone", () => {
// `def` is not a JSON Schema keyword but it's also not reserved. The
// detoxifier must only fire when `def.type` is a known Zod kind AND
// `node.type === def.type`, otherwise it would corrupt real schemas.
// `def` is not a JSON Schema keyword, so normalization must not corrupt
// schemas that use it as an ordinary property name.
const schema = {
type: "object",
properties: { def: { type: "string" } },
+31 -31
View File
@@ -1,7 +1,9 @@
import { describe, expect, it } from "bun:test";
import { type } from "@oh-my-pi/omptype";
import type { Tool, ToolCall } from "@oh-my-pi/pi-ai/types";
import {
adaptSchemaForStrict,
arkToWireSchema,
enforceStrictSchema,
isJsonSchemaValueValid,
isValidJsonSchema,
@@ -9,10 +11,8 @@ import {
sanitizeSchemaForStrictMode,
toolWireSchema,
tryEnforceStrictSchema,
zodToWireSchema,
} from "@oh-my-pi/pi-ai/utils/schema";
import { validateToolArguments } from "@oh-my-pi/pi-ai/utils/validation";
import { z } from "zod/v4";
describe("sanitizeSchemaForStrictMode", () => {
it("infers object type, strips non-structural keywords, and converts const to enum", () => {
@@ -490,10 +490,10 @@ describe("sanitizeSchemaForStrictMode", () => {
describe("enforceStrictSchema", () => {
it("converts optional properties to nullable schemas and requires all object keys", () => {
const schema = zodToWireSchema(
z.object({
requiredText: z.string(),
optionalCount: z.number().optional(),
const schema = arkToWireSchema(
type({
requiredText: type("string"),
optionalCount: type("number").optional(),
}),
);
@@ -507,9 +507,9 @@ describe("enforceStrictSchema", () => {
});
it("flattens optional union schemas instead of nesting anyOf wrappers", () => {
const schema = zodToWireSchema(
z.object({
paths: z.union([z.string(), z.array(z.string())]).optional(),
const schema = arkToWireSchema(
type({
paths: type.union([type("string"), type("string").array()]).optional(),
}),
);
@@ -588,12 +588,12 @@ describe("enforceStrictSchema", () => {
});
it("never emits undefined as a schema type", () => {
const schema = zodToWireSchema(
z.object({
questions: z.array(
z.object({
id: z.string(),
recommended: z.number().optional(),
const schema = arkToWireSchema(
type({
questions: type.array(
type({
id: type("string"),
recommended: type("number").optional(),
}),
),
}),
@@ -794,22 +794,22 @@ describe("tryEnforceStrictSchema", () => {
});
it("keeps shared object schemas strict-compatible after adaptation", () => {
const sharedTaskSchema = z.object({
content: z.string(),
status: z.string().optional(),
notes: z.string().optional(),
const sharedTaskSchema = type({
content: type("string"),
status: type("string").optional(),
notes: type("string").optional(),
});
const schema = zodToWireSchema(
z.object({
ops: z.array(
z.union([
z.object({
op: z.literal("replace"),
tasks: z.array(sharedTaskSchema),
const schema = arkToWireSchema(
type({
ops: type.array(
type.union([
type({
op: type.unit("replace"),
tasks: type.array(sharedTaskSchema),
}),
z.object({
op: z.literal("update"),
tasks: z.array(sharedTaskSchema).optional(),
type({
op: type.unit("update"),
tasks: type.array(sharedTaskSchema).optional(),
}),
]),
),
@@ -1005,7 +1005,7 @@ describe("Zod root extras preserved through normalize", () => {
const tool: Tool = {
name: "simple_tool",
description: "",
parameters: z.object({ assignment: z.string() }),
parameters: type({ assignment: type("string") }),
};
const toolCall: ToolCall = {
type: "toolCall",
@@ -1029,7 +1029,7 @@ describe("adaptSchemaForStrict — unrepresentable open branches fall back to no
const wire = toolWireSchema({
name: "t",
description: "d",
parameters: z.object({ a: z.string(), meta: z.unknown() }),
parameters: type({ a: type("string"), meta: type("unknown") }),
} as Tool);
expect((wire.properties as Record<string, unknown>).meta).toBe(true);
expect(adaptSchemaForStrict(wire, true).strict).toBe(false);
+2 -204
View File
@@ -1,149 +1,13 @@
import { describe, expect, it } from "bun:test";
import { type } from "@oh-my-pi/omptype";
import { normalizeAnthropicToolSchema } from "@oh-my-pi/pi-ai/providers/anthropic";
import type { Tool } from "@oh-my-pi/pi-ai/types";
import {
adaptSchemaForStrict,
decontaminateZodInstance,
isZodSchema,
normalizeEmptySchemas,
normalizeSchemaForCCA,
normalizeSchemaForGoogle,
stripSchemaDescriptions,
stripToolDescriptions,
toolWireSchema,
zodToWireSchema,
} from "@oh-my-pi/pi-ai/utils/schema";
import { z } from "zod/v4";
describe("isZodSchema", () => {
it("accepts a live Zod instance", () => {
expect(isZodSchema(z.object({ a: z.string() }))).toBe(true);
expect(isZodSchema(z.string())).toBe(true);
expect(isZodSchema(z.enum({ a: "a", b: "b" }))).toBe(true);
});
// Regression: issue #1101. Before tightening, `isZodSchema` returned true
// for `JSON.parse(JSON.stringify(zodSchema))` because the `_zod` property
// (and its object value) survived the round-trip — even though every Zod
// method had been stripped along with the prototype. The relaxed predicate
// fed garbage into `z.toJSONSchema` and (when callers bypassed conversion)
// shipped the raw Zod internals to Anthropic's strict validator.
it("rejects a JSON-roundtripped Zod schema (prototype lost)", () => {
const impostor = JSON.parse(JSON.stringify(z.object({ a: z.string() })));
expect(isZodSchema(impostor)).toBe(false);
});
it("rejects the raw gitnexus_impact.direction payload from issue #1101", () => {
const impostor = {
def: { type: "enum", entries: { upstream: "upstream", downstream: "downstream" } },
type: "enum",
enum: { upstream: "upstream", downstream: "downstream" },
options: ["upstream", "downstream"],
};
expect(isZodSchema(impostor)).toBe(false);
});
it("rejects plain JSON Schema objects", () => {
expect(isZodSchema({ type: "object", properties: {} })).toBe(false);
expect(isZodSchema({ type: "string" })).toBe(false);
});
it("rejects non-objects", () => {
expect(isZodSchema(null)).toBe(false);
expect(isZodSchema(undefined)).toBe(false);
expect(isZodSchema("string")).toBe(false);
expect(isZodSchema(42)).toBe(false);
});
});
// ---------------------------------------------------------------------------
// zodToWireSchema — empty-schema normalization (issue #1179)
// ---------------------------------------------------------------------------
describe("zodToWireSchema — empty-schema normalization", () => {
it("converts z.unknown() additionalProperties from {} to true (z.record case)", () => {
// Grammar-constrained samplers treat {} as "emit empty object" rather than
// "any JSON value". Normalizing to `true` lets models emit strings.
const schema = z.object({ extra: z.record(z.string(), z.unknown()) });
const wire = zodToWireSchema(schema);
const extra = (wire.properties as Record<string, unknown>).extra as Record<string, unknown>;
expect(extra.additionalProperties).toBe(true);
});
it("converts z.unknown() items from {} to true (z.array case)", () => {
const schema = z.object({ items: z.array(z.unknown()) });
const wire = zodToWireSchema(schema);
const items = (wire.properties as Record<string, unknown>).items as Record<string, unknown>;
expect(items.items).toBe(true);
});
it("converts z.unknown() property schemas from {} to true", () => {
const schema = z.object({ meta: z.unknown() });
const wire = zodToWireSchema(schema);
const meta = (wire.properties as Record<string, unknown>).meta;
expect(meta).toBe(true);
});
it("does not touch non-empty schemas or boolean values", () => {
const schema = z.object({ name: z.string() });
const wire = zodToWireSchema(schema);
const name = (wire.properties as Record<string, unknown>).name as Record<string, unknown>;
expect(name.type).toBe("string");
expect(name.additionalProperties).toBeUndefined();
});
});
describe("zodToWireSchema — nullable scalar normalization", () => {
it("rewrites nullable scalar anyOf to a type array while preserving metadata", () => {
const schema = z.object({ skip: z.number().nullable().describe("matches to skip") });
const wire = zodToWireSchema(schema);
const skip = (wire.properties as Record<string, unknown>).skip as Record<string, unknown>;
expect(skip).toEqual({
type: ["number", "null"],
description: "matches to skip",
});
});
it("preserves null semantics when rewriting nullable scalar enum anyOf", () => {
const wire = toolWireSchema({
name: "mcp__sentry_search_docs",
description: "",
parameters: {
type: "object",
properties: {
guide: {
anyOf: [{ type: "string", enum: ["javascript", "python"], description: "guide" }, { type: "null" }],
},
},
required: ["guide"],
},
async execute() {},
} as unknown as Tool);
const guide = (wire.properties as Record<string, unknown>).guide as Record<string, unknown>;
expect(guide).toEqual({
type: ["string", "null"],
enum: ["javascript", "python", null],
description: "guide",
});
});
it("keeps nullable integers free of Zod safe-integer bounds", () => {
const schema = z.object({ count: z.number().int().nullable() });
const wire = zodToWireSchema(schema);
const count = (wire.properties as Record<string, unknown>).count as Record<string, unknown>;
expect(count).toEqual({ type: ["integer", "null"] });
});
it("leaves mixed nullable unions as anyOf", () => {
const schema = z.object({ value: z.union([z.string(), z.number()]).nullable() });
const wire = zodToWireSchema(schema);
const value = (wire.properties as Record<string, unknown>).value as Record<string, unknown>;
expect(value.type).toBeUndefined();
expect(Array.isArray(value.anyOf)).toBe(true);
});
});
// ---------------------------------------------------------------------------
// normalizeEmptySchemas — provider-agnostic post-pipeline normalization
@@ -182,23 +46,14 @@ describe("normalizeEmptySchemas", () => {
});
// ---------------------------------------------------------------------------
// toolWireSchema — covers both Zod and TypeBox paths (issue #1179)
// toolWireSchema — raw JSON Schema normalization (issue #1179)
// ---------------------------------------------------------------------------
describe("toolWireSchema — empty-schema normalization across both paths", () => {
function zodTool(parameters: z.ZodType): Tool {
return { name: "t", description: "", parameters, async execute() {} } as unknown as Tool;
}
describe("toolWireSchema — raw JSON Schema normalization", () => {
function jsonTool(parameters: Record<string, unknown>): Tool {
return { name: "t", description: "", parameters, async execute() {} } as unknown as Tool;
}
it("normalizes {} → true for Zod tools (z.record(z.string(), z.unknown()))", () => {
const wire = toolWireSchema(zodTool(z.object({ extra: z.record(z.string(), z.unknown()) })));
const extra = (wire.properties as Record<string, unknown>).extra as Record<string, unknown>;
expect(extra.additionalProperties).toBe(true);
});
it("normalizes {} → true for TypeBox / raw JSON Schema tools", () => {
const wire = toolWireSchema(
jsonTool({
@@ -254,63 +109,6 @@ describe("toolWireSchema — empty-schema normalization across both paths", () =
});
});
// ---------------------------------------------------------------------------
// Provider downstream behavior with normalized `additionalProperties: true`
// (issue #1179 — verify Google and Anthropic don't break)
// ---------------------------------------------------------------------------
describe("provider normalizers on normalized open-record schemas", () => {
const wire = zodToWireSchema(
z.object({
action: z.enum(["apply", "discard"]),
extra: z.record(z.string(), z.unknown()).optional(),
}),
);
it("Anthropic preserves additionalProperties: true so strict-mode opt-out still fires", () => {
// `normalizeAnthropicStrictSchemaNode` rejects nodes where additionalProperties !== false.
// With normalization, the value is `true` (was `{}`); still !== false, so strict opts out.
const out = normalizeAnthropicToolSchema(wire) as Record<string, unknown>;
const extra = (out.properties as Record<string, unknown>).extra as Record<string, unknown>;
expect(extra.additionalProperties).toBe(true);
});
it("Google strips additionalProperties entirely (UNSUPPORTED_SCHEMA_FIELDS)", () => {
// Pre-existing behavior — Google never sees the open-record marker either way.
// `additionalProperties: true` is removed just like `additionalProperties: {}` was.
const out = normalizeSchemaForGoogle(wire) as Record<string, unknown>;
const extra = (out.properties as Record<string, unknown>).extra as Record<string, unknown>;
expect(extra).not.toHaveProperty("additionalProperties");
});
it("CCA (Claude on Cloud Code Assist) strips additionalProperties entirely", () => {
const out = normalizeSchemaForCCA(wire) as Record<string, unknown>;
const extra = (out.properties as Record<string, unknown>).extra as Record<string, unknown>;
expect(extra).not.toHaveProperty("additionalProperties");
});
});
// ---------------------------------------------------------------------------
// decontaminateZodInstance — nullable wrapping of non-scalar inner schemas
// ---------------------------------------------------------------------------
describe("decontaminateZodInstance — nullable union", () => {
it("z.union([z.string(), z.number()]).nullable() produces a null-tolerant schema", () => {
// Round-trip strips Zod methods; decontaminateZodInstance must then inject null.
const roundTripped = JSON.parse(JSON.stringify(z.union([z.string(), z.number()]).nullable()));
const out = decontaminateZodInstance(roundTripped) as Record<string, unknown>;
// The union inner schema surfaces as an anyOf shape (no scalar `type`), so
// nullable wrapping must produce { anyOf: [..., { type: "null" }] }.
const toleratesNull =
(Array.isArray(out.type) && (out.type as string[]).includes("null")) ||
(Array.isArray(out.anyOf) &&
(out.anyOf as unknown[]).some(
b => typeof b === "object" && b !== null && (b as Record<string, unknown>).type === "null",
));
expect(toleratesNull).toBe(true);
});
});
// ---------------------------------------------------------------------------
// arkToWireSchema — `T | undefined` value-union pruning (Codex strict-mode break)
// ---------------------------------------------------------------------------
+24 -24
View File
@@ -1,16 +1,16 @@
import { describe, expect, it } from "bun:test";
import { type } from "@oh-my-pi/omptype";
import type { Tool } from "@oh-my-pi/pi-ai/types";
import { validateToolArguments } from "@oh-my-pi/pi-ai/utils/validation";
import { z } from "zod/v4";
describe("Tool argument whitespace normalization", () => {
it("trims trailing whitespace from enum strings before validation", () => {
const tool: Tool = {
name: "todo",
description: "",
parameters: z.object({
op: z.enum(["append", "done", "drop", "init", "rm", "start", "view"]),
items: z.array(z.string()).optional(),
parameters: type({
op: type.enumeration(["append", "done", "drop", "init", "rm", "start", "view"]),
items: type("string").array().optional(),
}),
};
@@ -59,8 +59,8 @@ describe("Tool argument whitespace normalization", () => {
const tool: Tool = {
name: "tuple-op",
description: "",
parameters: z.object({
args: z.tuple([z.enum(["init"])]),
parameters: type({
args: type.tuple([type.enumeration(["init"])]),
}),
};
@@ -78,9 +78,9 @@ describe("Tool argument whitespace normalization", () => {
const tool: Tool = {
name: "read",
description: "",
parameters: z.object({
path: z.string(),
offset: z.number().optional(),
parameters: type({
path: type("string"),
offset: type("number").optional(),
}),
};
@@ -98,9 +98,9 @@ describe("Tool argument whitespace normalization", () => {
const tool: Tool = {
name: "search",
description: "",
parameters: z.object({
pattern: z.string(),
paths: z.array(z.string()),
parameters: type({
pattern: type("string"),
paths: type("string").array(),
}),
};
@@ -124,8 +124,8 @@ describe("Tool argument whitespace normalization", () => {
const tool: Tool = {
name: "search",
description: "",
parameters: z.object({
paths: z.union([z.string(), z.array(z.string())]),
parameters: type({
paths: type.union([type("string"), type("string").array()]),
}),
};
@@ -145,9 +145,9 @@ describe("Tool argument whitespace normalization", () => {
const tool: Tool = {
name: "write",
description: "",
parameters: z.object({
path: z.string(),
content: z.string(),
parameters: type({
path: type("string"),
content: type("string"),
}),
};
@@ -165,9 +165,9 @@ describe("Tool argument whitespace normalization", () => {
const tool: Tool = {
name: "http",
description: "",
parameters: z.object({
body: z.object({
title: z.string(),
parameters: type({
body: type({
title: type("string"),
}),
}),
};
@@ -186,10 +186,10 @@ describe("Tool argument whitespace normalization", () => {
const tool: Tool = {
name: "eval",
description: "",
parameters: z.object({
language: z.enum(["py", "js", "rb", "jl"]),
code: z.string(),
title: z.string().optional(),
parameters: type({
language: type.enumeration(["py", "js", "rb", "jl"]),
code: type("string"),
title: type("string").optional(),
}),
};
+243 -240
View File
@@ -1,14 +1,14 @@
import { describe, expect, it } from "bun:test";
import { type } from "@oh-my-pi/omptype";
import type { Tool, ToolCall } from "@oh-my-pi/pi-ai/types";
import { validateToolArguments } from "@oh-my-pi/pi-ai/utils/validation";
import { z } from "zod/v4";
describe("Tool argument coercion", () => {
it("coerces numeric strings when schema expects number", () => {
const tool: Tool = {
name: "t1",
description: "",
parameters: z.object({ timeout: z.number() }),
parameters: type({ timeout: type("number") }),
};
const toolCall: ToolCall = {
@@ -27,7 +27,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t2",
description: "",
parameters: z.object({ label: z.string() }),
parameters: type({ label: type("string") }),
};
const toolCall: ToolCall = {
@@ -46,7 +46,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "object-string",
description: "",
parameters: z.object({ payload: z.string() }),
parameters: type({ payload: type("string") }),
};
const result = validateToolArguments(tool, {
@@ -63,7 +63,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "array-string",
description: "",
parameters: z.object({ payload: z.string() }),
parameters: type({ payload: type("string") }),
};
const result = validateToolArguments(tool, {
@@ -80,7 +80,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "numeric-booleans",
description: "",
parameters: z.object({ enabled: z.boolean(), disabled: z.boolean() }),
parameters: type({ enabled: type("boolean"), disabled: type("boolean") }),
};
const result = validateToolArguments(tool, {
@@ -97,7 +97,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "boolean-numbers",
description: "",
parameters: z.object({ enabled: z.number(), disabled: z.number().int() }),
parameters: type({ enabled: type("number"), disabled: type("number.integer") }),
};
const result = validateToolArguments(tool, {
@@ -114,7 +114,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "invalid-numeric-boolean",
description: "",
parameters: z.object({ enabled: z.boolean() }),
parameters: type({ enabled: type("boolean") }),
};
expect(() =>
@@ -131,7 +131,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "raw-debug",
description: "",
parameters: z.object({ input: z.string() }),
parameters: type({ input: type("string") }),
};
const rawBlock = '<|start|>assistant<|channel|>commentary to=functions.edit <|message|>{"input":"x"}}<|call|>';
@@ -159,15 +159,15 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "string-booleans",
description: "",
parameters: z.object({
t: z.boolean(),
f: z.boolean(),
one: z.boolean(),
zero: z.boolean(),
yes: z.boolean(),
no: z.boolean(),
on: z.boolean(),
off: z.boolean(),
parameters: type({
t: type("boolean"),
f: type("boolean"),
one: type("boolean"),
zero: type("boolean"),
yes: type("boolean"),
no: type("boolean"),
on: type("boolean"),
off: type("boolean"),
}),
};
@@ -203,7 +203,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t3",
description: "",
parameters: z.object({ items: z.array(z.number()) }),
parameters: type({ items: type("number").array() }),
};
const toolCall: ToolCall = {
@@ -221,7 +221,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t3b",
description: "",
parameters: z.object({ paths: z.array(z.string()) }),
parameters: type({ paths: type("string").array() }),
};
const toolCall: ToolCall = {
@@ -239,7 +239,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "glob_paths",
description: "",
parameters: z.object({ paths: z.array(z.string()) }),
parameters: type({ paths: type("string").array() }),
};
const bracketResult = validateToolArguments(tool, {
@@ -270,14 +270,14 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "todo_like",
description: "",
parameters: z.object({
ops: z.array(
z.object({
op: z.literal("init"),
list: z.array(
z.object({
phase: z.string(),
items: z.array(z.string()),
parameters: type({
ops: type.array(
type({
op: type.unit("init"),
list: type.array(
type({
phase: type("string"),
items: type("string").array(),
}),
),
}),
@@ -306,14 +306,14 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "todo_like_json_array",
description: "",
parameters: z.object({
ops: z.array(
z.object({
op: z.literal("init"),
list: z.array(
z.object({
phase: z.string(),
items: z.array(z.string()),
parameters: type({
ops: type.array(
type({
op: type.unit("init"),
list: type.array(
type({
phase: type("string"),
items: type("string").array(),
}),
),
}),
@@ -339,14 +339,14 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "todo_like_double_json_array",
description: "",
parameters: z.object({
ops: z.array(
z.object({
op: z.literal("init"),
list: z.array(
z.object({
phase: z.string(),
items: z.array(z.string()),
parameters: type({
ops: type.array(
type({
op: type.unit("init"),
list: type.array(
type({
phase: type("string"),
items: type("string").array(),
}),
),
}),
@@ -373,14 +373,14 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "todo_like_json_object",
description: "",
parameters: z.object({
ops: z.array(
z.object({
op: z.literal("init"),
list: z.array(
z.object({
phase: z.string(),
items: z.array(z.string()),
parameters: type({
ops: type.array(
type({
op: type.unit("init"),
list: type.array(
type({
phase: type("string"),
items: type("string").array(),
}),
),
}),
@@ -406,14 +406,14 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "todo_like_malformed_json_array",
description: "",
parameters: z.object({
ops: z.array(
z.object({
op: z.literal("init"),
list: z.array(
z.object({
phase: z.string(),
items: z.array(z.string()),
parameters: type({
ops: type.array(
type({
op: type.unit("init"),
list: type.array(
type({
phase: type("string"),
items: type("string").array(),
}),
),
}),
@@ -436,7 +436,7 @@ describe("Tool argument coercion", () => {
else throw error;
}
expect(thrown?.message).toContain("ops: Invalid input: expected array, received string");
expect(thrown?.message).toContain("ops must be an array");
expect(thrown?.message).not.toContain("ops/0");
expect(thrown?.message).not.toContain('"normalized"');
});
@@ -445,7 +445,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "numeric_list",
description: "",
parameters: z.object({ values: z.array(z.number()) }),
parameters: type({ values: type("number").array() }),
};
const result = validateToolArguments(tool, {
@@ -459,11 +459,11 @@ describe("Tool argument coercion", () => {
});
it("does not wrap singleton values for array expectations from failed union branches", () => {
const entry = z.object({ id: z.number() });
const entry = type({ id: type("number") });
const tool: Tool = {
name: "union_shape",
description: "",
parameters: z.union([z.array(entry), entry]),
parameters: type.union([type.array(entry), entry]),
};
const result = validateToolArguments(tool, {
@@ -526,9 +526,9 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "tagged_union",
description: "",
parameters: z.union([
z.object({ type: z.literal("indices"), indices: z.array(z.number()) }),
z.object({ type: z.literal("all") }),
parameters: type.union([
type({ type: type.unit("indices"), indices: type("number").array() }),
type({ type: type.unit("all") }),
]),
};
@@ -581,7 +581,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t4",
description: "",
parameters: z.object({ payload: z.object({ a: z.number() }) }),
parameters: type({ payload: type({ a: type("number") }) }),
};
const toolCall: ToolCall = {
@@ -599,7 +599,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t4b",
description: "",
parameters: z.object({ command: z.string() }),
parameters: type({ command: type("string") }),
};
const result = validateToolArguments(tool, {
@@ -616,7 +616,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t4c",
description: "",
parameters: z.object({ env: z.record(z.string(), z.string()) }),
parameters: type({ env: type.record(type("string"), type("string")) }),
};
const result = validateToolArguments(tool, {
@@ -682,7 +682,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t5",
description: "",
parameters: z.object({ payload: z.object({ items: z.array(z.number()) }) }),
parameters: type({ payload: type({ items: type("number").array() }) }),
};
const toolCall: ToolCall = {
@@ -700,11 +700,11 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t9",
description: "",
parameters: z.object({
a: z.string(),
b: z.array(
z.object({
k: z.string(),
parameters: type({
a: type("string"),
b: type.array(
type({
k: type("string"),
}),
),
}),
@@ -726,11 +726,11 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t10",
description: "",
parameters: z.object({
a: z.string(),
b: z.array(
z.object({
k: z.string(),
parameters: type({
a: type("string"),
b: type.array(
type({
k: type("string"),
}),
),
}),
@@ -752,12 +752,12 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t7",
description: "",
parameters: z.object({
path: z.string(),
edits: z.array(
z.object({
target: z.string(),
new_content: z.string(),
parameters: type({
path: type("string"),
edits: type.array(
type({
target: type("string"),
new_content: type("string"),
}),
),
}),
@@ -780,19 +780,19 @@ describe("Tool argument coercion", () => {
});
it("coerces quoted edit arrays before stripping optional null fields", () => {
const textSchema = z.union([z.array(z.string()), z.string()]);
const textSchema = type.union([type("string").array(), type("string")]);
const tool: Tool = {
name: "atom-like-edit",
description: "",
parameters: z.object({
path: z.string(),
edits: z.array(
z.object({
loc: z.string(),
parameters: type({
path: type("string"),
edits: type.array(
type({
loc: type("string"),
set: textSchema.optional(),
pre: textSchema.optional(),
post: textSchema.optional(),
sub: z.tuple([z.string(), z.string()]).optional(),
sub: type.tuple([type("string"), type("string")]).optional(),
}),
),
}),
@@ -815,14 +815,14 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t16",
description: "",
parameters: z.object({
path: z.string(),
edits: z.array(
z.object({
op: z.string(),
pos: z.string(),
end: z.string(),
lines: z.array(z.string()),
parameters: type({
path: type("string"),
edits: type.array(
type({
op: type("string"),
pos: type("string"),
end: type("string"),
lines: type("string").array(),
}),
),
}),
@@ -852,12 +852,12 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t8",
description: "",
parameters: z.object({
path: z.string(),
edits: z.array(
z.object({
target: z.string(),
new_content: z.string(),
parameters: type({
path: type("string"),
edits: type.array(
type({
target: type("string"),
new_content: type("string"),
}),
),
}),
@@ -881,9 +881,9 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t11",
description: "",
parameters: z.object({
requiredText: z.string(),
optionalCount: z.number().optional(),
parameters: type({
requiredText: type("string"),
optionalCount: type("number").optional(),
}),
};
@@ -928,10 +928,10 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "empty-string-tool",
description: "",
parameters: z.object({
requiredText: z.string(),
optionalText: z.string().optional(),
optionalEnum: z.enum(["", "clear"]).optional(),
parameters: type({
requiredText: type("string"),
optionalText: type("string").optional(),
optionalEnum: type.enumeration(["", "clear"]).optional(),
}),
};
@@ -949,12 +949,12 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t12",
description: "",
parameters: z.object({
edits: z.array(
z.object({
target: z.string(),
pos: z.string().optional(),
end: z.string().optional(),
parameters: type({
edits: type.array(
type({
target: type("string"),
pos: type("string").optional(),
end: type("string").optional(),
}),
),
}),
@@ -972,26 +972,26 @@ describe("Tool argument coercion", () => {
});
it("drops null while preserving valid empty-string optional properties in anyOf object branches", () => {
const opSchema = z.union([
z.object({
op: z.literal("add_task"),
phase: z.string(),
content: z.string(),
const opSchema = type.union([
type({
op: type.unit("add_task"),
phase: type("string"),
content: type("string"),
}),
z.object({
op: z.literal("update"),
id: z.string(),
status: z.string().optional(),
content: z.string().optional(),
notes: z.string().optional(),
type({
op: type.unit("update"),
id: type("string"),
status: type("string").optional(),
content: type("string").optional(),
notes: type("string").optional(),
}),
]);
const tool: Tool = {
name: "t13",
description: "",
parameters: z.object({
ops: z.array(opSchema),
parameters: type({
ops: type.array(opSchema),
}),
};
@@ -1029,7 +1029,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t6",
description: "",
parameters: z.object({ timeout: z.number() }),
parameters: type({ timeout: type("number") }),
};
const toolCall: ToolCall = {
@@ -1047,7 +1047,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t14",
description: "",
parameters: z.object({ tick_size: z.number().optional() }),
parameters: type({ tick_size: type("number").optional() }),
};
const toolCall: ToolCall = {
type: "toolCall",
@@ -1064,7 +1064,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t15",
description: "",
parameters: z.object({ tick_size: z.number().optional() }),
parameters: type({ tick_size: type("number").optional() }),
};
const toolCall: ToolCall = {
type: "toolCall",
@@ -1079,9 +1079,9 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "edit-tool",
description: "",
parameters: z.object({
path: z.string(),
delete: z.boolean().optional(),
parameters: type({
path: type("string"),
delete: type("boolean").optional(),
}),
};
@@ -1100,9 +1100,9 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "edit-tool",
description: "",
parameters: z.object({
path: z.string(),
move: z.string().optional(),
parameters: type({
path: type("string"),
move: type("string").optional(),
}),
};
@@ -1121,8 +1121,8 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "required-tool",
description: "",
parameters: z.object({
path: z.string(),
parameters: type({
path: type("string"),
}),
};
@@ -1143,10 +1143,10 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "multi-optional",
description: "",
parameters: z.object({
required: z.string(),
optBool: z.boolean().optional(),
optString: z.string().optional(),
parameters: type({
required: type("string"),
optBool: type("boolean").optional(),
optString: type("string").optional(),
}),
};
@@ -1165,12 +1165,12 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "heal-1",
description: "",
parameters: z.object({
path: z.string(),
edits: z.array(
z.object({
target: z.string(),
content: z.string(),
parameters: type({
path: type("string"),
edits: type.array(
type({
target: type("string"),
content: type("string"),
}),
),
}),
@@ -1195,12 +1195,12 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "heal-2",
description: "",
parameters: z.object({
path: z.string(),
edits: z.array(
z.object({
target: z.string(),
content: z.string(),
parameters: type({
path: type("string"),
edits: type.array(
type({
target: type("string"),
content: type("string"),
}),
),
}),
@@ -1225,8 +1225,8 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "heal-esc-1",
description: "",
parameters: z.object({
edits: z.array(z.object({ target: z.string(), content: z.string() })),
parameters: type({
edits: type.array(type({ target: type("string"), content: type("string") })),
}),
};
@@ -1248,8 +1248,8 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "heal-trail-1",
description: "",
parameters: z.object({
edits: z.array(z.object({ target: z.string(), op: z.string() })),
parameters: type({
edits: type.array(type({ target: type("string"), op: type("string") })),
}),
};
@@ -1271,8 +1271,8 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "heal-3",
description: "",
parameters: z.object({
edits: z.array(z.object({ target: z.string() })),
parameters: type({
edits: type.array(type({ target: type("string") })),
}),
};
@@ -1292,14 +1292,14 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "todo_like",
description: "",
parameters: z.object({
phases: z.array(
z.object({
name: z.string(),
tasks: z.array(
z.object({
content: z.string(),
details: z.string().optional(),
parameters: type({
phases: type.array(
type({
name: type("string"),
tasks: type.array(
type({
content: type("string"),
details: type("string").optional(),
}),
),
}),
@@ -1334,9 +1334,11 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t-defaulted-null",
description: "",
parameters: z.object({
note: z.union([z.string(), z.null()]),
tags: z.array(z.string()).default([]),
parameters: type({
note: type.union([type("string"), type.unit(null)]),
tags: type("string")
.array()
.default(() => []),
}),
};
@@ -1355,8 +1357,10 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t-defaulted-isolation",
description: "",
parameters: z.object({
tags: z.array(z.string()).default([]),
parameters: type({
tags: type("string")
.array()
.default(() => []),
}),
};
@@ -1382,10 +1386,10 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t-optional-nulls",
description: "",
parameters: z.object({
path: z.string(),
offset: z.number().optional(),
limit: z.number().optional(),
parameters: type({
path: type("string"),
offset: type("number").optional(),
limit: type("number").optional(),
}),
};
@@ -1404,9 +1408,11 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t-root-json-null",
description: "",
parameters: z.object({
note: z.union([z.string(), z.null()]),
tags: z.array(z.string()).default([]),
parameters: type({
note: type.union([type("string"), type.unit(null)]),
tags: type("string")
.array()
.default(() => []),
}),
};
@@ -1428,10 +1434,10 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "t-nested-json",
description: "",
parameters: z.object({
payload: z.object({
flags: z.array(z.boolean()),
meta: z.object({ count: z.number() }),
parameters: type({
payload: type({
flags: type("boolean").array(),
meta: type({ count: type("number") }),
}),
}),
};
@@ -1457,15 +1463,14 @@ describe("Tool argument coercion", () => {
});
});
it("tolerates extra keys on .strict() Zod object schemas (loose-recursive)", () => {
it("tolerates extra keys on a rejecting object schema", () => {
const tool: Tool = {
name: "t-strict-root",
description: "",
parameters: z
.object({
op: z.string(),
})
.strict(),
parameters: type({
"+": "reject",
op: type("string"),
}),
};
const toolCall: ToolCall = {
@@ -1483,19 +1488,17 @@ describe("Tool argument coercion", () => {
expect(result.timeout).toBeUndefined();
});
it("tolerates extra keys on nested .strict() Zod object schemas", () => {
it("tolerates extra keys on nested rejecting object schemas", () => {
const tool: Tool = {
name: "t-strict-nested",
description: "",
parameters: z
.object({
config: z
.object({
host: z.string(),
})
.strict(),
})
.strict(),
parameters: type({
"+": "reject",
config: type({
"+": "reject",
host: type("string"),
}),
}),
};
const toolCall: ToolCall = {
@@ -1545,9 +1548,9 @@ describe("Tool argument coercion", () => {
const unionTool: Tool = {
name: "search",
description: "",
parameters: z.object({
pattern: z.string(),
paths: z.union([z.string(), z.array(z.string()).min(1)]),
parameters: type({
pattern: type("string"),
paths: type.union([type("string"), type("string").array().atLeastLength(1)]),
}),
};
@@ -1626,7 +1629,7 @@ describe("Tool argument coercion", () => {
const stringOnly: Tool = {
name: "string_only",
description: "",
parameters: z.object({ value: z.string() }),
parameters: type({ value: type("string") }),
};
const result = validateToolArguments(stringOnly, {
type: "toolCall",
@@ -1660,9 +1663,9 @@ describe("Tool argument coercion", () => {
const nestedTool: Tool = {
name: "nested_search",
description: "",
parameters: z.object({
payload: z.object({
paths: z.union([z.string(), z.array(z.string()).min(1)]),
parameters: type({
payload: type({
paths: type.union([type("string"), type("string").array().atLeastLength(1)]),
}),
}),
};
@@ -1684,11 +1687,11 @@ describe("Tool argument coercion", () => {
const opsTool: Tool = {
name: "todo",
description: "",
parameters: z.object({
ops: z.array(
z.object({
op: z.string(),
task: z.string().optional(),
parameters: type({
ops: type.array(
type({
op: type("string"),
task: type("string").optional(),
}),
),
}),
@@ -1716,7 +1719,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "rooted",
description: "",
parameters: z.object({ label: z.string() }),
parameters: type({ label: type("string") }),
};
const result = validateToolArguments(tool, {
type: "toolCall",
@@ -1731,7 +1734,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "deep",
description: "",
parameters: z.object({ label: z.string() }),
parameters: type({ label: type("string") }),
};
const result = validateToolArguments(tool, {
type: "toolCall",
@@ -1747,7 +1750,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "clobber",
description: "",
parameters: z.object({ value: z.string() }),
parameters: type({ value: type("string") }),
};
const result = validateToolArguments(tool, {
type: "toolCall",
@@ -1762,8 +1765,8 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "wrap",
description: "",
parameters: z.object({
payload: z.object({ op: z.string() }),
parameters: type({
payload: type({ op: type("string") }),
}),
};
const result = validateToolArguments(tool, {
@@ -1794,8 +1797,8 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "union",
description: "",
parameters: z.object({
items: z.union([z.string(), z.array(z.object({ op: z.string() }))]),
parameters: type({
items: type.union([type("string"), type.array(type({ op: type("string") }))]),
}),
};
const result = validateToolArguments(tool, {
@@ -1812,7 +1815,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "plain",
description: "",
parameters: z.object({ op: z.string(), count: z.number() }),
parameters: type({ op: type("string"), count: type("number") }),
};
const result = validateToolArguments(tool, {
type: "toolCall",
@@ -1829,7 +1832,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "single-arg",
description: "",
parameters: z.object({ input: z.string() }),
parameters: type({ input: type("string") }),
};
const result = validateToolArguments(tool, {
type: "toolCall",
@@ -1844,7 +1847,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "single-arg",
description: "",
parameters: z.object({ input: z.string() }),
parameters: type({ input: type("string") }),
};
const result = validateToolArguments(tool, {
type: "toolCall",
@@ -1859,7 +1862,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "multi-arg",
description: "",
parameters: z.object({ input: z.string(), path: z.string() }),
parameters: type({ input: type("string"), path: type("string") }),
};
expect(() =>
validateToolArguments(tool, {
@@ -1875,7 +1878,7 @@ describe("Tool argument coercion", () => {
const tool: Tool = {
name: "single-arg",
description: "",
parameters: z.object({ input: z.string() }),
parameters: type({ input: type("string") }),
};
expect(() =>
validateToolArguments(tool, {
@@ -1893,10 +1896,10 @@ describe("In-band arg spill healing", () => {
const todoTool: Tool = {
name: "todo",
description: "",
parameters: z.object({
op: z.enum(["append", "done", "drop", "init", "rm", "start", "view"]),
task: z.string().optional(),
phase: z.string().optional(),
parameters: type({
op: type.enumeration(["append", "done", "drop", "init", "rm", "start", "view"]),
task: type("string").optional(),
phase: type("string").optional(),
}),
};
@@ -1934,9 +1937,9 @@ describe("In-band arg spill healing", () => {
const tool: Tool = {
name: "spill-coerce",
description: "",
parameters: z.object({
op: z.enum(["read"]),
count: z.number().optional(),
parameters: type({
op: type.enumeration(["read"]),
count: type("number").optional(),
}),
};
const result = run(tool, {
@@ -1957,7 +1960,7 @@ describe("In-band arg spill healing", () => {
const tool: Tool = {
name: "spill-content",
description: "",
parameters: z.object({ content: z.string() }),
parameters: type({ content: type("string") }),
};
const content = "docs: emit </arg_key>\n<arg_key>path</arg_key>\n<arg_value>src/a.ts</arg_value> pairs";
const result = run(tool, { content });
+3
View File
@@ -2,6 +2,9 @@
## [Unreleased]
### Changed
- Migrated GitLab Duo Workflow discovery schemas from zod to omptype and removed the `zod` dependency
## [17.2.9] - 2026-08-05
### Fixed
+1 -2
View File
@@ -36,8 +36,7 @@
"dependencies": {
"@bufbuild/protobuf": "catalog:",
"@oh-my-pi/omptype": "catalog:",
"@oh-my-pi/pi-utils": "catalog:",
"zod": "catalog:"
"@oh-my-pi/pi-utils": "catalog:"
},
"devDependencies": {
"@oh-my-pi/pi-ai": "catalog:",
@@ -1,6 +1,6 @@
import * as fs from "node:fs/promises";
import * as path from "node:path";
import { z } from "zod/v4";
import { type } from "@oh-my-pi/omptype";
import type { FetchImpl, ModelSpec } from "../types";
import { discoveryFetch, isRecord } from "../utils";
@@ -54,20 +54,28 @@ const ProjectRootNamespaceQuery = `query omp_gitlabDuoWorkflowProjectRootNamespa
}
}`;
const modelRefSchema = z
.object({
name: z.string().optional().catch(undefined),
ref: z.string().optional().catch(undefined),
})
.loose();
const resilientString = type("unknown").pipe(value => {
if (value === undefined) return undefined;
const parsed = type("string")(value);
return parsed instanceof type.errors ? undefined : parsed;
});
const aiChatAvailableModelsSchema = z
.object({
defaultModel: z.unknown().nullable().optional(),
selectableModels: z.array(z.unknown()).nullable().optional().catch([]),
pinnedModel: z.unknown().nullable().optional(),
})
.loose();
const resilientUnknownArray = type("unknown").pipe(value => {
if (value === undefined || value === null) return value;
const parsed = type("unknown[]")(value);
return parsed instanceof type.errors ? [] : parsed;
});
const modelRefSchema = type({
"name?": resilientString,
"ref?": resilientString,
});
const aiChatAvailableModelsSchema = type({
"defaultModel?": "unknown",
"selectableModels?": resilientUnknownArray,
"pinnedModel?": "unknown",
});
type GitLabDuoWorkflowCandidateSource = "override" | "project" | "remote" | "group";
@@ -540,17 +548,15 @@ async function postGraphQL(
}
function parseAvailability(value: unknown): GitLabDuoWorkflowAvailability | null {
const parsed = aiChatAvailableModelsSchema.safeParse(value);
if (!parsed.success) {
return null;
}
const parsed = aiChatAvailableModelsSchema(value);
if (parsed instanceof type.errors) return null;
return {
defaultModel: parseModelRef(parsed.data.defaultModel),
selectableModels: (parsed.data.selectableModels ?? []).flatMap(model => {
defaultModel: parseModelRef(parsed.defaultModel),
selectableModels: (parsed.selectableModels ?? []).flatMap(model => {
const parsedModel = parseModelRef(model);
return parsedModel ? [parsedModel] : [];
}),
pinnedModel: parseModelRef(parsed.data.pinnedModel),
pinnedModel: parseModelRef(parsed.pinnedModel),
};
}
@@ -558,15 +564,13 @@ function parseModelRef(value: unknown): GitLabDuoWorkflowModelRef | null {
if (value === null || value === undefined) {
return null;
}
const parsed = modelRefSchema.safeParse(value);
if (!parsed.success) {
return null;
}
const ref = normalizeIdentifier(parsed.data.ref);
const parsed = modelRefSchema(value);
if (parsed instanceof type.errors) return null;
const ref = normalizeIdentifier(parsed.ref);
if (!ref) {
return null;
}
const name = normalizeIdentifier(parsed.data.name) ?? ref;
const name = normalizeIdentifier(parsed.name) ?? ref;
return { name, ref };
}
+6
View File
@@ -2,6 +2,12 @@
## [Unreleased]
### Breaking Changes
- Replaced the re-exported zod API with the omptype-backed zod-compat facade (`@oh-my-pi/omptype/zod`); plugins keep the zod-style builder surface while real-zod-specific APIs are gone
### Changed
- Replaced external dependencies with `@oh-my-pi/pi-utils` modules: `@agentclientprotocol/sdk` -> `acp` (also drops the package patch), `@mozilla/readability` -> `readability`, `@puppeteer/browsers` -> `browsers`, `@xterm/headless` -> `vterm`, `chalk` -> `chalk`, `fast-xml-parser` -> `xml`, `header-generator` -> `headers`, `linkedom` -> `dom`, `lru-cache` -> `lru`, `mammoth` -> `docx`, `turndown` and `turndown-plugin-gfm` -> `turndown`, and dev `marked` -> `marked`
## [17.2.9] - 2026-08-05
### Breaking Changes
@@ -96,7 +96,7 @@ renderResult(result, { expanded, isPartial }, theme) {
**Use `z.enum` for discriminated string tool args:**
```typescript
const { z } = pi.zod;
const z = pi.zod;
parameters: z.object({
action: z.enum(["list", "add"]),
@@ -114,7 +114,7 @@ export default function (pi: ExtensionAPI) {
**Use `z.enum` for discriminated string tool args:**
```typescript
const { z } = pi.zod;
const z = pi.zod;
parameters: z.object({
action: z.enum(["list", "add"]),
@@ -1,14 +1,13 @@
/**
* API Demo Extension
*
* Demonstrates using ExtensionAPI's logger, injected `pi.zod`, and pi module access.
* These features are now exposed directly on the ExtensionAPI, matching
* the CustomToolAPI interface.
* Demonstrates using ExtensionAPI's logger, injected schema builder, and pi
* module access.
*/
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
export default function (pi: ExtensionAPI) {
const { z } = pi.zod;
const z = pi.zod;
// Access the logger for debugging
pi.logger.debug("API demo extension loaded");
@@ -16,7 +15,7 @@ export default function (pi: ExtensionAPI) {
pi.registerTool({
name: "api_demo",
label: "API Demo",
description: "Demonstrates ExtensionAPI capabilities: logger, zod, and pi module access",
description: "Demonstrates ExtensionAPI capabilities: logger, schema validation, and pi module access",
parameters: z.object({
message: z.string().describe("Test message"),
logLevel: z.enum(["error", "warn", "debug"]).default("debug").describe("Log level to use"),
@@ -48,7 +47,7 @@ export default function (pi: ExtensionAPI) {
``,
`Features demonstrated:`,
`1. ✓ Logger access via pi.logger`,
`2. ✓ Zod access via pi.zod`,
`2. ✓ Schema builder access via pi.arktype`,
`3. ✓ Pi module access via pi.pi`,
``,
`Context:`,
@@ -3,7 +3,7 @@
* Tests that jiti can resolve npm modules correctly.
*/
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
export default function (pi: ExtensionAPI) {
// Log with colors using chalk
@@ -1,12 +1,12 @@
/**
* Hello Tool - Minimal custom tool example
*
* Demonstrates using ExtensionAPI's logger, injected `pi.zod`, and pi module access.
* Demonstrates using ExtensionAPI's logger and injected schema builder.
*/
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
export default function (pi: ExtensionAPI) {
const { z } = pi.zod;
const z = pi.zod;
pi.registerTool({
name: "hello",
@@ -8,7 +8,7 @@
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
export default function (pi: ExtensionAPI) {
const { z } = pi.zod;
const z = pi.zod;
// Command entrypoint for reload.
// Treat reload as terminal for this handler.
@@ -8,7 +8,7 @@ import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
import ms from "ms";
export default function (pi: ExtensionAPI) {
const { z } = pi.zod;
const z = pi.zod;
// Register a tool that uses ms
pi.registerTool({
@@ -41,7 +41,7 @@ console.log();
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
export default function (pi: ExtensionAPI) {
const { z } = pi.zod;
const z = pi.zod;
pi.on("agent_start", async () => {
console.log("[Extension] Agent starting");
+2 -18
View File
@@ -49,9 +49,7 @@
"bench:guard": "bun scripts/bench-guard.ts"
},
"dependencies": {
"@agentclientprotocol/sdk": "catalog:",
"@babel/parser": "catalog:",
"@mozilla/readability": "catalog:",
"@oh-my-pi/hashline": "catalog:",
"@oh-my-pi/omp-stats": "catalog:",
"@oh-my-pi/omptype": "catalog:",
@@ -75,29 +73,15 @@
"@opentelemetry/sdk-metrics": "catalog:",
"@opentelemetry/sdk-trace-base": "catalog:",
"@opentelemetry/sdk-trace-node": "catalog:",
"@puppeteer/browsers": "catalog:",
"@types/turndown": "catalog:",
"@xterm/headless": "catalog:",
"chalk": "catalog:",
"fast-xml-parser": "catalog:",
"handlebars": "catalog:",
"header-generator": "catalog:",
"linkedom": "catalog:",
"lru-cache": "catalog:",
"mammoth": "catalog:",
"mupdf": "catalog:",
"puppeteer-core": "catalog:",
"turndown": "catalog:",
"turndown-plugin-gfm": "catalog:",
"zod": "catalog:"
"puppeteer-core": "catalog:"
},
"optionalDependencies": {
"@huggingface/transformers": "catalog:",
"sherpa-onnx-node": "1.13.2"
},
"devDependencies": {
"@types/bun": "catalog:",
"marked": "catalog:"
"@types/bun": "catalog:"
},
"engines": {
"bun": ">=1.3.14"
+1 -11
View File
@@ -30,17 +30,7 @@ const ALWAYS_EXTERNAL = [
// import would load the unpatched npm package in users' installs (currently
// @ark/schema is patched, so it — and arktype, which pulls @ark/schema — stay
// bundled).
const RUNTIME_EXTERNAL = [
"puppeteer-core",
"@puppeteer/browsers",
"@babel/parser",
"@xterm/headless",
"turndown",
"turndown-plugin-gfm",
"@mozilla/readability",
"linkedom",
"@agentclientprotocol/sdk",
];
const RUNTIME_EXTERNAL = ["puppeteer-core", "@babel/parser"];
async function runCommand(command: string[]): Promise<void> {
const proc = Bun.spawn(command, {
+1 -1
View File
@@ -6,8 +6,8 @@
import * as fs from "node:fs/promises";
import * as path from "node:path";
import { getAgentDir, getProjectDir, isEnoent } from "@oh-my-pi/pi-utils";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { YAML } from "bun";
import chalk from "chalk";
import { theme } from "../modes/theme/theme";
import { loadBundledAgents } from "../task/agents";
import type { AgentDefinition } from "../task/types";
+1 -1
View File
@@ -2,7 +2,7 @@
* CLI argument parsing and help display
*/
import { $env, APP_NAME, logger } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import type { ServiceTierOpenAISettingValue } from "../config/service-tier";
import { CLI_THINKING_LEVELS, type ConfiguredThinkingLevel, parseCliThinkingLevel } from "../thinking";
import { BUILTIN_TOOL_NAMES, HIDDEN_TOOL_NAMES, normalizeToolNames } from "../tools/builtin-names";
@@ -34,9 +34,9 @@ import {
} from "@oh-my-pi/pi-ai";
import { AuthBrokerClient, DEFAULT_AUTH_BROKER_BIND, startAuthBroker } from "@oh-my-pi/pi-ai/auth-broker";
import { $which, APP_NAME, getAgentDbPath, getConfigRootDir, isEnoent, logger, VERSION } from "@oh-my-pi/pi-utils";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { setTransports as setLoggerTransports } from "@oh-my-pi/pi-utils/logger";
import { $ } from "bun";
import chalk from "chalk";
import { resolveAuthBrokerConfig } from "../session/auth-broker-config";
export type AuthBrokerAction = "serve" | "token" | "login" | "logout" | "status" | "import" | "migrate" | "list";
@@ -33,7 +33,7 @@ import {
import { DEFAULT_AUTH_GATEWAY_BIND, startAuthGateway } from "@oh-my-pi/pi-ai/auth-gateway";
import { type GeneratedProvider, getBundledModels } from "@oh-my-pi/pi-catalog/models";
import { getConfigRootDir, isEnoent, logger, VERSION } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { ModelRegistry } from "../config/model-registry";
import { type AuthBrokerClientConfig, resolveAuthBrokerConfig } from "../session/auth-broker-config";
+1 -1
View File
@@ -17,7 +17,7 @@ import { resolveModelServiceTier, streamSimple } from "@oh-my-pi/pi-ai";
import { buildModelProviderPriorityRank } from "@oh-my-pi/pi-catalog/identity";
import { replaceTabs, truncateToWidth } from "@oh-my-pi/pi-tui";
import { formatDuration, getProjectDir, prompt } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import type { ApiKeyResolverModel } from "../config/api-key-resolver";
import { ModelRegistry } from "../config/model-registry";
import {
@@ -10,7 +10,7 @@ import * as path from "node:path";
import * as tls from "node:tls";
import * as zlib from "node:zlib";
import { PtySession } from "@oh-my-pi/pi-natives";
import xterm from "@xterm/headless";
import xterm from "@oh-my-pi/pi-utils/vterm";
const DEFAULT_PROXY_HOST = "127.0.0.1";
const DEFAULT_PROXY_PORT = 8080;
+1 -1
View File
@@ -6,7 +6,7 @@
*/
import { APP_NAME, getAgentDir } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import {
getDefault,
getEnumValues,
@@ -14,7 +14,7 @@ import type {
import { streamSimple } from "@oh-my-pi/pi-ai";
import { replaceTabs, truncateToWidth } from "@oh-my-pi/pi-tui";
import { formatDuration, getProjectDir } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { ModelRegistry } from "../config/model-registry";
import {
formatModelString,
@@ -5,7 +5,7 @@ import * as fs from "node:fs";
import * as path from "node:path";
import type { ImageContent } from "@oh-my-pi/pi-ai";
import { getProjectDir, isEnoent, readImageMetadata } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { resolveReadPath } from "../tools/path-utils";
import { formatBytes } from "../tools/render-utils";
import { formatDimensionNote, resizeImage } from "../utils/image-resize";
+1 -1
View File
@@ -6,7 +6,7 @@
import * as path from "node:path";
import { GrepOutputMode, grep } from "@oh-my-pi/pi-natives";
import { APP_NAME } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { expandPath } from "../tools/path-utils";
export interface GrepCommandArgs {
@@ -1,7 +1,7 @@
/**
* CLI handler for `omp grievances` — view, clean, and manually push reported tool issues.
*/
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { Settings } from "../config/settings";
import { flushGrievances, openAutoQaDb } from "../tools/report-tool-issue";
+1 -1
View File
@@ -1,6 +1,6 @@
import "@oh-my-pi/pi-utils/env";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { APP_NAME, CONFIG_DIR_NAME } from "@oh-my-pi/pi-utils/dirs";
import chalk from "chalk";
export function getExtraHelpText(): string {
return `${chalk.bold("Environment Variables:")}
+1 -1
View File
@@ -14,7 +14,7 @@
import type { Api, Effort, Model } from "@oh-my-pi/pi-ai";
import { getSupportedEfforts } from "@oh-my-pi/pi-catalog/model-thinking";
import { formatNumber, getProjectDir } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { ModelRegistry } from "../config/model-registry";
import { Settings } from "../config/settings";
import { discoverAndLoadExtensions, ExtensionRunner, emitSessionShutdownEvent } from "../extensibility/extensions";
+1 -1
View File
@@ -5,7 +5,7 @@
*/
import { APP_NAME, getProjectDir } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { resolveOrDefaultProjectRegistryPath } from "../discovery/helpers";
import { PluginManager, parseSettingValue, validateSetting } from "../extensibility/plugins";
import {
+1 -1
View File
@@ -6,7 +6,7 @@
* (including truncation/limit notices appended by the meta-notice wrapper).
*/
import { getProjectDir } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { Settings } from "../config/settings";
import { extractUriScheme } from "../internal-urls/parse";
import { InternalUrlRouter } from "../internal-urls/router";
+1 -1
View File
@@ -5,7 +5,7 @@
*/
import * as path from "node:path";
import { APP_NAME, getProjectDir, getPythonEnvDir } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { Settings, settings } from "../config/settings";
import { checkPythonKernelAvailability } from "../eval/py/kernel";
import { theme } from "../modes/theme/theme";
+1 -1
View File
@@ -7,7 +7,7 @@ import * as path from "node:path";
import { createInterface } from "node:readline/promises";
import { Shell } from "@oh-my-pi/pi-natives";
import { APP_NAME, getProjectDir } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { Settings } from "../config/settings";
import { buildMinimizerOptions } from "../exec/bash-executor";
import { getOrCreateSnapshot } from "../utils/shell-snapshot";
+1 -1
View File
@@ -5,7 +5,7 @@
*/
import { getSSHConfigPath } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { addSSHHost, readSSHConfigFile, removeSSHHost, type SSHHostConfig } from "../ssh/config-writer";
// =============================================================================
+1 -1
View File
@@ -6,7 +6,7 @@
import { truncateToWidth } from "@oh-my-pi/pi-tui/utils";
import { APP_NAME, formatDuration, formatNumber, formatPercent } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { openPath } from "../utils/open";
/**
@@ -1,5 +1,5 @@
import { formatBytes } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import {
DEFAULT_TINY_TITLE_LOCAL_MODEL_KEY,
getTinyLocalModelSpec,
+1 -1
View File
@@ -13,8 +13,8 @@
import * as fs from "node:fs";
import * as path from "node:path";
import { AstMatchStrictness, astMatch, FileType, type GlobMatch, glob } from "@oh-my-pi/pi-natives";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { getProjectDir } from "@oh-my-pi/pi-utils/dirs";
import chalk from "chalk";
import { BUILTIN_DEFAULTS_PROVIDER_ID, compileRuleCondition, type Rule, ruleCapability } from "../capability/rule";
import { bucketRules } from "../capability/rule-buckets";
import { Settings } from "../config/settings";
+1 -1
View File
@@ -11,8 +11,8 @@ import * as path from "node:path";
import { Transform } from "node:stream";
import { pipeline } from "node:stream/promises";
import { $env, $which, APP_NAME, compareVersions, isEnoent, VERSION } from "@oh-my-pi/pi-utils";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { $ } from "bun";
import chalk from "chalk";
import { theme } from "../modes/theme/theme";
import { isTimeoutError, withTimeoutSignal } from "../utils/fetch-timeout";
+1 -1
View File
@@ -18,7 +18,7 @@ import {
type UsageUnit,
} from "@oh-my-pi/pi-ai";
import { formatDuration, formatNumber, sanitizeText } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { ModelRegistry } from "../config/model-registry";
import { discoverAuthStorage } from "../sdk";
@@ -5,7 +5,7 @@
*/
import { APP_NAME, getProjectDir } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { applyProviderGlobalsFromSettings } from "../config/provider-globals";
import { Settings } from "../config/settings";
import { initTheme, theme } from "../modes/theme/theme";
@@ -19,7 +19,7 @@
import * as fs from "node:fs/promises";
import * as path from "node:path";
import { getWorktreesDir, isEnoent } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { hasLiveIsolationOwner, ISOLATION_OWNER_FILE } from "../task/isolation-ownership";
import * as git from "../utils/git";
+1 -1
View File
@@ -10,8 +10,8 @@
*/
import { getProjectDir } from "@oh-my-pi/pi-utils";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
import chalk from "chalk";
import { sayHelp as commandHelp } from "../cli/command-help";
import { Settings, settings } from "../config/settings";
import { TTS_LOCAL_VOICE_VALUES } from "../tts/models";
+1 -1
View File
@@ -3,8 +3,8 @@
*/
import { PROVIDER_REGISTRY } from "@oh-my-pi/pi-ai";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
import chalk from "chalk";
import { tokenHelp as commandHelp } from "../cli/command-help";
import { isAuthenticated, ModelRegistry } from "../config/model-registry";
import { discoverAuthStorage } from "../sdk";
@@ -2,8 +2,8 @@ import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
import type { Api, Model } from "@oh-my-pi/pi-ai";
import { Markdown } from "@oh-my-pi/pi-tui";
import { prompt } from "@oh-my-pi/pi-utils";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { INTENT_FIELD } from "@oh-my-pi/pi-wire";
import chalk from "chalk";
import typesDescriptionPrompt from "../../commit/prompts/types-description.md" with { type: "text" };
import type { ModelRegistry } from "../../config/model-registry";
import type { Settings } from "../../config/settings";
+1 -1
View File
@@ -1,4 +1,4 @@
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import type { CommitCommandArgs } from "./types";
const FLAG_ALIASES = new Map<string, string>([
@@ -27,7 +27,7 @@ import { DEFAULT_MODEL_PER_PROVIDER } from "@oh-my-pi/pi-catalog/provider-models
import { resolveBareVariantAlias, resolveVariantAlias } from "@oh-my-pi/pi-catalog/variant-collapse";
import { fuzzyMatch } from "@oh-my-pi/pi-tui";
import { logger } from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import MODEL_PRIO from "../priority.json" with { type: "json" };
import {
AUTO_THINKING,
@@ -27,14 +27,15 @@ const flag = (opts as { enabled: boolean })["enabled"];
## Use
Prefer a schema parse at the boundary when a validator is available (Zod, Valibot, …) — validate once, then read from a fully typed value. If Zod is already in the project (e.g. Zod v4):
Prefer a schema parse at the boundary when a validator is available — validate
once, then read from a fully typed value:
```ts
import { z } from "zod/v4";
import { type } from "@oh-my-pi/omptype";
const Resp = z.object({ data: z.object({ id: z.string() }) });
const Resp = type({ data: { id: "string" } });
const resp = Resp.parse(raw); // throws on bad input; resp.data.id is typed string
const resp = Resp.assert(raw); // throws on bad input; resp.data.id is typed string
const id = resp.data.id;
```
@@ -6,8 +6,8 @@
*/
import * as fs from "node:fs";
import * as path from "node:path";
import * as arktype from "@oh-my-pi/omptype";
import * as zodModule from "@oh-my-pi/omptype/zod";
import { type } from "@oh-my-pi/omptype";
import * as zod from "@oh-my-pi/omptype/zod";
import { getAgentDir, getProjectDir, isEnoent, logger } from "@oh-my-pi/pi-utils";
import { getConfigDirs } from "../../config";
import { execCommand } from "../../exec/exec";
@@ -187,8 +187,8 @@ export async function loadCustomCommands(options: LoadCustomCommandsOptions = {}
exec: (command: string, args: string[], execOptions) =>
execCommand(command, args, execOptions?.cwd ?? cwd, execOptions),
typebox,
arktype,
zod: zodModule,
arktype: type,
zod,
pi: PiCodingAgent,
};
@@ -5,7 +5,7 @@
* Unlike markdown commands which expand to prompts, custom commands can execute
* arbitrary logic with full access to the hook context.
*/
import type * as arktype from "@oh-my-pi/omptype";
import type { type as ArkType } from "@oh-my-pi/omptype";
import type * as TypeBox from "@oh-my-pi/omptype/typebox";
import type * as zod from "@oh-my-pi/omptype/zod";
import type { ExecOptions, ExecResult, HookCommandContext } from "../../extensibility/hooks/types";
@@ -23,11 +23,11 @@ export interface CustomCommandAPI {
cwd: string;
/** Execute a shell command */
exec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;
/** Injected zod-backed typebox shim (legacy/compat). */
/** Injected TypeBox shim (legacy/compat). */
typebox: typeof TypeBox;
/** Injected arktype module for validation in custom commands. */
arktype: typeof arktype;
/** Injected omptype-backed zod facade for command validation. */
/** Injected omptype schema builder for custom commands. */
arktype: typeof ArkType;
/** Injected Zod-compatible omptype builder for custom commands. */
zod: typeof zod;
/** Injected pi-coding-agent exports */
pi: typeof PiCodingAgent;
@@ -1,12 +1,12 @@
/**
* Custom tool loader - loads TypeScript tool modules using native Bun import.
*
* Dependencies (the zod-backed typebox shim and pi-coding-agent) are injected via the
* CustomToolAPI to avoid import resolution issues with custom tools loaded from user directories.
* Dependencies are injected through CustomToolAPI so tools loaded from user
* directories do not depend on workspace module resolution.
*/
import * as path from "node:path";
import { type } from "@oh-my-pi/omptype";
import * as zodModule from "@oh-my-pi/omptype/zod";
import * as zod from "@oh-my-pi/omptype/zod";
import type { AgentToolResult } from "@oh-my-pi/pi-agent-core";
import { logger } from "@oh-my-pi/pi-utils";
import { toolCapability } from "../../capability/tool";
@@ -149,7 +149,7 @@ export class CustomToolLoader {
logger,
typebox,
arktype: type,
zod: zodModule,
zod,
pi,
pushPendingAction: action => {
if (!pushPendingAction) {
@@ -70,7 +70,7 @@ export interface CustomToolAPI {
typebox: typeof TypeBox;
/** Injected arktype module for arktype-authored custom tools. */
arktype: typeof ArkType;
/** Injected omptype-backed zod facade for parameter schemas. */
/** Injected Zod-compatible omptype builder for custom tools. */
zod: typeof zod;
/** Injected pi-coding-agent exports */
pi: typeof PiCodingAgent;
@@ -4,8 +4,8 @@
import type * as fs1 from "node:fs";
import * as fs from "node:fs/promises";
import * as path from "node:path";
import { Type } from "@oh-my-pi/omptype";
import * as zodModule from "@oh-my-pi/omptype/zod";
import { type } from "@oh-my-pi/omptype";
import * as zod from "@oh-my-pi/omptype/zod";
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
import type {
ImageContent,
@@ -141,8 +141,8 @@ export class ExtensionRuntime implements IExtensionRuntime {
class ConcreteExtensionAPI implements ExtensionAPI, IExtensionRuntime {
readonly logger = logger;
readonly typebox = TypeBox;
readonly arktype = Type;
readonly zod = zodModule;
readonly arktype = type;
readonly zod = zod;
readonly flagValues = new Map<string, boolean | string>();
readonly pendingProviderRegistrations: Array<{
name: string;
@@ -8,7 +8,7 @@
* - Interact with the user via UI primitives
*/
import type { Type as arktype } from "@oh-my-pi/omptype";
import type { type as ArkType } from "@oh-my-pi/omptype";
import type * as TypeBox from "@oh-my-pi/omptype/typebox";
import type * as zod from "@oh-my-pi/omptype/zod";
import type {
@@ -1109,12 +1109,13 @@ export interface ExtensionAPI {
/** File logger for error/warning/debug messages */
logger: typeof PiLogger;
/** Injected zod-backed typebox shim for legacy `Type.Object(...)` parameter authoring. */
/** Injected TypeBox shim for legacy `Type.Object(...)` parameter authoring. */
typebox: typeof TypeBox;
/** Injected arktype module for arktype-authored extension tools (canonical going forward). */
arktype: typeof arktype;
/** Injected omptype-backed zod facade for extension tool parameter schemas. */
/** Injected omptype schema builder for extension tools. */
arktype: typeof ArkType;
/** Injected Zod-compatible omptype builder for extension tools. */
zod: typeof zod;
/** Injected pi-coding-agent exports for accessing SDK utilities */
@@ -2,8 +2,8 @@
* Hook loader - loads TypeScript hook modules using native Bun import.
*/
import * as path from "node:path";
import * as arktype from "@oh-my-pi/omptype";
import * as zodModule from "@oh-my-pi/omptype/zod";
import { type } from "@oh-my-pi/omptype";
import * as zod from "@oh-my-pi/omptype/zod";
import { logger } from "@oh-my-pi/pi-utils";
import { hookCapability } from "../../capability/hook";
import type { Hook } from "../../discovery";
@@ -122,9 +122,8 @@ async function createHookAPI(
},
logger,
typebox,
// HookAPI.arktype is typed as the arktype `Type` constructor; expose it from the module namespace.
arktype: arktype.Type,
zod: zodModule,
arktype: type,
zod,
pi: PiCodingAgent,
} as HookAPI;
@@ -1,4 +1,4 @@
import type { Type } from "@oh-my-pi/omptype";
import type { type as ArkType } from "@oh-my-pi/omptype";
import type * as TypeBox from "@oh-my-pi/omptype/typebox";
import type * as zod from "@oh-my-pi/omptype/zod";
import type { ImageContent, Message, Model, TextContent } from "@oh-my-pi/pi-ai";
@@ -582,11 +582,11 @@ export interface HookAPI {
/** File logger for error/warning/debug messages */
logger: typeof PiLogger;
/** Injected zod-backed typebox shim (legacy/compat — prefer `arktype`). */
/** Injected TypeBox shim (legacy/compat — prefer `arktype`). */
typebox: typeof TypeBox;
/** Injected arktype module for arktype-authored hooks. */
arktype: typeof Type;
/** Injected omptype-backed zod facade for hook validation. */
/** Injected omptype schema builder for hooks. */
arktype: typeof ArkType;
/** Injected Zod-compatible omptype builder for hooks. */
zod: typeof zod;
/** Injected pi-coding-agent exports */
pi: typeof PiCodingAgent;
+2 -2
View File
@@ -2,12 +2,12 @@ import { HookEditorComponent, HookInputComponent, HookSelectorComponent } from "
// Core session management
export * as zod from "@oh-my-pi/omptype/zod";
export { z } from "@oh-my-pi/omptype/zod";
// Re-export TUI components for custom tool rendering
export { Container, Markdown, Spacer, Text } from "@oh-my-pi/pi-tui";
// Logging
export { getAgentDir, logger, VERSION } from "@oh-my-pi/pi-utils";
export * as zod from "zod/v4";
export { z } from "zod/v4";
export * from "./config/keybindings";
export * from "./config/model-registry";
// Prompt templates
@@ -1,5 +1,5 @@
import { logger } from "@oh-my-pi/pi-utils";
import xterm, { type Terminal as XtermTerminal } from "@xterm/headless";
import xterm, { type Terminal as XtermTerminal } from "@oh-my-pi/pi-utils/vterm";
import { readTerminalRows } from "../tools/terminal-output";
import { DAEMON_PTY_COLUMNS, DAEMON_PTY_ROWS } from "./protocol";
+1 -1
View File
@@ -21,7 +21,7 @@ import {
setProjectDir,
VERSION,
} from "@oh-my-pi/pi-utils";
import chalk from "chalk";
import chalk from "@oh-my-pi/pi-utils/chalk";
import { reset as resetCapabilities } from "./capability";
import { type Args, reportUnrecognizedFlags } from "./cli/args";
import { applyExtensionFlags, type ExtensionFlagSink } from "./cli/extension-flags";
@@ -1,6 +1,6 @@
// Adapted from markit-ai (MIT). See ../NOTICE.
import * as path from "node:path";
import mammoth from "mammoth";
import mammoth from "@oh-my-pi/pi-utils/docx";
import { createTurndown, normalizeTablesHtml } from "../../utils/turndown";
import type { ConversionResult, Converter, StreamInfo } from "../types";
@@ -1,5 +1,5 @@
// Adapted from markit-ai (MIT). See ../NOTICE.
import { XMLParser } from "fast-xml-parser";
import { XMLParser } from "@oh-my-pi/pi-utils/xml";
import { createTurndown, normalizeTablesHtml } from "../../utils/turndown";
import { unzip, unzipText } from "../../utils/zip";
import type { ConversionResult, Converter, StreamInfo } from "../types";
@@ -1,24 +0,0 @@
// Minimal ambient types for `mammoth` (ships no types). Declares only what
// DocxConverter uses. See ../NOTICE.
declare module "mammoth" {
interface MammothImage {
contentType?: string;
read(encoding: "base64"): Promise<string>;
}
interface ImgAttributes {
src: string;
alt?: string;
}
type ConvertImageHandler = (image: MammothImage) => Promise<ImgAttributes>;
interface ConvertOptions {
convertImage?: ConvertImageHandler;
}
interface ConvertResult {
value: string;
messages: unknown[];
}
export const images: { imgElement(fn: ConvertImageHandler): ConvertImageHandler };
export function convertToHtml(input: { buffer: Buffer }, options?: ConvertOptions): Promise<ConvertResult>;
const _default: { convertToHtml: typeof convertToHtml; images: typeof images };
export default _default;
}

Some files were not shown because too many files have changed in this diff Show More