{"_id":"pi-smart-router","_rev":"41-804530f3180850569f9dac9a66b8535d","name":"pi-smart-router","dist-tags":{"latest":"1.2.0"},"versions":{"0.1.0":{"name":"pi-smart-router","version":"0.1.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.1.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"22f5378eae796c40f58e1bcdb46da39bf254a71c","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.1.0.tgz","fileCount":310,"integrity":"sha512-zzz9a5XeZnkIvVno7DMooAE5VWlc+ymJoY97RE9Mnn9D1EyltyZUp1tcKJf5CnfiJP6WwhmT2LYV6ROWJQNoJw==","signatures":[{"sig":"MEYCIQCMlbUYN0TqxYyanWnowivzdqNyeDBQhYx5U1C3YcZNRwIhAKoaonfTvNfgiXlZrAv8t16aGqqTKVD0wFrrab9Pm/JI","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1390702},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"6c9fe85ffc4b38f7f22bf3725377f001e17dec21","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","release:check":"npm run verify:ci","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","routing:verify-calibration":"npm run build && node --experimental-strip-types scripts/verify-routing-calibration.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.3","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","yaml":"^2.9.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.1.0_1783462762111_0.9104123093535685","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"pi-smart-router","version":"0.1.1","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.1.1","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"c30868d55ad5de86f6a6d8a16ad5847683eb4ea5","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.1.1.tgz","fileCount":310,"integrity":"sha512-wMC7qAgtWZsujTHRQTI8DurtvLnQH9wXoaT8ROwIENaUXEuNJqj7cWDt1t9UiahQrecW87h/pHD3+L0zoW9gyA==","signatures":[{"sig":"MEUCIQD15ZKFozqHzUE1x2odjgkuC/X6P1Qtm1u5smjOteqitQIgGAjAeeXNua59xZVhWFRHUThafc7JAyhRYyAyL7d4jb8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1391387},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"24ce752426a9721b0826ca9636d8e26dfb445dab","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","release:check":"npm run verify:ci && npm run release:consumer-pack","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","routing:verify-calibration":"npm run build && node --experimental-strip-types scripts/verify-routing-calibration.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.3","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.1.1_1783467883134_0.7042938056685268","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"pi-smart-router","version":"0.2.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.2.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"1ab96868bac4ee4cfc45f537ee3feab4a4d2549e","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.2.0.tgz","fileCount":320,"integrity":"sha512-E9rBtiezEDTQ5yUQS5gFdt3VRWHTmvx0pLK94nethyTk6nnK4rbBRbeLkk0zrbMg8X+MsG5eF3jMl6FDSTBjnA==","signatures":[{"sig":"MEUCIQCJiZQaeXbk6vTYiKf+7hh6fPSz/xEiIO8E9EOjloOszQIgK4CHc1qo5AapwlaVeeOjlkEwbs1HlZ6yByVuVUHCFNY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1526819},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"6d6fdcfa1bfe546ee7a53f3a03321fab1234b383","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","release:check":"npm run verify:ci && npm run release:consumer-pack","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","routing:verify-calibration":"npm run build && node --experimental-strip-types scripts/verify-routing-calibration.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.3","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.2.0_1783611312988_0.35928008681446544","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"pi-smart-router","version":"0.3.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.3.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"448b44470545cb290fcc11cb3aa5ed76591389b3","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.3.0.tgz","fileCount":326,"integrity":"sha512-pMi/DVLAuQTkGyUbzfwqpplI+OYrbCnHig8FuUfTFPU5QCd3uJAwKE+wpeilF6fw1EPfNUwT34rc3fysU+deZg==","signatures":[{"sig":"MEYCIQC0V7UXR5LPrYBIGHUt6t+DW1lzvgcozNo1EWDmaF2N+wIhAKixcdHoBHQbEbpdukFdJi1EWPVHCl46S94vkf0h+P3i","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1612392},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"8558b322cc3cecc460fd8467cfa28dd4f8d1b722","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","release:check":"npm run verify:ci && npm run release:consumer-pack","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","routing:verify-calibration":"npm run build && node --experimental-strip-types scripts/verify-routing-calibration.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\""},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.3.0_1783624757415_0.26753836042286183","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"pi-smart-router","version":"0.4.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.4.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"178b2ccd422c5735c883f21f6cacc3d2692db09c","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.4.0.tgz","fileCount":327,"integrity":"sha512-bO6nLIhkuT7sFrVjJIe0wTWOSMRMjxET9v5RU9OvBmpC64n+JyplGKo4rYkDj3HekhcwNPSGBvKN5yjEAPW7Gw==","signatures":[{"sig":"MEYCIQCDp6LlKnbSlj5WyKH5melYa31xOJExJHnqmPh2WRGU/AIhAIWAH56O6c/SyuSFUfdqa2l5c/6HKt8nP4WBy8/VY6AR","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1669737},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"1943ebfe51b39cd4b4a8e5c373ce104c95ff418e","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","release:check":"npm run verify:ci && npm run release:consumer-pack","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","routing:verify-calibration":"npm run build && node --experimental-strip-types scripts/verify-routing-calibration.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\""},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.4.0_1783631263395_0.11057793729060572","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"pi-smart-router","version":"0.5.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.5.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"31279d24b04f142f8533005dca092faac3702de3","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.5.0.tgz","fileCount":332,"integrity":"sha512-NG2SzcNCfCOLgUtmZr3ZVFaPUzUkePTruzxfEPpRDNde3UOoDPbq+1C9ejIA4Hq6aGeEpDpXkRk6VcC8vABlTQ==","signatures":[{"sig":"MEYCIQDGTLQxJNVV7ikETQOXwiuUxVOApfb2uCtdDEaDBcld2gIhAP2Njd3JkkgAeDt9dxmfhmL5GsiCQi9OItP8V8QtWXSm","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1762502},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"28e4bd1fb718bf7acaf7f8ada92da79cb6119ebf","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","release:check":"npm run verify:ci && npm run release:consumer-pack","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"npm run build && node --experimental-strip-types scripts/verify-routing-calibration.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\""},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.5.0_1783639537412_0.8266718550654086","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"pi-smart-router","version":"0.6.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.6.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"ca9901f309d5cc17579e7a1b7fa74811d7747256","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.6.0.tgz","fileCount":353,"integrity":"sha512-QM/BAx6bBbcm9S7dEk9sP2Hd/SZ5kw/eH05YQ267t5xxHPgZD/2xW4d8Fmti+r/0sjW9ndB2R18z99XNwsit0w==","signatures":[{"sig":"MEUCIF3LMDWyGqulYL0UaoxHPjdsuGMC4TKpg5SGxDNK+JTvAiEA6fYnluciYdP5cLHst64i9SDqpqoQBW5dNb6xmraLdSs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1921600},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"c1886e2c18bdc855f8cc45138289dbc2687e5deb","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","release:check":"npm run verify:ci && npm run release:consumer-pack","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"npm run build && node --experimental-strip-types scripts/verify-routing-calibration.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\""},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.6.0_1783707126267_0.20602781520677116","host":"s3://npm-registry-packages-npm-production"}},"0.6.1":{"name":"pi-smart-router","version":"0.6.1","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.6.1","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"2ccd6fe35c19e3c4094d8d3680ad64e11eb8b54f","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.6.1.tgz","fileCount":354,"integrity":"sha512-mDN5Azhm+sHbQMgjWmkXS7ehCGcjBzVh9QIlWXV3SKhmo5qh+NiwVGjEDlZasTyimVilHd0/qkoeESPyDDnX8Q==","signatures":[{"sig":"MEQCIAt5NNwJDXjNdCzBBGZE8d6K6EClDC6Jh1IPptb6NFZsAiB9vFccDqr3P0gIKsTSHwyi9+QAg+YjoLdz1ghM3eWRTg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1940297},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"a83a1254bf455721fa09a49f5526fe913de9486a","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\""},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.6.1_1783716297401_0.46057704294550716","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"pi-smart-router","version":"0.7.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.7.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"e67530cd2677cda29228733f38a9b84549edbec0","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.7.0.tgz","fileCount":355,"integrity":"sha512-XnRkSqQfccjVXjrhRHPfhGovSjt6lJkX4Eq+6Ygg57I0C+TdqArfSb6FYaNRUKAsQeZKN7cczbYMZmZllgd0ug==","signatures":[{"sig":"MEYCIQDsDJmd4rLiCscfz5mjHViUqJuO+W8yhsamJjNcdescPgIhAKWbjaVTUCxunc+2CSgMya1RTTyD8AQ9d+P9HMPlC0Lu","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1954711},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"60b2965e823efb8c8e1d957f05a1411a80c99add","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\""},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.7.0_1783720917775_0.6125133454440319","host":"s3://npm-registry-packages-npm-production"}},"0.8.0":{"name":"pi-smart-router","version":"0.8.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.8.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"7f6f44d2dbf3df3d9ddb3547f02d40a435c15bca","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.8.0.tgz","fileCount":355,"integrity":"sha512-i6zXiz8eM5m4A2wu28gFbSPtyWNSgJweWEv7pIfEn33rqdo8fsvBugHdyPiX5qAroOzAz4kCakQxLMWZSoqt4Q==","signatures":[{"sig":"MEYCIQCFy4PmCGyPbrG+PodmBMDWLr9HhaSJyKKLrMQrPIeVrQIhAMjg7eEfzftipQ9ZaLu1ICobq8aBySLRV+wU5VcE2ehB","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1987222},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"c19175bd250fbe4f4224df12be8e021167998aeb","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\""},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.8.0_1783722728198_0.42931699484521735","host":"s3://npm-registry-packages-npm-production"}},"0.9.0":{"name":"pi-smart-router","version":"0.9.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.9.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"2ece62700e304eba0f9d579d709f78a38a5d680a","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.9.0.tgz","fileCount":355,"integrity":"sha512-6db83kKZZvq0HnXcRr0Z+gGs64cHem4LLbILxtpoeJ4xgE7DvCrhWUf+SorzeuuWIklltYlICcz3tkOypkiSBA==","signatures":[{"sig":"MEUCIQCGAQKKILtVgsRMJDHhIldMec640xNK3VcwXm5AgtZZ0AIgCjJ6mKmxDYkCDceRo8NG88EMuYLosnql8cSZyFWpe+Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1990402},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"161a83d555292297f05891f88958985e17c57216","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\""},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.9.0_1783732181907_0.94227212883637","host":"s3://npm-registry-packages-npm-production"}},"0.9.1":{"name":"pi-smart-router","version":"0.9.1","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.9.1","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"676655849562b9620a7516604e39f3eaf06acf47","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.9.1.tgz","fileCount":355,"integrity":"sha512-jxgh9ui+2IYED+ey/pLrH15leywas69B0A7jnvUYLayX+cIqPyl6cehopyfTNm18fQwwPdElYsvotyZY6s0xsA==","signatures":[{"sig":"MEYCIQD6S5ZpMRBBKcGj8CLhNHWSUFBP88Z3axgD2G5MDD5VPAIhALL1uAWgnYh1yAbk8s2PZSsEfV6NmGO3D409kn9Hu/uH","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1993433},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"053f8eb1de4442341120442ca3a6ab2bafaea872","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.9.1_1783741364479_0.5297187558851044","host":"s3://npm-registry-packages-npm-production"}},"0.9.2":{"name":"pi-smart-router","version":"0.9.2","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.9.2","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"bfa4308f3253168bd0cbbfd595e6114c84620684","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.9.2.tgz","fileCount":355,"integrity":"sha512-4rl9ZwhIhRB+YRAr5mRchs29A6PgWuqpjlQgZF8d2sic4fgyAmp21mc8jFG16OMOWfpJX83ytFmKXYoVzOgEow==","signatures":[{"sig":"MEUCIAHc/cCGc6C4knPQtfWq22dNLVAGbEthkW5BLTj3RqI2AiEAgPzty4pOy4tzLCt8ftL/1mBh8t5UDM4PGGRq6rA/vnM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1997039},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"b937a7aac9ec78862a83274c8289abc7dbbb887c","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.9.2_1783793195673_0.5562404035084982","host":"s3://npm-registry-packages-npm-production"}},"0.9.3":{"name":"pi-smart-router","version":"0.9.3","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.9.3","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"30ad3a5a455bf27ab17410e516041addc9fa941f","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.9.3.tgz","fileCount":355,"integrity":"sha512-v/XqqZBAiF46HtLup2m40kHTxREa6oxsvVB9fTY0aQxupQnEKeYRenqigOSnJV3f1Y4GZ1MiptDSurSqOl1MgQ==","signatures":[{"sig":"MEYCIQCXjmSGsG23TkgZS3lVMg8I/9ImSWkFrce+kfrYCxK+fgIhAN3wK8GO/xMdYrSmlWdpSQVrOAryxlUZs3Q7QiLeiy8u","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2001159},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"55a1cc63f33b09ae4cbd272461503f2a537f8ea1","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.9.3_1783802218939_0.44324805378482424","host":"s3://npm-registry-packages-npm-production"}},"0.10.0":{"name":"pi-smart-router","version":"0.10.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.10.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"de1f9a6b59630c562bb0b33cd73ea5b390d3a6da","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.10.0.tgz","fileCount":355,"integrity":"sha512-QggijgGcJbJhOGdBLORZf0DmVhPhVA72235jWXyDniDNzK4oLo7gjT0eB22HHioi/WZzZkSmHA4XZv79iH+M1A==","signatures":[{"sig":"MEYCIQDBiK3QkiezQ2km3fAK23Y1gsMk+ILa3V7T1GvHy/0wPgIhAJHGc+G52PHlA76ZrT8yNxED5hCDBanKwW5jylSYfMe9","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2004988},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"3c9d298a438af97a1e2c02d7132f608be75d3f80","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.10.0_1783805770237_0.8522058232865928","host":"s3://npm-registry-packages-npm-production"}},"0.11.0":{"name":"pi-smart-router","version":"0.11.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.11.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"a99222fcc64b81b29af137b98f118e1d4a1bdb4c","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.11.0.tgz","fileCount":359,"integrity":"sha512-boOI0m9a3YjAqCTfQwtv3+Wy+GfqVb8LwKzuZnlWnVNPbicm+5FOSSH1aErgx+PVgqka1Ly8A8OvIjxCUYR90Q==","signatures":[{"sig":"MEQCIASdMV54FuLVWsnJ0I7Q5xTZgMjiwNyYwzZ/SjMqjNDYAiAbWeDvCNxMjy8vJeS3wYdZTOxBbiIb5ia0R415qYwYQA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2034014},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"7841c34e1caf90516f87fb181733f23838a8c8bd","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.11.0_1783817702212_0.555792107989141","host":"s3://npm-registry-packages-npm-production"}},"0.12.0":{"name":"pi-smart-router","version":"0.12.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.12.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"7830a38724010abccd0c27ffe869538c9c350459","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.12.0.tgz","fileCount":359,"integrity":"sha512-eKKKxxZqm7yhnl8XC38hi9MSHamDlb6pslYcYH7zOHORB600n1gk7Q9nYta8gf2BA1JO7rKj8SlSMftavB032g==","signatures":[{"sig":"MEUCIGONEXVTH7ael1GMTiM8hCP/qLW5bC/VSSZ/jCYw1mW0AiEAsXYhk+MgAm9d2zgGrIEQkJOq+lqY9WIufDp+GlGtcpc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2036816},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"fd9b3a16743d96b694e9d4f6e1e7510c32e0cfdd","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.12.0_1783881222333_0.45289684135229336","host":"s3://npm-registry-packages-npm-production"}},"0.12.1":{"name":"pi-smart-router","version":"0.12.1","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.12.1","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"26e71f9be7e47620927eb3ec6097d62549e8e143","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.12.1.tgz","fileCount":364,"integrity":"sha512-AcIDkRgJdHIcrMKbugqwMSuiFRgIAw63rsa95K/ayq6MmCCfKBjLDueduBmPhVxzuUHfRHl5QX+JfgTA7UverA==","signatures":[{"sig":"MEYCIQD1uMoR8FmGDqOdZyNy1iQoS4aOBattybMW+90LlBSoGgIhANuew6LCWnlvtj9KQj50OHETzBhs4JZnRsX/HMbhqO9C","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2069446},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"266b9701df25ef2448f8bc206b5ebc033708544d","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"*","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.3","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.12.1_1783993483237_0.6368070883383312","host":"s3://npm-registry-packages-npm-production"}},"0.12.2":{"name":"pi-smart-router","version":"0.12.2","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.12.2","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"032a1514791d41c9cb40a26604a6e57da0f6d1b1","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.12.2.tgz","fileCount":364,"integrity":"sha512-Q8AENeiikuMHC8r7moJEs/PKCL4eXkQ6rz93Hh0uPl6bEirOOEC51e1EdMy7pW6KM6EyfQP9tGeF97YhWFxhvw==","signatures":[{"sig":"MEUCIQD4xxf8Y50U9dSyyqhzvhdwoVc3x52WlOR3d/8ENYg09gIgYHuNJEfGjBI5WoikMqjqCzmACdm6LSkG6ZtAnJjDpI0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2071025},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"60909627fc4cd9cbbdb26e586f01acf489fe660b","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm test && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.10","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.10","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.12.2_1784251382637_0.5933670510898688","host":"s3://npm-registry-packages-npm-production"}},"0.13.0":{"name":"pi-smart-router","version":"0.13.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.13.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"d614993b13a778f060abeaa7ec63ee428e512aa9","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.13.0.tgz","fileCount":364,"integrity":"sha512-z7Lho5l9ptlAjvOmaFQzj28t6pSeabeWCZBWyiTA+QEJ1jODwx/kStijX0uJt5JB29I/JjGd1mr97AlXzlD5NQ==","signatures":[{"sig":"MEUCIDeJ43VawZN7vwVSZegNovjvF9Xos3h1UHKWOpWXFs5+AiEAvLJFmfI7Ww3wmHwp16k7x6hUgMBVU6Goyi39cHm1/oM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2091966},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"7585a9643535410277c133986c743205384b1c24","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.10","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.10","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.13.0_1784586441258_0.7643124843357667","host":"s3://npm-registry-packages-npm-production"}},"0.14.0":{"name":"pi-smart-router","version":"0.14.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.14.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"00987d5fa4e47ccf12f9b4e1e4b7c838e1864f7b","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.14.0.tgz","fileCount":374,"integrity":"sha512-w3PBZuY/UiTNBqxBdIq6rYWhnyEdhjuXEd3avOyWNAK9lM8fGixwtWERFNlm6Zi1ImgIf0Y5jEF+ofWTkF5BNA==","signatures":[{"sig":"MEUCIDW1XBOYoDLIRKWk/Y49+tdq2iQvBHrIQUpeTwrDrdBPAiEA53BT43Tgq2RMWSSrP2XVPha+KH1SOdaDzzw7W7MxKSc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2212369},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"b141394b0f8665e08751fbc98c39c85456b333ea","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.10","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.10","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.14.0_1785716561161_0.9328780603250939","host":"s3://npm-registry-packages-npm-production"}},"0.15.0":{"name":"pi-smart-router","version":"0.15.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.15.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"46c313f5ad5f0b531a313f8a882ffe381169ca1d","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.15.0.tgz","fileCount":399,"integrity":"sha512-CHq6BC5WZhP0b7bYvJrlEIpfhrJhxOIu2Fyqto0pzkBQmaMd6JQsvyRCSRIalr3Dz0IZ3inMIyIau7Dkkhl65A==","signatures":[{"sig":"MEUCIQD4fof5Y1CrCDsMOd9TNWR+CjkJ8saJz697P6drYKpdTAIgB6h2cLPJewGeNDpmdXKbdSoRGAPzq/zz1iIQLUtS1e0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2428098},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"88d5be9cacfba8daa3805eb6ad1473cdf5d6f0af","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.10","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.10","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.15.0_1785739451346_0.16444880347942759","host":"s3://npm-registry-packages-npm-production"}},"0.16.0":{"name":"pi-smart-router","version":"0.16.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.16.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"831fcb7f37be9610d9fbc8d1143986d94a5b4948","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.16.0.tgz","fileCount":399,"integrity":"sha512-DT4akN7+CCBER7nteHhiYJ1zZHXxvDMX91ALzNJpfrzv2S13VOTg5U9KgfJyVTsCv8suHIbA58jyfvmBXTCWZg==","signatures":[{"sig":"MEYCIQD7MIvY2jfE6h+Ux0T7IHPJgckaVN0I+Il2QyyVPXZLCQIhANQEpjZamEZ4WmCeJeSRg6EwBFgYY79boMebfeKtqYWd","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2428522},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"ce03be7d7fabec8574659b4a5bc2658b88364566","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.1","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.10","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.10","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.16.0_1785799442121_0.2706473051432934","host":"s3://npm-registry-packages-npm-production"}},"0.16.1":{"name":"pi-smart-router","version":"0.16.1","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.16.1","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"8c5feb481824ae39a97c98e61a7b0961ee625014","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.16.1.tgz","fileCount":399,"integrity":"sha512-+YURbNTKUJPUSJu+pvynfjWAsqjR4JznZTQw6BKxZr37+SIpQoYyAAXX5S/wAcP8jRmPebc1IqxeyxwCC+Isjg==","signatures":[{"sig":"MEYCIQCo25w1kTU3g30kbQe9BkUBkZRV/U1YX8lNiOFAxaOWDAIhAPCaKP9YLvbz/cSPece14ukW0ZTK57sAeAHfpAmzUM0g","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2433909},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"d37e5799bc4cb0019ba19ca7f2ac891de1f086fd","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.2","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.10","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.10","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.16.1_1787258655865_0.3064055680999995","host":"s3://npm-registry-packages-npm-production"}},"0.16.2":{"name":"pi-smart-router","version":"0.16.2","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.16.2","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"1f0cded7fcc9d6534a245937239e506931ea5861","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.16.2.tgz","fileCount":399,"integrity":"sha512-YZcPcopL404lZIYu0MVbRD88uPn6WGDZh94ZXXZ3tN5Oo9dXwJwxQAqS1P+/ZwoJJkoeDRciFYXdDwJjNAl/EQ==","signatures":[{"sig":"MEUCICfQVRzICx6l1rOmcdZbjYXDOKJcVIyNORW25h1tLPP4AiEAs9VICpI4jssqJmigzTK88fseB/oOsZux9JGu8x/tIYQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2438606},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"b0fa41a35f69553f963c419b251025208a68000a","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.2","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.10","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.10","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.16.2_1787423751472_0.47417412171606","host":"s3://npm-registry-packages-npm-production"}},"0.17.0":{"name":"pi-smart-router","version":"0.17.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.17.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"f471ebb9965c2173c390878c1cafe4c71472b874","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.17.0.tgz","fileCount":399,"integrity":"sha512-zr8ZP2SoOTUGFBHhOPJ3uzM0nKXtZgREoo2pbJV4xWdeRoNy3G7v8lfox1Um0bGoGpFH+em320hwS5G5A0Nwvg==","signatures":[{"sig":"MEYCIQDSDTzWM3T2zLbUPgp0dvpuNge08/FtUC4D0VAMWUGkTQIhAPPf3pxaLLByNqc7RMNjrUbstwCZsGS8jdJd3IrErsjU","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2499995},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"332da7e390db6ae5e31ebcb3a4cb3c6e67ae3521","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.2","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.10","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.10","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.17.0_1787445999290_0.657543593029996","host":"s3://npm-registry-packages-npm-production"}},"0.19.0":{"name":"pi-smart-router","version":"0.19.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.19.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"c3da157c4b673b051e8cc3e1847d712cb81d9721","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.19.0.tgz","fileCount":404,"integrity":"sha512-6GYjzMgKEHyeoojIGBxAbakgcE3ozZdpk84WHbYFkzI8K2F0fkqBVOMddqZk2J413Ab1DY++K7qoWiosTlxmUA==","signatures":[{"sig":"MEUCIQCvl81zOQnCdkU5rl9Yvtnh02uFO0jA5l0x5XadWMMrAwIgXPfNUkdP77wCcoZv0rATBfVOGR/IKh09Z/TVZfEVpQs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2558443},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"855fb08bbfc4b8a49e443efcfc5f96a7d5bbd74a","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"deprecated":"Accidental empty bump during v0.18.0 publish; use 0.18.0","repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.2","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.10","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.10","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.19.0_1787944464990_0.04879566566249349","host":"s3://npm-registry-packages-npm-production"}},"0.18.0":{"name":"pi-smart-router","version":"0.18.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.18.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"ff23a8ad81dea9c3f14d82a5018b61f4584c695c","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.18.0.tgz","fileCount":404,"integrity":"sha512-Z5ammSUy+wUwA05ZOibVuhjeYkHROvVVG63LgN1UL6vFEQU8S3/WVcRRcj2rg+my3169sUQUm16fSY9iitIQUQ==","signatures":[{"sig":"MEUCIB4e+kpMllWb8bgDiykuxnrNgW5EYS72F117Z2PCqvp1AiEAhoFWI2mPW8p7id0AJDtcO4MvrQmQsYShLVviBX48BfM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2558443},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"3c98cc04adb21509eb01c8e7890f650f31cb588b","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.2","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.10","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.10","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.18.0_1787944479070_0.35625223896491964","host":"s3://npm-registry-packages-npm-production"}},"0.19.1":{"name":"pi-smart-router","version":"0.19.1","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.19.1","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"1b5666388e724315a006fc73e6600dce8df23c3a","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.19.1.tgz","fileCount":404,"integrity":"sha512-iaDCNZkM5YacAfAxLwKJKTvEbunuzVazdWVDP0z7TYX9o2c+NhIR8SYDiunBGJfWp7Gj8/83FgKmy0Q6YaPb+w==","signatures":[{"sig":"MEYCIQCoUQspDO5sb9dfleh6cUI4IApFLOmX29mOIIiHEqMScQIhAOjDdGiZRYXXhuen5XFJ3vGq1WMMShFnS6uBPc7cpE4U","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2564780},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"4d11ada89ebbf3cf97c394449ec0835139f0557a","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.2","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.10","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.10","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.19.1_1787972322256_0.4769306489095333","host":"s3://npm-registry-packages-npm-production"}},"0.19.2":{"name":"pi-smart-router","version":"0.19.2","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.19.2","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"66e5f0cc85acfbafefc8a31b413f9ff157600d27","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.19.2.tgz","fileCount":404,"integrity":"sha512-JZnUFCU+X3yJg3PliIypKBtUBZfKBk5CsnnlXyGaN5YRq45bnUOLUcsKF45SlkCrAERl1QPOdR2ZWYG9dzKUbw==","signatures":[{"sig":"MEUCIQDdxmXzXqmzXvtyWwg9kWWKSmTLkItz6JtQ1XSXZXEGAQIgJb5Pc1Uzt6G+K9Hl2npM+yShoahU/LrZahw9A4Cu4rw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2566927},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"196b367745008e8bf92002392212b8acb13654b9","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.2","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.80.10","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.80.10","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.19.2_1788034506161_0.411861462332225","host":"s3://npm-registry-packages-npm-production"}},"0.19.3":{"name":"pi-smart-router","version":"0.19.3","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.19.3","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"7f510c3b485859e74f9661040ca6d19da1144eca","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.19.3.tgz","fileCount":404,"integrity":"sha512-DXcDP6/I5n9E5UGyp+h1mtbtOLxMHhQ+CQHhPfqZPDuNCbJ5ocM41Q/pzbBqBmsctaCtl7XJCUi4X7xzc5pkxA==","signatures":[{"sig":"MEYCIQDInBOftyJf0ouQTOZ8kfCFQLW478RzF2bwvkUf/R7jagIhAPjeiMJCt3HMhxXCyMnPG0nPgqFLahW24wF/tnqljlei","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2566930},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"6302059fa1962c5f19ac99bbb3dc8fad6993cc6f","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.2","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.84.4","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.84.4","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.19.3_1788120572647_0.4835686524204845","host":"s3://npm-registry-packages-npm-production"}},"0.19.4":{"name":"pi-smart-router","version":"0.19.4","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.19.4","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"c4938d97541d1c1f19954df6ac52ec0a5739fd98","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.19.4.tgz","fileCount":404,"integrity":"sha512-RpJQC1px8J8hOnVvtThMOhMmKT3yulyRnWSfIDhSBuitjz1xhI8CIhbzRtvB0RkOq5SH2NqKcZ19fcCmYMGgUA==","signatures":[{"sig":"MEQCIF3qsZ007pC20tmzML0wOnEGrdpgcA8noJINjXIJBDqEAiBkVSRF7n4fyC9SBu0rsgHg8GEfgrj+3u5HIhe/XW4OnQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2566930},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"c96aaf301ac4955c92feceee3f91fd1c2bc193de","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"deprecated":"Accidental empty bump after v0.19.3; use 0.20.0 or later.","repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.2","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.84.4","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.84.4","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.19.4_1788120594348_0.11582265428383476","host":"s3://npm-registry-packages-npm-production"}},"0.20.0":{"name":"pi-smart-router","version":"0.20.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.20.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"a100d97d49e2df9f6fa1fa3516d742788aaec095","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.20.0.tgz","fileCount":414,"integrity":"sha512-TyWs3XBu6kBILrM6a5QkdXLXa4WqWLWEogKzouCz9SdeJSjRsvCx2IKT1XPxu+bK/LMtCkFXMQMFkxgaxpXDPA==","signatures":[{"sig":"MEUCIQCcP1rSp0n4xj7JNk4oV2o3yrAnB8v1o9DX3m8E63yI6QIgGWJ9ZnDCsKlIw/tr8r9p+8vyiVtfuzDVei/EJcKz18g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2753674},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"de8d5ec0a554038eb4e87c6211060be3cb5fa887","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","release:assert-content":"bash scripts/assert-release-has-content.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.2","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.84.4","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.84.4","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.20.0_1788368361045_0.7108443058676626","host":"s3://npm-registry-packages-npm-production"}},"0.21.0":{"name":"pi-smart-router","version":"0.21.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.21.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"d527ce29a6687c0cec82b6c4ffb7d7bf060e434d","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.21.0.tgz","fileCount":424,"integrity":"sha512-qtZdJRCfC230S70YhiFWXuMAv+PrBJm67EeLeh2vPi+beWkPmrkT8reFF3L7r5ZibUESg4gYmO87OEOus/2Efw==","signatures":[{"sig":"MEQCIEzjJIoqumzz74i4VDS5agEo357WRrnyVDYbvpV8ju99AiBH82mQbntQHQs9ambS4nEzY3W6kFAltqEJ2Bak1+xleQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2793790},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"ccaedba497e02a94a5a9ba8524260c13e74b65f9","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","release:assert-content":"bash scripts/assert-release-has-content.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.2","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.84.4","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.84.4","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.21.0_1788478883920_0.29337593235505266","host":"s3://npm-registry-packages-npm-production"}},"0.22.0":{"name":"pi-smart-router","version":"0.22.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@0.22.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.80.8"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"58a6327f868c700de4c5cf91c88fe08e392fd785","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-0.22.0.tgz","fileCount":425,"integrity":"sha512-EOanwcHgdaz0MkL7SM7C5AMvX8Lhm+LYYPpXUkVDygJzPBThqwQqDy4+XP65wA48iIJVFfUZdVPr3shcE/78hg==","signatures":[{"sig":"MEUCIQDCqSKNLVVyp7pqNQj/c63d+i8aN9j02KFkSx9TXAHXHQIgNLstq1mcX/ymYbdU1X8IjEI3a/xH0+Vk5MBuPZcRAKg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2835868},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"d2fce2617a84e26da3e450884d0dd3cd35175630","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","release:assert-content":"bash scripts/assert-release-has-content.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"node --experimental-strip-types scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"node --experimental-strip-types scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"node --experimental-strip-types scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.8","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.23.2","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.84.4","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.84.4","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_0.22.0_1788640795716_0.31313726267464936","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"pi-smart-router","version":"1.0.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@1.0.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.85.1"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"d58c8e9ee24bbb435e6f5e2f785fcfca6ca62996","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-1.0.0.tgz","fileCount":527,"integrity":"sha512-cZFxJc28IiWZRsxwANnCh8mzaXgL/tZ2sfiIHYIqEz8OcjmxlZDJJcUOeszik7DnwDQBiF09Y5jezpvTLr4olw==","signatures":[{"sig":"MEUCIQDAP8Vx/OektiCP/OilFy2Y7DAm4SYuJiJ+VtIm0oUkWAIgHatck1jBxrX0WA8vHcqCWLWoSrVcxLUaMKj5JVVHw/s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3050447},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"26acd3300f68c03b26f2e7b51dec460923d6bd09","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run verify:script-artifacts && npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","qa:dogfood-soft-feed":"tsx scripts/qa/dogfood-soft-feed.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","release:assert-content":"bash scripts/assert-release-has-content.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","verify:script-artifacts":"bash scripts/assert-no-script-artifacts.sh","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"tsx scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"tsx scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"tsx scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.3","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.19.0","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.85.1","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.85.1","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_1.0.0_1789076952472_0.8874475164200275","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"pi-smart-router","version":"1.1.0","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"license":"MIT","_id":"pi-smart-router@1.1.0","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"pi":{"skills":["./skills"],"extensions":[".pi/extensions/smart-router/index.ts"],"minPiVersion":"0.85.1"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"dist":{"shasum":"e88e2ec4cf28c94096a0e9fdc9b2b1bb4117f7c6","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-1.1.0.tgz","fileCount":532,"integrity":"sha512-spwQu1qcyXLcVhqz6Kbf59nMRW+VQ2kAUKGxqfT5P7OR2X+JtaUPK2iWHpWfi782ktZfu9dQt3ELsc4VHQ/9wQ==","signatures":[{"sig":"MEQCIBMYpzRPBYu2IPghA1gVyAwMXFpVgZ2dnJURN1x+uV6lAiAX8oj2pT/VuBazz0eZ4WEI3Hz/sMaYYMsqVH/mFFdnZw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3108465},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"c8d77180e22867d0b4f2ec959a30abee22183417","scripts":{"lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","test":"vitest run","build":"tsc --project tsconfig.build.json","typecheck":"tsc --noEmit","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","test:release":"vitest run --testNamePattern '@release'","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run verify:script-artifacts && npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","coverage:check":"vitest run --coverage","prepublishOnly":"npm run release:check","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","qa:dogfood-soft-feed":"tsx scripts/qa/dogfood-soft-feed.ts","routing:eval-harness":"tsx scripts/eval/run-harness.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","release:assert-content":"bash scripts/assert-release-has-content.sh","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","verify:script-artifacts":"bash scripts/assert-no-script-artifacts.sh","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:train-calibration":"tsx scripts/train-routing-calibration.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:bootstrap-centroids":"tsx scripts/bootstrap-routing-centroids.ts","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:calibration-aggregate":"tsx scripts/calibration-aggregate.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only"},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"repository":{"url":"git+https://github.com/beettlle/pi-smart-router.git","type":"git"},"_npmVersion":"10.9.3","description":"Auto-model router middleware for the pi.dev coding agent","directories":{},"_nodeVersion":"22.19.0","allowScripts":{"better-sqlite3@12.11.1":true},"dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","better-sqlite3":"^12.11.1","@earendil-works/pi-ai":"^0.85.1","@huggingface/transformers":"^4.2.0"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.0","eslint":"^8.57.1","vitest":"^3.2.3","typescript":"^5.8.3","@types/node":"^22.15.21","ajv-formats":"^3.0.1","@vitest/coverage-v8":"^3.2.3","@types/better-sqlite3":"^7.6.13","@typescript-eslint/parser":"^8.62.1","@earendil-works/pi-coding-agent":"^0.85.1","@typescript-eslint/eslint-plugin":"^8.62.1"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/pi-smart-router_1.1.0_1789254747385_0.9029003436733309","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"pi-smart-router","version":"1.2.0","description":"Auto-model router middleware for the pi.dev coding agent","type":"module","license":"MIT","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"repository":{"type":"git","url":"git+https://github.com/beettlle/pi-smart-router.git"},"homepage":"https://github.com/beettlle/pi-smart-router#readme","bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"engines":{"node":">=22.19.0"},"bin":{"pi-smart-router":"bin/pi-smart-router.mjs"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"main":"./dist/index.js","types":"./dist/index.d.ts","scripts":{"build":"tsc --project tsconfig.build.json","prepublishOnly":"npm run release:check","release:check":"bash -c 'export VITEST_MAX_WORKERS=\"${VITEST_MAX_WORKERS:-2}\"; npm run verify:script-artifacts && npm run release:refresh-benchmarks && npm run verify:ci && npm run release:consumer-pack && npm run release:functional-smoke'","release:assert-content":"bash scripts/assert-release-has-content.sh","release:refresh-benchmarks":"tsx scripts/release-refresh-benchmark-profiles.ts","release:consumer-pack":"bash scripts/verify-consumer-pack.sh","release:functional-smoke":"npm run routing:verify-calibration -- --skip-embed && npm run routing:verify-benchmark-profiles && tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/fixtures --baseline-version 0.6.0","typecheck":"tsc --noEmit","test":"vitest run","test:release":"vitest run --testNamePattern '@release'","coverage:check":"vitest run --coverage","lint":"eslint . --ext .ts && node --input-type=module -e \"import { readFileSync } from 'node:fs'; import { parse } from 'yaml'; const doc = parse(readFileSync('config/models.yaml.example', 'utf8')); if (!Array.isArray(doc.models) || doc.models.length < 3) throw new Error('models.yaml.example must list at least one model per tier'); const tiers = new Set(doc.models.map((m) => m.tier)); for (const tier of ['zero-tier', 'economical-cloud', 'frontier-cloud']) { if (!tiers.has(tier)) throw new Error('missing tier: ' + tier); } console.log('models.yaml.example: valid');\"","routing:bootstrap-centroids":"tsx scripts/bootstrap-routing-centroids.ts","routing:calibration-aggregate":"tsx scripts/calibration-aggregate.ts","routing:train-calibration":"tsx scripts/train-routing-calibration.ts","routing:train-p-success":"tsx scripts/train-p-success-weights.ts","routing:ingest-benchmarks":"tsx scripts/ingest-benchmark-profiles.ts","routing:verify-benchmark-profiles":"vitest run tests/unit/ingest-benchmark-profiles.test.ts -t \"checked-in artifact matches fixture ingest\"","routing:verify-calibration":"bash -c 'if [[ \" $* \" == *\" --skip-embed \"* ]]; then vitest run tests/unit/train-routing-calibration.test.ts -t \"verifyRoutingCalibration passes|evaluates benchmark triage gates\"; else npm run build && tsx scripts/verify-routing-calibration.ts \"$@\"; fi' --","routing:calibration-dry-run":"tsx scripts/verify-routing-calibration.ts --dry-run-packs","routing:eval-replay":"tsx scripts/eval/counterfactual-replay.ts","routing:eval-k4-ab":"tsx scripts/eval/counterfactual-replay.ts --k4-ab --corpus tests/eval/corpus/twinrouterbench/ci-subset.json","routing:eval-harness":"tsx scripts/eval/run-harness.ts","routing:eval-harness:smoke":"tsx scripts/eval/run-harness.ts --summary-only","routing:eval-harness:corpus-smoke":"tsx scripts/eval/run-harness.ts --fixtures tests/eval/corpus/twinrouterbench --summary-only","routing:assert-release-gates:corpus-report":"tsx scripts/eval/assert-release-gates.ts --fixtures tests/eval/corpus/twinrouterbench --report-only","routing:analyze-overrouting":"tsx scripts/eval/analyze-twinrouterbench-overrouting.ts","routing:twinrouterbench:full-ingest":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; mkdir -p \"$CACHE\"; npm run routing:ingest-twinrouterbench -- --input \"$CACHE/question_bank.jsonl\" --output \"$CACHE/full-static-track.json\"'","routing:twinrouterbench:full-report":"bash -c 'set -euo pipefail; CACHE=\"${TRB_CACHE_DIR:-.pi-smart-router/eval-cache/twinrouterbench}\"; DIR=\"$CACHE/full-track\"; mkdir -p \"$DIR\"; cp \"$CACHE/full-static-track.json\" \"$DIR/full-static-track.json\"; npm run routing:eval-harness -- --fixtures \"$DIR\" --summary-only; npx tsx scripts/eval/assert-release-gates.ts --fixtures \"$DIR\" --report-only'","routing:twinrouterbench:full-track":"bash scripts/eval/twinrouterbench-full-track.sh","routing:community-bench":"tsx scripts/eval/community-bench.ts","routing:ingest-twinrouterbench":"tsx scripts/eval/ingest-twinrouterbench-corpus.ts","routing:ingest-llmrouterbench":"tsx scripts/eval/ingest-llmrouterbench-subset.ts","routing:llmrouterbench-regret":"tsx scripts/eval/llmrouterbench-regret-report.ts","routing:ingest-swe-gym":"tsx scripts/ingest-swe-gym-labels.ts","routing:ingest-fc-rewardbench":"tsx scripts/ingest-fc-rewardbench-labels.ts","routing:ingest-twinrouterbench-weak":"tsx scripts/ingest-twinrouterbench-weak-labels.ts","routing:capture-baseline":"tsx scripts/eval/capture-baseline.ts","routing:test-projection":"npm run build && node --experimental-strip-types scripts/test-hydra-projection.ts","benchmark:encoder":"tsx scripts/benchmark-encoder-latency.ts","qa:shadow-dogfood":"bash scripts/qa/shadow-dogfood-session.sh","qa:dogfood-soft-feed":"tsx scripts/qa/dogfood-soft-feed.ts","qa:count-labeled-econ":"tsx scripts/qa/count-labeled-econ.ts","qa:export-dogfood-snapshot":"tsx scripts/qa/export-dogfood-snapshot.ts","qa:dogfood-gather":"bash scripts/qa/dogfood-gather.sh","verify:ci":"npm run build && npm run typecheck && npm run lint && npm run coverage:check","verify:script-artifacts":"bash scripts/assert-no-script-artifacts.sh"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"@earendil-works/pi-ai":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"devDependencies":{"@earendil-works/pi-coding-agent":"^0.85.1","@types/better-sqlite3":"^7.6.13","@types/node":"^22.15.21","@typescript-eslint/eslint-plugin":"^8.62.1","@typescript-eslint/parser":"^8.62.1","@vitest/coverage-v8":"^3.2.3","ajv":"^8.20.0","ajv-formats":"^3.0.1","eslint":"^8.57.1","tsx":"^4.23.0","typescript":"^5.8.3","vitest":"^3.2.3"},"dependencies":{"@earendil-works/pi-ai":"^0.85.1","@huggingface/transformers":"^4.2.0","better-sqlite3":"^12.11.1","yaml":"^2.9.0","zod":"^4.4.3"},"allowScripts":{"better-sqlite3@12.11.1":true},"pi":{"extensions":[".pi/extensions/smart-router/index.ts"],"skills":["./skills"],"minPiVersion":"0.85.1"},"_id":"pi-smart-router@1.2.0","gitHead":"760f82b91d93dc2f95f66ba717d915165aa2ac8b","_nodeVersion":"22.19.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-i/a2vrZiV6oojlBL7IOgphw0JCt2V5lqgSX+DgGreAk3XWmWdTiD5bysjAljFAAIW3DJFsXRVvhi61TJZft1bw==","shasum":"9a460305519b8cf7cf6f5f863aabb3ba79dfe1de","tarball":"https://registry.npmjs.org/pi-smart-router/-/pi-smart-router-1.2.0.tgz","fileCount":537,"unpackedSize":3166740,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDs6ymKTkxljBqGEuiBshWlXbc7fAYAksk3UWlLcjCpVQIgDBanXEJIgQ92r7OZDvankJTdl4gQYfLZst761LoVMFw="}]},"_npmUser":{"name":"beettlle","email":"45plaid_caution@icloud.com"},"directories":{},"maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pi-smart-router_1.2.0_1789319221315_0.7977001635251502"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-07T22:19:22.001Z","modified":"2026-09-13T17:07:01.614Z","0.1.0":"2026-07-07T22:19:22.323Z","0.1.1":"2026-07-07T23:44:43.318Z","0.2.0":"2026-07-09T15:35:13.172Z","0.3.0":"2026-07-09T19:19:17.587Z","0.4.0":"2026-07-09T21:07:43.589Z","0.5.0":"2026-07-09T23:25:37.643Z","0.6.0":"2026-07-10T18:12:06.481Z","0.6.1":"2026-07-10T20:44:57.590Z","0.7.0":"2026-07-10T22:01:57.951Z","0.8.0":"2026-07-10T22:32:08.342Z","0.9.0":"2026-07-11T01:09:42.107Z","0.9.1":"2026-07-11T03:42:44.632Z","0.9.2":"2026-07-11T18:06:35.932Z","0.9.3":"2026-07-11T20:36:59.133Z","0.10.0":"2026-07-11T21:36:10.374Z","0.11.0":"2026-07-12T00:55:02.369Z","0.12.0":"2026-07-12T18:33:42.484Z","0.12.1":"2026-07-14T01:44:43.466Z","0.12.2":"2026-07-17T01:23:02.811Z","0.13.0":"2026-07-20T22:27:21.531Z","0.14.0":"2026-08-03T00:22:41.342Z","0.15.0":"2026-08-03T06:44:11.547Z","0.16.0":"2026-08-03T23:24:02.313Z","0.16.1":"2026-08-20T20:44:16.057Z","0.16.2":"2026-08-22T18:35:51.661Z","0.17.0":"2026-08-23T00:46:39.503Z","0.19.0":"2026-08-28T19:14:25.209Z","0.18.0":"2026-08-28T19:14:39.254Z","0.19.1":"2026-08-29T02:58:42.501Z","0.19.2":"2026-08-29T20:15:06.352Z","0.19.3":"2026-08-30T20:09:32.837Z","0.19.4":"2026-08-30T20:09:54.545Z","0.20.0":"2026-09-02T16:59:21.218Z","0.21.0":"2026-09-03T23:41:24.132Z","0.22.0":"2026-09-05T20:39:55.940Z","1.0.0":"2026-09-10T21:49:12.618Z","1.1.0":"2026-09-12T23:12:27.578Z","1.2.0":"2026-09-13T17:07:01.469Z"},"bugs":{"url":"https://github.com/beettlle/pi-smart-router/issues"},"license":"MIT","homepage":"https://github.com/beettlle/pi-smart-router#readme","keywords":["pi-package","pi-extension","pi","smart-router","routing","ai","agent"],"repository":{"type":"git","url":"git+https://github.com/beettlle/pi-smart-router.git"},"description":"Auto-model router middleware for the pi.dev coding agent","maintainers":[{"name":"beettlle","email":"45plaid_caution@icloud.com"}],"readme":"# pi-smart-router\n\n**Auto-model router middleware for the [pi](https://pi.dev) coding agent.**\n\n> **v1.0 — SemVer stable (honest defaults).** From the `1.0.0` release on, the public API and documented operator surface follow [semantic versioning](https://semver.org): breaking changes land only in a new major version, each accompanied by a migration guide — start with [docs/migration-v1.md](docs/migration-v1.md). **1.0 means stable API + honest calibration floors + gates that catch Sept-class failures** — not a claim that cheap-tier routing is behaviorally proven. [#95](https://github.com/beettlle/pi-smart-router/issues/95) / [#110](https://github.com/beettlle/pi-smart-router/issues/110) remain open for verifier-graded recalibration. The published release always mirrors `package.json` ([npm](https://www.npmjs.com/package/pi-smart-router)).\n\npi-smart-router intercepts every LLM inference request and dynamically routes it to the optimal execution engine — balancing cost, capability, latency, and time-to-first-token (TTFT) — without requiring you to manually pick a model for each turn.\n\n| pi-smart-router is | pi-smart-router is not |\n|--------------------|------------------------|\n| A pi extension that auto-selects the best model per request | A replacement for pi or your LLM provider |\n| A three-tier router: local, economical cloud, frontier cloud | A post-generation output judger (FrugalGPT-style) |\n| Cache-aware with session pinning to preserve prompt-cache economics | A turn-by-turn model switcher that shatters provider caching |\n| Registry-driven in pi (no YAML copy for normal use) | An RL-trained router requiring agent trace datasets |\n\n## How it works\n\n```text\nrequest → hardware probe → loop escalation → turn envelope → context-fit gate\n        → low-intensity tier gate → session pin → deterministic triage\n        → local zero-tier → triage cloud fallback → HyDRA embedding matcher\n        → safe cloud default → context overflow fallback\n```\n\nThe pipeline runs **12 stages sequentially with early exit** — the moment any stage reaches a routing decision, subsequent stages are skipped. Every decision includes the stage name, reason code, candidates considered, estimated cost, and routing latency for full observability.\n\n| Stage | Budget | What it does |\n|-------|--------|--------------|\n| Hardware Probe | — | Checks platform/RAM/battery to gate local inference |\n| Loop Escalation | — | Detects repeated identical tool failures; escalates session to frontier |\n| Turn Envelope | <2ms | Classifies turn type: tool_result, planning, subagent, main_loop |\n| Context-Fit Gate | — | Filters fleet to models whose context window fits estimated input tokens |\n| Low-Intensity Gate | — | Structural tier hint, cluster match, and P(success) expected-cost scoring |\n| Session Pin | <1ms | Returns pinned model if session has one; breaks pin on compaction or overflow |\n| Deterministic Triage | <5ms | Aho-Corasick keyword scan + cyclomatic complexity analysis |\n| Local Zero-Tier | <15ms | Pings LM Studio + Ollama in parallel; routes locally when eligible |\n| Triage Cloud Fallback | <2ms | Trivial prompts not claimed locally route to the first healthy economical-cloud model |\n| HyDRA Matcher | 80-120ms | ONNX embeddings, 3D requirement projection, shortfall gate, multi-objective scoring |\n| Safe Cloud Default | — | First healthy economical-cloud model (context-fit aware) |\n| Context Overflow Fallback | — | Escalates to largest-fit model when economical tiers cannot fit |\n\n## Research lineage\n\npi-smart-router builds on ideas from several production and research routing systems:\n\n- **Adopted:** [GitHub Copilot HyDRA](https://arxiv.org/abs/2409.08379) (shortfall matching decoupled from model identities), Zero-Tier local edge-cache pattern, [Weave Router](https://github.com/workweave/router) session pinning and multi-objective selection\n- **Rejected:** FrugalGPT sequential cascading (tail latency), RouteLLM matrix factorization (confounder vulnerability), turn-by-turn dynamic routing (cache destruction)\n\nSee [docs/PRD.md](docs/PRD.md) for full architectural justification, [docs/deep-research.md](docs/deep-research.md) for the research survey, [docs/routing-roadmap.md](docs/routing-roadmap.md) for the prioritized quality backlog, [docs/gemini-research.md](docs/gemini-research.md) for the second-source agent-router report, and [docs/research/README.md](docs/research/README.md) for research provenance.\n\n## Prerequisites\n\n| Dependency | Required | Notes |\n|------------|----------|-------|\n| [Node.js](https://nodejs.org/) >= 22.19.0 | Yes | ES module package; matches `package.json` `engines.node` and CI (workflows pin Node `22.19.0`) |\n\n> **Engine floor:** `package.json` declares `engines.node >= 22.19.0`. If you (or your environment) enable `engine-strict=true` in `.npmrc`, installs on Node < 22.19.0 fail with `EBADENGINE`; on a supported Node (>= 22.19.0), `npm ci` completes with no `EBADENGINE` warnings.\n| [pi](https://pi.dev) coding agent | Yes | Extension host |\n| macOS Apple Silicon | MVP | Primary supported platform |\n| Linux (x64/arm64) | Experimental | Probe logic supported; not validated on real hardware |\n| Windows (x64/arm64) | Experimental | Probe logic supported; not validated on real hardware |\n| [LM Studio](https://lmstudio.ai/) or [Ollama](https://ollama.com) | Optional | Required for zero-tier local routing |\n| Authenticated cloud providers in pi | Recommended | Anthropic, OpenAI, Google, etc. |\n\n## Install\n\n> **Security:** Pi packages run with full system access. Extensions execute arbitrary code. Review source before installing third-party packages ([pi packages docs](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/packages.md)).\n\n### Via pi (recommended)\n\nInstall from [npm](https://www.npmjs.com/package/pi-smart-router) / [pi.dev/packages](https://pi.dev/packages):\n\n```bash\npi install npm:pi-smart-router\npi --list-models | grep smart-router\n```\n\nProject-local install (writes to `.pi/settings.json`):\n\n```bash\npi install -l npm:pi-smart-router\n```\n\nThen in pi:\n\n```text\n/model smart-router/auto\n/smart-router status\n```\n\n**First run:** `pi install` runs `npm install` for package dependencies (`better-sqlite3` compiles natively). The first routed request downloads HyDRA ONNX weights to `.pi-smart-router/models/` under your state directory.\n\n### Via npm (library API)\n\n```bash\nnpm install pi-smart-router\n```\n\nUse `createRouter()` / `createRouterFromFleet()` for programmatic integration without the pi extension. That path is the **catalog / routing-core** composition root (not full extension wiring). See [Library vs extension](#library-vs-extension) and [Optional: YAML fleet (library API)](#optional-yaml-fleet-library-api).\n\n### From source (contributors)\n\n```bash\ngit clone https://github.com/beettlle/pi-smart-router.git\ncd pi-smart-router\nnpm install\n```\n\nThe repo ships a **project-local pi extension** at `.pi/extensions/smart-router/`. pi auto-discovers it when you run `pi` from the repo root (after the project is trusted — see [Develop from clone](#develop-from-clone)).\n\n## Quick start\n\nAfter installing via `pi install npm:pi-smart-router` (or from clone — see below):\n\n1. Authenticate providers (`/login`) and enable models in your scoped list if you use one (`/scoped-models`)\n2. `/model smart-router/auto` — every turn runs through the routing pipeline\n3. `/smart-router status`, `/smart-router history`, or `/smart-router stats` — inspect routing decisions and window aggregates\n\nSet `SMART_ROUTER_LOG_ROUTING=1` before starting pi to print each routing decision to stderr (see [Environment variables](#environment-variables)).\n\n## Use with pi\n\nDetailed steps for the operator path above.\n\n### Installed via npm\n\nGlobal install (`pi install npm:pi-smart-router`) registers the extension from `~/.pi/agent/settings.json`. No project `/trust` prompt is required for npm-installed extensions — start `pi` from any directory.\n\nAfter auth or model list changes, restart pi or run `/reload`.\n\n### Develop from clone\n\nRequires **Pi ≥ 0.85.1** (`pi.minPiVersion`). The extension loads TypeScript from this repo via pi’s loader — no `npm run build` needed for dogfooding.\n\n**Recommended (works from any cwd):** install the clone as a **path package** and remove any published npm copy. npm and path packages have different identities; leaving both installed can double-load and you may keep running a stale npm tarball.\n\n```bash\n# From anywhere — remove published package if present\npi remove npm:pi-smart-router\n\n# Prefer an absolute path (relative paths are resolved from the install cwd first).\n# Pi stores a path relative to ~/.pi/agent/ in settings (same pattern as other local packages).\npi install /path/to/pi-smart-router\n\n# Pi does not run npm install for path packages\ncd /path/to/pi-smart-router && npm install\n\npi list   # must show this clone path, not ~/.pi/agent/npm/.../pi-smart-router\npi --list-models | grep smart-router\n```\n\n**Alternative (repo-root discovery only):** with the npm package removed, start `pi` with cwd at this repo root. Project-local extensions under `.pi/extensions/` load only after the project is trusted — without trust, `smart-router` never appears in `/scoped-models` or `/model`.\n\n**On first run**, pi prompts you to trust the project when it detects `.pi/extensions/`. Accept the prompt.\n\n**Later or missed prompt:** run `/trust` inside pi to save a trust decision for this directory (or its parent) to `~/.pi/agent/trust.json`. Trust on a **parent folder** (for example `~/Documents/github`) applies to this repo as well. After `/trust`, **restart pi** — the current session is not reloaded automatically.\n\n**Verify the extension loaded:**\n\n```bash\npi --list-models | grep smart-router\n```\n\nYou should see `smart-router  auto`. If the line is missing:\n\n1. Confirm `pi list` points at this clone (path package) or that cwd is the repo root (discovery mode).\n2. Confirm no `npm:pi-smart-router` entry remains in settings while developing from clone.\n3. Confirm the project is trusted if relying on `.pi/extensions/` discovery (`/trust`, or check `~/.pi/agent/trust.json`).\n4. Restart pi or run `/reload` after trusting or changing packages.\n\nNon-interactive one-shot checks can pass `--approve` to trust project-local resources for that run only.\n\n### Select the auto model\n\nSwitch to the smart-router provider (from any directory after npm install, or from repo root when developing from clone):\n\n```text\n/model smart-router/auto\n```\n\nIf you use **scoped models** (`/scoped-models` or `enabledModels` in settings), enable `smart-router/auto` there first — when a scoped list is active, `/model` only resolves models in that list.\n\nThis registers `smart-router` as a custom provider with a single `auto` model. Every inference request runs through the routing pipeline and delegates to the selected underlying provider's streaming API.\n\n#### `cursor/auto` vs `smart-router/auto`\n\npi exposes two different **auto** models. They are easy to confuse but play different roles:\n\n| Model | Provider | Role |\n|-------|----------|------|\n| `smart-router/auto` | `smart-router` (this extension) | Runs the routing pipeline on every turn and **delegates** to whichever underlying model HyDRA selects |\n| `cursor/auto` | `cursor` (pi registry) | Cursor's opaque auto model — **direct** inference target when selected; Cursor picks the backend model |\n\n**Recommended dogfood setup:** use `/model smart-router/auto` so routing, pinning, and telemetry stay active. Enable `cursor/auto` (and other Cursor models such as `composer-latest`) in your scoped fleet so the router can select them when appropriate — for example on planning turns or when the [Gemini tool-history guard](#gemini-thought_signature-400-errors) excludes unrepairable Google replay state.\n\n**When to pin `/model cursor/auto` directly (bypass the router):**\n\n- You want Cursor's opaque auto selection on every turn with no routing overhead\n- You are debugging Cursor SDK auth or delegation outside the router\n- You need a stable, non-routed session for comparison with routed behavior\n\n**When to use `smart-router/auto`:**\n\n- You want cost/capability-aware model selection across your full authenticated fleet\n- You rely on session pinning, failover, or `/smart-router status` / `history` / `stats` telemetry\n- Tool-heavy sessions with Gemini economical models work via in-repo replay repair (cross-provider included); the tool-history guard reroutes to non-Google models such as `cursor/auto` for unrepairable replay state (see [pi-smart-router#85](https://github.com/beettlle/pi-smart-router/issues/85), [pi-smart-router#158](https://github.com/beettlle/pi-smart-router/issues/158))\n\nCursor models (`cursor/*`, `composer-*`, and the opaque fleet id `default`) map to **frontier-cloud** tier in `pi-model-mapper.ts` so HyDRA can score them against Gemini and Claude instead of treating them as unknown economical models ([pi-smart-router#40](https://github.com/beettlle/pi-smart-router/issues/40), [pi-smart-router#70](https://github.com/beettlle/pi-smart-router/issues/70)). Related: [pi-smart-router#23](https://github.com/beettlle/pi-smart-router/issues/23) (turn envelope / pin order), [pi-smart-router#37](https://github.com/beettlle/pi-smart-router/issues/37) (Gemini `thought_signature` errors).\n\n#### Cursor subscription quota vs API cost\n\nCursor models bill against your **Cursor Pro subscription quota**, not per-token API rates. The mapper sets `fallback_cost_per_1m: 0` (no API billing) and a separate **`quota_cost_per_1m`** virtual rate used only for frugality scoring and telemetry ([SP-096](https://github.com/beettlle/pi-smart-router/issues/70)). Economical API models (e.g. `gemini-flash-lite`) can outscore `composer-latest` on routine `main_loop` turns when capabilities are sufficient.\n\n**Quota-sensitive fleet hygiene:** if you are near Cursor usage limits, **exclude `composer-latest`** (and other heavy Cursor frontier models) from your pi scoped fleet enable-list. Leave economical API models enabled so turn envelope and HyDRA prefer paid API tiers over subscription quota. The opaque id `default` is mapped to frontier tier — do not rely on it as an economical fallback.\n\n### Operator commands\n\n| Command | Purpose |\n|---------|---------|\n| `/smart-router` | Same as `status` (default when no subcommand is given) |\n| `/smart-router status` | Show fleet mode, fleet size, pricing freshness/staleness, and the last routing decision (stage, tier, selected model, latency) |\n| `/smart-router history` | Show recent routing telemetry from SQLite (default limit; optional numeric limit, e.g. `/smart-router history 20`). Displays the concrete delegated model id (never bare virtual `auto`) |\n| `/smart-router stats` | Privacy-safe session/window aggregates from routing telemetry: count, mean cost/latency with `cost_basis` labeling (actual vs estimated, SP-241), planning_delegate vs direct share, local vs cloud when distinguishable, and role cost breakdown. Optional vs-always-frontier savings when frontier fleet prices exist (omitted otherwise). The JSON snapshot (`buildStatsSnapshot`, automation surface) additionally carries warm rolling `cost_calibration` actual/estimate buckets (SP-242). Optional numeric limit, e.g. `/smart-router stats 50` |\n| `/smart-router mode scoped` | Route only among pi's **enabled model patterns** (default) |\n| `/smart-router mode all` | Route among **all authenticated models** in the registry |\n| `/smart-router pricing refresh` | Manually fetch LiteLLM pricing from `LITELLM_PRICING_URL`, persist to SQLite, and rebuild the fleet with updated rates |\n| `/smart-router export dataset [--limit N]` | Export opt-in routing dataset as JSONL (requires `SMART_ROUTER_DATASET=1`) |\n| `/smart-router export telemetry-contrib [--limit N] [--embeddings]` | Export privacy-safe community telemetry JSON for calibration contributions (`--embeddings` opts in to captured 384-dim embedding rows) |\n| `/smart-router feedback good\\|bad` | Label the last auto-routed request outcome (requires `SMART_ROUTER_DATASET=1`) |\n| `/smart-router unpin` | Clear the current session pin (in-memory and SQLite) so the next request runs the full routing pipeline |\n| `/smart-router plan [--json]` | **Read-only** local placement report: encoder resident status, local model warm/cold, RAM/disk constraints, cold vs warm TPS, and bottleneck guess. `--json` prints the schema-stable report for automation |\n| `/smart-router doctor` | **Read-only** local readiness checklist (✓/✗) with bottleneck guess and recommendation — validate placement without starting a route |\n\nFleet mode persists in the session. Use `scoped` to respect your `/model` enable-list; use `all` when you want the router to consider every provider you have logged into.\n\n### Local placement plan / doctor (read-only, #116)\n\n`/smart-router plan` and `/smart-router doctor` report **local placement readiness without mutating anything** — no route, pin, or gate is touched. Inspired by Colibrì's `coli plan` / `coli doctor`.\n\nThe report covers:\n\n- **Encoder** — whether HyDRA ONNX artifacts are resident in the cache (`.pi-smart-router/models/`) or will download on first route\n- **Local model warm/cold** — LM Studio / Ollama reachability and whether a model is actually loaded (`warm`) vs reachable-but-unloaded (`cold-start expected`)\n- **Hardware** — platform/arch, total/free RAM, hardware-probe verdict (`full_local` / `classification_only` / `disabled`), battery state\n- **Disk** — free GiB; flagged constrained below 2 GiB\n- **Throughput (cold vs warm TPS)** — see formula below\n- **Bottleneck guess** — one of `none`, `unsupported-platform`, `battery`, `memory`, `disk`, `no-local-runtime`, `cold-start`, `cold-throughput`, `warm-throughput`, with a rationale string\n- **Recommendation** — `local-ready`, `local-warmup-needed`, or `local-unavailable`\n\n`/smart-router plan --json` prints the same report as schema-stable JSON (`schemaVersion: 1`, `kind: \"smart-router-placement-plan\"`; all keys always present, unknowns are `null`) for automation.\n\n**Cold vs warm TPS formula.** Throughput samples are tagged by phase: `warm` samples measure steady-state generation after model load; `cold` samples include cold-start load cost and never count toward viability. `warmMedianTps = median(tps where phase='warm')`; viability is `warmSamples > 0 AND warmMedianTps >= threshold` (default 25 tok/s). **Cold-only windows fail closed**: when only cold samples exist, local viability is false by policy (`requireWarmSamples: true`) — cold-start cost must not masquerade as steady-state throughput.\n\n**Quality-preserving resource policy.** Under RAM/disk/battery pressure the router prefers **\"local unavailable / escalate safely\"** to a cloud default over silently weakening encoder fidelity (no quantization flips, no cheaper cascades, no FrugalGPT-style downgrade chains). `plan`/`doctor` surface this policy verbatim in the report's `policy` block.\n\nAfter typing `/smart-router ` (with a trailing space), press **TAB** to see subcommands. Continue TAB-completing after `mode` or `pricing` for sub-options (`scoped`/`all`, `refresh`).\n\n### 5. Verify\n\n```bash\nnpm run verify:ci\n```\n\n## Concurrency contract\n\n`RouterPipeline.route()` calls on a single router instance are **single-flight**: concurrent calls are serialized internally (SP-230, [#141](https://github.com/beettlle/pi-smart-router/issues/141)). Each exclusive route owns one per-route `RoutingContext`; overlapping executions are queued rather than interleaved — each queued call waits at most one routing latency. This applies to `createRouter()` / `createRouterFromFleet()` handles: a shared `router.dispatch` is safe to call concurrently, and serialization does not change routing policy outcomes. For parallel routing throughput, create separate router instances.\n\n## Library vs extension\n\npi-smart-router ships in two shapes, and they are **not** feature-identical ([#153](https://github.com/beettlle/pi-smart-router/issues/153)):\n\n| Path | What you get |\n|------|--------------|\n| **Pi extension** (`pi install npm:pi-smart-router`, or project-local `.pi/extensions/smart-router/` when developing from clone) — **supported product composition root** | The full product — the routing pipeline **plus** the stream-level behaviors below, with hardware probe + store-backed telemetry wired via `createDispatchOptions()` in `.pi/extensions/smart-router/fleet-bootstrap.ts` |\n| **npm library** (`createRouter()` / `createRouterFromFleet()` / `GatewayDispatch`) — **catalog / embedder composition root** | The routing core — the 12-stage pipeline, fleet mapping, gateway health/failover *selection*, and constructor defaults for **`costEstimator` + `localRuntime` only**. Hardware probe stays disabled and telemetry is opt-in unless you pass those ports. Stream-level behaviors are stubbed or left to your embedder loop |\n\n### Extension-only capabilities\n\nThese behaviors run in `.pi/extensions/smart-router/` and have **no equivalent in the library API**:\n\n| Capability | Extension implementation | Library status |\n|------------|--------------------------|----------------|\n| **Planning delegate spawn** — cache-preserving ephemeral frontier sub-call on planning turns, with observation injection and bounded timeouts (SP-144, SP-213 / [#71](https://github.com/beettlle/pi-smart-router/issues/71), [#120](https://github.com/beettlle/pi-smart-router/issues/120)) | `.pi/extensions/smart-router/planning-delegate.ts` — compressed-context sub-call via `streamSimple`; falls back to direct frontier with a documented `fallback_reason` | The pipeline still emits `planning_delegate` decisions with delegate model and compressed limits, but **nothing spawns the delegate** — an embedder must implement the sub-call itself or accept direct-frontier routing |\n| **Stream failover loop** — live provider-error failover across candidate models with user-facing notices (atomic state machine, [#33](https://github.com/beettlle/pi-smart-router/issues/33)) | `.pi/extensions/smart-router/route-and-delegate.ts` (~L377–595) — retries stream delegation across alternates, emits failover notices, ends in SP-226 fail-open safe default | `GatewayDispatch.selectFailover()` only **selects** an alternate model; no stream retry loop runs. The embedder owns iterating over failures and re-dispatching |\n| **Output headroom escalation** — exclude failover candidates whose context window cannot fit input plus the required output floor (SP-108) | `route-and-delegate.ts` + `.pi/extensions/smart-router/delegation-runtime.ts` — per-attempt `computeOutputHeadroom` checks; `headroomExcludedModelIds` accumulate across the failover loop | `src/domain/delegation/output-headroom.ts` ships the helper, but **no library caller wires it** into `GatewayDispatch.dispatch()` — the embedder must apply it per attempt |\n| **Cursor quota handling** — subscription-quota exhaustion detection and failover to `cursor/auto` or economical API models with `cursor_quota_exhausted` telemetry (SP-097 / [#70](https://github.com/beettlle/pi-smart-router/issues/70)) | The extension stream loop catches quota errors from live streams and drives `selectFailover` reactively | Detection and failover *selection* exist in `src/infrastructure/gateway/gateway-dispatch.ts` (`isCursorQuotaExhaustedError`, per-model quota tracking), but the **reactive trigger lives in the extension's stream loop** — library dispatch alone does not observe provider stream errors |\n\n### The middleware is a lifecycle stub, not a router\n\n`createPiRouterMiddleware()` / `RouterHandle.register()` (`src/api/middleware/pi-router-middleware.ts`) registers **lifecycle hooks only** — compaction flags and `model_select` overrides consumed when building the next routing request. It does **not** intercept LLM streams, route requests, or delegate inference. The production stream path lives in the pi extension (`route-and-delegate.ts`, `stream-delegation.ts`, `delegate-stream.ts`), not in the npm-exported middleware. Treat `middleware` as a flag registrar; routing happens through your call to `router.dispatch.dispatch()` or the extension's stream path.\n\n### Recommended integration path\n\n- **pi users:** install the **extension** (`pi install npm:pi-smart-router`). It is the supported composition root — everything in the table above works out of the box, including failover, delegate spawn, headroom escalation, quota reaction, hardware probe, and store-backed routing telemetry.\n- **npm embedders:** you get the **routing core** (12-stage pipeline, fleet mapping, gateway health tracking, failover *selection*). Bare `createRouter()` does **not** wire hardware probe or telemetry by default — pass `GatewayDispatchOptions` on `createRouterFromFleet(fleet, options)` when you need those ports. Plan to implement your own stream delegation, failover iteration, headroom checks, and planning-delegate spawn around the decisions the pipeline returns — or track [#149](https://github.com/beettlle/pi-smart-router/issues/149) (**extension public facade**), the migration plan for exposing the extension's stream/delegation surface as supported library API so this gap closes over time. Until #149 lands, the extension modules also import `src/**` internals directly, so deep imports into `src/` are not a stable API. See [docs/extension-package-boundary.md](docs/extension-package-boundary.md) for the facade vs internal-API boundary, the deep-import lint guard, and the extension coverage gate. See also [Composition roots in the 1.0 migration guide](docs/migration-v1.md#composition-roots-library-createrouter-vs-pi-extension).\n\n```text\npi extension path (full product)        npm library path (routing core)\n────────────────────────────────        ───────────────────────────────\npi (host agent)                         your host application\n  └─ .pi/extensions/smart-router/         └─ createRouter() / createRouterFromFleet()\n       ├─ routing pipeline (src/)  ════════    ├─ routing pipeline (src/)        ← shared core\n       ├─ stream failover loop          ✗      ├─ GatewayDispatch: health tracking,\n       ├─ planning delegate spawn       ✗      │   failover selection only\n       ├─ output headroom escalation    ✗      ├─ lifecycle middleware (stub: hooks only)\n       └─ cursor quota failover         ✗      └─ embedder implements: stream loop,\n                                            delegate spawn, headroom checks, quota reaction\n```\n\n`✗` = capability exists only on the extension path today; [#149](https://github.com/beettlle/pi-smart-router/issues/149) is the plan to close the gap.\n\n## Fleet behavior\n\nWhen you use `smart-router/auto`, the extension does **not** read `config/models.yaml`. Instead:\n\n1. **Discover** — `modelRegistry.getAvailable()` returns authenticated models from pi.\n2. **Scope** — In `scoped` mode, filter to patterns from pi settings (`getEnabledModels()`). In `all` mode, use the full registry.\n3. **Map** — `src/config/pi-model-mapper.ts` maps each pi model to a `ModelProfile` (tier, capabilities, pricing) using provider and model-id patterns.\n4. **Route** — `createRouterFromFleet()` runs the 12-stage pipeline on each request.\n5. **Delegate** — The extension resolves the chosen model in the registry and forwards the stream via pi-ai's built-in provider APIs.\n\nUnknown models receive conservative economical-cloud defaults. Local providers (`lmstudio`, `ollama`) map to `zero-tier`. Cursor provider models (`cursor/*`, `composer-*`, opaque id `default`) map to `frontier-cloud` with explicit capability defaults (SP-086, SP-098). Benchmark-grounded capability vectors (including multi-fleet `github-copilot/*`, Gemini, and Anthropic dogfood IDs, aliased family-by-family) are documented in the [capability profile coverage report](docs/capability-profile-coverage.md) ([#108](https://github.com/beettlle/pi-smart-router/issues/108) / [#124](https://github.com/beettlle/pi-smart-router/issues/124)).\n\nTo refresh after auth or settings changes, restart pi or `/reload` extensions.\n\n## Optional: YAML fleet (library API)\n\nFor programmatic integration **without** the pi extension, load a static fleet catalog from YAML and route via `GatewayDispatch.dispatch()`.\n\nThis path is **catalog-oriented**: `createRouter()` loads `models.yaml` and constructs `GatewayDispatch` with library defaults (`costEstimator` + `localRuntime`). It does **not** call the extension's `createDispatchOptions()` — so hardware probe remains disabled and no store-backed `telemetryEmitter` is attached unless you pass those options yourself. Prefer the [pi extension](#library-vs-extension) when you want the full product composition root.\n\n```bash\ncp config/models.yaml.example ./config/models.yaml\n# Edit config/models.yaml — at least one model per tier\n```\n\n```typescript\nimport { createRouter, createRouterFromFleet } from 'pi-smart-router';\n\nconst router = createRouter({ modelsPath: './config/models.yaml' });\nrouter.register(piExtensionHooks); // lifecycle only: compaction + model override\n\nconst decision = await router.dispatch.dispatch(routingRequest);\n// Embedder forwards inference to decision.selected_model_id\n\n// Optional: wire probe/telemetry yourself (same options bag as GatewayDispatch)\n// createRouterFromFleet(fleet, { systemInfoProvider, hardwareConfig, telemetryEmitter, ... })\n```\n\n### Embedder integration paths\n\n| Path | When to use | Routing | Lifecycle hooks |\n|------|-------------|---------|-----------------|\n| **Pi extension** (recommended) | Running inside pi | `pi install npm:pi-smart-router` (or project-local `.pi/extensions/smart-router/` when developing from clone) registers `smart-router/auto` and delegates streams | Extension calls `router.register()`; compaction/model overrides wired automatically |\n| **Library API** | Custom host, tests, or non-pi embedders | Your code calls `router.dispatch.dispatch()` (or wraps the pipeline) | Call `router.register(hooks)` to wire compaction and `model_select` events |\n\nThe library `createPiRouterMiddleware()` / `RouterHandle.register()` registers **lifecycle hooks only** — not routing, context capture, or `before_provider_request`. Do not expect `middleware` to intercept LLM streams; that is the extension's `streamSimple` path or your embedder's dispatch loop.\n\n`createRouter()` returns a `RouterHandle`:\n\n| Property | Type | Purpose |\n|----------|------|---------|\n| `middleware` | `PiRouterMiddleware` | Lifecycle hook registrar (`register`, `lifecycleHookState`) |\n| `dispatch` | `GatewayDispatch` | Gateway with circuit breaker, failover, rate limiting |\n| `fleet` | `readonly ModelProfile[]` | Loaded fleet catalog |\n| `register` | `(hooks) => void` | Alias for `middleware.register` — attach pi lifecycle hooks |\n\nYou can also pass a pre-built fleet:\n\n```typescript\nimport { createRouterFromFleet } from 'pi-smart-router';\n\nconst router = createRouterFromFleet(myFleetProfiles);\n```\n\nExample fleet entry:\n\n```yaml\nmodels:\n  - id: local-gemma-4-7b\n    tier: zero-tier\n    provider: lmstudio\n    endpoint: http://localhost:1234/v1\n    capabilities:\n      reasoning: 0.3\n      code_gen: 0.6\n      tool_use: 0.1\n    pricing:\n      registry_key: local/free\n      fallback_cost_per_1m: 0.0\n\n  - id: claude-3.5-haiku\n    tier: economical-cloud\n    provider: anthropic\n    # ...\n\n  - id: claude-3.5-sonnet\n    tier: frontier-cloud\n    provider: anthropic\n    # ...\n```\n\nTiers: `zero-tier`, `economical-cloud`, `frontier-cloud`. See [config/models.yaml.example](config/models.yaml.example).\n\n### Routing cluster catalog (library API)\n\nReference prompts grouped by tier bias for semantic cluster matching (SP-099). Operators tune clusters in YAML without code changes. Precomputed centroids live in `config/routing-centroids.json` (SP-114); when that file is absent, centroids are computed at load time as the mean embedding of each cluster's reference prompts.\n\n```bash\ncp config/routing-clusters.yaml.example ./config/routing-clusters.yaml\ncp config/routing-centroids.json.example ./config/routing-centroids.json\n# Edit reference_prompts, min_similarity, and min_margin per cluster\n# Regenerate centroids after catalog changes:\nnpm run routing:bootstrap-centroids\n```\n\nThe bootstrap script embeds each reference prompt via the HyDRA MiniLM ONNX pipeline (384-dim), mean-pools to centroid vectors, and writes `config/routing-centroids.json` with `{ cluster_id, tier_bias, centroid, reference_count }` per cluster. ONNX artifacts cache under `.pi-smart-router/models/` on first run.\n\n```typescript\nimport { loadRoutingClusters } from 'pi-smart-router';\n\nconst catalog = await loadRoutingClusters({\n  filePath: './config/routing-clusters.yaml',\n  embedder: myTextEmbedder, // shared ONNX embedder (SP-100)\n});\n// Reason codes: cluster_${id} — e.g. cluster_low_stakes_general\n\n// createClusterMatcher (cluster-matcher module) prefers routing-centroids.json when present.\n```\n\nCluster IDs are stable reason-code prefixes (`cluster_low_stakes_general`, `cluster_architecture`, etc.). See [config/routing-clusters.yaml.example](config/routing-clusters.yaml.example).\n\n## Configuration\n\n### Environment variables\n\n| Variable | Default | Purpose |\n|----------|---------|---------|\n| `ROUTER_STATE_DB_PATH` | `./.pi-smart-router/state.db` | Override SQLite state store location (telemetry, pricing catalog, session data) |\n| `SMART_ROUTER_LOG_ROUTING` | (unset) | Set to `1` to log each routing decision to stderr as JSON (debugging dogfood sessions). Canonical payload builder (`buildRoutingDecisionLogPayload`) includes top-level `stage`, `reason_code`, `low_intensity_score`, `tier_hint`, `local_eligible_reason`, and `cluster_id` (plus nested `cluster_summary` / `features`). The pi extension’s live stderr logger is still a slim subset — see [LOG_ROUTING field checklist](#log_routing-field-checklist) |\n| `SMART_ROUTER_DATASET` | (unset) | Set to `1` to opt in to privacy-safe routing dataset capture (metadata and feature fields only; 30-day / 10k-row retention). Prompt text, messages, and tool arguments are never stored. Required for outcome labels and P(success) training export. See [#8](https://github.com/beettlle/pi-smart-router/issues/8). |\n| `SMART_ROUTER_DATASET_FINGERPRINT` | (unset) | Set to `1` (requires `SMART_ROUTER_DATASET=1`) to store an install-local HMAC-SHA256 fingerprint of each normalized prompt for duplicate detection within this install. The install pepper lives in `.pi-smart-router/.dataset-key` (gitignored) and is never exported. **Warning:** short or common prompts are vulnerable to offline rainbow-table guessing; use only when you accept that tradeoff. See [#10](https://github.com/beettlle/pi-smart-router/issues/10). |\n| `SMART_ROUTER_DATASET_EMBEDDINGS` | (unset) | Set to `1` (requires `SMART_ROUTER_DATASET=1`) to capture the raw 384-dim HyDRA encoder embedding on each dataset row (derived dense vector of the metadata-prefixed routing input — never prompt text). Embeddings stay local until you additionally export with `--embeddings`; they exist so the hydra_projection ≥100-row training floor can ever be met. See [#170](https://github.com/beettlle/pi-smart-router/issues/170). |\n| `MODELS_YAML_PATH` | `./config/models.yaml` | Fleet catalog path (library API only) |\n| `SMART_ROUTER_PLANNING_TURN_BUFFER` | `2` | SAAR planning buffer: frontier planning turns allowed before hard-lock ([v0.2.0 Continuity](https://github.com/beettlle/pi-smart-router/issues/72)) |\n| `SMART_ROUTER_PLANNING_DELEGATE_ENABLED` | `true` | Enable cache-preserving planning delegate ([#71](https://github.com/beettlle/pi-smart-router/issues/71)) |\n| `SMART_ROUTER_PLANNING_DELEGATE_MAX_MESSAGES` | `12` | Compressed-context message cap for frontier sub-call |\n| `SMART_ROUTER_PLANNING_DELEGATE_MAX_TOKENS` | `16384` | Compressed-context token cap for frontier sub-call |\n| `SMART_ROUTER_PLANNING_DELEGATE_EXCLUDE_EXECUTION_HISTORY` | `true` | Exclude tool execution history from delegate payload |\n| `SMART_ROUTER_PLANNING_DELEGATE_GLOBAL_TIMEOUT_MS` | `120000` | Global cap (ms) on the whole planning-delegate stage per planning turn — bounds fan-out wall-clock so a stalled worker cannot hang TTFT ([#120](https://github.com/beettlle/pi-smart-router/issues/120)) |\n| `SMART_ROUTER_PLANNING_DELEGATE_SUB_CALL_TIMEOUT_MS` | `30000` | Per-call cap (ms) on each delegate sub-call worker; on expiry the worker is cancelled/abandoned and routing falls back to direct frontier with `planning_delegate_timeout` ([#120](https://github.com/beettlle/pi-smart-router/issues/120)) |\n| `SMART_ROUTER_ADAPTIVE_REASONING_ENABLED` | `true` | Master switch for the adaptive thinking-level policy ([#166](https://github.com/beettlle/pi-smart-router/issues/166)); `false` passes the session thinking level through unchanged |\n| `SMART_ROUTER_ADAPTIVE_REASONING_MIN_LEVEL` | (unset) | Floor on policy-derived thinking levels (`minimal\\|low\\|medium\\|high\\|xhigh\\|max`) — see [Adaptive reasoning](#adaptive-reasoning-thinking-level-166) |\n| `SMART_ROUTER_ADAPTIVE_REASONING_MAX_LEVEL` | (unset) | Ceiling on policy-derived thinking levels (incl. turn-class upgrades) — see [Adaptive reasoning](#adaptive-reasoning-thinking-level-166) |\n| `SMART_ROUTER_PREFIX_CACHE_WEIGHT` | `0.20` | SAAR weight on warm prefix value in cache breakeven math (0–1; [#73](https://github.com/beettlle/pi-smart-router/issues/73)) |\n| `SMART_ROUTER_IDLE_TIMEOUT_SECONDS` | `300` | SAAR idle seconds before pin reopens for full re-route |\n| `SMART_ROUTER_SWITCH_THRESHOLD` | `0.5` | SAAR switch score gate (0–1) for tier upgrades during hard-lock |\n| `ROUTER_SAFE_DEFAULT_TIER` | `economical-cloud` | Fallback tier on any routing failure |\n| `LITELLM_PRICING_URL` | — | LiteLLM pricing JSON source |\n\n### LOG_ROUTING field checklist\n\nWhen `SMART_ROUTER_LOG_ROUTING=1`, prefer the canonical payload from `buildRoutingDecisionLogPayload` (library / tests). Checklist for [#99](https://github.com/beettlle/pi-smart-router/issues/99):\n\n| Field | In payload builder? | Notes |\n|-------|---------------------|-------|\n| `stage` | Yes (top-level) | Pipeline stage that decided |\n| `reason_code` | Yes (top-level) | Machine-readable reason |\n| `low_intensity_score` | Yes (top-level + `cluster_summary`) | Null when low-intensity stage did not run |\n| `tier_hint` | Yes (top-level + `cluster_summary`) | Null when no tier hint |\n| `local_eligible_reason` | Yes (top-level + `features`) | Null when local_zero did not evaluate eligibility |\n| `cluster_id` | Yes (top-level + `cluster_summary`) | Null when no cluster match |\n| `pricing_window` | Yes (top-level + `peak_pricing_summary`) | Peak vs off-peak rationale for the selected model (SP-244 / #165); the extension stderr logger carries `pricing_window` + `peak_pricing` |\n\n**Gap:** the pi extension’s live stderr path (`logRoutingDecision` in `.pi/extensions/smart-router`) still emits a slim JSON object (`selected_model_id`, `stage`, `reason_code`, `features`, `delegate`) and does **not** yet call `buildRoutingDecisionLogPayload`. SQLite `/smart-router history` and the payload builder carry the full checklist; wire the extension logger in a follow-up if dogfood needs identical stderr shape.\n\n**History model id:** `/smart-router history` resolves bare/`smart-router` virtual `auto` to the concrete planning-delegate primary (or qualifies Cursor opaque `auto` as `cursor/auto`) so operators see the delegated fleet model, not the virtual router id.\n\n### SAAR session pin and cache breakeven (v0.2.0 Continuity)\n\nv0.2.0 adds **Session-Aware Agentic Routing (SAAR)** pin knobs ([#72](https://github.com/beettlle/pi-smart-router/issues/72)) and a **cache breakeven gate** ([#73](https://github.com/beettlle/pi-smart-router/issues/73)) that blocks tier switches when `marginal_savings + future_cache_value <= cache_reprime_cost` — preventing cheap-turn savings from invalidating a warm prefix cache.\n\n| Knob | Env var | Default | Effect |\n|------|---------|---------|--------|\n| Planning buffer | `SMART_ROUTER_PLANNING_TURN_BUFFER` | `2` | First N turns may route planning to frontier while pin metadata stays economical |\n| Prefix cache weight | `SMART_ROUTER_PREFIX_CACHE_WEIGHT` | `0.20` | Discounted future cache credit in breakeven |\n| Idle reopen | `SMART_ROUTER_IDLE_TIMEOUT_SECONDS` | `300` | Seconds of inactivity before SAAR resets and pin reopens |\n| Hard-lock upgrade gate | `SMART_ROUTER_SWITCH_THRESHOLD` | `0.5` | Score threshold for tier upgrades after buffer exhaust |\n\n**Dogfood verification (multi-turn planning session)**\n\n1. Start pi with routing logs: `SMART_ROUTER_LOG_ROUTING=1 pi` (optional: tune SAAR env vars above).\n2. Run `/model smart-router/auto` and begin a multi-turn planning session (planning turns mixed with tool results).\n3. Inspect stderr JSON lines — confirm `saar_summary.buffer_active` / `saar_reason_code: saar_buffer_active` on early planning turns, then `hard_lock: true` / `saar_hard_lock` after the buffer exhausts.\n4. On a warm pinned session, trigger a `tool_result` sub-route — when breakeven fails, expect `breakeven_summary.decision: \"blocked\"` and `breakeven_reason_code: breakeven_blocked` while the pin holds.\n5. Use `pi router explain` (or `POST /v1/route/explain`) on the same session — `features.breakeven` and `features.saar` mirror telemetry fields for operator audit.\n\nSee [routing-roadmap.md](docs/routing-roadmap.md) §2 P0 for design context.\n\n**Long-running pi sessions — in-memory state eviction (v0.21.0, [#145](https://github.com/beettlle/pi-smart-router/issues/145)).** Session pins and in-memory routing snapshots live in process memory, not in the SQLite telemetry store. When pi ends a session, the extension's `session_shutdown` handler (reason: `quit` / `reload` / `new` / `resume` / `fork`) calls `evictInMemorySessionState` (`src/api/session-eviction.ts`) and drops **all** in-memory routing state for that session — pins, cache-breakeven snapshots, turn metadata. A new session starts cold: no stale pin, no warm-cache assumption carries over. Persistent telemetry in `.pi-smart-router/state.db` is untouched. As a safety net for orphaned sessions (e.g. a crashed pi process that never emitted `session_shutdown`), a sweep on `session_start` evicts sessions idle longer than `ORPHAN_SESSION_TTL_MS` (**24 hours**, exported from `.pi/extensions/smart-router/session-lifecycle.ts`); the sweep fails open — a missing session id or sweep error never blocks session start.\n\n### Planning delegate (v0.4.0 Delegate)\n\nWhen a **planning** turn would route primary inference to frontier while a warm **economical** session pin is active, smart-router prefers **cache-preserving delegation** ([#71](https://github.com/beettlle/pi-smart-router/issues/71)):\n\n1. **Pipeline** (`turn_envelope`) emits `planning_delegate` — primary stays on the pinned economical model; `features.planning_delegate` names the frontier **delegate** model and compressed-context limits.\n2. **Pi extension** (`.pi/extensions/smart-router`) runs an ephemeral frontier sub-call with compressed context (tool execution history excluded by default), injects the result as an observation user message, then delegates **primary** streaming to the pinned economical model.\n3. **Fallback** — when delegate is disabled, spawn fails, or the delegate model is missing from the registry, the extension falls back to a **direct frontier** route with a documented `fallback_reason` in explain/telemetry.\n\n**Stream piping (SP-170):** Primary delegated inference **live-forwards** provider events to pi (`start` / `text_delta` / … as they arrive). The planning-delegate sub-call stays **buffered** — only the final observation text is injected into primary context; frontier tokens from the ephemeral sub-call are discarded and never reach the user-facing stream. On infra failover, a synthetic `text_delta` notice is pushed after the retry stream's `start` (no mutation of a buffered event array).\n\n| Knob | Env var | Default | Effect |\n|------|---------|---------|--------|\n| Delegate enabled | `SMART_ROUTER_PLANNING_DELEGATE_ENABLED` | `true` | When `false`, SAAR buffer allows direct frontier planning (`planning_direct_frontier` + `planning_delegate_disabled`) |\n| Compressed message cap | `SMART_ROUTER_PLANNING_DELEGATE_MAX_MESSAGES` | `12` | Max messages sent to the frontier sub-call |\n| Compressed token cap | `SMART_ROUTER_PLANNING_DELEGATE_MAX_TOKENS` | `16384` | Token budget for compressed delegate context |\n| Exclude tool history | `SMART_ROUTER_PLANNING_DELEGATE_EXCLUDE_EXECUTION_HISTORY` | `true` | Strip tool-call / tool-result turns from delegate payload |\n\n**Coordination boundary with pi core:** smart-router owns **routing** (when to delegate, which models, compressed limits, fallback reason codes). **Sub-agent spawn and observation injection** run in the pi extension via `streamSimple` — pi core must expose a delegate/stream API the extension can call; smart-router does not orchestrate pi's outer sub-agent scheduler. Operators enabling `/model smart-router/auto` get delegate behavior automatically when the extension is loaded; no separate pi sub-agent config is required beyond a frontier model in the registry.\n\n**Dogfood verification (planning delegate)**\n\n1. Start pi with routing logs: `SMART_ROUTER_LOG_ROUTING=1 pi` and `/model smart-router/auto`.\n2. Begin a session on an economical pin (routine prompts), then trigger planning turns (e.g. architecture or multi-step design work).\n3. Inspect stderr JSON — on delegate turns expect `reason_code: planning_delegate`, `planning_delegate_summary.path: \"delegate\"`, `primary_model_id` equal to the pin, and `delegate_model_id` pointing at frontier.\n4. Confirm primary inference stays on the economical model (cache-friendly) while stderr shows `[smart-router] planning delegate sub-call completed` with the frontier model id.\n5. Disable delegate (`SMART_ROUTER_PLANNING_DELEGATE_ENABLED=false`) and repeat — expect `planning_direct_frontier` with `fallback_reason: planning_delegate_disabled`.\n6. Use `pi router explain` (or `POST /v1/route/explain`) on the same session — `features.planning_delegate` mirrors live routing (`path: delegate` vs `direct`, `fallback_reason` when applicable).\n\nSee [routing-roadmap.md](docs/routing-roadmap.md) §2 P0 and GitHub [#71](https://github.com/beettlle/pi-smart-router/issues/71) for acceptance criteria.\n\n### Adaptive reasoning (thinking level) (#166)\n\nAdaptive reasoning tunes the **thinking intensity of the model already selected** — it never changes which model runs. Per turn class:\n\n| Turn class | Policy level |\n|-----------|--------------|\n| `tool_result` | `minimal` |\n| `main_loop` | `low` |\n| planning / `planning_delegate` | `medium` |\n| frontier escalation / `loop_escalation` | `high` |\n\npi passes the session thinking level on every call; the router treats pi's ambient default (`medium`) as adjustable by policy, and any **other** explicit level as an operator `/thinking` floor that is **never lowered** (a turn-class upgrade may still raise it). Chatty profiles (high `verbosity_factor`) additionally get a one-line conciseness nudge at `minimal`/`low`.\n\n**Three knobs that sound alike, do different things:**\n\n| Knob | Acts on | What it changes |\n|------|---------|-----------------|\n| **Adaptive reasoning** (`adaptive_reasoning.*`) | The delegated call's `reasoning` option | Thinking *intensity* of the already-selected model — cost of thinking, not model choice |\n| `frugality.lambda_verbosity` | Multi-objective **selection** scoring | Which model gets picked — penalizes verbose models while ranking candidates; never touches the delegated call's reasoning option |\n| `/thinking` (pi session command) | The caller-provided reasoning level | Explicit operator override — an explicit level is never lowered by policy or bounds |\n\n**Operator knobs** (config `adaptive_reasoning` / env):\n\n| Key | Env var | Default | Effect |\n|-----|---------|---------|--------|\n| `enabled` | `SMART_ROUTER_ADAPTIVE_REASONING_ENABLED` | `true` | When `false`, the policy is skipped — delegated calls pass the session thinking level through unchanged (`reasoning_reason_code: adaptive_reasoning_disabled`) |\n| `min_level` | `SMART_ROUTER_ADAPTIVE_REASONING_MIN_LEVEL` | (none) | Floor: policy-derived levels are raised to at least this level. Discrete level (`minimal\\|low\\|medium\\|high\\|xhigh\\|max`) — deliberately **not** a free-form verbosity percent |\n| `max_level` | `SMART_ROUTER_ADAPTIVE_REASONING_MAX_LEVEL` | (none) | Ceiling: policy-derived levels (incl. turn-class upgrades) are capped at this level. When `min_level` exceeds `max_level` (e.g. via env), the ceiling wins (cost-safe) |\n\nFloor/ceiling bind only what the policy itself derives. An explicit operator `/thinking` choice is never **lowered** by either bound (a floor can still *raise* one via the policy-upgrade path). Both bounds re-clamp down to the model's supported levels.\n\n**Fail-open behavior:** models that do not support reasoning options (`reasoning: false`, or a `thinkingLevelMap` mapping every relevant level to `null`) pass caller options through unchanged — telemetry records `reasoning_reason_code: reasoning_unsupported` and the route never fails. Providers that ignore reasoning options degrade to a no-op.\n\n**Telemetry:** each routed delegation records `reasoning_level_requested` (the session/caller level), `reasoning_level_applied` (the effective delegated level), and `reasoning_reason_code` (e.g. `turn_envelope_main_loop`, `operator_thinking_floor`, `operator_floor_applied`, `operator_ceiling_applied`, `reasoning_unsupported`) on the routing telemetry row — enriched post-delegation like usage actuals ([SP-241](https://github.com/beettlle/pi-smart-router/issues/164)). Inspect via `/smart-router history`.\n\n### Degraded neural failover sandwich (#119)\n\nWhen the encoder/neural stage (HyDRA) **fails, is misconfigured, or exceeds its latency budget without a selection**, routing fails open through a cheap chain instead of crashing the host agent ([#119](https://github.com/beettlle/pi-smart-router/issues/119)):\n\n1. **learned** — optional privacy-safe map keyed by requirement fingerprint (SHA-256 of the rounded requirement vector) or cluster id → preferred tier. **Raw prompt text is never stored.** Exact-key policy: fingerprint match first, cluster id second (no fuzzy matching). Writes are validated (bounded floats, snake_case cluster ids, tier enum) and capped (FIFO eviction) so confounder attacks cannot poison routing memory.\n2. **heuristic** — optional operator **pattern pack** (router_rules-style regex overlay) for known-simple intents. Deny-by-default (no match → no decision) and **fail closed on invalid regex** (the rule is rejected at load and never applies).\n3. **safe_default** — context-fit aware safe economical/frontier default (`degraded_safe_default`).\n\nExplain/telemetry expose `route_path` (`neural` \\| `learned` \\| `heuristic` \\| `safe_default`) plus `route_path_confidence` on every decision; degraded decisions carry reason codes `degraded_learned_route`, `degraded_pattern_<rule_id>`, or `degraded_safe_default`. A learned/pattern suggestion toward a cheaper tier is only honored when the cheap tool-use cue estimate is below `pattern_tool_use_ceiling` — a cheap overlay **never alone overrides a predicted capability shortfall**.\n\n| Knob (`degraded_route` operator config) | Default | Effect |\n|------|---------|--------|\n| `enabled` | `true` | When `false`, neural failures use the legacy `safe_default` stage pass-through |\n| `learned_min_confidence` | `0.6` | Minimum learned-entry confidence to honor a tier suggestion |\n| `learned_max_entries` | `512` | Learned-map cap per key space (FIFO eviction) |\n| `pattern_tool_use_ceiling` | `0.3` | Tool-use cue ceiling for honoring cheaper-tier learned/pattern suggestions |\n| `fail_closed_on_missing_weights` | `false` | When `true`, missing/placeholder neural weights fail **closed**: the matcher throws before paying embedding cost and the pipeline routes through the degraded sandwich (`neural_misconfigured`) with the SP-251 reason codes on the decision. When `false` (default), routing stays fail-open — placeholder weights score with neutral defaults and the reason codes are advisory telemetry only |\n\n**Missing-weights reason codes (v0.21.0, [#148](https://github.com/beettlle/pi-smart-router/issues/148)).** When the HyDRA matcher cannot load real neural weights, the decision surfaces structured reason codes (`src/domain/matching/missing-weights-reason-codes.ts`) on the routing decision / `requirement_reason_codes` — visible in explain (`pi router explain` / `POST /v1/route/explain`), `/smart-router history`, and telemetry — not stderr-only:\n\n| Reason code | Meaning | Operator action |\n|-------------|---------|-----------------|\n| `hydra_weights_missing` | HyDRA projection-head weights artifact is absent or unloadable, so neural scoring is running on fallback behavior | Restore the weights artifact (see [HyDRA model cache](#hydra-model-cache)); routing continues fail-open unless `fail_closed_on_missing_weights` is set |\n| `k4_heads_placeholder` | ModernBERT K4 heads are placeholder (untrained) weights — scores are neutral defaults, not learned predictions | Regenerate/install the trained K4 heads artifact; treat current K4 scores as non-authoritative |\n\nWith the default fail-open behavior these codes are advisory: the route proceeds with safe defaults. Set `degraded_route.fail_closed_on_missing_weights: true` when you prefer an explicit degraded-route decision (sandwich chain above, `route_path` records the branch taken) over silently routing on placeholder neural scores.\n\nDistinct from soft heat affinity (healthy-path bias): this is failover / skip-expensive-stage only. Routing remains **pre-generation** — no FrugalGPT-style cascades (see [routing-roadmap.md](docs/routing-roadmap.md) §1).\n\n### Virtual cost v2 (v0.5.0 subscription economics)\n\n**Virtual cost v2** extends SP-096 flat `quota_cost_per_1m` with deterministic subscription-window economics ([#78](https://github.com/beettlle/pi-smart-router/issues/78)). It inflates effective frontier cost late in a rolling quota window and credits warm prefix-cache value on active pins — without MDP or reinforcement-learning quota policy (SeqRoute HBR+CQL is deferred).\n\n**Formula (per turn)**\n\n`effective_cost_usd = base × λ + quota_arbitrage_premium + exhaustion_risk_premium + kv_cache_savings`\n\n| Component | Meaning |\n|-----------|---------|\n| `base` | SP-096 subscription virtual cost (`quota_cost_per_1m`) or sticker `fallback_cost_per_1m` |\n| **λ (quota decay)** | Multiplier rising from 1 at full window toward `lambda_max_multiplier` as budget depletes |\n| **Quota arbitrage premium** | Opportunity-cost uplift for burning subscription quota late in the window |\n| **Exhaustion risk premium** | Extra penalty when remaining window fraction falls below `exhaustion_risk_threshold` |\n| **KV-cache savings** | Negative credit when pin is active and prefix is warm (`prefix_cache_discount` × `prefix_cache_weight`) |\n\n**Window position**\n\nRolling-window position is supplied to the router pipeline as `quotaWindowPosition` (library API / telemetry integration). Use `remaining_window_fraction` in `[0, 1]` (1 = full budget). Optionally derive it from elapsed time and consumed quota via `deriveRemainingWindowFraction(elapsed_seconds, consumed_fraction)` in `virtual-cost-v2.ts` (defaults assume a Cursor-style **5h** window).\n\n**Quota window feed (producer, [#125](https://github.com/beettlle/pi-smart-router/issues/125))**\n\nThere is no universal cross-provider \"remaining quota\" API, so `src/domain/pricing/quota-window-feed.ts` produces the position via an adapter + degrade chain: (1) a provider `QuotaWindowAdapter` when a trustworthy signal exists, (2) a telemetry-derived **pool-level** burn estimate over the rolling window (subscription-pool models = fleet entries with `quota_cost_per_1m`; enabled via `SMART_ROUTER_QUOTA_POOL_BUDGET_TOKENS` + `SMART_ROUTER_QUOTA_WINDOW_SECONDS`), (3) omit → flat virtual cost + SP-097 exhaustion failover. The smart-router extension resolves the feed at fleet rebuild and passes it through `createDispatchOptions` (SP-173 wiring gap closed). Soft bias only — no hard ban at any threshold; SP-097 reactive failover remains the safety net when the feed is missing or stale. Per-model fractions for shared pools are never invented.\n\nWhen `quotaWindowPosition` is omitted, λ stays at 1 and quota premiums are zero — behavior matches SP-096 flat virtual cost.\n\n**Operator knobs** (`VirtualCostV2Config` — wire through `RouterPipeline` options today; defaults in `DEFAULT_VIRTUAL_COST_V2_CONFIG`):\n\n| Knob | Default | Effect |\n|------|---------|--------|\n| `window_duration_seconds` | `18000` (5h) | Rolling window length for time-based remaining fraction |\n| `lambda_decay_exponent` | `2` | Curvature of λ rise as window depletes |\n| `lambda_max_multiplier` | `3` | λ cap at exhaustion |\n| `quota_arbitrage_weight` | `0.5` | Weight on late-window arbitrage premium |\n| `exhaustion_risk_weight` | `1` | Weight on exhaustion risk below threshold |\n| `exhaustion_risk_threshold` | `0.2` | Remaining fraction below which exhaustion premium applies |\n| `prefix_cache_discount` | `0.9` | Assumed prefix-cache discount on warm tokens |\n| `prefix_cache_weight` | `0.2` | Retained future cache value (aligned with SAAR `SMART_ROUTER_PREFIX_CACHE_WEIGHT`) |\n\n**Where v2 applies**\n\n- **Expected-cost tier selection** — frontier/composer effective cost rises near window exhaustion; economical tiers can win when subscription quota is scarce.\n- **Cache breakeven gate** — marginal switch savings and observability use v2 when `quotaWindowPosition` is set; KV credit on the pinned model reduces marginal savings and can block unnecessary pin breaks.\n\n**Dogfood verification**\n\n1. Configure a fleet with subscription `quota_cost_per_1m` on cursor/composer frontier models (see `config/models.yaml.example`).\n2. Run routing with `quotaWindowPosition: { remaining_window_fraction: 0.05 }` via library `RouterPipeline` options — inspect `tier_selection` / expected-cost rationale for `v2 λ=`, `quota_premium=`, `exhaustion=`, `cache_credit=` strings.\n3. On a warm pinned session with low `remaining_window_fraction`, trigger a `tool_result` sub-route — when cache credit plus reprime math fails breakeven, expect pin hold (`breakeven_blocked`) in routing logs and `features.breakeven` on explain.\n4. Compare `remaining_window_fraction: 1` vs `0.02` on the same request — late-window runs should show higher frontier `effective_cost_usd` in `features.tier_selection.tier_costs[].virtual_cost_v2`.\n\nSee [routing-roadmap.md](docs/routing-roadmap.md) §2 P2 and GitHub [#78](https://github.com/beettlle/pi-smart-router/issues/78).\n\n### Usage actuals (post-turn capture)\n\nWhen pi reports an assistant message `usage` object after a delegated turn, the smart-router persists it onto that turn's routing telemetry row ([#164](https://github.com/beettlle/pi-smart-router/issues/164)): `actual_cost_usd`, `actual_input_tokens`, `actual_output_tokens`, and cache read/write token counts — while retaining `estimated_cost_usd`. Capture fails open: library embeds and non-pi hosts that report no usage simply leave the actual fields null, and a telemetry write error never fails the route. Subscription/OAuth models report `cost.total === 0`: token actuals are still recorded, but no USD is invented — `/smart-router stats` labels its totals `cost_basis: 'actual' | 'estimated' | 'mixed'` accordingly.\n\n### Rolling cost calibration (v0.20.0 usage actuals)\n\n**Rolling cost calibration** soft-biases future cost estimates with the ratio your models *actually* bill versus what the router estimated ([#164](https://github.com/beettlle/pi-smart-router/issues/164)). It is built from the privacy-safe post-turn [usage actuals](#usage-actuals-post-turn-capture) — no new state to configure, and prompt/message bodies are never touched.\n\n**How it works**\n\n1. Every routed turn records an `estimated_cost_usd` (input tokens × catalog rate) and, when pi reports it, an `actual_cost_usd` on the same telemetry row.\n2. `buildCostCalibrationPrior` derives per-**model** and per-**tier** mean `actual / estimate` ratios over the rolling telemetry window. Per-pair outliers are clamped (±10×) before averaging; the aggregate is clamped to a soft band of **[0.5, 2.0]** so calibration can never hard-ban or hard-favor a model on cost alone.\n3. When warm (≥ 3 usable pairs per bucket), the ratio multiplies the tier's base per-1M cost **before** the virtual-cost v2 λ/premium/KV chain — so quota decay and cache credits compound on the calibrated base. Model buckets win over tier buckets.\n4. `estimateRoutingCost` accepts the same prior as an optional argument, soft-biasing per-request cost estimates identically.\n\n**Cold start fails open.** No prior, an empty prior, or a bucket below the warmup threshold resolves ratio 1 — the catalog estimate is used unchanged. Subscription rows (host reports `cost.total === 0`) never contribute: stats and calibration never invent USD.\n\n**Where it applies**\n\n- **Expected-cost tier selection** — pass `costCalibration` into `selectTierByExpectedCost` / `computeExpectedCost` (library API, same pattern as `heatBias`). A warm ratio that doubles an economical tier's effective cost can flip the next selection to frontier; the price-delta and pin-economics hard gates still apply after the soft bias.\n- **Pre-route estimates** — `estimateRoutingCost(model, request, catalog, calibration?)`; the router pipeline's uncalibrated call is unchanged.\n- **`/smart-router stats`** — the aggregate's JSON snapshot (`aggregateSessionStats` / `buildStatsSnapshot`, the automation/MCP surface) carries a `cost_calibration` array (model buckets first, then tier buckets, each `{key, kind, ratio, samples}`); omitted entirely when cold so automation can treat absence as catalog-only. The human-readable stats text keeps rendering cost basis and role breakdown only.\n\n**Observing the bias** — run with `SMART_ROUTER_LOG_ROUTING=1` and read the expected-cost gate line: calibrated winners carry a `[cost-calib ×N.NN from rolling actuals (SP-242)]` note on the rationale, and each tier's `calibrationRatio` appears in the expected-cost breakdown (`features.tier_selection.tier_costs[]`).\n\n**Knobs** (`DEFAULT_COST_CALIBRATION_CONFIG`): `minSamples` 3 (warmup), `minRatio`/`maxRatio` 0.5/2.0 (soft band), `sampleMinRatio`/`sampleMaxRatio` 0.1/10 (per-pair outlier clamp). Not a vendor peak-clock schedule — see [#165](https://github.com/beettlle/pi-smart-router/issues/165) for time-of-day pricing.\n\n### Peak/off-peak pricing adapters (v0.20.0, #165)\n\nTwo vendors publish documented **time-of-day rate cards**. The peak-pricing adapters (`src/domain/pricing/peak-pricing.js`, SP-243) soft-bias the resolved cost-per-1M by the current pricing window — they never hard-ban a model, and non-target providers (OpenAI / Anthropic / Gemini / local / unknown) always resolve `window: 'none'` with multiplier 1 (fail open).\n\n| Vendor | Adapter | Peak window | Off-peak rate | Docs |\n|--------|---------|-------------|---------------|------|\n| Z.ai GLM Coding Plan | `zai` (matches `zai`/`glm`/`zhipu` providers and `glm-*` ids) | Mon–Fri 14:00–18:00 Asia/Singapore (UTC+8) | 0.5× the standard credit rate | [Z.ai GLM Coding Plan docs](https://docs.z.ai/devpack/overview) |\n| DeepSeek pay-as-you-go API | `deepseek` (matches `deepseek` provider / ids) | Mon–Fri 01:00–04:00 and 06:00–10:00 UTC | ½ the peak rate on cache-hit input, cache-miss input, and output | [DeepSeek Models & Pricing](https://api-docs.deepseek.com/quick_start/pricing) |\n\n**Z.ai plan profiles.** The default plan profile is `credits` — off-peak usage at 0.5× the standard credit rate, peak at 1×. **Legacy plans** (e.g. GLM-5.3 legacy at 3× peak / 1× off-peak, Flash at 1.2× / 0.4×) share the same window but use different multipliers; they are available **only** via an explicit operator override (`PeakPricingConfig.zai`: `plan_profile: 'legacy'` plus documented `peak_multiplier` / `off_peak_multiplier`). The adapter never scrapes the live account plan — legacy multipliers are documented override inputs, not detected state.\n\n**Configuration.** Adapters are on by default; `PeakPricingConfig.enabled: false` returns to flat rates. `PeakPricingConfig.deepseek.off_peak_multiplier` overrides the documented 0.5 off-peak discount if DeepSeek changes its schedule.\n\n**Observing the window.** Every routed turn records `pricing_window: 'peak' | 'off_peak' | 'none'` on its telemetry row (SP-243). With `SMART_ROUTER_LOG_ROUTING=1`, the routing-decision payload surfaces the rationale as top-level `pricing_window` plus `peak_pricing_summary` (`window`, `cost_multiplier`, `adapter_id`) on the canonical `buildRoutingDecisionLogPayload`, and `pricing_window` + `peak_pricing` on the extension stderr logger (SP-244).\n\n### P(success) training export (baseline classifier)\n\nWhen `SMART_ROUTER_DATASET=1`, the router records privacy-safe dataset rows and behavioral outcome labels. Export labeled training data from pi:\n\n```bash\n/smart-router export dataset [--limit N]\n```\n\nEach JSONL row joins dataset features with `success_label` and `outcome_signals`. Success means no negative outcome signals were recorded for that `request_id` (for example `model_override` or `feedback_bad` mark failure). Prompt plaintext is never included.\n\n#### Behavioral-first bootstrap (zero manual labels)\n\nPrimary path for [#110](https://github.com/beettlle/pi-smar","readmeFilename":"README.md"}