From 81add2045e78bd33f21a910f35928ec524d2c082 Mon Sep 17 00:00:00 2001 From: Juan ignacio Gipponi Date: Thu, 21 May 2026 22:01:40 -0300 Subject: [PATCH 1/2] feat: extract Tool class + lib/tool/ modules into src/ (#3) Copy 7 modules from kael.factory lib/tool/ into standalone package src/: types, args, json-schema, output-helpers, introspection, envelopes, tool-class. Create lean src/utils.ts with ToolOutput, jsonOutput, stringifyError. Add zod v4 as production dependency. Replace placeholder barrel with public API re-exports. Add 15 smoke tests covering Tool construction, invoke dispatch, error envelopes, and output helpers. --- bun.lock | 150 ++++---- ...ct-tool-class-lib-tool-modules-into-src.md | 137 +++++++ package.json | 10 +- src/args.ts | 122 ++++++ src/envelopes.ts | 217 +++++++++++ src/index.ts | 30 +- src/introspection.ts | 78 ++++ src/json-schema.ts | 40 ++ src/output-helpers.ts | 96 +++++ src/tool-class.ts | 349 ++++++++++++++++++ src/types.ts | 79 ++++ src/utils.ts | 23 ++ tests/index.test.ts | 192 +++++++++- tsconfig.json | 5 + 14 files changed, 1450 insertions(+), 78 deletions(-) create mode 100644 docs/specs/issue-3-extract-tool-class-lib-tool-modules-into-src.md create mode 100644 src/args.ts create mode 100644 src/envelopes.ts create mode 100644 src/introspection.ts create mode 100644 src/json-schema.ts create mode 100644 src/output-helpers.ts create mode 100644 src/tool-class.ts create mode 100644 src/types.ts create mode 100644 src/utils.ts diff --git a/bun.lock b/bun.lock index 68f25c5..4d22fad 100644 --- a/bun.lock +++ b/bun.lock @@ -3,9 +3,9 @@ "configVersion": 1, "workspaces": { "": { - "name": "@code-first-agents/tool", + "name": "bun-ts-template", "dependencies": { - "zod": "^3.25.1", + "zod": "^4.0.0", }, "devDependencies": { "@biomejs/biome": "latest", @@ -19,11 +19,11 @@ }, }, "packages": { - "@actions/core": ["@actions/core@3.0.1", "", { "dependencies": { "@actions/exec": "^3.0.0", "@actions/http-client": "^4.0.0" } }, "sha512-a6d/Nwahm9fliVGRhdhofo40HjHQasUPusmc7vBfyky+7Z+P2A1J68zyFVaNcEclc/Se+eO595oAr5nwEIoIUA=="], + "@actions/core": ["@actions/core@3.0.0", "", { "dependencies": { "@actions/exec": "^3.0.0", "@actions/http-client": "^4.0.0" } }, "sha512-zYt6cz+ivnTmiT/ksRVriMBOiuoUpDCJJlZ5KPl2/FRdvwU3f7MPh9qftvbkXJThragzUZieit2nyHUyw53Seg=="], "@actions/exec": ["@actions/exec@3.0.0", "", { "dependencies": { "@actions/io": "^3.0.2" } }, "sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw=="], - "@actions/http-client": ["@actions/http-client@4.0.1", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^6.23.0" } }, "sha512-+Nvd1ImaOZBSoPbsUtEhv+1z99H12xzncCkz0a3RuehINE81FZSe2QTj3uvAPTcJX/SCzUQHQ0D1GrPMbrPitg=="], + "@actions/http-client": ["@actions/http-client@4.0.0", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^6.23.0" } }, "sha512-QuwPsgVMsD6qaPD57GLZi9sqzAZCtiJT8kVBCDpLtxhL5MydQ4gS+DrejtZZPdIYyB1e95uCK9Luyds7ybHI3g=="], "@actions/io": ["@actions/io@3.0.2", "", {}, "sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw=="], @@ -31,23 +31,23 @@ "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], - "@biomejs/biome": ["@biomejs/biome@2.4.15", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.15", "@biomejs/cli-darwin-x64": "2.4.15", "@biomejs/cli-linux-arm64": "2.4.15", "@biomejs/cli-linux-arm64-musl": "2.4.15", "@biomejs/cli-linux-x64": "2.4.15", "@biomejs/cli-linux-x64-musl": "2.4.15", "@biomejs/cli-win32-arm64": "2.4.15", "@biomejs/cli-win32-x64": "2.4.15" }, "bin": { "biome": "bin/biome" } }, "sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw=="], + "@biomejs/biome": ["@biomejs/biome@2.4.10", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.10", "@biomejs/cli-darwin-x64": "2.4.10", "@biomejs/cli-linux-arm64": "2.4.10", "@biomejs/cli-linux-arm64-musl": "2.4.10", "@biomejs/cli-linux-x64": "2.4.10", "@biomejs/cli-linux-x64-musl": "2.4.10", "@biomejs/cli-win32-arm64": "2.4.10", "@biomejs/cli-win32-x64": "2.4.10" }, "bin": { "biome": "bin/biome" } }, "sha512-xxA3AphFQ1geij4JTHXv4EeSTda1IFn22ye9LdyVPoJU19fNVl0uzfEuhsfQ4Yue/0FaLs2/ccVi4UDiE7R30w=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vuzzI1cWqDVzOMIkYyHbKqp+AkQq4K7k+UCXWpkYcY/HDn1UxdsbsfgtVpa40shem8Kax4TLDLlx8kMAecgqiw=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.15", "", { "os": "darwin", "cpu": "x64" }, "sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-14fzASRo+BPotwp7nWULy2W5xeUyFnTaq1V13Etrrxkrih+ez/2QfgFm5Ehtf5vSjtgx/IJycMMpn5kPd5ZNaA=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-7MH1CMW5uuxQ/s7FLST63qF8B3Hgu2HRdZ7tA1X1+mk+St4JOuIrqdhIBnnyqeyWJNI+Bww7Es5QZ0wIc1Cmkw=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-WrJY6UuiSD/Dh+nwK2qOTu8kdMDlLV3dLMmychIghHPAysWFq1/DGC1pVZx8POE3ZkzKR3PUUnVrtZfMfaJjyQ=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.15", "", { "os": "linux", "cpu": "x64" }, "sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.10", "", { "os": "linux", "cpu": "x64" }, "sha512-tZLvEEi2u9Xu1zAqRjTcpIDGVtldigVvzug2fTuPG0ME/g8/mXpRPcNgLB22bGn6FvLJpHHnqLnwliOu8xjYrg=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.15", "", { "os": "linux", "cpu": "x64" }, "sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.10", "", { "os": "linux", "cpu": "x64" }, "sha512-kDTi3pI6PBN6CiczsWYOyP2zk0IJI08EWEQyDMQWW221rPaaEz6FvjLhnU07KMzLv8q3qSuoB93ua6inSQ55Tw=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.15", "", { "os": "win32", "cpu": "arm64" }, "sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-umwQU6qPzH+ISTf/eHyJ/QoQnJs3V9Vpjz2OjZXe9MVBZ7prgGafMy7yYeRGnlmDAn87AKTF3Q6weLoMGpeqdQ=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.15", "", { "os": "win32", "cpu": "x64" }, "sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.10", "", { "os": "win32", "cpu": "x64" }, "sha512-aW/JU5GuyH4uxMrNYpoC2kjaHlyJGLgIa3XkhPEZI0uKhZhJZU8BuEyJmvgzSPQNGozBwWjC972RaNdcJ9KyJg=="], "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], @@ -67,7 +67,7 @@ "@octokit/plugin-throttling": ["@octokit/plugin-throttling@11.0.3", "", { "dependencies": { "@octokit/types": "^16.0.0", "bottleneck": "^2.15.3" }, "peerDependencies": { "@octokit/core": "^7.0.0" } }, "sha512-34eE0RkFCKycLl2D2kq7W+LovheM/ex3AwZCYN8udpi6bxsyjZidb2McXs69hZhLmJlDqTSP8cH+jSRpiaijBg=="], - "@octokit/request": ["@octokit/request@10.0.9", "", { "dependencies": { "@octokit/endpoint": "^11.0.3", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "content-type": "^2.0.0", "fast-content-type-parse": "^3.0.0", "json-with-bigint": "^3.5.3", "universal-user-agent": "^7.0.2" } }, "sha512-o8Bi3f608eyM+7BmBiUWxFsdjLb3/ym1cQek5LZOv9KkZcxRrHCPhhRzm6xjO6HVZ85ItD6+sTsjxo821SVa/A=="], + "@octokit/request": ["@octokit/request@10.0.8", "", { "dependencies": { "@octokit/endpoint": "^11.0.3", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "json-with-bigint": "^3.5.3", "universal-user-agent": "^7.0.2" } }, "sha512-SJZNwY9pur9Agf7l87ywFi14W+Hd9Jg6Ifivsd33+/bGUQIjNujdFiXII2/qSlN2ybqUHfp5xpekMEjIBTjlSw=="], "@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], @@ -89,11 +89,11 @@ "@semantic-release/git": ["@semantic-release/git@10.0.1", "", { "dependencies": { "@semantic-release/error": "^3.0.0", "aggregate-error": "^3.0.0", "debug": "^4.0.0", "dir-glob": "^3.0.0", "execa": "^5.0.0", "lodash": "^4.17.4", "micromatch": "^4.0.0", "p-reduce": "^2.0.0" }, "peerDependencies": { "semantic-release": ">=18.0.0" } }, "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w=="], - "@semantic-release/github": ["@semantic-release/github@12.0.8", "", { "dependencies": { "@octokit/core": "^7.0.0", "@octokit/plugin-paginate-rest": "^14.0.0", "@octokit/plugin-retry": "^8.0.0", "@octokit/plugin-throttling": "^11.0.0", "@semantic-release/error": "^4.0.0", "aggregate-error": "^5.0.0", "debug": "^4.3.4", "dir-glob": "^3.0.1", "http-proxy-agent": "^9.0.0", "https-proxy-agent": "^9.0.0", "issue-parser": "^7.0.0", "lodash-es": "^4.17.21", "mime": "^4.0.0", "p-filter": "^4.0.0", "tinyglobby": "^0.2.14", "undici": "^7.0.0", "url-join": "^5.0.0" }, "peerDependencies": { "semantic-release": ">=24.1.0" } }, "sha512-tej5AAgK5X9wHRoDmYhecMXEHEkFeGOY1XsEblKxu8pIQwahzf1STYyr7iPU6Lpbg6C5I3N2w/ocXrBo+L7jhw=="], + "@semantic-release/github": ["@semantic-release/github@12.0.6", "", { "dependencies": { "@octokit/core": "^7.0.0", "@octokit/plugin-paginate-rest": "^14.0.0", "@octokit/plugin-retry": "^8.0.0", "@octokit/plugin-throttling": "^11.0.0", "@semantic-release/error": "^4.0.0", "aggregate-error": "^5.0.0", "debug": "^4.3.4", "dir-glob": "^3.0.1", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "issue-parser": "^7.0.0", "lodash-es": "^4.17.21", "mime": "^4.0.0", "p-filter": "^4.0.0", "tinyglobby": "^0.2.14", "undici": "^7.0.0", "url-join": "^5.0.0" }, "peerDependencies": { "semantic-release": ">=24.1.0" } }, "sha512-aYYFkwHW3c6YtHwQF0t0+lAjlU+87NFOZuH2CvWFD0Ylivc7MwhZMiHOJ0FMpIgPpCVib/VUAcOwvrW0KnxQtA=="], "@semantic-release/npm": ["@semantic-release/npm@13.1.5", "", { "dependencies": { "@actions/core": "^3.0.0", "@semantic-release/error": "^4.0.0", "aggregate-error": "^5.0.0", "env-ci": "^11.2.0", "execa": "^9.0.0", "fs-extra": "^11.0.0", "lodash-es": "^4.17.21", "nerf-dart": "^1.0.0", "normalize-url": "^9.0.0", "npm": "^11.6.2", "rc": "^1.2.8", "read-pkg": "^10.0.0", "registry-auth-token": "^5.0.0", "semver": "^7.1.2", "tempy": "^3.0.0" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-Hq5UxzoatN3LHiq2rTsWS54nCdqJHlsssGERCo8WlvdfFA9LoN0vO+OuKVSjtNapIc/S8C2LBj206wKLHg62mg=="], - "@semantic-release/release-notes-generator": ["@semantic-release/release-notes-generator@14.1.1", "", { "dependencies": { "conventional-changelog-angular": "^8.0.0", "conventional-changelog-writer": "^8.0.0", "conventional-commits-filter": "^5.0.0", "conventional-commits-parser": "^6.0.0", "debug": "^4.0.0", "import-from-esm": "^2.0.0", "lodash-es": "^4.17.21", "read-package-up": "^11.0.0" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-Pbd2e2XRMUD0OxehHpgd5/YghsE76cddkRHSoDvKLK+OCy4Ewxn49rWR631MEUU01lgwF/uyVXvbnVuu6+Z6VA=="], + "@semantic-release/release-notes-generator": ["@semantic-release/release-notes-generator@14.1.0", "", { "dependencies": { "conventional-changelog-angular": "^8.0.0", "conventional-changelog-writer": "^8.0.0", "conventional-commits-filter": "^5.0.0", "conventional-commits-parser": "^6.0.0", "debug": "^4.0.0", "get-stream": "^7.0.0", "import-from-esm": "^2.0.0", "into-stream": "^7.0.0", "lodash-es": "^4.17.21", "read-package-up": "^11.0.0" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-CcyDRk7xq+ON/20YNR+1I/jP7BYKICr1uKd1HHpROSnnTdGqOTburi4jcRiTYz0cpfhxSloQO3cGhnoot7IEkA=="], "@simple-libs/stream-utils": ["@simple-libs/stream-utils@1.2.0", "", {}, "sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA=="], @@ -101,11 +101,11 @@ "@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="], - "@types/node": ["@types/node@25.9.1", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg=="], + "@types/node": ["@types/node@25.5.2", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg=="], "@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="], - "agent-base": ["agent-base@9.0.0", "", {}, "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA=="], + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="], @@ -129,7 +129,7 @@ "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - "bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="], + "bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="], "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], @@ -153,8 +153,6 @@ "config-chain": ["config-chain@1.1.13", "", { "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" } }, "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ=="], - "content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], - "conventional-changelog-angular": ["conventional-changelog-angular@8.3.1", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg=="], "conventional-changelog-writer": ["conventional-changelog-writer@8.4.0", "", { "dependencies": { "@simple-libs/stream-utils": "^1.2.0", "conventional-commits-filter": "^5.0.0", "handlebars": "^4.7.7", "meow": "^13.0.0", "semver": "^7.5.2" }, "bin": { "conventional-changelog-writer": "dist/cli/index.js" } }, "sha512-HHBFkk1EECxxmCi4CTu091iuDpQv5/OavuCUAuZmrkWpmYfyD816nom1CvtfXJ/uYfAAjavgHvXHX291tSLK8g=="], @@ -215,13 +213,15 @@ "find-versions": ["find-versions@6.0.0", "", { "dependencies": { "semver-regex": "^4.0.5", "super-regex": "^1.0.0" } }, "sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA=="], - "fs-extra": ["fs-extra@11.3.5", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg=="], + "from2": ["from2@2.3.0", "", { "dependencies": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" } }, "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g=="], + + "fs-extra": ["fs-extra@11.3.4", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA=="], "function-timeout": ["function-timeout@1.0.2", "", {}, "sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA=="], "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], - "get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="], + "get-east-asian-width": ["get-east-asian-width@1.5.0", "", {}, "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA=="], "get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], @@ -237,11 +237,11 @@ "hook-std": ["hook-std@4.0.0", "", {}, "sha512-IHI4bEVOt3vRUDJ+bFA9VUJlo7SzvFARPNLw75pqSmAOP2HmTWfFJtPvLBrDrlgjEYXY9zs7SFdHPQaJShkSCQ=="], - "hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="], + "hosted-git-info": ["hosted-git-info@9.0.2", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg=="], - "http-proxy-agent": ["http-proxy-agent@9.0.0", "", { "dependencies": { "agent-base": "9.0.0", "debug": "^4.3.4" } }, "sha512-FcF8VhXYLQcxWCnt/cCpT2apKsRDUGeVEeMqGu4HSTu29U8Yw0TLOjdYIlDsYk3IkUh+taX4IDWpPcCqKDhCjA=="], + "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], - "https-proxy-agent": ["https-proxy-agent@9.0.0", "", { "dependencies": { "agent-base": "9.0.0", "debug": "^4.3.4" } }, "sha512-/MVmHp58WkOypgFhCLk4fzpPcFQvTJ/e6LBI7irpIO2HfxUbpmYoHF+KzipzJpxxzJu7aJNWQ0xojJ/dzV2G5g=="], + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], "human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], @@ -259,6 +259,8 @@ "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + "into-stream": ["into-stream@7.0.0", "", { "dependencies": { "from2": "^2.3.0", "p-is-promise": "^3.0.0" } }, "sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw=="], + "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], @@ -277,7 +279,7 @@ "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - "issue-parser": ["issue-parser@7.0.2", "", { "dependencies": { "lodash.capitalize": "^4.2.1", "lodash.escaperegexp": "^4.1.2", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.uniqby": "^4.7.0" } }, "sha512-7atWPjhGEIX3JEtMrOYd8TKzboYlq+5sNbdl9POiLYOI14G5HZiQbZP0Xj5EZdrufQVXfJlpTV0hys0CuxwxZw=="], + "issue-parser": ["issue-parser@7.0.1", "", { "dependencies": { "lodash.capitalize": "^4.2.1", "lodash.escaperegexp": "^4.1.2", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.uniqby": "^4.7.0" } }, "sha512-3YZcUUR2Wt1WsapF+S/WiA2WmlW0cWAoPccMqne7AxEBhCdFeTPjfv/Axb8V2gyCgY3nRw+ksZ3xSUX+R47iAg=="], "java-properties": ["java-properties@1.0.2", "", {}, "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ=="], @@ -291,29 +293,29 @@ "json-with-bigint": ["json-with-bigint@3.5.8", "", {}, "sha512-eq/4KP6K34kwa7TcFdtvnftvHCD9KvHOGGICWwMFc4dOOKF5t4iYqnfLK8otCRCRv06FXOzGGyqE8h8ElMvvdw=="], - "jsonfile": ["jsonfile@6.2.1", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q=="], + "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], - "lefthook": ["lefthook@2.1.8", "", { "optionalDependencies": { "lefthook-darwin-arm64": "2.1.8", "lefthook-darwin-x64": "2.1.8", "lefthook-freebsd-arm64": "2.1.8", "lefthook-freebsd-x64": "2.1.8", "lefthook-linux-arm64": "2.1.8", "lefthook-linux-x64": "2.1.8", "lefthook-openbsd-arm64": "2.1.8", "lefthook-openbsd-x64": "2.1.8", "lefthook-windows-arm64": "2.1.8", "lefthook-windows-x64": "2.1.8" }, "bin": { "lefthook": "bin/index.js" } }, "sha512-tJIoVpFF52PuU8YPJI9bRprGwzI6FR2GNeBbpMnXdRjjfJHyOR4VRLXilzoQ6lbhKVHfTohXhrQgLpU41bKITg=="], + "lefthook": ["lefthook@2.1.4", "", { "optionalDependencies": { "lefthook-darwin-arm64": "2.1.4", "lefthook-darwin-x64": "2.1.4", "lefthook-freebsd-arm64": "2.1.4", "lefthook-freebsd-x64": "2.1.4", "lefthook-linux-arm64": "2.1.4", "lefthook-linux-x64": "2.1.4", "lefthook-openbsd-arm64": "2.1.4", "lefthook-openbsd-x64": "2.1.4", "lefthook-windows-arm64": "2.1.4", "lefthook-windows-x64": "2.1.4" }, "bin": { "lefthook": "bin/index.js" } }, "sha512-JNfJ5gAn0KADvJ1I6/xMcx70+/6TL6U9gqGkKvPw5RNMfatC7jIg0Evl97HN846xmfz959BV70l8r3QsBJk30w=="], - "lefthook-darwin-arm64": ["lefthook-darwin-arm64@2.1.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-6dZr2QUdJOOvy9FjQHZoFVfPjgxb9IH5f9DeU0OBYMQ0cUGvb5YjHnkUkRrWIlASmwFm1bk3OPwhqKU7pTsICw=="], + "lefthook-darwin-arm64": ["lefthook-darwin-arm64@2.1.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BUAAE9+rUrjr39a+wH/1zHmGrDdwUQ2Yq/z6BQbM/yUb9qtXBRcQ5eOXxApqWW177VhGBpX31aqIlfAZ5Q7wzw=="], - "lefthook-darwin-x64": ["lefthook-darwin-x64@2.1.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-DW1yc+W5RBHdwaPJ94/mwFNROmNHI8Osu0iziIeJFXJIdkQ2P+KHfoxBWejYd2QA2Eu5W9i+gBssTDkJ4kX2kA=="], + "lefthook-darwin-x64": ["lefthook-darwin-x64@2.1.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-K1ncIMEe84fe+ss1hQNO7rIvqiKy2TJvTFpkypvqFodT7mJXZn7GLKYTIXdIuyPAYthRa9DwFnx5uMoHwD2F1Q=="], - "lefthook-freebsd-arm64": ["lefthook-freebsd-arm64@2.1.8", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-rmWVdImTihY/V1bLSb3zeDxEHjRBQtudnkKKsoph934enIWPwzIap5zVHHAj8q9mzp0wpn5r1ybX55aO2wM61A=="], + "lefthook-freebsd-arm64": ["lefthook-freebsd-arm64@2.1.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-PVUhjOhVN71YaYsVdQyNbFZ4a2jFB2Tg5hKrrn9kaWpx64aLz/XivLjwr8sEuTaP1GRlEWBpW6Bhrcsyo39qFw=="], - "lefthook-freebsd-x64": ["lefthook-freebsd-x64@2.1.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-o1AG4CpmgESxLqZWzkXhne+PhLhLFV0GHVAIJCmieOwq4q2+rDYAudGhtot/NrgSpyMCo84qVSQmI8Dgnu1XJw=="], + "lefthook-freebsd-x64": ["lefthook-freebsd-x64@2.1.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-ZWV9o/LeyWNEBoVO+BhLqxH3rGTba05nkm5NvMjEFSj7LbUNUDbQmupZwtHl1OMGJO66eZP0CalzRfUH6GhBxQ=="], - "lefthook-linux-arm64": ["lefthook-linux-arm64@2.1.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-er3zTjx2DMxojPJ1LZv0G3ug9Th+mAapqWrt5ZZhQNcXWW28pfvo2fCqBs6Fz14GMn4xassmwOpGovutSh1UtA=="], + "lefthook-linux-arm64": ["lefthook-linux-arm64@2.1.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-iWN0pGnTjrIvNIcSI1vQBJXUbybTqJ5CLMniPA0olabMXQfPDrdMKVQe+mgdwHK+E3/Y0H0ZNL3lnOj6Sk6szA=="], - "lefthook-linux-x64": ["lefthook-linux-x64@2.1.8", "", { "os": "linux", "cpu": "x64" }, "sha512-3yGx0VFbPcaKiIir313ETNcyq34CfAwkIU+Ry3WMGDjrsRNuA/YlDxm0BHKLcum7u+rpVfT4Uz6r8gHdaHXolg=="], + "lefthook-linux-x64": ["lefthook-linux-x64@2.1.4", "", { "os": "linux", "cpu": "x64" }, "sha512-96bTBE/JdYgqWYAJDh+/e/0MaxJ25XTOAk7iy/fKoZ1ugf6S0W9bEFbnCFNooXOcxNVTan5xWKfcjJmPIKtsJA=="], - "lefthook-openbsd-arm64": ["lefthook-openbsd-arm64@2.1.8", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Dq+GJdJdclOwxt4NneTFHjLSA4v8tI7XUZq40KUVtpUQDpZcYhXSdkTytB0uLmD52tbFKt9Kx0VbB6uvxPvLvw=="], + "lefthook-openbsd-arm64": ["lefthook-openbsd-arm64@2.1.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-oYUoK6AIJNEr9lUSpIMj6g7sWzotvtc3ryw7yoOyQM6uqmEduw73URV/qGoUcm4nqqmR93ZalZwR2r3Gd61zvw=="], - "lefthook-openbsd-x64": ["lefthook-openbsd-x64@2.1.8", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/Gv2EdlzyiDoK+9fDWIn+EeTgrNeVncQsSeAF47X2Abe5LGxuFjZbBXxEIkY1BU79OQNNLnkx0gFHbrr5mmd9Q=="], + "lefthook-openbsd-x64": ["lefthook-openbsd-x64@2.1.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-i/Dv9Jcm68y9cggr1PhyUhOabBGP9+hzQPoiyOhKks7y9qrJl79A8XfG6LHekSuYc2VpiSu5wdnnrE1cj2nfTg=="], - "lefthook-windows-arm64": ["lefthook-windows-arm64@2.1.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-S+/pBBj/7hMQOl9pLBS4Ut8+U0feQbzmD7iN0ifNth4r/uqW8UFFAHwERbclfsVnni4ceHpt7lFr7sXsu0RU8g=="], + "lefthook-windows-arm64": ["lefthook-windows-arm64@2.1.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-hSww7z+QX4YMnw2lK7DMrs3+w7NtxksuMKOkCKGyxUAC/0m1LAICo0ZbtdDtZ7agxRQQQ/SEbzFRhU5ysNcbjA=="], - "lefthook-windows-x64": ["lefthook-windows-x64@2.1.8", "", { "os": "win32", "cpu": "x64" }, "sha512-MpdgKMU/JLLCsEpTqJ9jWlxngSdDh3EknvUHveWePrIms7G11y6R3oZBNRSqZ+zx/PGNl/HKvqEtbwtw8Hz3gw=="], + "lefthook-windows-x64": ["lefthook-windows-x64@2.1.4", "", { "os": "win32", "cpu": "x64" }, "sha512-eE68LwnogxwcPgGsbVGPGxmghyMGmU9SdGwcc+uhGnUxPz1jL89oECMWJNc36zjVK24umNeDAzB5KA3lw1MuWw=="], "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], @@ -335,7 +337,7 @@ "lodash.uniqby": ["lodash.uniqby@4.7.0", "", {}, "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww=="], - "lru-cache": ["lru-cache@11.5.0", "", {}, "sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA=="], + "lru-cache": ["lru-cache@11.2.7", "", {}, "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA=="], "make-asynchronous": ["make-asynchronous@1.1.0", "", { "dependencies": { "p-event": "^6.0.0", "type-fest": "^4.6.0", "web-worker": "^1.5.0" } }, "sha512-ayF7iT+44LXdxJLTrTd3TLQpFDDvPCBxXxbv+pMUSuHA5Q8zyAfwkRP6aHHwNVFBUFWtxAHqwNJxF8vMZLAbVg=="], @@ -367,9 +369,9 @@ "normalize-package-data": ["normalize-package-data@8.0.0", "", { "dependencies": { "hosted-git-info": "^9.0.0", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" } }, "sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ=="], - "normalize-url": ["normalize-url@9.0.1", "", {}, "sha512-ARftfC5HdUNu9jJeL8pHj8debUIHA2b91FizCoMzY4lG6dDX13jdvTK0TBe24IBDRf2HvJSzzwEPvmbkQWHRSg=="], + "normalize-url": ["normalize-url@9.0.0", "", {}, "sha512-z9nC87iaZXXySbWWtTHfCFJyFvKaUAW6lODhikG7ILSbVgmwuFjUqkgnheHvAUcGedO29e2QGBRXMUD64aurqQ=="], - "npm": ["npm@11.15.0", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/arborist": "^9.6.0", "@npmcli/config": "^10.9.1", "@npmcli/fs": "^5.0.0", "@npmcli/map-workspaces": "^5.0.3", "@npmcli/metavuln-calculator": "^9.0.3", "@npmcli/package-json": "^7.0.5", "@npmcli/promise-spawn": "^9.0.1", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.4", "@sigstore/tuf": "^4.0.2", "abbrev": "^4.0.0", "archy": "~1.0.0", "cacache": "^20.0.4", "chalk": "^5.6.2", "ci-info": "^4.4.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.3", "glob": "^13.0.6", "graceful-fs": "^4.2.11", "hosted-git-info": "^9.0.3", "ini": "^6.0.0", "init-package-json": "^8.2.5", "is-cidr": "^6.0.4", "json-parse-even-better-errors": "^5.0.0", "libnpmaccess": "^10.0.3", "libnpmdiff": "^8.1.8", "libnpmexec": "^10.2.8", "libnpmfund": "^7.0.22", "libnpmorg": "^8.0.1", "libnpmpack": "^9.1.8", "libnpmpublish": "^11.2.0", "libnpmsearch": "^9.0.1", "libnpmteam": "^8.0.2", "libnpmversion": "^8.0.3", "make-fetch-happen": "^15.0.5", "minimatch": "^10.2.5", "minipass": "^7.1.3", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", "node-gyp": "^12.3.0", "nopt": "^9.0.0", "npm-audit-report": "^7.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.2", "npm-pick-manifest": "^11.0.3", "npm-profile": "^12.0.1", "npm-registry-fetch": "^19.1.1", "npm-user-validate": "^4.0.0", "p-map": "^7.0.4", "pacote": "^21.5.0", "parse-conflict-json": "^5.0.1", "proc-log": "^6.1.0", "qrcode-terminal": "^0.12.0", "read": "^5.0.1", "semver": "^7.8.0", "spdx-expression-parse": "^4.0.0", "ssri": "^13.0.1", "supports-color": "^10.2.2", "tar": "^7.5.15", "text-table": "~0.2.0", "tiny-relative-date": "^2.0.2", "treeverse": "^3.0.0", "validate-npm-package-name": "^7.0.2", "which": "^6.0.1" }, "bin": { "npm": "bin/npm-cli.js", "npx": "bin/npx-cli.js" } }, "sha512-+k0tk7lRnpMUPnC7kTuU/yrV/mnFoPhJQ75VfLtZ6fwbzOVXaPsTE/Il9Pn1DHi482byMyqkHv/XsQ76mNjXLw=="], + "npm": ["npm@11.12.1", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/arborist": "^9.4.2", "@npmcli/config": "^10.8.1", "@npmcli/fs": "^5.0.0", "@npmcli/map-workspaces": "^5.0.3", "@npmcli/metavuln-calculator": "^9.0.3", "@npmcli/package-json": "^7.0.5", "@npmcli/promise-spawn": "^9.0.1", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.4", "@sigstore/tuf": "^4.0.2", "abbrev": "^4.0.0", "archy": "~1.0.0", "cacache": "^20.0.4", "chalk": "^5.6.2", "ci-info": "^4.4.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.3", "glob": "^13.0.6", "graceful-fs": "^4.2.11", "hosted-git-info": "^9.0.2", "ini": "^6.0.0", "init-package-json": "^8.2.5", "is-cidr": "^6.0.3", "json-parse-even-better-errors": "^5.0.0", "libnpmaccess": "^10.0.3", "libnpmdiff": "^8.1.5", "libnpmexec": "^10.2.5", "libnpmfund": "^7.0.19", "libnpmorg": "^8.0.1", "libnpmpack": "^9.1.5", "libnpmpublish": "^11.1.3", "libnpmsearch": "^9.0.1", "libnpmteam": "^8.0.2", "libnpmversion": "^8.0.3", "make-fetch-happen": "^15.0.5", "minimatch": "^10.2.4", "minipass": "^7.1.3", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", "node-gyp": "^12.2.0", "nopt": "^9.0.0", "npm-audit-report": "^7.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.2", "npm-pick-manifest": "^11.0.3", "npm-profile": "^12.0.1", "npm-registry-fetch": "^19.1.1", "npm-user-validate": "^4.0.0", "p-map": "^7.0.4", "pacote": "^21.5.0", "parse-conflict-json": "^5.0.1", "proc-log": "^6.1.0", "qrcode-terminal": "^0.12.0", "read": "^5.0.1", "semver": "^7.7.4", "spdx-expression-parse": "^4.0.0", "ssri": "^13.0.1", "supports-color": "^10.2.2", "tar": "^7.5.11", "text-table": "~0.2.0", "tiny-relative-date": "^2.0.2", "treeverse": "^3.0.0", "validate-npm-package-name": "^7.0.2", "which": "^6.0.1" }, "bin": { "npm": "bin/npm-cli.js", "npx": "bin/npx-cli.js" } }, "sha512-zcoUuF1kezGSAo0CqtvoLXX3mkRqzuqYdL6Y5tdo8g69NVV3CkjQ6ZBhBgB4d7vGkPcV6TcvLi3GRKPDFX+xTA=="], "npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="], @@ -383,6 +385,8 @@ "p-filter": ["p-filter@4.1.0", "", { "dependencies": { "p-map": "^7.0.1" } }, "sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw=="], + "p-is-promise": ["p-is-promise@3.0.0", "", {}, "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ=="], + "p-limit": ["p-limit@1.3.0", "", { "dependencies": { "p-try": "^1.0.0" } }, "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q=="], "p-locate": ["p-locate@2.0.0", "", { "dependencies": { "p-limit": "^1.1.0" } }, "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg=="], @@ -443,7 +447,7 @@ "semantic-release": ["semantic-release@25.0.3", "", { "dependencies": { "@semantic-release/commit-analyzer": "^13.0.1", "@semantic-release/error": "^4.0.0", "@semantic-release/github": "^12.0.0", "@semantic-release/npm": "^13.1.1", "@semantic-release/release-notes-generator": "^14.1.0", "aggregate-error": "^5.0.0", "cosmiconfig": "^9.0.0", "debug": "^4.0.0", "env-ci": "^11.0.0", "execa": "^9.0.0", "figures": "^6.0.0", "find-versions": "^6.0.0", "get-stream": "^6.0.0", "git-log-parser": "^1.2.0", "hook-std": "^4.0.0", "hosted-git-info": "^9.0.0", "import-from-esm": "^2.0.0", "lodash-es": "^4.17.21", "marked": "^15.0.0", "marked-terminal": "^7.3.0", "micromatch": "^4.0.2", "p-each-series": "^3.0.0", "p-reduce": "^3.0.0", "read-package-up": "^12.0.0", "resolve-from": "^5.0.0", "semver": "^7.3.2", "signale": "^1.2.1", "yargs": "^18.0.0" }, "bin": { "semantic-release": "bin/semantic-release.js" } }, "sha512-WRgl5GcypwramYX4HV+eQGzUbD7UUbljVmS+5G1uMwX/wLgYuJAxGeerXJDMO2xshng4+FXqCgyB5QfClV6WjA=="], - "semver": ["semver@7.8.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg=="], + "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], "semver-regex": ["semver-regex@4.0.5", "", {}, "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw=="], @@ -505,7 +509,7 @@ "time-span": ["time-span@5.1.0", "", { "dependencies": { "convert-hrtime": "^5.0.0" } }, "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA=="], - "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], @@ -513,15 +517,15 @@ "tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="], - "type-fest": ["type-fest@5.6.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA=="], + "type-fest": ["type-fest@5.5.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g=="], - "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + "typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="], "uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="], - "undici": ["undici@7.25.0", "", {}, "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ=="], + "undici": ["undici@7.24.7", "", {}, "sha512-H/nlJ/h0ggGC+uRL3ovD+G0i4bqhvsDOpbDv7At5eFLlj2b41L8QliGbnl2H7SnDiYhENphh1tQFJZf+MyfLsQ=="], - "undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="], + "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], "unicode-emoji-modifier-base": ["unicode-emoji-modifier-base@1.0.0", "", {}, "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g=="], @@ -557,9 +561,9 @@ "yoctocolors": ["yoctocolors@2.1.2", "", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="], - "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], - "@actions/http-client/undici": ["undici@6.25.0", "", {}, "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg=="], + "@actions/http-client/undici": ["undici@6.24.1", "", {}, "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA=="], "@pnpm/network.ca-file/graceful-fs": ["graceful-fs@4.2.10", "", {}, "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="], @@ -573,6 +577,8 @@ "@semantic-release/npm/execa": ["execa@9.6.1", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.1.1" } }, "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA=="], + "@semantic-release/release-notes-generator/get-stream": ["get-stream@7.0.1", "", {}, "sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ=="], + "@semantic-release/release-notes-generator/read-package-up": ["read-package-up@11.0.0", "", { "dependencies": { "find-up-simple": "^1.0.0", "read-pkg": "^9.0.0", "type-fest": "^4.6.0" } }, "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ=="], "cli-highlight/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], @@ -585,6 +591,8 @@ "env-ci/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="], + "fdir/picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], "load-json-file/parse-json": ["parse-json@4.0.0", "", { "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" } }, "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw=="], @@ -599,9 +607,9 @@ "npm/@npmcli/agent": ["@npmcli/agent@4.0.0", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^11.2.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA=="], - "npm/@npmcli/arborist": ["@npmcli/arborist@9.6.0", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^5.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/map-workspaces": "^5.0.0", "@npmcli/metavuln-calculator": "^9.0.2", "@npmcli/name-from-folder": "^4.0.0", "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/query": "^5.0.0", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.0", "bin-links": "^6.0.0", "cacache": "^20.0.1", "common-ancestor-path": "^2.0.0", "hosted-git-info": "^9.0.0", "json-stringify-nice": "^1.1.4", "lru-cache": "^11.2.1", "minimatch": "^10.0.3", "nopt": "^9.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.0", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "pacote": "^21.0.2", "parse-conflict-json": "^5.0.1", "proc-log": "^6.0.0", "proggy": "^4.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "semver": "^7.3.7", "ssri": "^13.0.0", "treeverse": "^3.0.0", "walk-up-path": "^4.0.0" }, "bundled": true, "bin": { "arborist": "bin/index.js" } }, "sha512-Dku9UWbrrX+UCu8rQ1obGKaQAL4kwdt3hHCNXrd0n0R/4B8oq3CzloUAShwFjfsAGM6KY27gPuNftOUEZ4nhOw=="], + "npm/@npmcli/arborist": ["@npmcli/arborist@9.4.2", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^5.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/map-workspaces": "^5.0.0", "@npmcli/metavuln-calculator": "^9.0.2", "@npmcli/name-from-folder": "^4.0.0", "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/query": "^5.0.0", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.0", "bin-links": "^6.0.0", "cacache": "^20.0.1", "common-ancestor-path": "^2.0.0", "hosted-git-info": "^9.0.0", "json-stringify-nice": "^1.1.4", "lru-cache": "^11.2.1", "minimatch": "^10.0.3", "nopt": "^9.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.0", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "pacote": "^21.0.2", "parse-conflict-json": "^5.0.1", "proc-log": "^6.0.0", "proggy": "^4.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "semver": "^7.3.7", "ssri": "^13.0.0", "treeverse": "^3.0.0", "walk-up-path": "^4.0.0" }, "bundled": true, "bin": { "arborist": "bin/index.js" } }, "sha512-omJgPyzt11cEGrxzgrECoOyxAunmPMgBFTcAB/FbaB+9iOYhGmRdsQqySV8o0LWQ/l2kTeASUIMR4xJufVwmtw=="], - "npm/@npmcli/config": ["@npmcli/config@10.9.1", "", { "dependencies": { "@npmcli/map-workspaces": "^5.0.0", "@npmcli/package-json": "^7.0.0", "ci-info": "^4.0.0", "ini": "^6.0.0", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "walk-up-path": "^4.0.0" }, "bundled": true }, "sha512-ziECnKCDsGIQ++hHqi4Igl6b6zM2YDDEKAI03o5c3IdN8jF9KDS+n8Rkq8NZH6FjV9pkFQAceZpD4LyUJFXoeA=="], + "npm/@npmcli/config": ["@npmcli/config@10.8.1", "", { "dependencies": { "@npmcli/map-workspaces": "^5.0.0", "@npmcli/package-json": "^7.0.0", "ci-info": "^4.0.0", "ini": "^6.0.0", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "walk-up-path": "^4.0.0" }, "bundled": true }, "sha512-MAYk9IlIGiyC0c9fnjdBSQfIFPZT0g1MfeSiD1UXTq2zJOLX55jS9/sETJHqw/7LN18JjITrhYfgCfapbmZHiQ=="], "npm/@npmcli/fs": ["@npmcli/fs@5.0.0", "", { "dependencies": { "semver": "^7.3.5" }, "bundled": true }, "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og=="], @@ -631,7 +639,7 @@ "npm/@sigstore/core": ["@sigstore/core@3.2.0", "", {}, "sha512-kxHrDQ9YgfrWUSXU0cjsQGv8JykOFZQ9ErNKbFPWzk3Hgpwu8x2hHrQ9IdA8yl+j9RTLTC3sAF3Tdq1IQCP4oA=="], - "npm/@sigstore/protobuf-specs": ["@sigstore/protobuf-specs@0.5.1", "", {}, "sha512-/ScWUhhoFasJsSRGTVBwId1loQjjnjAfE4djL6ZhrXRpNCmPTnUKF5Jokd58ILseOMjzET3UrMOtJPS9sYeI0g=="], + "npm/@sigstore/protobuf-specs": ["@sigstore/protobuf-specs@0.5.0", "", {}, "sha512-MM8XIwUjN2bwvCg1QvrMtbBmpcSHrkhFSCu1D11NyPvDQ25HEc4oG5/OcQfd/Tlf/OxmKWERDj0zGE23jQaMwA=="], "npm/@sigstore/sign": ["@sigstore/sign@4.1.1", "", { "dependencies": { "@gar/promise-retry": "^1.0.2", "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.2.0", "@sigstore/protobuf-specs": "^0.5.0", "make-fetch-happen": "^15.0.4", "proc-log": "^6.1.0" } }, "sha512-Hf4xglukg0XXQ2RiD5vSoLjdPe8OBUPA8XeVjUObheuDcWdYWrnH/BNmxZCzkAy68MzmNCxXLeurJvs6hcP2OQ=="], @@ -653,11 +661,11 @@ "npm/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], - "npm/bin-links": ["bin-links@6.0.2", "", { "dependencies": { "cmd-shim": "^8.0.0", "npm-normalize-package-bin": "^5.0.0", "proc-log": "^6.0.0", "read-cmd-shim": "^6.0.0", "write-file-atomic": "^7.0.0" } }, "sha512-frE1t78WOwJ45PKV2cF2tNPjTcs9L1J9s6VkrV59wanRP4GlaomuxYPVma7BwthMg8WnfSory4w5PTE6FZZ81w=="], + "npm/bin-links": ["bin-links@6.0.0", "", { "dependencies": { "cmd-shim": "^8.0.0", "npm-normalize-package-bin": "^5.0.0", "proc-log": "^6.0.0", "read-cmd-shim": "^6.0.0", "write-file-atomic": "^7.0.0" } }, "sha512-X4CiKlcV2GjnCMwnKAfbVWpHa++65th9TuzAEYtZoATiOE2DQKhSp4CJlyLoTqdhBKlXjpXjCTYPNNFS33Fi6w=="], "npm/binary-extensions": ["binary-extensions@3.1.0", "", {}, "sha512-Jvvd9hy1w+xUad8+ckQsWA/V1AoyubOvqn0aygjMOVM4BfIaRav1NFS3LsTSDaV4n4FtcCtQXvzep1E6MboqwQ=="], - "npm/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + "npm/brace-expansion": ["brace-expansion@5.0.5", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ=="], "npm/cacache": ["cacache@20.0.4", "", { "dependencies": { "@npmcli/fs": "^5.0.0", "fs-minipass": "^3.0.0", "glob": "^13.0.0", "lru-cache": "^11.1.0", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", "ssri": "^13.0.0" }, "bundled": true }, "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA=="], @@ -667,7 +675,7 @@ "npm/ci-info": ["ci-info@4.4.0", "", { "bundled": true }, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - "npm/cidr-regex": ["cidr-regex@5.0.5", "", {}, "sha512-59tdLZcC+BJXa4C5rOmVSuJTy/UneqfJJtCraqwdx5BDHTkGrBtKCUl3u2uiCFvXu+wk0kVuX8axX7yHCZOI9w=="], + "npm/cidr-regex": ["cidr-regex@5.0.3", "", {}, "sha512-zfPT2uurEroxXqefaL2L7/fT5ED2XTutC6UwFbSZfqSOk1vk5VFY6xa6/R6pBxB4Uc8MNPbRW5ykqutFG5P5ww=="], "npm/cmd-shim": ["cmd-shim@8.0.0", "", {}, "sha512-Jk/BK6NCapZ58BKUxlSI+ouKRbjH1NLZCgJkYoab+vEHUY3f6OzpNBN9u7HFSv9J6TRDGs4PLOHezoKGaFRSCA=="], @@ -693,7 +701,7 @@ "npm/graceful-fs": ["graceful-fs@4.2.11", "", { "bundled": true }, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "npm/hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" }, "bundled": true }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="], + "npm/hosted-git-info": ["hosted-git-info@9.0.2", "", { "dependencies": { "lru-cache": "^11.1.0" }, "bundled": true }, "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg=="], "npm/http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], @@ -709,9 +717,9 @@ "npm/init-package-json": ["init-package-json@8.2.5", "", { "dependencies": { "@npmcli/package-json": "^7.0.0", "npm-package-arg": "^13.0.0", "promzard": "^3.0.1", "read": "^5.0.1", "semver": "^7.7.2", "validate-npm-package-name": "^7.0.0" }, "bundled": true }, "sha512-IknQ+upLuJU6t3p0uo9wS3GjFD/1GtxIwcIGYOWR8zL2HxQeJwvxYTgZr9brJ8pyZ4kvpkebM8ZKcyqOeLOHSg=="], - "npm/ip-address": ["ip-address@10.2.0", "", {}, "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA=="], + "npm/ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], - "npm/is-cidr": ["is-cidr@6.0.4", "", { "dependencies": { "cidr-regex": "^5.0.4" }, "bundled": true }, "sha512-tOIBU3QiXy0W4LvHbcKWAWSuQfGwDiEILphFCAZtDqj7C57uv3ClO6K8aNEGV4VTA7bWJlpQ0suKQkUe6Rd6ag=="], + "npm/is-cidr": ["is-cidr@6.0.3", "", { "dependencies": { "cidr-regex": "^5.0.1" }, "bundled": true }, "sha512-tPdsizbDiISrc4PoII6ZfpmAokx0oDKeYqAUp5bXOfznauOFXfEeosKBRrl0o0SriE4xoRR05Czn4YPCFMjSHA=="], "npm/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], @@ -727,17 +735,17 @@ "npm/libnpmaccess": ["libnpmaccess@10.0.3", "", { "dependencies": { "npm-package-arg": "^13.0.0", "npm-registry-fetch": "^19.0.0" }, "bundled": true }, "sha512-JPHTfWJxIK+NVPdNMNGnkz4XGX56iijPbe0qFWbdt68HL+kIvSzh+euBL8npLZvl2fpaxo+1eZSdoG15f5YdIQ=="], - "npm/libnpmdiff": ["libnpmdiff@8.1.8", "", { "dependencies": { "@npmcli/arborist": "^9.6.0", "@npmcli/installed-package-contents": "^4.0.0", "binary-extensions": "^3.0.0", "diff": "^8.0.2", "minimatch": "^10.0.3", "npm-package-arg": "^13.0.0", "pacote": "^21.0.2", "tar": "^7.5.1" }, "bundled": true }, "sha512-/cTo5lAFiQ33f2wjKNDv5xGOTg8oYNwRyEGvBV26GrVL/05NVGcQLAp6GgGSEzjW82YgwA/w7FunEZRWSQUstg=="], + "npm/libnpmdiff": ["libnpmdiff@8.1.5", "", { "dependencies": { "@npmcli/arborist": "^9.4.2", "@npmcli/installed-package-contents": "^4.0.0", "binary-extensions": "^3.0.0", "diff": "^8.0.2", "minimatch": "^10.0.3", "npm-package-arg": "^13.0.0", "pacote": "^21.0.2", "tar": "^7.5.1" }, "bundled": true }, "sha512-3tknN/GosDOpIYjBplXpr7WVjpBDodAxXkZEtv410XlIsfMD+v/6mt9sYe/s/x+TRmmCRpzP/bxfhUorvV6Cqg=="], - "npm/libnpmexec": ["libnpmexec@10.2.8", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/arborist": "^9.6.0", "@npmcli/package-json": "^7.0.0", "@npmcli/run-script": "^10.0.0", "ci-info": "^4.0.0", "npm-package-arg": "^13.0.0", "pacote": "^21.0.2", "proc-log": "^6.0.0", "read": "^5.0.1", "semver": "^7.3.7", "signal-exit": "^4.1.0", "walk-up-path": "^4.0.0" }, "bundled": true }, "sha512-ZYFDXwh1BM5g51IDpeSH/pp0/jJy9SuSbn4Fgz6EOFrFi43ch+7UdOKk4Z8B84eeAtzViY4JBb87Fp/Wkk45sg=="], + "npm/libnpmexec": ["libnpmexec@10.2.5", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/arborist": "^9.4.2", "@npmcli/package-json": "^7.0.0", "@npmcli/run-script": "^10.0.0", "ci-info": "^4.0.0", "npm-package-arg": "^13.0.0", "pacote": "^21.0.2", "proc-log": "^6.0.0", "read": "^5.0.1", "semver": "^7.3.7", "signal-exit": "^4.1.0", "walk-up-path": "^4.0.0" }, "bundled": true }, "sha512-ayouyoml/4NmcgH+nWzK6QB5w0gKrftsYB8TAHu5TB5v6Nj3fgz8ZBK9FsG2A1SNuHZVTjvrNMDyF2VzDih/bA=="], - "npm/libnpmfund": ["libnpmfund@7.0.22", "", { "dependencies": { "@npmcli/arborist": "^9.6.0" }, "bundled": true }, "sha512-Ex8OlXoBZmJwDj/pU+8S7UEOl+BwRlfIS1KJG3eENlvS0skdm+aDeeCKQquPGWX7ZVLKj9wcp7zlHKR/13nQmw=="], + "npm/libnpmfund": ["libnpmfund@7.0.19", "", { "dependencies": { "@npmcli/arborist": "^9.4.2" }, "bundled": true }, "sha512-RNyp5gnjVXaqlx0asRLmAOrFkTwANntzqkRyTT6Iu2nUt1F2eiMZNMOpO2HNfA7/NceBVBk/xsrzas3miCz9oQ=="], "npm/libnpmorg": ["libnpmorg@8.0.1", "", { "dependencies": { "aproba": "^2.0.0", "npm-registry-fetch": "^19.0.0" }, "bundled": true }, "sha512-/QeyXXg4hqMw0ESM7pERjIT2wbR29qtFOWIOug/xO4fRjS3jJJhoAPQNsnHtdwnCqgBdFpGQ45aIdFFZx2YhTA=="], - "npm/libnpmpack": ["libnpmpack@9.1.8", "", { "dependencies": { "@npmcli/arborist": "^9.6.0", "@npmcli/run-script": "^10.0.0", "npm-package-arg": "^13.0.0", "pacote": "^21.0.2" }, "bundled": true }, "sha512-PFcS/hXIifEBu07dEX7UtnhbT62kycmWH1c656L0ZE85/DUnQ3geUs9xmrmkQApRpvcYtkTzS4g8YTCg9SBdgQ=="], + "npm/libnpmpack": ["libnpmpack@9.1.5", "", { "dependencies": { "@npmcli/arborist": "^9.4.2", "@npmcli/run-script": "^10.0.0", "npm-package-arg": "^13.0.0", "pacote": "^21.0.2" }, "bundled": true }, "sha512-H1IX364ZwpeRfrL6UYSuxFNgP16/TvlwtCm8ZallbB7/1FZ3h1FBZHamQtv7PqcZUTWE27mygdQ4wCCW2BmVlg=="], - "npm/libnpmpublish": ["libnpmpublish@11.2.0", "", { "dependencies": { "@npmcli/package-json": "^7.0.0", "ci-info": "^4.0.0", "npm-package-arg": "^13.0.0", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", "semver": "^7.3.7", "sigstore": "^4.0.0", "ssri": "^13.0.0" }, "bundled": true }, "sha512-fAEts7UCM2r1xhI82Dv9PK4gFGZoyD7Z5sfIwBQKoO/f67VNVDC0DeH3uH1Yi+T4kwt5iBuCKkZ5XcpxfvsGHQ=="], + "npm/libnpmpublish": ["libnpmpublish@11.1.3", "", { "dependencies": { "@npmcli/package-json": "^7.0.0", "ci-info": "^4.0.0", "npm-package-arg": "^13.0.0", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", "semver": "^7.3.7", "sigstore": "^4.0.0", "ssri": "^13.0.0" }, "bundled": true }, "sha512-NVPTth/71cfbdYHqypcO9Lt5WFGTzFEcx81lWd7GDJIgZ95ERdYHGUfCtFejHCyqodKsQkNEx2JCkMpreDty/A=="], "npm/libnpmsearch": ["libnpmsearch@9.0.1", "", { "dependencies": { "npm-registry-fetch": "^19.0.0" }, "bundled": true }, "sha512-oKw58X415ERY/BOGV3jQPVMcep8YeMRWMzuuqB0BAIM5VxicOU1tQt19ExCu4SV77SiTOEoziHxGEgJGw3FBYQ=="], @@ -745,7 +753,7 @@ "npm/libnpmversion": ["libnpmversion@8.0.3", "", { "dependencies": { "@npmcli/git": "^7.0.0", "@npmcli/run-script": "^10.0.0", "json-parse-even-better-errors": "^5.0.0", "proc-log": "^6.0.0", "semver": "^7.3.7" }, "bundled": true }, "sha512-Avj1GG3DT6MGzWOOk3yA7rORcMDUPizkIGbI8glHCO7WoYn3NYNmskLDwxg2NMY1Tyf2vrHAqTuSG58uqd1lJg=="], - "npm/lru-cache": ["lru-cache@11.5.0", "", {}, "sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA=="], + "npm/lru-cache": ["lru-cache@11.2.7", "", {}, "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA=="], "npm/make-fetch-happen": ["make-fetch-happen@15.0.5", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/agent": "^4.0.0", "@npmcli/redact": "^4.0.0", "cacache": "^20.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^6.0.0", "ssri": "^13.0.0" }, "bundled": true }, "sha512-uCbIa8jWWmQZt4dSnEStkVC6gdakiinAm4PiGsywIkguF0eWMdcjDz0ECYhUolFU3pFLOev9VNPCEygydXnddg=="], @@ -771,7 +779,7 @@ "npm/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], - "npm/node-gyp": ["node-gyp@12.3.0", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "tar": "^7.5.4", "tinyglobby": "^0.2.12", "undici": "^6.25.0", "which": "^6.0.0" }, "bundled": true, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg=="], + "npm/node-gyp": ["node-gyp@12.2.0", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", "make-fetch-happen": "^15.0.0", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "tar": "^7.5.4", "tinyglobby": "^0.2.12", "which": "^6.0.0" }, "bundled": true, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-q23WdzrQv48KozXlr0U1v9dwO/k59NHeSzn6loGcasyf0UnSrtzs8kRxM+mfwJSf0DkX0s43hcqgnSO4/VNthQ=="], "npm/nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bundled": true, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="], @@ -825,7 +833,7 @@ "npm/safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], - "npm/semver": ["semver@7.8.1", "", { "bundled": true, "bin": { "semver": "bin/semver.js" } }, "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg=="], + "npm/semver": ["semver@7.7.4", "", { "bundled": true, "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], "npm/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], @@ -833,7 +841,7 @@ "npm/smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], - "npm/socks": ["socks@2.8.9", "", { "dependencies": { "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" } }, "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw=="], + "npm/socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="], "npm/socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], @@ -847,20 +855,18 @@ "npm/supports-color": ["supports-color@10.2.2", "", { "bundled": true }, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], - "npm/tar": ["tar@7.5.15", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" }, "bundled": true }, "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ=="], + "npm/tar": ["tar@7.5.13", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" }, "bundled": true }, "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng=="], "npm/text-table": ["text-table@0.2.0", "", { "bundled": true }, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="], "npm/tiny-relative-date": ["tiny-relative-date@2.0.2", "", { "bundled": true }, "sha512-rGxAbeL9z3J4pI2GtBEoFaavHdO4RKAU54hEuOef5kfx5aPqiQtbhYktMOTL5OA33db8BjsDcLXuNp+/v19PHw=="], - "npm/tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], + "npm/tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], "npm/treeverse": ["treeverse@3.0.0", "", { "bundled": true }, "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ=="], "npm/tuf-js": ["tuf-js@4.1.0", "", { "dependencies": { "@tufjs/models": "4.1.0", "debug": "^4.4.3", "make-fetch-happen": "^15.0.1" } }, "sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ=="], - "npm/undici": ["undici@6.25.0", "", {}, "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg=="], - "npm/util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], "npm/validate-npm-package-name": ["validate-npm-package-name@7.0.2", "", { "bundled": true }, "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A=="], diff --git a/docs/specs/issue-3-extract-tool-class-lib-tool-modules-into-src.md b/docs/specs/issue-3-extract-tool-class-lib-tool-modules-into-src.md new file mode 100644 index 0000000..c385fda --- /dev/null +++ b/docs/specs/issue-3-extract-tool-class-lib-tool-modules-into-src.md @@ -0,0 +1,137 @@ +--- +issue_number: 3 +issue_title: "[#1] feat: extract Tool class + lib/tool/ modules into src/" +repo: "beogip/code-first-agents-tool" +labels: [enhancement] +plan_level: "lean" +depth: "medium" +branch_name: "feat/3-extract-tool-class-modules" +created_at: "2026-05-21T00:00:00Z" +--- + +# Implementation Plan: #3 — [#1] feat: extract Tool class + lib/tool/ modules into src/ + +## Files + +| # | Action | Path | Purpose | +|---|--------|------|---------| +| 1 | create | src/types.ts | Tool type definitions (ToolMeta, ParsedArgs, HandlerReturn, SubcommandSpec) | +| 2 | create | src/args.ts | CLI argv parsing and input validation | +| 3 | create | src/json-schema.ts | Safe Zod-to-JSON-Schema converter | +| 4 | create | src/output-helpers.ts | L1/L2/L3 output schema composers | +| 5 | create | src/introspection.ts | Schema/help subcommand payload builders | +| 6 | create | src/envelopes.ts | Error envelope factories (import adjusted to ./utils.ts) | +| 7 | create | src/tool-class.ts | Tool orchestrator class (import adjusted to ./utils.ts) | +| 8 | create | src/utils.ts | Extracted utility functions: ToolOutput, jsonOutput, stringifyError | +| 9 | modify | src/index.ts | Replace placeholder with barrel re-exports | +| 10 | modify | package.json | Add zod as production dependency | + +## Codebase Context + +- **Source**: beogip/kael.factory main branch, `lib/tool/` directory (7 files) + `lib/utils.ts` (3 needed symbols) +- **Runtime**: Bun (ESNext target, bundler module resolution, strict TypeScript) +- **Linter**: Biome 2.4.10 (double quotes, 2-space indent, 100 line width, trailing commas, semicolons) +- **Barrel pattern**: kael.factory's `lib/Tool.ts` re-exports public API from `lib/tool/*.ts` — `src/index.ts` mirrors this pattern +- **Dependency**: `zod` v4 required (for `z.toJSONSchema` in `json-schema.ts`) — currently absent from `package.json` +- **External import**: `envelopes.ts` and `tool-class.ts` import from `../utils.ts` in kael.factory — must be redirected to local `./utils.ts` + +## Steps + +1. **Add zod as production dependency** → `package.json` + **Done when:** `bun install` succeeds and `zod` is listed in `dependencies` + +2. **Create `src/utils.ts`** with only the symbols needed by tool modules: `ToolOutput` type, `jsonOutput` function, `stringifyError` function + **Done when:** file exists and exports exactly those 3 symbols with no kael.factory references + +3. **Copy `types.ts` verbatim** from kael.factory `lib/tool/` → `src/types.ts` + **Done when:** file exists with content matching GitHub main + +4. **Copy `args.ts` verbatim** from kael.factory `lib/tool/` → `src/args.ts` + **Done when:** file exists with content matching GitHub main + +5. **Copy `json-schema.ts` verbatim** from kael.factory `lib/tool/` → `src/json-schema.ts` + **Done when:** file exists with content matching GitHub main + +6. **Copy `output-helpers.ts` verbatim** from kael.factory `lib/tool/` → `src/output-helpers.ts` + **Done when:** file exists with content matching GitHub main + +7. **Copy `introspection.ts` verbatim** from kael.factory `lib/tool/` → `src/introspection.ts` + **Done when:** file exists with content matching GitHub main + +8. **Copy `envelopes.ts`**, adjust `import { stringifyError } from "../utils.ts"` → `import { stringifyError } from "./utils.ts"` → `src/envelopes.ts` + **Done when:** file imports from `./utils.ts`, not `../utils.ts` + +9. **Copy `tool-class.ts`**, adjust `import { jsonOutput, type ToolOutput } from "../utils.ts"` → `import { jsonOutput, type ToolOutput } from "./utils.ts"` → `src/tool-class.ts` + **Done when:** file imports from `./utils.ts`, not `../utils.ts` + +10. **Replace `src/index.ts`** with barrel re-exports mirroring kael.factory's `lib/Tool.ts` + **Done when:** exports Tool, ToolError, l1Output, l2Output, l3Output, buildHelpPayload, buildSchemaOutput, and all public types + +11. **Run `bunx tsc --noEmit`** to verify TypeScript compilation + **Done when:** zero TypeScript errors + +## Interfaces + +- **ToolMeta**: `{ name: string; description: string }` — metadata describing the tool itself +- **ParsedArgs**: `{ flags: Record; positional: string[] }` — raw CLI args after parsing +- **HandlerReturn\**: `Omit, "ok">` — what a handler returns (base class stamps `ok: true`) +- **SubcommandSpec\**: `{ name, description, input: I, output: O, handler }` — a registered subcommand +- **ToolOutput**: `{ ok: boolean; message: string; [key: string]: unknown }` — standard JSON envelope for tool stdout + +## Function Design + +- **utils.ts**: `jsonOutput(data: ToolOutput): never` — serialize to JSON, print to stdout, exit(0) +- **utils.ts**: `stringifyError(err: unknown): string` — Error → string coercion for catch blocks +- **args.ts**: `parseArgs(argv: string[]): { subcommand, parsed: ParsedArgs }` — argv tokenizer +- **args.ts**: `validateInput(parsed, inputSchema): SafeParseResult` — Zod validation of parsed args +- **json-schema.ts**: `safeToJSONSchema(schema): JSONSchemaResult` — Zod → JSON Schema (fail-soft, never throws) +- **output-helpers.ts**: `l1Output`, `l2Output`, `l3Output` — level-specific output schema composers +- **envelopes.ts**: 7 error envelope factories (`unknownSubcommand`, `inputValidationError`, `schemaViolation`, `nonObjectReturn`, `unexpectedError`, `toolError`) + `ToolError` class +- **introspection.ts**: `buildSchemaOutput` (full JSON Schemas per subcommand), `buildHelpPayload` (help listing) +- **tool-class.ts**: `Tool` class — `subcommand()` (register), `run()` (CLI dispatch), `invoke()` (programmatic entry point) + +## Acceptance Criteria (EARS) + +- **AC-1.** [ubiquitous] The package shall contain all 7 modules (tool-class.ts, args.ts, envelopes.ts, introspection.ts, json-schema.ts, output-helpers.ts, types.ts) in `src/`. +- **AC-2.** [ubiquitous] Internal imports between modules shall resolve correctly using relative paths within `src/`. +- **AC-3.** [ubiquitous] TypeScript shall compile (`bunx tsc --noEmit`) with zero errors. +- **AC-4.** [unwanted-behavior] If any import references `../lib/utils.ts` or any kael.factory-specific path, then the build shall fail — no such references shall exist. +- **AC-5.** [inferred] The package shall include `zod` as a production dependency to satisfy type and runtime imports. + +## Out of Scope + +- Unit/integration tests for the Tool class (separate issue) +- Updating existing `tests/index.test.ts` (will break — handled in a separate issue) +- Any runtime behavior changes to the Tool class logic + +## Edge Cases + Error Handling + +| # | Scenario | Source | Handling | +|---|----------|--------|---------| +| 1 | Bun-only APIs in source files | [from issue] | Checked — none found. `process.argv` and `process.exit` are available in both Node and Bun | +| 2 | `../utils.ts` import in envelopes.ts and tool-class.ts | [from issue] | Adjust to `./utils.ts` pointing to local lean utils | +| 3 | `console.log` in `jsonOutput` triggers biome `noConsole` warning | [inferred] | Keep — `jsonOutput` is the designated output channel for tools. Biome rule is `warn`, not `error` | +| 4 | Zod v4 required for `z.toJSONSchema` | [inferred] | Add `zod@^4.0.0` to `package.json` dependencies | +| 5 | Existing `src/index.ts` placeholder will be overwritten | [inferred] | Expected — replace with barrel exports | +| 6 | Existing `tests/index.test.ts` will break | [inferred] | Out of scope — test updates are a separate concern | + +## Done Criteria per Feature + +| Feature | Done when | +|---------|-----------| +| Module extraction | AC-1, AC-2, AC-4 | +| TypeScript compilation | AC-3, AC-5 | +| Clean imports | AC-2, AC-4 | + +## Risks + +| Risk | Mitigation | +|------|------------| +| Zod v4 version compatibility | Pin to `^4.0.0` which the source was written against | +| Existing test breakage | Out of scope — documented as expected consequence | + +## Test Strategy + +- **Compile check (AC-3):** `bunx tsc --noEmit` — must produce zero errors +- **No kael.factory paths (AC-4):** `grep -r '../lib/' src/` — must return zero matches +- **All files exist (AC-1):** `ls src/` — must list all 7 modules + utils.ts + index.ts diff --git a/package.json b/package.json index a64fd10..c448abb 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,14 @@ "description": "Code-first agent tool definitions with Zod schemas", "license": "MIT", "type": "module", + "main": "dist/index.js", + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "files": ["dist", "src"], "scripts": { "dev": "bun run --watch src/index.ts", "build": "bun build src/index.ts --outdir dist --target bun", @@ -14,7 +22,7 @@ "prepare": "lefthook install" }, "dependencies": { - "zod": "^3.25.1" + "zod": "^4.0.0" }, "devDependencies": { "@biomejs/biome": "latest", diff --git a/src/args.ts b/src/args.ts new file mode 100644 index 0000000..f0fd710 --- /dev/null +++ b/src/args.ts @@ -0,0 +1,122 @@ +/** + * args.ts — CLI argv parsing and input validation for the Tool base class. + * + * Contains only the pre-dispatch concerns: turning `process.argv.slice(2)` + * into a structured `{subcommand, ParsedArgs}` pair and validating the + * parsed args against a subcommand's Zod input schema. + * + * @module code-first-agents-tool/args + */ + +import type { z } from "zod"; +import type { ParsedArgs } from "./types.ts"; + +/** + * Subcommand names reserved by the base class (`schema`, `help`). + * Module-private: not re-exported from `./index.ts`. + */ +export const RESERVED_SUBCOMMANDS: ReadonlySet = new Set(["schema", "help"]); + +/** + * Normalize the subcommand token: strip a leading `--` prefix so that both + * `help` and `--help` resolve to the same subcommand name. The bare `--` + * sentinel and `undefined` both return an empty string (no subcommand). + * + * Only a single `--` prefix is stripped: `---help` normalizes to `-help` + * (not `help`), which will be rejected as an unknown subcommand. + * + * @param raw - The raw first token from argv (may be `undefined`). + * @returns The normalized subcommand name, or empty string. + */ +function normalizeSubcommand(raw: string | undefined): string { + if (raw === undefined || raw === "--") return ""; + return raw.startsWith("--") ? raw.slice(2) : raw; +} + +/** + * Parse a raw argv slice into subcommand + typed flags + positional args. + * + * Rules: + * - `argv[0]` is the subcommand. A leading `--` prefix is stripped so that + * `--help` and `help` both resolve to `"help"`. The bare `--` sentinel + * yields an empty subcommand. + * - When `argv[0]` is NOT already a reserved builtin, a `--help` or + * `--schema` flag in the remaining tokens (up to the `--` sentinel) + * promotes to the subcommand (global-flag override). + * - Tokens starting with `--` are flag keys; the next token (if not also a + * flag) is the value. A bare `--flag` at end-of-argv or followed by + * another `--flag` resolves to `true`. + * - Repeated `--flag v1 --flag v2` → last-one-wins (`v2`). + * - The bare `--` token is the end-of-options sentinel (POSIX convention): + * all subsequent tokens become positional, even if they start with `--`. + * - Non-flag tokens become positional args in order. + * + * Pure function — no I/O, no side effects. + * + * @param argv - Array of CLI tokens, typically `process.argv.slice(2)`. + * @returns Parsed subcommand + {@link ParsedArgs}. + */ +export function parseArgs(argv: string[]): { subcommand: string; parsed: ParsedArgs } { + let subcommand = normalizeSubcommand(argv[0]); + const flags: Record = {}; + const positional: string[] = []; + + let i = 1; + while (i < argv.length) { + // biome-ignore lint/style/noNonNullAssertion: loop guard `i < argv.length` ensures defined + const tok = argv[i]!; + + // End-of-options sentinel (POSIX convention): all remaining tokens are positional. + if (tok === "--") { + positional.push(...argv.slice(i + 1)); + break; + } + + if (!tok.startsWith("--")) { + positional.push(tok); + i += 1; + continue; + } + + const key = tok.slice(2); + + // Global-flag override: --help or --schema promotes to subcommand, + // but only when argv[0] was not already an explicit builtin. + if (RESERVED_SUBCOMMANDS.has(key) && !RESERVED_SUBCOMMANDS.has(subcommand)) { + subcommand = key; + i += 1; + continue; + } + + const next = argv[i + 1]; + + if (next === undefined || next.startsWith("--")) { + flags[key] = true; + i += 1; + continue; + } + + flags[key] = next; + i += 2; + } + + return { subcommand, parsed: { flags, positional } }; +} + +/** + * Validate raw {@link ParsedArgs} against a subcommand's input Zod schema. + * Flags are merged as-is; positional args are attached under a reserved `_` + * key only when present (so strict schemas without `_` stay happy when no + * positional args are passed). + * + * @param parsed - Raw parsed args from {@link parseArgs}. + * @param inputSchema - The subcommand's input Zod schema. + * @returns The Zod `safeParse` result carrying either validated data or a structured error. + */ +export function validateInput(parsed: ParsedArgs, inputSchema: I) { + const toValidate: Record = { ...parsed.flags }; + if (parsed.positional.length > 0) { + toValidate._ = parsed.positional; + } + return inputSchema.safeParse(toValidate); +} diff --git a/src/envelopes.ts b/src/envelopes.ts new file mode 100644 index 0000000..88e150e --- /dev/null +++ b/src/envelopes.ts @@ -0,0 +1,217 @@ +/** + * envelopes.ts — Typed error-envelope factories for the Tool base class. + * + * The four error codes (`unknown_subcommand`, `input_validation_error`, + * `schema_violation`, `unexpected_error`) are modeled as a discriminated + * union so extras (`subcommands`, `input_schema`, `detail`) stay type-safe + * per-code. Each builder owns the exact message template for its code, + * which previously lived inline in `Tool#run`. + * + * @module code-first-agents-tool/envelopes + */ + +import type { z } from "zod"; +import { buildHelpPayload, type HelpPayload } from "./introspection.ts"; +import { safeToJSONSchema } from "./json-schema.ts"; +import type { SubcommandSpec } from "./types.ts"; +import { stringifyError } from "./utils.ts"; + +/** + * Discriminated union of every error envelope the base class can emit. + * Each variant is assignable to `ToolOutput` from `./utils.ts` via its + * index signature, so `jsonOutput` consumes them without casts. + * + * The final variant (`error: string`) covers handler-emitted business + * errors thrown via {@link ToolError} — the `error` code is whatever the + * handler chose. + */ +export type ErrorEnvelope = + | { + ok: false; + error: "unknown_subcommand"; + message: string; + subcommands: HelpPayload; + } + | { + ok: false; + error: "input_validation_error"; + message: string; + detail: string; + input_schema: unknown; + } + | { + ok: false; + error: "schema_violation"; + message: string; + detail: string; + } + | { + ok: false; + error: "non_object_return"; + message: string; + } + | { + ok: false; + error: "unexpected_error"; + message: string; + detail?: string | Record; + } + | { + ok: false; + error: string; + message: string; + detail?: string | Record; + }; + +/** + * Error class a handler can throw to emit a structured error envelope with + * a business-specific `error` code (e.g. `"path_not_found"`, `"rate_limited"`). + * The base class catches instances of this class and produces the envelope + * via {@link toolErrorEnvelope}; anything else thrown becomes an + * `unexpected_error` envelope. + * + * @example + * handler: ({ path }) => { + * if (!existsSync(path)) { + * throw new ToolError("path_not_found", `Path does not exist: ${path}`); + * } + * return { message: "ok", ... }; + * } + */ +export class ToolError extends Error { + /** Machine-readable error code emitted in the envelope's `error` field. */ + public readonly code: string; + /** Optional extra context included in the envelope's `detail` field. */ + public readonly detail?: string | Record; + + /** + * @param code - Machine-readable error code (emitted verbatim). Conventionally snake_case. + * @param message - Human-readable message. + * @param detail - Optional extra context (string or structured object). + */ + constructor(code: string, message: string, detail?: string | Record) { + super(message); + this.name = "ToolError"; + this.code = code; + if (detail !== undefined) { + this.detail = detail; + } + } +} + +/** + * Build the `unknown_subcommand` envelope. When `name === ""` (empty argv), + * the message notes the absence; otherwise it names the unrecognized input. + * Always includes the full `subcommands` listing so an LLM caller can + * self-correct on retry. + * + * @param name - The unrecognized subcommand (or empty string for empty argv). + * @param subs - The Tool's registered-subcommands map. + * @returns A typed `unknown_subcommand` envelope. + */ +export function unknownSubcommandEnvelope( + name: string, + subs: ReadonlyMap>, +): ErrorEnvelope { + const message = + name === "" + ? "No subcommand provided — see 'subcommands' for available options" + : `Unknown subcommand '${name}' — see 'subcommands' for available options`; + return { + ok: false as const, + error: "unknown_subcommand" as const, + message, + subcommands: buildHelpPayload(subs), + }; +} + +/** + * Build the `input_validation_error` envelope. Attaches the input JSON + * Schema (or `$error` fallback) so the LLM can correct the flags and retry. + * + * @param name - The subcommand whose input failed validation. + * @param zerr - The Zod error produced by `safeParse`. + * @param inputSchema - The subcommand's declared input Zod schema. + * @returns A typed `input_validation_error` envelope. + */ +export function inputValidationErrorEnvelope( + name: string, + zerr: z.ZodError, + inputSchema: z.ZodTypeAny, +): ErrorEnvelope { + const conv = safeToJSONSchema(inputSchema); + const input_schema: unknown = conv.ok ? conv.schema : { $error: conv.$error }; + return { + ok: false as const, + error: "input_validation_error" as const, + message: `Input validation failed for subcommand '${name}'`, + detail: zerr.message, + input_schema, + }; +} + +/** + * Build the `schema_violation` envelope. Fires when a handler returns a + * value that fails the subcommand's output Zod schema. + * + * @param name - The subcommand whose handler return failed validation. + * @param zerr - The Zod error produced by output `safeParse`. + * @returns A typed `schema_violation` envelope. + */ +export function schemaViolationEnvelope(name: string, zerr: z.ZodError): ErrorEnvelope { + return { + ok: false as const, + error: "schema_violation" as const, + message: `Handler output failed schema validation for subcommand '${name}'`, + detail: zerr.message, + }; +} + +/** + * Build the `unexpected_error` envelope. Catches anything the handler (or + * the base class plumbing itself) throws that is NOT a {@link ToolError}. + * The error's stack is included in `detail` when available. + * + * @param err - The thrown value (or rejected Promise reason). + * @returns A typed `unexpected_error` envelope. + */ +export function unexpectedErrorEnvelope(err: unknown): ErrorEnvelope { + const message = stringifyError(err); + const stack = err instanceof Error ? err.stack : undefined; + return stack !== undefined + ? { ok: false as const, error: "unexpected_error" as const, message, detail: stack } + : { ok: false as const, error: "unexpected_error" as const, message }; +} + +/** + * Build a handler-emitted error envelope from a {@link ToolError}. Preserves + * the custom `code`, `message`, and optional `detail` the handler declared, + * so consumers see a business-specific error envelope instead of a generic + * `unexpected_error`. + * + * @param err - The {@link ToolError} the handler threw. + * @returns An envelope carrying the handler's custom `error` code. + */ +export function toolErrorEnvelope(err: ToolError): ErrorEnvelope { + return err.detail !== undefined + ? { ok: false as const, error: err.code, message: err.message, detail: err.detail } + : { ok: false as const, error: err.code, message: err.message }; +} + +/** + * Build the `non_object_return` envelope. Fires when a handler returns a + * non-plain-object value (null, string, array, etc.) that cannot be spread + * into the output envelope. + * + * @param name - The subcommand whose handler returned a non-object. + * @param value - The actual value the handler returned (used to describe the type). + * @returns A typed `non_object_return` envelope. + */ +export function nonObjectReturnEnvelope(name: string, value: unknown): ErrorEnvelope { + const type = value === null ? "null" : Array.isArray(value) ? "array" : typeof value; + return { + ok: false as const, + error: "non_object_return", + message: `Handler for '${name}' must return a plain object, got ${type}`, + }; +} diff --git a/src/index.ts b/src/index.ts index cb0ff5c..e271cf6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1,29 @@ -export {}; +/** + * index.ts — Barrel for the code-first-agents Tool base class. + * + * Implementation lives in `src/*.ts`. This file re-exports the public API + * so consumers import from the package root: + * + * import { Tool, l1Output, l2Output, l3Output } from "@code-first-agents/tool"; + * + * @module @code-first-agents/tool + */ + +export type { ErrorEnvelope } from "./envelopes.ts"; +export { ToolError } from "./envelopes.ts"; +export type { + HelpPayload, + HelpPayloadEntry, + SchemaOutputEntry, +} from "./introspection.ts"; +export { buildHelpPayload, buildSchemaOutput } from "./introspection.ts"; +export type { JSONSchemaResult } from "./json-schema.ts"; +export { l1Output, l2Output, l3Output } from "./output-helpers.ts"; +export { Tool } from "./tool-class.ts"; +export type { + HandlerReturn, + ParsedArgs, + SubcommandSpec, + ToolMeta, +} from "./types.ts"; +export type { ToolOutput } from "./utils.ts"; diff --git a/src/introspection.ts b/src/introspection.ts new file mode 100644 index 0000000..2d41812 --- /dev/null +++ b/src/introspection.ts @@ -0,0 +1,78 @@ +/** + * introspection.ts — Builders for the auto-registered `schema` and `help` + * subcommand payloads, plus the help listing carried inside the + * `unknown_subcommand` error envelope. + * + * Both builders delegate to `safeToJSONSchema` so exotic Zod constructs + * fail soft (one subcommand emits `{$error}` instead of crashing the whole + * response). + * + * @module code-first-agents-tool/introspection + */ + +import type { z } from "zod"; +import { safeToJSONSchema } from "./json-schema.ts"; +import type { SubcommandSpec } from "./types.ts"; + +/** One entry in the `subcommands` help listing. */ +export interface HelpPayloadEntry { + /** Subcommand name as registered. */ + name: string; + /** One-line description from the spec. */ + description: string; + /** Input JSON Schema (draft-2020-12) or `{$error}` fallback. */ + input_schema: unknown; +} + +/** The shape returned by {@link buildHelpPayload} — an array of entries. */ +export type HelpPayload = HelpPayloadEntry[]; + +/** One entry in the `schemas` map emitted by the `schema` subcommand. */ +export type SchemaOutputEntry = { input: unknown; output: unknown } | { $error: string }; + +/** + * Convert a registered subcommand map into a `{name: {input, output}}` + * record of JSON Schemas (draft-2020-12). Per-subcommand conversion is + * fail-soft via {@link safeToJSONSchema}: a failing sub gets a `$error` + * entry instead of crashing the whole `schema` response. + * + * @param subs - Map from subcommand name to its spec. + * @returns Record keyed by subcommand name, each value either `{input, output}` or `{$error}`. + */ +export function buildSchemaOutput( + subs: ReadonlyMap>, +): Record { + const result: Record = {}; + for (const [name, spec] of subs) { + const inputResult = safeToJSONSchema(spec.input); + const outputResult = safeToJSONSchema(spec.output); + if (!inputResult.ok) { + result[name] = { $error: inputResult.$error }; + } else if (!outputResult.ok) { + result[name] = { $error: outputResult.$error }; + } else { + result[name] = { input: inputResult.schema, output: outputResult.schema }; + } + } + return result; +} + +/** + * Build the `subcommands` array used by `help` output and the + * `unknown_subcommand` error envelope. Each entry carries the input JSON + * Schema so an LLM caller can discover which flags a subcommand expects. + * + * @param subs - Map from subcommand name to its spec. + * @returns Array of `{name, description, input_schema}` entries. + */ +export function buildHelpPayload( + subs: ReadonlyMap>, +): HelpPayload { + const result: HelpPayload = []; + for (const [name, spec] of subs) { + const conv = safeToJSONSchema(spec.input); + const input_schema: unknown = conv.ok ? conv.schema : { $error: conv.$error }; + result.push({ name, description: spec.description, input_schema }); + } + return result; +} diff --git a/src/json-schema.ts b/src/json-schema.ts new file mode 100644 index 0000000..0f89620 --- /dev/null +++ b/src/json-schema.ts @@ -0,0 +1,40 @@ +/** + * json-schema.ts — Safe wrapper around `z.toJSONSchema`. + * + * `z.toJSONSchema` throws on exotic Zod constructs (e.g. `.transform()`). + * This helper centralizes the try/catch and the target version + * (`draft-2020-12`) so the three call sites — `buildSchemaOutput`, + * `buildHelpPayload`, and the `input_validation_error` envelope builder — + * share a single fail-soft path. + * + * **Known limitation:** Zod v4's `toJSONSchema` emits `required` for fields + * that have `.default(...)`. The emitted JSON Schema says the field is + * mandatory even though Zod's runtime validation accepts its absence and + * fills the default. This can mislead LLM callers reading `input_schema` + * for self-correction (they may conclude a defaulted flag is required). + * No workaround applied — consumers should test with the actual tool, not + * rely on the schema's `required` array for defaulted fields. + * + * @module code-first-agents-tool/json-schema + */ + +import { z } from "zod"; + +/** Result of converting a Zod schema to JSON Schema — success carries the schema; failure carries a message. */ +export type JSONSchemaResult = { ok: true; schema: unknown } | { ok: false; $error: string }; + +/** + * Convert a Zod schema to JSON Schema (draft-2020-12) without throwing. + * On success returns `{ ok: true, schema }`; on failure returns + * `{ ok: false, $error }` carrying the thrown message. + * + * @param schema - Any Zod schema. + * @returns A discriminated result — never throws. + */ +export function safeToJSONSchema(schema: z.ZodTypeAny): JSONSchemaResult { + try { + return { ok: true, schema: z.toJSONSchema(schema, { target: "draft-2020-12" }) }; + } catch (err) { + return { ok: false, $error: err instanceof Error ? err.message : String(err) }; + } +} diff --git a/src/output-helpers.ts b/src/output-helpers.ts new file mode 100644 index 0000000..f799d94 --- /dev/null +++ b/src/output-helpers.ts @@ -0,0 +1,96 @@ +/** + * output-helpers.ts — Level-specific output-schema composers for the + * code-first-agents Tool contract. + * + * Every tool output includes the `ok: z.literal(true)` + `message: z.string()` + * envelope. These helpers bake that in and add the fields the spec requires + * for each level (none for L1; required `classification` enum for L2; + * required `instructions` string for L3), so the caller can't forget them + * and VS Code shows a fully-resolved handler return type. + * + * Opt-in: tools with shapes that don't fit a level may pass a raw + * `z.object({...})` to `output`. The base class doesn't require a helper. + * + * @module code-first-agents-tool/output-helpers + */ + +import { z } from "zod"; + +/** + * Compose an **L1 (data)** output schema: envelope + arbitrary raw fields. + * Use when the tool returns facts for the LLM to interpret. + * + * @example + * const schema = l1Output({ checkboxes: z.number(), file_paths: z.number() }); + * + * @param fields - Raw data fields to include alongside the envelope. + * @returns A `z.object` carrying `ok`, `message`, and the caller's fields. + */ +export function l1Output(fields: T) { + return z.object({ + ok: z.literal(true), + message: z.string(), + ...fields, + }); +} + +/** + * Compose an **L2 (classification)** output schema: envelope + a required + * `classification` enum + optional extras. Use when the tool returns a + * discrete category the skill can branch on. + * + * @example + * const schema = l2Output( + * z.enum(["lean", "standard", "full"]), + * { score: z.number(), signals: z.object({ checkboxes: z.number() }) }, + * ); + * + * @param classification - Zod enum describing the discrete classification result. + * @param fields - Optional extras (e.g. score, raw signals) merged into the output. + * @returns A `z.object` carrying `ok`, `message`, `classification`, and extras. + */ +export function l2Output( + classification: C, + fields: T, +): z.ZodObject<{ ok: z.ZodLiteral; message: z.ZodString; classification: C } & T>; +// No-arg overload intentionally omits `& T` — the base shape is the full type when no extras are passed. +export function l2Output( + classification: C, +): z.ZodObject<{ ok: z.ZodLiteral; message: z.ZodString; classification: C }>; +export function l2Output(classification: z.ZodTypeAny, fields?: z.ZodRawShape) { + return z.object({ + ok: z.literal(true), + message: z.string(), + classification, + ...(fields ?? {}), + }); +} + +/** + * Compose an **L3 (instructions)** output schema: envelope + a required + * `instructions` string + optional extras. Use when the tool builds a + * verbatim procedure for the LLM to execute. + * + * @example + * const schema = l3Output({ plan_level: z.enum(["lean", "standard", "full"]) }); + * + * @param fields - Optional extras (e.g. classification alongside instructions) merged into the output. + * @returns A `z.object` carrying `ok`, `message`, `instructions`, and extras. + */ +export function l3Output( + fields: T, +): z.ZodObject<{ ok: z.ZodLiteral; message: z.ZodString; instructions: z.ZodString } & T>; +// No-arg overload intentionally omits `& T` — the base shape is the full type when no extras are passed. +export function l3Output(): z.ZodObject<{ + ok: z.ZodLiteral; + message: z.ZodString; + instructions: z.ZodString; +}>; +export function l3Output(fields?: z.ZodRawShape) { + return z.object({ + ok: z.literal(true), + message: z.string(), + instructions: z.string(), + ...(fields ?? {}), + }); +} diff --git a/src/tool-class.ts b/src/tool-class.ts new file mode 100644 index 0000000..fa1f868 --- /dev/null +++ b/src/tool-class.ts @@ -0,0 +1,349 @@ +/** + * tool-class.ts — The `Tool` orchestrator for code-first-agents deterministic tools. + * + * Implements the tool contract defined in the code-first agents pattern: + * - Subcommand dispatch with typed input/output Zod schemas + * - Validated JSON output (the shape IS the validator) + * - Self-describing `schema` subcommand (auto-registered) + * - `help` subcommand + unknown-subcommand fallback that exposes input schemas + * so LLM callers can self-correct + * - Always exits with code 0; errors communicated via `ok: false` envelope + * + * Spec: https://beogip.github.io/code-first-agents/patterns/deterministic-tools.html + * + * ## Usage + * + * ```ts + * import { z } from "zod"; + * import { Tool, l2Output } from "code-first-agents-tool"; + * + * new Tool({ name: "level-classifier", description: "..." }) + * .subcommand({ + * name: "classify", + * description: "Classify a SKILL.md by code-first level", + * input: z.object({ path: z.string() }).strict(), + * output: l2Output(z.enum(["L1", "L2", "L3"])), + * // Handler returns message + data. `ok: true` is framework-added. + * handler: ({ path }) => ({ + * message: `classified ${path}`, + * classification: "L2", + * }), + * }) + * .run(process.argv.slice(2)); + * ``` + * + * ## Output envelope contract + * + * Handlers return the output shape **without `ok`** — the base class stamps + * `ok: true` onto the handler's result before validating against the output + * schema. This keeps handlers focused on `message` + business data and avoids + * TypeScript widening `ok: true` to `boolean` in object-literal returns. + * + * Use the level helpers (`l1Output`, `l2Output`, `l3Output` from + * `./output-helpers.ts`) to get the envelope + level-specific required + * fields baked in; fall back to raw `z.object({...})` when the tool's shape + * doesn't fit a level (remember to include `ok: z.literal(true)` and + * `message: z.string()` in the raw schema so validation covers the whole + * envelope). + * + * Error envelopes (`schema_violation`, `input_validation_error`, + * `unknown_subcommand`, `unexpected_error`) are class-authored — see + * `./envelopes.ts`. + * + * @module code-first-agents-tool/tool-class + */ + +import { z } from "zod"; +import { parseArgs, RESERVED_SUBCOMMANDS, validateInput } from "./args.ts"; +import { + inputValidationErrorEnvelope, + nonObjectReturnEnvelope, + schemaViolationEnvelope, + ToolError, + toolErrorEnvelope, + unexpectedErrorEnvelope, + unknownSubcommandEnvelope, +} from "./envelopes.ts"; +import { buildHelpPayload, buildSchemaOutput } from "./introspection.ts"; +import type { ParsedArgs, SubcommandSpec, ToolMeta } from "./types.ts"; +import { jsonOutput, type ToolOutput } from "./utils.ts"; + +/** Internal alias for the type-erased spec stored in the registry. */ +type AnySpec = SubcommandSpec; + +function isPlainObject(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +/** + * Orchestrator for a code-first deterministic tool. Register subcommands via + * {@link Tool.subcommand}, then call {@link Tool.run} with `process.argv.slice(2)`. + * + * The class always terminates the process with exit code 0 via `jsonOutput`; + * errors are communicated through the JSON envelope's `ok: false` + `error` + * fields. + * + * Reserved subcommand names `schema` and `help` are auto-registered by the + * class — attempting to register them manually throws `RangeError`. + */ +export class Tool { + private readonly meta: ToolMeta; + private readonly subs: Map = new Map(); + + /** + * @param meta - Tool metadata (name + description). + */ + constructor(meta: ToolMeta) { + this.meta = meta; + } + + /** + * Register a subcommand. Chainable (returns `this`). + * + * Throws synchronously on: + * - reserved name collision (`schema`, `help`) → `RangeError` + * - duplicate name → `RangeError` + * - missing `input` schema → `TypeError` + * - missing `output` schema → `TypeError` + * + * @param spec - {@link SubcommandSpec} carrying name, description, input/output Zod schemas, and handler. + * @returns This tool instance, for chaining. + */ + subcommand(spec: SubcommandSpec): this { + this.validateRegistration(spec); + this.subs.set(spec.name, spec as unknown as AnySpec); + return this; + } + + /** + * Dispatch a subcommand from parsed `argv`. Always terminates the process + * via `jsonOutput` with exit code 0. + * + * Pure dispatch — each branch delegates to a single-responsibility helper: + * 1. {@link Tool.dispatchBuiltin} handles `schema` / `help`. + * 2. {@link Tool.rejectUnknown} handles empty or unregistered subcommands. + * 3. {@link Tool.runSubcommand} runs the validate → handler → validate pipeline. + * 4. Outer try/catch: {@link ToolError} → handler-emitted envelope with the + * custom code; anything else → `unexpected_error`. + * + * @param argv - CLI tokens, typically `process.argv.slice(2)`. + * @returns Never — the process exits via `jsonOutput`. + */ + async run(argv: string[]): Promise { + try { + const { subcommand, parsed } = parseArgs(argv); + const builtin = this.dispatchBuiltin(subcommand); + if (builtin) return jsonOutput(builtin); + const miss = this.rejectUnknown(subcommand); + if (miss) return jsonOutput(miss); + return jsonOutput(await this.runSubcommand(subcommand, parsed)); + } catch (err) { + if (err instanceof ToolError) return jsonOutput(toolErrorEnvelope(err)); + return jsonOutput(unexpectedErrorEnvelope(err)); + } + } + + /** + * Pre-flight checks for a subcommand registration. Called by + * {@link Tool.subcommand}; throws synchronously on any violation. + * + * @param spec - The {@link SubcommandSpec} to validate. + * @throws `RangeError` for reserved-name collision or duplicate registration. + * @throws `TypeError` when `input` is missing. + */ + private validateRegistration( + spec: SubcommandSpec, + ): void { + if (RESERVED_SUBCOMMANDS.has(spec.name)) { + throw new RangeError( + `Subcommand name "${spec.name}" is reserved — the base class auto-registers 'schema' and 'help'`, + ); + } + if (this.subs.has(spec.name)) { + throw new RangeError(`Subcommand "${spec.name}" is already registered`); + } + if (spec.input === undefined || spec.input === null) { + throw new TypeError( + `Subcommand "${spec.name}" is missing required 'input' Zod schema (use z.object({}).strict() for argless subs)`, + ); + } + if (spec.output === undefined || spec.output === null) { + throw new TypeError( + `Subcommand "${spec.name}" is missing required 'output' Zod schema (use l1Output({}) for minimal output)`, + ); + } + } + + /** + * Handle the auto-registered `schema` and `help` subcommands. Returns the + * success envelope for those names, or `null` to signal the caller should + * fall through to user-registered dispatch. + * + * @param name - The parsed subcommand name. + * @returns A success envelope for `schema`/`help`, or `null` otherwise. + */ + private dispatchBuiltin(name: string): ToolOutput | null { + if (name === "schema") { + return { + ok: true, + message: + this.subs.size === 0 + ? `Tool "${this.meta.name}" has no subcommands registered` + : `JSON Schemas for ${this.subs.size} subcommand(s)`, + schemas: buildSchemaOutput(this.subs), + }; + } + if (name === "help") { + return { + ok: true, + message: this.meta.description || `Help for ${this.meta.name}`, + tool: { name: this.meta.name }, + subcommands: buildHelpPayload(this.subs), + }; + } + return null; + } + + /** + * Handle empty argv and unregistered-subcommand cases. Returns the + * `unknown_subcommand` envelope (carrying the help listing for LLM + * self-correction) when applicable, or `null` when the subcommand is + * registered and should proceed. + * + * @param name - The parsed subcommand name. + * @returns An `unknown_subcommand` envelope, or `null` if the name is registered. + */ + private rejectUnknown(name: string): ToolOutput | null { + if (name === "" || !this.subs.has(name)) { + return unknownSubcommandEnvelope(name, this.subs); + } + return null; + } + + /** + * Execute a registered subcommand: validate input → `await` handler → + * stamp `ok: true` → validate output. Returns whichever envelope the + * pipeline produced (success or one of the validation errors). + * + * Preconditions: `name` must be a registered subcommand name. Callers + * should run {@link Tool.rejectUnknown} first. + * + * @param name - The subcommand to execute. + * @param parsed - Raw parsed args from {@link parseArgs}. + * @returns A success envelope or a typed error envelope. + */ + private async runSubcommand(name: string, parsed: ParsedArgs): Promise { + const spec = this.subs.get(name); + if (!spec) { + // Unreachable: rejectUnknown would have caught this. Kept as a type guard. + return unexpectedErrorEnvelope( + new Error(`Subcommand '${name}' vanished between rejectUnknown and runSubcommand`), + ); + } + + const inputResult = validateInput(parsed, spec.input); + if (!inputResult.success) { + return inputValidationErrorEnvelope(name, inputResult.error, spec.input); + } + + const handlerResult = await spec.handler(inputResult.data); + + if (!isPlainObject(handlerResult)) { + return nonObjectReturnEnvelope(name, handlerResult); + } + + // `ok` last — prevents a handler from overriding the framework-managed field. + const fullResult = { ...handlerResult, ok: true as const }; + const outputResult = spec.output.safeParse(fullResult); + if (!outputResult.success) { + return schemaViolationEnvelope(name, outputResult.error); + } + + // Guard: Zod strip mode may remove `ok` if the output schema doesn't + // declare it (e.g. raw z.object without `ok: z.literal(true)`). + const data = outputResult.data as Record; + if (!("ok" in data)) { + return schemaViolationEnvelope( + name, + new z.ZodError([ + { + code: "custom", + path: ["ok"], + message: + "Output schema is missing 'ok' field — add ok: z.literal(true) or use l1Output/l2Output/l3Output helpers", + }, + ]), + ); + } + + return data as ToolOutput; + } + + /** + * Programmatic entry point — runs a subcommand in-process without CLI + * arg parsing or `process.exit`. Identical validation pipeline to + * {@link Tool.run}, but accepts a plain object instead of argv tokens. + * + * @param subcommand - The subcommand name to dispatch. + * @param args - Input data as a plain object (bypasses CLI parsing). + * @returns The output envelope (success or error). + * + * Unlike `run()`, this method does NOT promote global flags (e.g. `--path`) + * into subcommand args. Callers must pass the full args object directly. + * Also, stderr output from handlers is not capturable — spawn the tool + * as a subprocess in tests that need to assert on stderr content. + */ + async invoke(subcommand: string, args: Record = {}): Promise { + try { + const builtin = this.dispatchBuiltin(subcommand); + if (builtin) return builtin; + const miss = this.rejectUnknown(subcommand); + if (miss) return miss; + + const spec = this.subs.get(subcommand); + if (!spec) { + return unexpectedErrorEnvelope( + new Error(`Subcommand '${subcommand}' vanished between rejectUnknown and invoke`), + ); + } + + const inputResult = spec.input.safeParse(args); + if (!inputResult.success) { + return inputValidationErrorEnvelope(subcommand, inputResult.error, spec.input); + } + + const handlerResult = await spec.handler(inputResult.data); + + if (!isPlainObject(handlerResult)) { + return nonObjectReturnEnvelope(subcommand, handlerResult); + } + + // `ok` last — prevents a handler from overriding the framework-managed field. + const fullResult = { ...handlerResult, ok: true as const }; + const outputResult = spec.output.safeParse(fullResult); + if (!outputResult.success) { + return schemaViolationEnvelope(subcommand, outputResult.error); + } + + const data = outputResult.data as Record; + if (!("ok" in data)) { + return schemaViolationEnvelope( + subcommand, + new z.ZodError([ + { + code: "custom", + path: ["ok"], + message: + "Output schema is missing 'ok' field — add ok: z.literal(true) or use l1Output/l2Output/l3Output helpers", + }, + ]), + ); + } + + return data as ToolOutput; + } catch (err) { + if (err instanceof ToolError) return toolErrorEnvelope(err); + return unexpectedErrorEnvelope(err); + } + } +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..6cd7cc3 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,79 @@ +/** + * types.ts — Public interfaces for the code-first-agents Tool base class. + * + * Kept pure: no imports beyond `zod`, no runtime logic. Consumers of the + * `Tool` class type their code against these. + * + * @module code-first-agents-tool/types + */ + +import type { z } from "zod"; + +/** Metadata describing the tool itself. Used in help output. */ +export interface ToolMeta { + /** Tool identifier (usually matches the filename stem). */ + name: string; + /** One-line human description shown in help output. */ + description: string; +} + +/** + * Raw CLI args after parsing. Flags are `--key value` pairs; bare `--flag` + * (with no following value) resolves to `true`. Positional args are any + * tokens that don't start with `--`. + */ +export interface ParsedArgs { + /** Flag key → value mapping. Last-one-wins on repeated keys. */ + flags: Record; + /** Positional (non-flag) tokens in order. */ + positional: string[]; +} + +/** + * What a handler is expected to return: the output shape **without** `ok`. + * The base class stamps `ok: true` onto the result before output validation, + * so handlers stay focused on `message` + business data. This also avoids + * TypeScript widening `ok: true` to `boolean` in object-literal returns. + */ +export type HandlerReturn = Omit, "ok">; + +/** + * A registered subcommand spec. Both `input` and `output` Zod schemas are + * required — they validate CLI args before the handler runs and the + * handler's return value before emit. + * + * @typeParam I - Input Zod schema type + * @typeParam O - Output Zod schema type + */ +export interface SubcommandSpec { + /** Subcommand name as it appears on the CLI (e.g. "classify"). */ + name: string; + /** One-line description shown in help output. */ + description: string; + /** + * Zod schema for the validated flags + positional args. Positional args + * are exposed under a reserved `_` key when present. Use `.strict()` to + * reject unknown flags loudly. + * + * **Sync only:** the base class uses `safeParse` (not `safeParseAsync`). + * Schemas with `.refine(async ...)` or `.transform(async ...)` will cause + * a hard runtime throw at dispatch time (caught by the outer `unexpected_error` + * envelope, but with a cryptic message). Use synchronous validators only. + */ + input: I; + /** + * Zod schema for the full output envelope (including `ok: z.literal(true)` + * and `message: z.string()`). Use the level helpers `l1Output` / `l2Output` + * / `l3Output` to get the envelope baked in, or pass a raw `z.object`. + * The handler returns everything **except** `ok`; the base class adds it. + * + * **Sync only:** same constraint as `input` — no async transforms or refinements. + */ + output: O; + /** + * Business logic. Receives the validated, typed input. Returns the output + * shape **without** `ok` — the base class adds `ok: true` before validating + * against the output schema. May return a plain value or a Promise. + */ + handler: (args: z.infer) => HandlerReturn | Promise>; +} diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..91f6fd4 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,23 @@ +/** Standard JSON envelope for all tool stdout output. */ +export type ToolOutput = { ok: boolean; message: string; [key: string]: unknown }; + +/** + * Print a {@link ToolOutput} as JSON to stdout and terminate with exit code 0. + * @param data - The tool output envelope to serialize. + * @returns Never — the process exits. + */ +export function jsonOutput(data: ToolOutput): never { + // biome-ignore lint/suspicious/noConsole: designated tool output channel + console.log(JSON.stringify(data)); + process.exit(0); +} + +/** + * Extract a human-readable message from an unknown thrown value. Preserves + * the `Error.message` when available; otherwise coerces via `String(...)`. + * @param err - The caught value (Error instance, string, null, etc.). + * @returns A non-undefined string suitable for envelope `message` / log output. + */ +export function stringifyError(err: unknown): string { + return err instanceof Error ? err.message : String(err); +} diff --git a/tests/index.test.ts b/tests/index.test.ts index 002c516..cb1aee4 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -1,8 +1,192 @@ import { describe, expect, it } from "bun:test"; -import * as index from "../src/index"; +import { z } from "zod"; +import type { HelpPayload, ToolMeta } from "../src/index.ts"; +import { l1Output, l2Output, l3Output, Tool, ToolError } from "../src/index.ts"; -describe("@code-first-agents/tool", () => { - it("exports a module", () => { - expect(index).toBeDefined(); +describe("Tool", () => { + const meta: ToolMeta = { name: "test-tool", description: "A test tool" }; + + it("constructs without error", () => { + const tool = new Tool(meta); + expect(tool).toBeInstanceOf(Tool); + }); + + it("registers a subcommand and chains", () => { + const tool = new Tool(meta).subcommand({ + name: "ping", + description: "Ping", + input: z.object({}).strict(), + output: l1Output({}), + handler: () => ({ message: "pong" }), + }); + expect(tool).toBeInstanceOf(Tool); + }); + + it("rejects reserved subcommand name 'schema'", () => { + expect(() => + new Tool(meta).subcommand({ + name: "schema", + description: "bad", + input: z.object({}).strict(), + output: l1Output({}), + handler: () => ({ message: "nope" }), + }), + ).toThrow(RangeError); + }); + + it("rejects reserved subcommand name 'help'", () => { + expect(() => + new Tool(meta).subcommand({ + name: "help", + description: "bad", + input: z.object({}).strict(), + output: l1Output({}), + handler: () => ({ message: "nope" }), + }), + ).toThrow(RangeError); + }); + + it("rejects duplicate subcommand name", () => { + expect(() => + new Tool(meta) + .subcommand({ + name: "dup", + description: "first", + input: z.object({}).strict(), + output: l1Output({}), + handler: () => ({ message: "first" }), + }) + .subcommand({ + name: "dup", + description: "second", + input: z.object({}).strict(), + output: l1Output({}), + handler: () => ({ message: "second" }), + }), + ).toThrow(RangeError); + }); +}); + +describe("Tool.invoke", () => { + const meta: ToolMeta = { name: "test-tool", description: "A test tool" }; + + it("dispatches a valid subcommand", async () => { + const tool = new Tool(meta).subcommand({ + name: "greet", + description: "Greet someone", + input: z.object({ name: z.string() }).strict(), + output: l1Output({ greeting: z.string() }), + handler: ({ name }) => ({ message: "ok", greeting: `Hello, ${name}!` }), + }); + + const result = await tool.invoke("greet", { name: "World" }); + expect(result.ok).toBe(true); + expect((result as Record).greeting).toBe("Hello, World!"); + }); + + it("returns unknown_subcommand for missing subcommand", async () => { + const tool = new Tool(meta); + const result = await tool.invoke("nonexistent"); + expect(result.ok).toBe(false); + expect((result as Record).error).toBe("unknown_subcommand"); + }); + + it("returns input_validation_error for bad input", async () => { + const tool = new Tool(meta).subcommand({ + name: "strict", + description: "Strict input", + input: z.object({ required_field: z.string() }).strict(), + output: l1Output({}), + handler: () => ({ message: "ok" }), + }); + + const result = await tool.invoke("strict", {}); + expect(result.ok).toBe(false); + expect((result as Record).error).toBe("input_validation_error"); + }); + + it("returns help envelope", async () => { + const tool = new Tool(meta).subcommand({ + name: "ping", + description: "Ping pong", + input: z.object({}).strict(), + output: l1Output({}), + handler: () => ({ message: "pong" }), + }); + + const result = await tool.invoke("help"); + expect(result.ok).toBe(true); + const subcommands = (result as Record).subcommands as HelpPayload; + expect(subcommands).toHaveLength(1); + expect(subcommands[0]?.name).toBe("ping"); + }); + + it("returns schema envelope", async () => { + const tool = new Tool(meta).subcommand({ + name: "ping", + description: "Ping pong", + input: z.object({}).strict(), + output: l1Output({}), + handler: () => ({ message: "pong" }), + }); + + const result = await tool.invoke("schema"); + expect(result.ok).toBe(true); + expect((result as Record).schemas).toBeDefined(); + }); + + it("catches ToolError and returns business envelope", async () => { + const tool = new Tool(meta).subcommand({ + name: "fail", + description: "Always fails", + input: z.object({}).strict(), + output: l1Output({}), + handler: () => { + throw new ToolError("custom_error", "Something broke", { key: "val" }); + }, + }); + + const result = await tool.invoke("fail", {}); + expect(result.ok).toBe(false); + const err = result as Record; + expect(err.error).toBe("custom_error"); + expect(err.message).toBe("Something broke"); + expect(err.detail).toEqual({ key: "val" }); + }); + + it("catches unexpected errors", async () => { + const tool = new Tool(meta).subcommand({ + name: "boom", + description: "Throws raw error", + input: z.object({}).strict(), + output: l1Output({}), + handler: () => { + throw new Error("kaboom"); + }, + }); + + const result = await tool.invoke("boom", {}); + expect(result.ok).toBe(false); + expect((result as Record).error).toBe("unexpected_error"); + }); +}); + +describe("output helpers", () => { + it("l1Output includes ok and message", () => { + const schema = l1Output({ count: z.number() }); + const result = schema.safeParse({ ok: true, message: "ok", count: 42 }); + expect(result.success).toBe(true); + }); + + it("l2Output includes classification", () => { + const schema = l2Output(z.enum(["a", "b"])); + const result = schema.safeParse({ ok: true, message: "ok", classification: "a" }); + expect(result.success).toBe(true); + }); + + it("l3Output includes instructions", () => { + const schema = l3Output(); + const result = schema.safeParse({ ok: true, message: "ok", instructions: "do this" }); + expect(result.success).toBe(true); }); }); diff --git a/tsconfig.json b/tsconfig.json index 96fd379..378dd38 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,11 @@ "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + // TODO: noEmit is required by allowImportingTsExtensions, but package.json + // declares "types": "./dist/index.d.ts". Add a tsconfig.build.json with + // emitDeclarationOnly: true when setting up the build pipeline. + "noEmit": true, "lib": ["ESNext"], "types": ["bun-types"], "strict": true, From 3459e10db88be2893a4f437c8004caa63cc31b19 Mon Sep 17 00:00:00 2001 From: Juan ignacio Gipponi Date: Thu, 21 May 2026 22:39:27 -0300 Subject: [PATCH 2/2] fix: update package name in JSDoc + biome formatting --- package.json | 5 ++++- src/tool-class.ts | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c448abb..fac13b2 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,10 @@ "types": "./dist/index.d.ts" } }, - "files": ["dist", "src"], + "files": [ + "dist", + "src" + ], "scripts": { "dev": "bun run --watch src/index.ts", "build": "bun build src/index.ts --outdir dist --target bun", diff --git a/src/tool-class.ts b/src/tool-class.ts index fa1f868..3ff1050 100644 --- a/src/tool-class.ts +++ b/src/tool-class.ts @@ -15,7 +15,7 @@ * * ```ts * import { z } from "zod"; - * import { Tool, l2Output } from "code-first-agents-tool"; + * import { Tool, l2Output } from "@code-first-agents/tool"; * * new Tool({ name: "level-classifier", description: "..." }) * .subcommand({