{"_id":"@andywangzzm/pi-switch","_rev":"15-a5a18c80a4e4b78d6c9dd3e3d23eb5c8","name":"@andywangzzm/pi-switch","dist-tags":{"latest":"0.5.14"},"versions":{"0.5.0":{"name":"@andywangzzm/pi-switch","version":"0.5.0","keywords":["pi","pi-package","models","switch"],"license":"MIT","_id":"@andywangzzm/pi-switch@0.5.0","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts"]},"bin":{"pi-switch":"bin/pi-switch.js"},"dist":{"shasum":"f7b9a90b5b612685eeb11c8e8e8b766a9ef2bd7e","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.0.tgz","fileCount":19,"integrity":"sha512-AEu5suuCXY0yUgb7A1793Cmwtt5QahCu6mQ3QlXQ+/hSXrpaL6RpdAJvtKw96lXZ0nXIs25q+Pp5J7QPSKMeTw==","signatures":[{"sig":"MEYCIQDEh8TxtVWSbdSepAGIFDlKFDwy0BuZAVjcaWPXAoKHNgIhAO2HNWfJcYA2yf3LfPOKGBc1syni2J3wL0cRLyo6BNFL","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37152419},"main":"./index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"],"binaryName":"pi-switch-native"},"type":"module","types":"./index.d.ts","engines":{"node":">=23.6"},"gitHead":"03a2fca4ba4c37bb03103187562ae820542860b2","scripts":{"test":"node --test \"extensions/**/*.test.ts\"","build":"npm run build:webui && npm run build:native","doctor":"node ./bin/pi-switch.js doctor","artifacts":"napi artifacts","dev:webui":"npm --prefix webui run dev","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform"},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"_npmVersion":"10.9.8","description":"Lightweight profile switcher for pi models.json","directories":{},"_nodeVersion":"22.23.1","_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_npmOperationalInternal":{"tmp":"tmp/pi-switch_0.5.0_1786208479269_0.31318804470521355","host":"s3://npm-registry-packages-npm-production"}},"0.5.1":{"name":"@andywangzzm/pi-switch","version":"0.5.1","keywords":["pi","pi-package","models","switch"],"license":"MIT","_id":"@andywangzzm/pi-switch@0.5.1","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts"]},"bin":{"pi-switch":"bin/pi-switch.js"},"dist":{"shasum":"48c93357ebd58d16aa5dd2efd47d6b7426ceeabc","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.1.tgz","fileCount":19,"integrity":"sha512-PpACeTOJSeO4JtZj52p6H5awCMcWR4ALFsmMb3BhhcDTFnYUNdFbDmDiam+PZiUD/vtc5Q9Z5kFwIuskAti7PA==","signatures":[{"sig":"MEYCIQDmmEhZIXYVZtrxAGenuviVOqMga56oPwi2cNdNnTJBJQIhALWJGrP4ihsRu9gUWaQPZ5pr3lTrbJL8T7/t2WT1AnuH","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37152826},"main":"./index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"],"binaryName":"pi-switch-native"},"type":"module","types":"./index.d.ts","engines":{"node":">=23.6"},"gitHead":"a7acb89f3a68e235af0edb208a97f64582daa9ad","scripts":{"test":"node --test \"extensions/**/*.test.ts\"","build":"npm run build:webui && npm run build:native","doctor":"node ./bin/pi-switch.js doctor","artifacts":"napi artifacts","dev:webui":"npm --prefix webui run dev","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform"},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"_npmVersion":"10.9.8","description":"Lightweight profile switcher for pi models.json","directories":{},"_nodeVersion":"22.23.1","_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_npmOperationalInternal":{"tmp":"tmp/pi-switch_0.5.1_1786210811464_0.9369202867197013","host":"s3://npm-registry-packages-npm-production"}},"0.5.2":{"name":"@andywangzzm/pi-switch","version":"0.5.2","keywords":["pi","pi-package","models","switch"],"license":"MIT","_id":"@andywangzzm/pi-switch@0.5.2","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts"]},"bin":{"pi-switch":"bin/pi-switch.js"},"dist":{"shasum":"d824f5c0ff46526c42561178d6adf3e50d29271f","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.2.tgz","fileCount":19,"integrity":"sha512-Ebq6aHaR+s1+SAhzsVGDvvrY9kV2IGgVLoBuXCyaUq+DlXzDGrFStwlnWvNzSTrmle73NL547hOhf9mgWoVfxQ==","signatures":[{"sig":"MEUCIQCCpr0ZzK6FV+2UOBCp67KpnWHuQn7gygAyCpqskiygwgIgOkQRjKeWgKHjVoGQk9CsMcoLZsq0JsevCxoRn6e4lQM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37237402},"main":"./index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"],"binaryName":"pi-switch-native"},"type":"module","types":"./index.d.ts","engines":{"node":">=23.6"},"gitHead":"8efe9856046f41de72d5652fed8a9d7cd9682ea7","scripts":{"test":"node --test \"extensions/**/*.test.ts\"","build":"npm run build:webui && npm run build:native","doctor":"node ./bin/pi-switch.js doctor","artifacts":"napi artifacts","dev:webui":"npm --prefix webui run dev","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform"},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"_npmVersion":"10.9.8","description":"Lightweight profile switcher for pi models.json","directories":{},"_nodeVersion":"22.23.1","_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_npmOperationalInternal":{"tmp":"tmp/pi-switch_0.5.2_1786246872325_0.34111629354762596","host":"s3://npm-registry-packages-npm-production"}},"0.5.3":{"name":"@andywangzzm/pi-switch","version":"0.5.3","keywords":["pi","pi-package","models","switch"],"license":"MIT","_id":"@andywangzzm/pi-switch@0.5.3","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts","./extensions/failover-watchdog.ts"]},"bin":{"pi-switch":"bin/pi-switch.js"},"dist":{"shasum":"6f8b66d1308239374716473b15f3cbe64fec2b21","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.3.tgz","fileCount":20,"integrity":"sha512-f1Kx2DgkTv4IFrMlI7TuCAB0hiSoEqdbKlw6RB9d4nBkg/RLY9tiHvd3Yj0iUTr0I5Gk3uTivFJlWitW0kz77Q==","signatures":[{"sig":"MEUCIFonjLUFDDrGKoShcLZRFuG6vCf3akNDAkVi0Y4jBWeMAiEA8vkTGx9IsBwEVIbn9IEbFQRunTkcpYAj/xQZgBVkZuc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37997148},"main":"./index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"],"binaryName":"pi-switch-native"},"type":"module","types":"./index.d.ts","engines":{"node":">=23.6"},"gitHead":"d993f1d3c92bda936bab4602d7657d867b5e003b","scripts":{"test":"node --test \"extensions/**/*.test.ts\"","build":"npm run build:webui && npm run build:native","doctor":"node ./bin/pi-switch.js doctor","artifacts":"napi artifacts","dev:webui":"npm --prefix webui run dev","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform"},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"_npmVersion":"10.9.8","description":"Lightweight profile switcher for pi models.json","directories":{},"_nodeVersion":"22.23.1","_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_npmOperationalInternal":{"tmp":"tmp/pi-switch_0.5.3_1786497465306_0.21672943742725592","host":"s3://npm-registry-packages-npm-production"}},"0.5.4":{"name":"@andywangzzm/pi-switch","version":"0.5.4","keywords":["pi","pi-package","models","switch"],"license":"MIT","_id":"@andywangzzm/pi-switch@0.5.4","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts","./extensions/failover-watchdog.ts"]},"bin":{"pi-switch":"bin/pi-switch.js"},"dist":{"shasum":"6bb7020bb26724d6aa005fd9f4bd2c426ba39aeb","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.4.tgz","fileCount":20,"integrity":"sha512-vYGnRwV4O5aXIEicArOoffQ3v1C/2BsFueldKMnKBrWZcyIb5NDXchyTtecghG3lbOs2ppr2Wu0b9hodwqawgA==","signatures":[{"sig":"MEYCIQCdngJ92jF/Cut3WdfBzTRF6cNKQyEwe8ucCsgh0KP8kwIhAP1M5FCR8F3a/O5cnZQYL35em05r68aEkyS9K10HkWw7","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37997286},"main":"./index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"],"binaryName":"pi-switch-native"},"type":"module","types":"./index.d.ts","engines":{"node":">=23.6"},"gitHead":"bfd223ec3cc63f94be4eff28d07ea273877cfe2e","scripts":{"test":"node --test \"extensions/**/*.test.ts\"","build":"npm run build:webui && npm run build:native","doctor":"node ./bin/pi-switch.js doctor","artifacts":"napi artifacts","dev:webui":"npm --prefix webui run dev","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform"},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"_npmVersion":"10.9.8","description":"Lightweight profile switcher for pi models.json","directories":{},"_nodeVersion":"22.23.2","_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_npmOperationalInternal":{"tmp":"tmp/pi-switch_0.5.4_1786499130091_0.16656758149951023","host":"s3://npm-registry-packages-npm-production"}},"0.5.5":{"name":"@andywangzzm/pi-switch","version":"0.5.5","keywords":["pi","pi-package","models","switch"],"license":"MIT","_id":"@andywangzzm/pi-switch@0.5.5","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts","./extensions/failover-watchdog.ts"]},"bin":{"pi-switch":"bin/pi-switch.js"},"dist":{"shasum":"f44c7c9abed066b1725073f12420246f39fea6bf","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.5.tgz","fileCount":20,"integrity":"sha512-sbOi6GCiJDazT6usELRDeFIIvXmWU4D56Vikz2LK8L7010VFD60CBSsJN+HFGuYve5JveajB+pey+Pqm3h0c7A==","signatures":[{"sig":"MEUCIFacOgq3TKNn62dTtjoZRJYL9ihiDNRDaJ/qA6Wdgx6gAiEA5jmBpy4qgyEyEvNwdz91weMN6A6jMrRU+z+3F7/JOuI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37997286},"main":"./index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"],"binaryName":"pi-switch-native"},"type":"module","types":"./index.d.ts","engines":{"node":">=23.6"},"gitHead":"1d1ae8740fc615cb98ed43f7317da85e28267099","scripts":{"test":"node --test \"extensions/**/*.test.ts\"","build":"npm run build:webui && npm run build:native","doctor":"node ./bin/pi-switch.js doctor","artifacts":"napi artifacts","dev:webui":"npm --prefix webui run dev","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform"},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"_npmVersion":"10.9.8","description":"Lightweight profile switcher for pi models.json","directories":{},"_nodeVersion":"22.23.1","_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_npmOperationalInternal":{"tmp":"tmp/pi-switch_0.5.5_1786501649502_0.8416214069475723","host":"s3://npm-registry-packages-npm-production"}},"0.5.6":{"name":"@andywangzzm/pi-switch","version":"0.5.6","keywords":["pi","pi-package","models","switch"],"license":"MIT","_id":"@andywangzzm/pi-switch@0.5.6","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts","./extensions/failover-watchdog.ts"]},"bin":{"pi-switch":"bin/pi-switch.js"},"dist":{"shasum":"775d4e7d5901dfe7f41085194081b6ae7f724c46","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.6.tgz","fileCount":20,"integrity":"sha512-Exg/AY6Z5TR5hmwuaKUogi0KvjirwZ19Dy36JejGi8LY+CS2w66AR5ImjcX1jkCp8vo87weWZMbd2RwU+M8aDQ==","signatures":[{"sig":"MEQCIA8Z7qwSEI3GcUAj8F+0p3wC8ti8ZDryiR8VSTMCJSqmAiAlvi5cAt6cfVCoCSHaqlS2qv/sFuQ/FMDx2J/ey+WIpg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38379122},"main":"./index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"],"binaryName":"pi-switch-native"},"type":"module","types":"./index.d.ts","engines":{"node":">=23.6"},"gitHead":"52970ac07fc1105d816e1319676a7076394083c5","scripts":{"test":"node --test \"extensions/**/*.test.ts\"","build":"npm run build:webui && npm run build:native","doctor":"node ./bin/pi-switch.js doctor","artifacts":"napi artifacts","dev:webui":"npm --prefix webui run dev","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform"},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"_npmVersion":"10.9.8","description":"Lightweight profile switcher for pi models.json","directories":{},"_nodeVersion":"22.23.2","_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_npmOperationalInternal":{"tmp":"tmp/pi-switch_0.5.6_1786764738915_0.4184394779731626","host":"s3://npm-registry-packages-npm-production"}},"0.5.7":{"name":"@andywangzzm/pi-switch","version":"0.5.7","keywords":["pi","pi-package","models","switch"],"license":"MIT","_id":"@andywangzzm/pi-switch@0.5.7","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts","./extensions/failover-watchdog.ts"]},"bin":{"pi-switch":"bin/pi-switch.js"},"dist":{"shasum":"3421434d80ead6eae572300c6fea6b7487d4d68d","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.7.tgz","fileCount":20,"integrity":"sha512-kWUePQpGZ64t40RM/1lnbfEjdIU9REQ/HgjqWF8lW04i+8t7Da4YIedFiuXRyl2Uh8t5zlwBoVLV1sX+b4ppdA==","signatures":[{"sig":"MEUCIAQxTCEDJZ72VTeRrAECsfe9T8s414FLDOErtVEksus7AiEA5NSHkHIL7+kfgIjtyfY2J/xVsGhTTtWNFd9qJi5cQY0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38341402},"main":"./index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"],"binaryName":"pi-switch-native"},"type":"module","types":"./index.d.ts","engines":{"node":">=23.6"},"gitHead":"2527131b7542a55b6b2856400be0a5e1faf16dd1","scripts":{"test":"node --test \"extensions/**/*.test.ts\"","build":"npm run build:webui && npm run build:native","doctor":"node ./bin/pi-switch.js doctor","artifacts":"napi artifacts","dev:webui":"npm --prefix webui run dev","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform"},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"_npmVersion":"10.9.8","description":"Lightweight profile switcher for pi models.json","directories":{},"_nodeVersion":"22.23.2","_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_npmOperationalInternal":{"tmp":"tmp/pi-switch_0.5.7_1786767183619_0.5000846239853158","host":"s3://npm-registry-packages-npm-production"}},"0.5.8":{"name":"@andywangzzm/pi-switch","version":"0.5.8","keywords":["pi","pi-package","models","switch"],"license":"MIT","_id":"@andywangzzm/pi-switch@0.5.8","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts","./extensions/failover-watchdog.ts"]},"bin":{"pi-switch":"bin/pi-switch.js"},"dist":{"shasum":"b1dc808f48826040d8d8744e024a7f8b7a8d40be","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.8.tgz","fileCount":20,"integrity":"sha512-T/zm8o+lpVca7uBKrRUD0M31WKbA6I08Vzb9+tRQhk9fZ2zWIEV3SUrNOH1aaPhBL2GaP25odqoYarxLdK7Xyw==","signatures":[{"sig":"MEYCIQD2ksCDT4gftrP7Vk+l/synDkKdcUIMPljenihKdq3diwIhANxK6jQHCZA0xnaixaLOqE+z54R37bWGmK+5z1p4VQIM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38376019},"main":"./index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"],"binaryName":"pi-switch-native"},"type":"module","types":"./index.d.ts","engines":{"node":">=23.6"},"gitHead":"cafa55657156d363274c4a289ab824a747e0b2bb","scripts":{"test":"node --test \"extensions/**/*.test.ts\"","build":"npm run build:webui && npm run build:native","doctor":"node ./bin/pi-switch.js doctor","artifacts":"napi artifacts","dev:webui":"npm --prefix webui run dev","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform"},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"_npmVersion":"10.9.8","description":"Lightweight profile switcher for pi models.json","directories":{},"_nodeVersion":"22.23.2","_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_npmOperationalInternal":{"tmp":"tmp/pi-switch_0.5.8_1786787776091_0.6954149924025541","host":"s3://npm-registry-packages-npm-production"}},"0.5.9":{"name":"@andywangzzm/pi-switch","version":"0.5.9","keywords":["pi","pi-package","models","switch"],"license":"MIT","_id":"@andywangzzm/pi-switch@0.5.9","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts","./extensions/failover-watchdog.ts"]},"bin":{"pi-switch":"bin/pi-switch.js"},"dist":{"shasum":"b1347b65ca9ddfceee1dfdaf3f90ff1c9971d61f","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.9.tgz","fileCount":20,"integrity":"sha512-mj/BuyAFxQh7PpXG4FaaTj4O27GgRjC6f8BRb9v/XNB+odwlC04QV4Z2fZg6p/eGHKPr6URE3agtezNwzv6PVA==","signatures":[{"sig":"MEUCIQDVMG6dU1y7hEihP8E/F+4sK1C9IrH5+dUL1wyXV/K1AAIgHWWMeYQ40aMhZqtFCH8NPMwg5m8bg/ET3txsg3wofl4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38376019},"main":"./index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"],"binaryName":"pi-switch-native"},"type":"module","types":"./index.d.ts","engines":{"node":">=23.6"},"gitHead":"c659ad711a5d40a139f6795cf4ecc404502f8744","scripts":{"test":"node --test \"extensions/**/*.test.ts\"","build":"npm run build:webui && npm run build:native","doctor":"node ./bin/pi-switch.js doctor","artifacts":"napi artifacts","dev:webui":"npm --prefix webui run dev","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform"},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"_npmVersion":"10.9.8","description":"Lightweight profile switcher for pi models.json","directories":{},"_nodeVersion":"22.23.2","_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_npmOperationalInternal":{"tmp":"tmp/pi-switch_0.5.9_1786791768919_0.36144461083028645","host":"s3://npm-registry-packages-npm-production"}},"0.5.10":{"name":"@andywangzzm/pi-switch","version":"0.5.10","keywords":["pi","pi-package","models","switch"],"license":"MIT","_id":"@andywangzzm/pi-switch@0.5.10","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts","./extensions/failover-watchdog.ts"]},"bin":{"pi-switch":"bin/pi-switch.js"},"dist":{"shasum":"03835a0c705a53d3b9029e0471509ddbe9d548cd","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.10.tgz","fileCount":20,"integrity":"sha512-T1Rr36q66mqxVNeNuj2ZyEpEFqdLOJ0hiz8ZIsogoO8ObiwBpz4e6PDXu+DI6cLfa59QPImaFgoQTfYkshHqGg==","signatures":[{"sig":"MEQCIBMcPTkNgYOzGzzAgKMscuYH2LEh0k/N3IbS73KYUac1AiBB1o7KaAm8zRnsKNjnsFYNPSpuBQ/K7jgWaN6TBgWRFw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38445884},"main":"./index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"],"binaryName":"pi-switch-native"},"type":"module","types":"./index.d.ts","engines":{"node":">=23.6"},"gitHead":"8148fe7c9ae82c3608a56fe1b856e2be0a22fb5b","scripts":{"test":"node --test \"extensions/**/*.test.ts\"","build":"npm run build:webui && npm run build:native","doctor":"node ./bin/pi-switch.js doctor","artifacts":"napi artifacts","dev:webui":"npm --prefix webui run dev","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform"},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"_npmVersion":"10.9.8","description":"Lightweight profile switcher for pi models.json","directories":{},"_nodeVersion":"22.23.2","_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_npmOperationalInternal":{"tmp":"tmp/pi-switch_0.5.10_1786808584787_0.8980163195251569","host":"s3://npm-registry-packages-npm-production"}},"0.5.11":{"name":"@andywangzzm/pi-switch","version":"0.5.11","keywords":["pi","pi-package","models","switch"],"license":"MIT","_id":"@andywangzzm/pi-switch@0.5.11","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts","./extensions/failover-watchdog.ts"]},"bin":{"pi-switch":"bin/pi-switch.js"},"dist":{"shasum":"9cc8a4934f158a938b3981e9299e4332fc109199","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.11.tgz","fileCount":20,"integrity":"sha512-cHq4iwE6gUInDBKz3Fd0X2y5peXL9gqJiTVgwLoyw/y8wezhOIRdE6rDt4iDLC1ZV7tuurDq0tru/a5UBWXL1Q==","signatures":[{"sig":"MEYCIQC7lFVSftdFjJvQAkiI6xH38hRcpa/APierd527VTaAxgIhAI+R1Bkc3QoUZlvuIcLipEAEJBUdkdvsKGKekQkNiyil","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38429645},"main":"./index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"],"binaryName":"pi-switch-native"},"type":"module","types":"./index.d.ts","engines":{"node":">=23.6"},"gitHead":"dd485de0f3e21808127a5d5c530279eac3e901bc","scripts":{"test":"node --test \"extensions/**/*.test.ts\"","build":"npm run build:webui && npm run build:native","doctor":"node ./bin/pi-switch.js doctor","artifacts":"napi artifacts","dev:webui":"npm --prefix webui run dev","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform"},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"_npmVersion":"10.9.8","description":"Lightweight profile switcher for pi models.json","directories":{},"_nodeVersion":"22.23.2","_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_npmOperationalInternal":{"tmp":"tmp/pi-switch_0.5.11_1786844021544_0.9773954264063214","host":"s3://npm-registry-packages-npm-production"}},"0.5.12":{"name":"@andywangzzm/pi-switch","version":"0.5.12","keywords":["pi","pi-package","models","switch"],"license":"MIT","_id":"@andywangzzm/pi-switch@0.5.12","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts","./extensions/failover-watchdog.ts"]},"bin":{"pi-switch":"bin/pi-switch.js"},"dist":{"shasum":"295de4e7dd377ac8754dbc164ed7c92f694a4cbf","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.12.tgz","fileCount":20,"integrity":"sha512-H63RI0CJbcDa8hHYt80UYpupIfVeegeezwpFkDDJnnZ8KWkAEkT2VQFPK3lau3NOMLTQPWAPflC/ox+mCsAw8g==","signatures":[{"sig":"MEUCIEQTqBSR498Wh9BpAP7lcXf6YIucsT6Yx/o/RACWC6C4AiEAoDUPx07pFyWiUWBlqnY/ENoXVaIOVc3i/LQ+ykFJ0jw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38438709},"main":"./index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"],"binaryName":"pi-switch-native"},"type":"module","types":"./index.d.ts","engines":{"node":">=23.6"},"gitHead":"98de9f0f7852976db80d3c12a715ecf5b8699ed1","scripts":{"test":"node --test \"extensions/**/*.test.ts\"","build":"npm run build:webui && npm run build:native","doctor":"node ./bin/pi-switch.js doctor","artifacts":"napi artifacts","dev:webui":"npm --prefix webui run dev","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform"},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"_npmVersion":"10.9.8","description":"Lightweight profile switcher for pi models.json","directories":{},"_nodeVersion":"22.23.2","_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_npmOperationalInternal":{"tmp":"tmp/pi-switch_0.5.12_1786844977452_0.25323403500291497","host":"s3://npm-registry-packages-npm-production"}},"0.5.13":{"name":"@andywangzzm/pi-switch","version":"0.5.13","keywords":["pi","pi-package","models","switch"],"license":"MIT","_id":"@andywangzzm/pi-switch@0.5.13","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts","./extensions/failover-watchdog.ts"]},"bin":{"pi-switch":"bin/pi-switch.js"},"dist":{"shasum":"f74ab9775f4a0466b075d86d5eac820f8cb84a93","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.13.tgz","fileCount":20,"integrity":"sha512-UJNjCA8pkpAaAz0aMOVN65/1AvmKvehfy3281Wxdp0/XDn4zlsc5sleh5Yqfq67mg2TZKxTKbh1za/crYCosuQ==","signatures":[{"sig":"MEUCIHPdlbydSzt4s0sI0oT0XRunkNxiRD4OrF+gkh7+mUVKAiEAjYSS5/gg90lh+Y9OK6idU7IVeCSzLrTRuhM7YX64vW0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38555973},"main":"./index.js","napi":{"targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"],"binaryName":"pi-switch-native"},"type":"module","types":"./index.d.ts","engines":{"node":">=23.6"},"gitHead":"60946bb78844a40a4cda0742325fbe321413e041","scripts":{"test":"node --test \"extensions/**/*.test.ts\"","build":"npm run build:webui && npm run build:native","doctor":"node ./bin/pi-switch.js doctor","artifacts":"napi artifacts","dev:webui":"npm --prefix webui run dev","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform"},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"_npmVersion":"10.9.8","description":"Lightweight profile switcher for pi models.json","directories":{},"_nodeVersion":"22.23.2","_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_npmOperationalInternal":{"tmp":"tmp/pi-switch_0.5.13_1786935034391_0.4168158233285981","host":"s3://npm-registry-packages-npm-production"}},"0.5.14":{"name":"@andywangzzm/pi-switch","version":"0.5.14","description":"Lightweight profile switcher for pi models.json","type":"module","bin":{"pi-switch":"bin/pi-switch.js"},"main":"./index.js","napi":{"binaryName":"pi-switch-native","targets":["x86_64-apple-darwin","aarch64-apple-darwin","x86_64-unknown-linux-gnu","x86_64-unknown-linux-musl","x86_64-pc-windows-msvc"]},"scripts":{"artifacts":"napi artifacts","build":"npm run build:webui && npm run build:native","build:webui":"npm --prefix webui install && npm --prefix webui run build","build:native":"napi build --platform --release","build:native:debug":"napi build --platform","dev:webui":"npm --prefix webui run dev","doctor":"node ./bin/pi-switch.js doctor","test":"node --test \"extensions/**/*.test.ts\""},"keywords":["pi","pi-package","models","switch"],"pi":{"extensions":["./extensions/index.ts","./extensions/conversation-id-inject.ts","./extensions/failover-watchdog.ts"]},"license":"MIT","engines":{"node":">=23.6"},"devDependencies":{"@napi-rs/cli":"^3.7.1"},"_id":"@andywangzzm/pi-switch@0.5.14","gitHead":"0699439d60776ededb69b84f8c15218b525d8802","types":"./index.d.ts","_nodeVersion":"22.23.2","_npmVersion":"10.9.8","dist":{"integrity":"sha512-o0Vmcgnkn7JX3DGSvvVnJNv+IDKOqf+k4QI1bf0AYCcvM9/C2aDTlf7NbFet1eb21f3CjwUbRtS4tAJYpH8+Ow==","shasum":"7ca3291b4647a7b5f2bffa74f9b211a2c53fee17","tarball":"https://registry.npmjs.org/@andywangzzm/pi-switch/-/pi-switch-0.5.14.tgz","fileCount":20,"unpackedSize":38552993,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIB9Be8pdTQn08Q5N8qojKCfl1yyTDk9Lc4QCqfI+KQYuAiABsk0CM+zd/KYENiE1V7EAZLhxSQhGDe/tT+hRp6DAkw=="}]},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"directories":{},"maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pi-switch_0.5.14_1787390411512_0.5209254863648514"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-08T17:01:19.046Z","modified":"2026-08-22T09:20:12.071Z","0.5.0":"2026-08-08T17:01:19.633Z","0.5.1":"2026-08-08T17:40:11.950Z","0.5.2":"2026-08-09T03:41:12.796Z","0.5.3":"2026-08-12T01:17:45.716Z","0.5.4":"2026-08-12T01:45:30.558Z","0.5.5":"2026-08-12T02:27:29.926Z","0.5.6":"2026-08-15T03:32:19.286Z","0.5.7":"2026-08-15T04:13:03.996Z","0.5.8":"2026-08-15T09:56:16.564Z","0.5.9":"2026-08-15T11:02:49.283Z","0.5.10":"2026-08-15T15:43:05.178Z","0.5.11":"2026-08-16T01:33:41.920Z","0.5.12":"2026-08-16T01:49:37.808Z","0.5.13":"2026-08-17T02:50:34.778Z","0.5.14":"2026-08-22T09:20:11.910Z"},"license":"MIT","keywords":["pi","pi-package","models","switch"],"description":"Lightweight profile switcher for pi models.json","maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"readme":"<div align=\"center\">\n\n# pi-switch\n\n[![Version](https://img.shields.io/badge/version-0.4.5-blue.svg)](https://github.com/user/pi-switch/releases)\n[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey.svg)](https://github.com/user/pi-switch/releases)\n[![Built with Rust](https://img.shields.io/badge/built%20with-Rust-orange.svg)](https://www.rust-lang.org/)\n[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)\n\n**TUI + CLI dual-mode profile switcher for pi agent**\n\nManage provider profiles and run a local model-name routing gateway with failover — via an interactive TUI or CLI.\n\n[English](#) | [中文](README_ZH.md)\n\n</div>\n\n---\n\n## 📸 Screenshots\n\n<div align=\"center\">\n  <img src=\"assets/main.png\" alt=\"pi-switch TUI\" width=\"80%\"/>\n</div>\n\n---\n\n## 📥 Installation\n\n```bash\n# npm (recommended)\nnpm install -g @andywangzzm/pi-switch\n\n# or via pi\npi install npm:@andywangzzm/pi-switch\n```\n\n**Build from source** (requires Node.js >= 20, Rust 1.80+):\n\n```bash\ngit clone https://github.com/user/pi-switch.git\ncd pi-switch\nnpm install\nnpm run build:native\nnode bin/pi-switch.js tui\n```\n\n### System Compatibility\n\n**Supported platforms:**\n- ✅ Windows (x64)\n- ✅ macOS (Intel & Apple Silicon)\n- ✅ Linux (x64) - glibc & musl\n\n**Linux users:** This package includes prebuilt binaries for both glibc and musl systems. If you encounter a GLIBC version error, the package will automatically fallback to the musl binary which has broader compatibility.\n\n**Troubleshooting GLIBC errors:**\n```bash\n# If you see \"GLIBC_X.XX not found\", build from source:\nnpm install -g @andywangzzm/pi-switch --build-from-source\n```\n\n---\n\n## 🚀 Quick Start\n\n```bash\npi-switch tui          # Interactive TUI (recommended)\npi-switch webui start --daemon  # Browser UI at http://127.0.0.1:43110 (background daemon)\npi-switch doctor       # Run environment diagnostics\n```\n\n> **Three ways, one core.** CLI, TUI, and WebUI are thin adapters over the same\n> Rust core. See [WEBUI_GUIDE.md](./WEBUI_GUIDE.md) for the WebUI and how to keep\n> the three interfaces in sync.\n\n### Essential CLI Commands\n\n```bash\n# Provider management\npi-switch provider add <name> [--preset <id>] [--api-key <key>]\npi-switch provider list\npi-switch provider show <name>\npi-switch provider delete <name>\npi-switch provider expose <name> <model-ids...>    # Expose models to pi agent\npi-switch provider fetch-models <name>             # Fetch models from API\n\n# Proxy (gateway)\npi-switch proxy rules list                              # Show failover rules\npi-switch proxy rules set '<json>'                     # Set failover rules (rule-based, provider-level)\npi-switch proxy rules clear                            # Remove all failover rules\npi-switch proxy start --daemon                     # Start proxy daemon\npi-switch proxy status\n\n# Package management\npi-switch package list                             # List installed packages\npi-switch package add <id> <name> <version>        # Add a new package\npi-switch package toggle <id>                      # Enable/disable package\npi-switch package remove <id>                      # Remove package\npi-switch package show <id>                        # Show package details\n\n# WebUI (browser config) — always use --daemon so it runs in the\n# background and can be stopped with `pi-switch webui stop`\npi-switch webui start --daemon [--host <ip>] [--port <port>]\npi-switch webui status\npi-switch webui stop\n\n# Other\npi-switch presets list                             # List built-in presets\npi-switch config show                               # Display current config\npi-switch config backups                            # List backup files\npi-switch config export <passphrase>                # Encrypted export\npi-switch config import <path> <passphrase>         # Encrypted import\npi-switch import ccswitch [--path <db>] [--all] [--force]  # Import providers from cc-switch\npi-switch stats                                     # View request statistics\n```\n\n---\n\n## ✨ Features\n\n| Category | Highlights |\n|----------|------------|\n| 🔌 **Provider Management** | CRUD, duplicate, search/filter, model management, expose to pi agent, configure Responses API passthrough/conversion mode |\n| ⇥ **cc-switch Import** | One-click import of providers from cc-switch (Claude Code / Codex / Gemini), dedup by base URL, skip official presets — CLI, TUI, WebUI |\n| 💡 **Built-in Presets** | OpenRouter, Anthropic, DeepSeek, SiliconFlow, OpenAI — add profiles instantly |\n| 🌉 **Model-Name Gateway** | Stateless routing by `profile/model` in the request body, SSE streaming, User-Agent disguise, request-body filtering, OpenAI ↔ Anthropic conversion, Responses ↔ Chat Completions conversion with function tools, native OpenAI Responses passthrough, failover, circuit breaker |\n| 📦 **Package Management** | Install, enable/disable, and manage packages across CLI, TUI, and WebUI |\n| 🖥️ **Interactive TUI** | ratatui-powered, Dracula theme, mouse support, vim keys (`hjkl`) |\n| 🌐 **Bilingual** | English / 中文, persisted to config, toggle in Settings |\n| 📊 **Usage Stats** | Per-provider, per-model request metrics & latency; four-dimension token totals (input/output/cached/reasoning), cache hit rate, time-window queries (today/24h/7d/custom), per-conversation breakdown |\n| 💾 **Backup & Sync** | Auto-backup on mutation, AES-256-CBC encrypted export/import |\n| 🩺 **Diagnostics** | `doctor` command checks config, models.json, structure |\n\n---\n\n## ⇥ Import from cc-switch\n\nAlready using [cc-switch](https://github.com/farion1231/cc-switch)? You can import its providers into pi-switch with one command instead of re-adding them by hand:\n\n```bash\npi-switch import ccswitch                 # interactive selection\npi-switch import ccswitch --all           # import everything new\npi-switch import ccswitch --path /path/to/cc-switch.db   # custom db location\n```\n\n- Reads `~/.cc-switch/cc-switch.db` (SQLite, read-only — cc-switch is never modified)\n- Maps the three common client types: **Claude** → `anthropic-messages`, **Codex** → `openai-responses`, **Gemini** → `google-generative-ai`\n- Official presets (e.g. `claude-official`) are skipped\n- **Dedup by base URL**: providers already in pi-switch are flagged as existing and skipped (use `--force` to overwrite)\n- Name collisions resolve to `name (cc)` instead of silently overwriting\n- If the default db path is missing, you are prompted for the path to `cc-switch.db` (or you can cancel)\n\nAvailable in all three UIs: CLI (`pi-switch import ccswitch`), TUI (Profiles → `i`), WebUI (Profiles → *Import from cc-switch*).\n\n---\n\n## 📊 Usage Statistics\n\nEvery proxied request is appended to `~/.pi-switch/requests.log` as a JSON line. For streaming responses the upstream SSE stream is teed: each request's input/output/cached/reasoning token counts (when the upstream reports them) and conversation id are parsed on the side and the log line is written when the stream ends — the stream itself is never buffered. Reasoning tokens are a subset of output tokens (parsed from `completion_tokens_details.reasoning_tokens` / `output_tokens_details.reasoning_tokens` where the upstream reports them); they never inflate the total.\n\n- **TUI Stats page** shows the cumulative input/output tokens and the cache hit rate.\n- **Stats API** (`GET /api/stats`) returns `totalTokens` with four dimensions — input / output / cached / reasoning (`total = input + output`, reasoning is a subset of output) — plus `cacheHitRate`, per-provider token columns, and `byConversation` — conversations sorted by most recent activity (top 20), with requests without an id merged into a single `unlabeled` group.\n- **Time window** — the WebUI stats page has a time-range picker: **Today** (local calendar day from 00:00), **Last 24h** and **Last 7d** (rolling windows), and **Custom** (start day 00:00 → end day 24:00, both dates required). The default is Today. The picker converts the window to `from`/`to` epoch-millis and calls `GET /api/stats?range=<today|last24h|last7d|custom>&from=<ms>&to=<ms>`; a bare request with no window parameters returns the full history.\n- **WebUI dashboard** — token totals render as five tiles (Input / Output / Cached / Reasoning / Total) with subset badges (`Cached ⊆ Input`, `Reasoning ⊆ Output`), and each conversation row adds Input / Output / Cached / Reasoning / cache hit rate / Total in a two-line layout when over-wide; missing or zero token values show `-`.\n- **Request details** — below the conversation card, the stats page lists every request in the current window, newest first, capped at the most recent 100: time, provider, model, status (with error for failures), and input / output / cached / reasoning / total tokens plus per-request cache hit rate. Rows without reported usage show `-`, never a misleading zero.\n- **Cache hit rate** = cached input tokens ÷ total input tokens (output tokens excluded). When no cache data exists it shows `-`, never a misleading `0%`.\n- **Conversation id** comes from the client: `x-conversation-id` header first, `x-opencode-session` second (sent by pi/open-code clients), `conversation_id` body field as fallback (ADR-0002).\n- Only successful requests with reported usage count towards token totals; failover/retry intermediate rows and old log lines without token fields are excluded gracefully, so upgrading never breaks or blanks existing history.\n\n---\n\n## 🔍 Raw Request/Response Log (Web UI only)\n\nIn addition to the metadata log (`requests.log`), the proxy writes the **raw client request** and the **raw upstream response** for every upstream attempt to `~/.pi-switch/raw-requests.log` (JSON Lines), so you can analyze byte-for-byte what was sent and what the upstream returned.\n\n- **What is captured**: the client request (method, path, headers, raw body) plus each upstream attempt (provider, URL, status, upstream response headers, raw response body — SSE streams are accumulated chunk-by-chunk). Failover attempts against the same client request share a `requestId`; each attempt is its own entry so you can compare what each upstream returned.\n- **Credentials are masked**: `authorization` / `x-api-key` / `cookie` / `set-cookie` header values are redacted (e.g. `Bearer ***`); hop-by-hop headers (`host`, `content-length`, …) are not recorded.\n- **Size cap**: a request or response body is captured up to 2 MiB by default (`settings.proxy.rawLog.maxBodyBytes`); longer bodies are kept from the head and flagged `bodyTruncated`, so long streams cannot balloon memory or disk.\n- **Viewable only in the Web UI**: the CLI and TUI never read this file. The WebUI **Raw Logs** page auto-refreshes (5s/30s/5min), groups attempts per request, expands into the raw headers/bodies, and can clear everything. API: `GET /api/rawlogs` (list, metadata only), `GET /api/rawlogs/:id` (single entry with bodies), `DELETE /api/rawlogs` (clear).\n- **Toggle**: enabled by default; the Settings → Proxy card can disable capture (`settings.proxy.rawLog.enabled`).\n\n---\n\n## 🎯 Core Workflow\n\n### Gateway Routing & Failover\n\n```mermaid\ngraph LR\n    subgraph Setup[\"⚙️ Setup\"]\n        A[Add Provider] --> B[Configure Models]\n        B --> C[Expose to Pi]\n        C --> D[Set Failover Rules]\n    end\n\n    subgraph Runtime[\"🚀 Runtime\"]\n        E[\"Request<br/>model: provider-a/gpt-5.4\"] --> F{Resolve Route}\n        F --> G[Try provider-a]\n        G --> H{Success?}\n        H -->|✓| I[Response]\n        H -->|✗ 429/5xx| J[Try provider-b]\n        J --> K{Success?}\n        K -->|✓| I\n        K -->|✗| L[Circuit Breaker]\n        L --> M[60s Cooldown]\n        M --> N[Half-Open Probe]\n        N -->|✓| G\n        N -->|✗| M\n    end\n\n    Setup --> Runtime\n\n    style A fill:#50fa7b,stroke:#50fa7b,color:#282a36\n    style E fill:#8be9fd,stroke:#8be9fd,color:#282a36\n    style I fill:#50fa7b,stroke:#50fa7b,color:#282a36\n    style L fill:#ff5555,stroke:#ff5555,color:#f8f8f2\n```\n\n### Step by Step\n\n**1. Add a provider** (CLI or TUI)\n```bash\npi-switch provider add provider-a --api openai-completions --base-url https://api.example.com/v1 \\\n    --api-key '$API_KEY' --models gpt-5.4,claude-sonnet-4-5\n```\nIn TUI: `Profiles → a → fill form → Ctrl+S`\n\n**2. Expose models to pi agent** — choose which models appear in `~/.pi/agent/models.json`\n```bash\npi-switch provider expose provider-a gpt-5.4\n```\nIn TUI: `Profiles → select provider → x`\n\n**3. Start the proxy** — it writes a single `pi-switch` gateway provider to pi\n```bash\npi-switch proxy rules set '[{\"match\":{\"modelPrefix\":\"gpt\"},\"providers\":[\"provider-a\",\"provider-b\"]}]'  # optional rule-based failover\npi-switch proxy start --daemon\n```\n\n**4. Use in pi** — select the `pi-switch` provider, then pick a `profile/model` like `provider-a/gpt-5.4`\n\n### How Gateway Routing Works\n\nRequests are routed by the model name in the request body — no out-of-band state, no \"current target\":\n\n- **Model-name routing** — `\"model\": \"provider-a/gpt-5.4\"` resolves to profile `provider-a`, real model `gpt-5.4`; the proxy rewrites the body before forwarding upstream\n- **Single gateway provider** — pi sees one `pi-switch` provider advertising every exposed model as `profile/realModelId`; switching model in pi = sending a different model string = instant routing change\n- **Rule-based failover** — the first rule whose match conditions hit the requested model decides the provider chain, tried in order on 429/5xx errors or network failures (provider-level granularity; providers may map the model via `modelMap`). Each rule can set `\"mode\"` (default `stable`):\n  - `\"mode\": \"stable\"` (**stability-first**, default) — candidates are tried healthiest-first by a recent EWMA success score (stored per node as `score` in `circuit.json`); a node that fails again shortly after recovery (flapping) has its circuit cooldown escalated ×2 per flap (capped at 32× — up to ~32 min at the 60s baseline), Maximizes upstream success rate, may skip the configured order. The backoff only gates the traffic path (half-open probes); when the whole chain is down the recovery monitor still probes eagerly, so a total outage recovers within one probe interval.\n  - `\"mode\": \"cost\"` (**cost-first**) — original behavior, unchanged: configured order, fixed cooldown, immediate failback to the configured primary whenever its circuit is closed.\n- **Circuit breaker** — after 3 consecutive failures, provider enters 60s cooldown; auto-recovery on half-open probe success (fixed cooldown in cost mode; exponential backoff for flapping nodes on stable multi-provider chains)\n- **Recovery monitor** — when every upstream of a chain is circuit-open, the proxy kernel periodically probes the broken nodes per `settings.proxy.monitor`; a recovered node exits circuit-break and appends one line to `recovery.jsonl`, which the pi extension watches to auto-send a `continue` so pi retries. Recovery events carry the conversation ids whose requests failed during the outage — **only the pi session(s) actually affected receive the `continue`**; failures caused by other clients (curl, other agents, no `x-conversation-id` header) never trigger it. Probing is mode-agnostic: the monitor only acts on fully-broken chains, where eager recovery is always the right call\n- **Streaming (SSE)** — same-format requests (openai→openai, anthropic→anthropic) stream token-by-token; upstream response headers (Content-Type, etc.) are preserved\n- **OpenAI ↔ Anthropic** — transparently converts between chat completions and messages APIs\n- **User-Agent disguise** — built-in presets (Claude Code / Codex / Gemini) send the matching client's real User-Agent (and headers like `anthropic-beta`) to pass upstream client checks; settable globally or per-profile\n\n> **Known limitation** — the OpenAI ↔ Anthropic **conversion** path can't stream: it parses the full JSON to convert formats. If pi sends `stream: true` but the model routes to a cross-format upstream (OpenAI request → Anthropic upstream, or vice-versa), the reply comes back as a single non-streamed response. Same-format routes stream normally.\n\n---\n\n## 🏗️ Architecture\n\n```\npi-switch/\n├── bin/pi-switch.js         # CLI entry point\n├── index.js                 # ESM wrapper for native addon\n├── pi-switch-native.cjs     # NAPI loader (auto platform detection)\n├── src-rust/                # Rust native core (napi-rs)\n│   ├── lib.rs               # NAPI function exports\n│   ├── config.rs            # Config load/save, types\n│   ├── ops.rs               # Core operations\n│   ├── presets.rs           # Built-in provider presets\n│   ├── proxy.rs             # Proxy server (gateway routing, failover, circuit breaker)\n│   ├── monitor.rs           # Upstream recovery monitor (probe broken chains, emit recovery events)\n│   ├── daemon.rs            # Daemon lifecycle\n│   ├── stats.rs             # Request log aggregation + token usage stats\n│   ├── usage.rs             # Token usage extraction & SSE stream parsing\n│   ├── sync.rs              # Encrypted export/import\n│   └── tui/                 # Interactive terminal UI (ratatui)\n│       ├── app.rs           # State machine + key handler\n│       ├── form.rs          # Provider form state\n│       ├── i18n.rs          # Bilingual (EN/ZH)\n│       └── ui/              # Rendering (chrome, pages, overlays)\n├── src/                     # JavaScript layer (pi extension support)\n├── extensions/index.ts      # Pi agent extension (/piswitch)\n├── extensions/failover-watchdog.ts  # Pi agent extension (recovery event → \"continue\" bridge)\n└── Cargo.toml\n```\n\n**Config files:**\n- `~/.pi-switch/config.json` — profiles, proxy settings, failover chain\n- `~/.pi-switch/requests.log` — per-request JSON log (status, latency, token usage, conversation id)\n- `~/.pi-switch/backups/` — timestamped auto-backups on every mutation\n- `~/.pi/agent/models.json` — pi's provider registry (pi-switch writes a single gateway provider)\n- `~/.pi-switch/recovery.jsonl` — recovery events emitted by the monitor (watched by the pi extension; events carry the affected `x-conversation-id`s)\n\n---\n\n## ❓ FAQ\n\n<details>\n<summary><b>How do I switch models in pi?</b></summary>\n<br>\n\nIn pi, open `/model` and pick any advertised `profile/model` (e.g. `provider-a/gpt-5.4`). The proxy routes by the model name in each request — no extra step needed.\n\nTo add more models, expose them in TUI (`Profiles → select provider → x`) or via CLI:\n```bash\npi-switch provider expose <name> <model-id>...\n```\n\n</details>\n\n<details>\n<summary><b>How do I set up failover?</b></summary>\n<br>\n\nIn TUI: `Settings → Failover rules` → `Enter`. Each rule pairs match conditions\n(`modelPrefix` / `modelContains`, ANDed) with an ordered provider chain:\n\n```json\n{\n  \"match\": { \"modelPrefix\": \"deepseek\" },\n  \"providers\": [\"deepseek-a\", \"deepseek-b\"]\n}\n```\n\nOr via CLI:\n```bash\npi-switch proxy rules set '[{\"match\":{\"modelPrefix\":\"deepseek\"},\"providers\":[\"deepseek-a\",\"deepseek-b\"]}]'\n```\n\nThe first matching rule wins; its providers are tried in order when the primary fails.\nRules are matched against the requested model id (the part after `profile/`).\n\n</details>\n\n<details>\n<summary><b>What does the [proxy] badge mean?</b></summary>\n\n<br>\n\nThe `[proxy]` badge indicates this profile is a meta-profile (with `\"proxy\": true`). Proxy profiles are used to register a pi provider that points to the local gateway. They are excluded from upstream routing.\n\nIn the current gateway mode, proxy profiles are typically not needed — the proxy automatically writes a single `pi-switch` gateway provider to pi's models.json on startup.\n\n</details>\n\n<details>\n<summary><b>How does gateway routing work?</b></summary>\n\n<br>\n\nThe proxy advertises every exposed model as `profile/realModelId` under a single `pi-switch` provider. When pi sends a request with `\"model\": \"provider-a/gpt-5.4\"`, the proxy:\n\n1. Splits on the first `/` — profile `provider-a`, real model `gpt-5.4`\n2. Routes to the `provider-a` profile's upstream, rewriting `body.model` to `gpt-5.4`\n3. On failure (429/5xx), follows the first matching rule's provider chain (or falls back\nto any other profile exposing `gpt-5.4` when no rule matches)\n\n```bash\n# 1. Expose models (per profile)\npi-switch provider expose provider-a gpt-5.4\npi-switch provider expose provider-b gpt-5.4\n\n# 2. Set failover rules (optional)\npi-switch proxy rules set '[{\"match\":{\"modelPrefix\":\"gpt\"},\"providers\":[\"provider-a\",\"provider-b\"]}]'\n\n# 3. Start proxy daemon\npi-switch proxy start --daemon\n```\n\nIn pi, select the `pi-switch` provider, then `provider-a/gpt-5.4`. The model name in each request determines the route — no \"target\" to manage.\n\n</details>\n\n<details>\n<summary><b>How does User-Agent disguise work?</b></summary>\n<br>\n\nSome upstream channels only accept requests from whitelisted clients (checking the User-Agent name prefix). pi-switch has three built-in presets that send the matching client's real identity:\n\n| Preset | User-Agent | Extra headers |\n|--------|------------|---------------|\n| Claude Code | `claude-cli/2.1.161 (external, cli)` | `anthropic-version`, `anthropic-beta` |\n| Codex | `codex_cli_rs/0.1.0` | — |\n| Gemini | `gemini-cli/0.1.5` | `x-goog-api-client` |\n\n- **Global**: `Settings → User-Agent`, cycle with `←/→`.\n- **Per-profile**: in a profile's detail view press `u` to cycle; a per-profile value overrides the global one. Useful when only some upstreams enforce a UA whitelist.\n\nNote: this only passes checks that look at the client name. It does not fabricate deeper per-request tokens (turn state, session ids), which strict first-party endpoints validate.\n\n</details>\n\n<details>\n<summary><b>Where is my data stored?</b></summary>\n<br>\n\nEverything under `~/.pi-switch/`. Pi's own registry is `~/.pi/agent/models.json`. No data leaves your machine.\n\n</details>\n\n---\n\n## 🛠️ Development\n\n```bash\nnpm run build:native:debug     # Build Rust addon (debug)\nnpm run build:native           # Build Rust addon (release)\ncargo build                    # Rust-only build\ncargo clippy                   # Lint\ncargo fmt                      # Format\ncargo test --release --lib     # Run unit tests\n```\n\n**Note:** Stop the TUI/daemon before `npm run build:native` to avoid file-lock errors on Windows.\n\n---\n\n## 🙏 Acknowledgments\n\n- **[cc-switch](https://github.com/farion1231/cc-switch)** — the original TUI-based profile switcher for Claude Code, which pioneered the interactive terminal UI pattern and proxy failover design\n- **[cc-switch-cli](https://github.com/SaladDay/cc-switch-cli)** — the CLI counterpart, providing a clean command-line interface for provider management\n\nThanks also to the **[LINUX DO](https://linux.do/)** community for the discussions that sparked this project.\n\n---\n\n## 📜 License\n\nMIT\n","readmeFilename":"README.md"}