{"_id":"@eddieparc/senpi-accounts","_rev":"13-b5304dceceb74d62ffce126d10452bf1","name":"@eddieparc/senpi-accounts","dist-tags":{"latest":"0.4.5"},"versions":{"0.2.0":{"name":"@eddieparc/senpi-accounts","version":"0.2.0","keywords":["pi-package","senpi","senpi-extension","kiro","multi-account","provider-accounts"],"license":"MIT","_id":"@eddieparc/senpi-accounts@0.2.0","maintainers":[{"name":"eddieparc","email":"jgp3620@gmail.com"}],"pi":{"extensions":["./dist/index.js"]},"dist":{"shasum":"f29fb32f3b615856ffa301682a80180d7983476e","tarball":"https://registry.npmjs.org/@eddieparc/senpi-accounts/-/senpi-accounts-0.2.0.tgz","fileCount":73,"integrity":"sha512-3bPf0524/yfLn/PRAn6W9BuOBfSLwRA/6Bdu5F/fYL40P54WcCL6NQxawW83a7jK+Ojx9s/bNMMOU9DE5nl2gg==","signatures":[{"sig":"MEQCIB0zwpYCP0SKdlodtLEdpROYnbVg03QcwqBl/Yyi89iCAiA9ntuyz34uEDpWRkf+SaHBiA7R6Q8nUZk2ly6oGaVRug==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":266669},"type":"module","gitHead":"3eca9ddee2c72a8703aa1409b16e02fda84b0c24","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","prepare":"[ -f tsconfig.build.json ] && npm run build || exit 0","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"eddieparc","email":"jgp3620@gmail.com"},"deprecated":"Broken: a turn with two or more tool calls fails with \"Invalid native tool call event order\" and senpi discards every tool call in that turn. Fixed in 0.2.2 -- please upgrade.","_npmVersion":"11.11.0","description":"Senpi addon: multi-account subscription providers (Kiro) with cache-preserving routing, usage-aware placement and 429 failover.","directories":{},"_nodeVersion":"24.14.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.10","typescript":"^5.9.3","@types/node":"^24.13.3","@code-yeongyu/senpi":"^2026.7.29"},"peerDependencies":{"@code-yeongyu/senpi":">=2026.7.28"},"_npmOperationalInternal":{"tmp":"tmp/senpi-accounts_0.2.0_1785427109188_0.471440637383576","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@eddieparc/senpi-accounts","version":"0.2.1","keywords":["pi-package","senpi","senpi-extension","kiro","multi-account","provider-accounts"],"license":"MIT","_id":"@eddieparc/senpi-accounts@0.2.1","maintainers":[{"name":"eddieparc","email":"jgp3620@gmail.com"}],"pi":{"extensions":["./dist/index.js"]},"dist":{"shasum":"a3ceea7e3fba110950a080472de808298413ce35","tarball":"https://registry.npmjs.org/@eddieparc/senpi-accounts/-/senpi-accounts-0.2.1.tgz","fileCount":73,"integrity":"sha512-kDX0D6sCWNATh5ewJU0OPJUWMP+xbf1SPzYzD8EKYSBfzjL7+ldCDcvEpazQbrszHDyyxZGqFgaUa335hbe5jw==","signatures":[{"sig":"MEUCIDv1XqAnxynko9vqkQ073+0Az+yFMJ4ePLWMHblTldpvAiEAl2nGASFJbLOfAnligs6D8bbPaa8RMXbT5GDnUXKrN30=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":267033},"type":"module","gitHead":"b0e9279d1936a2253b0f418075d5b840c7640f51","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","prepare":"[ -f tsconfig.build.json ] && npm run build || exit 0","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"eddieparc","email":"jgp3620@gmail.com"},"deprecated":"Broken: a turn with two or more tool calls fails with \"Invalid native tool call event order\" and senpi discards every tool call in that turn. Fixed in 0.2.2 -- please upgrade.","_npmVersion":"11.11.0","description":"Senpi addon: multi-account subscription providers (Kiro) with cache-preserving routing, usage-aware placement and 429 failover.","directories":{},"_nodeVersion":"24.14.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.10","typescript":"^5.9.3","@types/node":"^24.13.3","@code-yeongyu/senpi":"^2026.7.29"},"peerDependencies":{"@code-yeongyu/senpi":">=2026.7.28"},"_npmOperationalInternal":{"tmp":"tmp/senpi-accounts_0.2.1_1785427435920_0.5139531918859517","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@eddieparc/senpi-accounts","version":"0.2.2","keywords":["pi-package","senpi","senpi-extension","kiro","multi-account","provider-accounts"],"license":"MIT","_id":"@eddieparc/senpi-accounts@0.2.2","maintainers":[{"name":"eddieparc","email":"jgp3620@gmail.com"}],"pi":{"extensions":["./dist/index.js"]},"dist":{"shasum":"14dc0fd4cd45035cbd216151e75161822d37c8cb","tarball":"https://registry.npmjs.org/@eddieparc/senpi-accounts/-/senpi-accounts-0.2.2.tgz","fileCount":71,"integrity":"sha512-1tP0lN9Ko1yoFKwYq15mIX4+PG516KfKwtLOrkB+0cp5caBcflFCKgFRrC/98CqQo83OkDFLcso2B+NEjgtTkg==","signatures":[{"sig":"MEUCIGxhREtSXEdnANOse50X92wxZ7MQn4qi/PiU1VfMHXpsAiEAwRBdbZMdkWat68DxpawVGDu/5h66rr6pjNIPJZADvc0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":261408},"type":"module","gitHead":"85f81d054334324191249ab940691d5cbcd7950e","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","prepare":"[ -f tsconfig.build.json ] && npm run build || exit 0","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"eddieparc","email":"jgp3620@gmail.com"},"_npmVersion":"11.11.0","description":"Senpi addon: multi-account subscription providers (Kiro) with cache-preserving routing, usage-aware placement and 429 failover.","directories":{},"_nodeVersion":"24.14.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.10","typescript":"^5.9.3","@types/node":"^24.13.3","@code-yeongyu/senpi":"^2026.7.29"},"peerDependencies":{"@code-yeongyu/senpi":">=2026.7.28"},"_npmOperationalInternal":{"tmp":"tmp/senpi-accounts_0.2.2_1785431662725_0.34349236631119884","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"name":"@eddieparc/senpi-accounts","version":"0.2.3","keywords":["pi-package","senpi","senpi-extension","kiro","multi-account","provider-accounts"],"license":"MIT","_id":"@eddieparc/senpi-accounts@0.2.3","maintainers":[{"name":"eddieparc","email":"jgp3620@gmail.com"}],"homepage":"https://github.com/eddieparc/senpi-accounts#readme","bugs":{"url":"https://github.com/eddieparc/senpi-accounts/issues"},"pi":{"extensions":["./dist/index.js"]},"dist":{"shasum":"90acfca15d5f442a32ea647a7257f066aebb27f6","tarball":"https://registry.npmjs.org/@eddieparc/senpi-accounts/-/senpi-accounts-0.2.3.tgz","fileCount":71,"integrity":"sha512-V6Q7nQ3HFRqzFVPOzvV2BrRHeXqDPByy1M2b6VI6Y7RyfHgNj5EFATSrtSs9EJj6O46mDWnwcn0Nq+tKyeXzxA==","signatures":[{"sig":"MEQCIChvZTKWnh09dGNUFBnO42pAFjNax7YznDaf43vPhQkfAiAC2ze9SssTXNHmMWorks4kQ+R6kpyWFwzWyBOcd14OFw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eddieparc%2fsenpi-accounts@0.2.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":261664},"type":"module","gitHead":"0da7fb9f08bb9dd9685acc5c6987c096a8b4a77f","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","prepare":"[ -f tsconfig.build.json ] && npm run build || exit 0","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:4efd9388-d0e7-4181-9818-96806520deff"}},"repository":{"url":"git+https://github.com/eddieparc/senpi-accounts.git","type":"git"},"_npmVersion":"11.16.0","description":"Senpi addon: multi-account subscription providers (Kiro) with cache-preserving routing, usage-aware placement and 429 failover.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.10","typescript":"^5.9.3","@types/node":"^24.13.3","@code-yeongyu/senpi":"^2026.7.29"},"peerDependencies":{"@code-yeongyu/senpi":">=2026.7.28"},"_npmOperationalInternal":{"tmp":"tmp/senpi-accounts_0.2.3_1785459596139_0.5245000730076221","host":"s3://npm-registry-packages-npm-production"}},"0.2.4":{"name":"@eddieparc/senpi-accounts","version":"0.2.4","keywords":["pi-package","senpi","senpi-extension","kiro","multi-account","provider-accounts"],"license":"MIT","_id":"@eddieparc/senpi-accounts@0.2.4","maintainers":[{"name":"eddieparc","email":"jgp3620@gmail.com"}],"homepage":"https://github.com/eddieparc/senpi-accounts#readme","bugs":{"url":"https://github.com/eddieparc/senpi-accounts/issues"},"pi":{"extensions":["./dist/index.js"]},"dist":{"shasum":"b0074ab65b114f58770d90050d2fcadc4674dd93","tarball":"https://registry.npmjs.org/@eddieparc/senpi-accounts/-/senpi-accounts-0.2.4.tgz","fileCount":71,"integrity":"sha512-tc7aqNrmTwdXsFjqs9KyeI1IRYS8RtfVnfj+hlfNjNLUB7RNttr3oz3hT3rdzVlagc49d7XCxq3gEy9FcbMxBg==","signatures":[{"sig":"MEUCIBuRPpBhsCb27uTNKV7eT2XvXCg5XfvsqMnlvO2lG1/FAiEA51qOofZgJWab1ND9szNaYWwQV1XU4xtC6lvE4eNBDrw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eddieparc%2fsenpi-accounts@0.2.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":262733},"type":"module","gitHead":"2263158ee9809b3543c104b39204943a35c42118","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","prepare":"[ -f tsconfig.build.json ] && npm run build || exit 0","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:4efd9388-d0e7-4181-9818-96806520deff"}},"repository":{"url":"git+https://github.com/eddieparc/senpi-accounts.git","type":"git"},"_npmVersion":"11.16.0","description":"Senpi addon: multi-account subscription providers (Kiro) with cache-preserving routing, usage-aware placement and 429 failover.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.10","typescript":"^5.9.3","@types/node":"^24.13.3","@code-yeongyu/senpi":"^2026.7.29"},"peerDependencies":{"@code-yeongyu/senpi":">=2026.7.28"},"_npmOperationalInternal":{"tmp":"tmp/senpi-accounts_0.2.4_1785461386132_0.613668079283431","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@eddieparc/senpi-accounts","version":"0.3.0","keywords":["pi-package","senpi","senpi-extension","kiro","multi-account","provider-accounts"],"license":"MIT","_id":"@eddieparc/senpi-accounts@0.3.0","maintainers":[{"name":"eddieparc","email":"jgp3620@gmail.com"}],"homepage":"https://github.com/eddieparc/senpi-accounts#readme","bugs":{"url":"https://github.com/eddieparc/senpi-accounts/issues"},"pi":{"extensions":["./dist/index.js"]},"dist":{"shasum":"e3b6946ed59ebf490af124103efbec9a7baa0461","tarball":"https://registry.npmjs.org/@eddieparc/senpi-accounts/-/senpi-accounts-0.3.0.tgz","fileCount":73,"integrity":"sha512-+ApVmoIguW+7p3nNhztmJn/+R3HN4g3RjyVLwGf6EA0iB7froKLybJLLasDGboCsQf3holmD9amA1S/8m/Qtww==","signatures":[{"sig":"MEYCIQCre/7K0m0x4kfYrVf9kXS5Jy9UZx2i1rLVjAROiqy+wgIhAJ9hD0MiFNk1T2oTELRtPxexUWgtWFSRE8WNGjkVg5Ox","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eddieparc%2fsenpi-accounts@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":276347},"type":"module","gitHead":"3ccbf5892a9f94e898a934c2f5952f1d4675ddb3","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","prepare":"[ -f tsconfig.build.json ] && npm run build || exit 0","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:4efd9388-d0e7-4181-9818-96806520deff"}},"repository":{"url":"git+https://github.com/eddieparc/senpi-accounts.git","type":"git"},"_npmVersion":"11.16.0","description":"Senpi addon: multi-account subscription providers (Kiro) with cache-preserving routing, usage-aware placement and 429 failover.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.10","typescript":"^5.9.3","@types/node":"^24.13.3","@code-yeongyu/senpi":"^2026.7.29"},"peerDependencies":{"@code-yeongyu/senpi":">=2026.7.28"},"_npmOperationalInternal":{"tmp":"tmp/senpi-accounts_0.3.0_1785473419262_0.5960820899173658","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@eddieparc/senpi-accounts","version":"0.4.0","keywords":["pi-package","senpi","senpi-extension","kiro","multi-account","provider-accounts"],"license":"MIT","_id":"@eddieparc/senpi-accounts@0.4.0","maintainers":[{"name":"eddieparc","email":"jgp3620@gmail.com"}],"homepage":"https://github.com/eddieparc/senpi-accounts#readme","bugs":{"url":"https://github.com/eddieparc/senpi-accounts/issues"},"pi":{"extensions":["./dist/index.js"]},"dist":{"shasum":"d611807713088b7a04cdc8790e169c33a4941ab2","tarball":"https://registry.npmjs.org/@eddieparc/senpi-accounts/-/senpi-accounts-0.4.0.tgz","fileCount":73,"integrity":"sha512-EM159TFFuKoShRkl00QEDUSQvCYysL07gLBQAxCPez2va3A7hOWyzc3KGq+yYV0e2SwM3jiv56hR5SIO/adQ9A==","signatures":[{"sig":"MEYCIQDak73A6F8W8UgTyqMOcUu09vmGxPoAedH6Q2ohy4a2OQIhAMwh4fyNG/2/H9cCF4cL0u+1ubEg9dUsH2qHR7yaEg1y","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eddieparc%2fsenpi-accounts@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":285598},"type":"module","gitHead":"c228ba2fce92dca27557cbd3cef8541bf163f733","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","prepare":"[ -f tsconfig.build.json ] && npm run build || exit 0","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:4efd9388-d0e7-4181-9818-96806520deff"}},"repository":{"url":"git+https://github.com/eddieparc/senpi-accounts.git","type":"git"},"_npmVersion":"11.16.0","description":"Senpi addon: multi-account subscription providers (Kiro) with cache-preserving routing, usage-aware placement and 429 failover.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.10","typescript":"^5.9.3","@types/node":"^24.13.3","@code-yeongyu/senpi":"^2026.7.29"},"peerDependencies":{"@code-yeongyu/senpi":">=2026.7.28"},"_npmOperationalInternal":{"tmp":"tmp/senpi-accounts_0.4.0_1785479780858_0.859303793427459","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@eddieparc/senpi-accounts","version":"0.4.1","keywords":["pi-package","senpi","senpi-extension","kiro","multi-account","provider-accounts"],"license":"MIT","_id":"@eddieparc/senpi-accounts@0.4.1","maintainers":[{"name":"eddieparc","email":"jgp3620@gmail.com"}],"homepage":"https://github.com/eddieparc/senpi-accounts#readme","bugs":{"url":"https://github.com/eddieparc/senpi-accounts/issues"},"pi":{"extensions":["./dist/index.js"]},"dist":{"shasum":"3b6cfa7d4773f737de8646ed6dbd6f3562652161","tarball":"https://registry.npmjs.org/@eddieparc/senpi-accounts/-/senpi-accounts-0.4.1.tgz","fileCount":73,"integrity":"sha512-T7EzXDeFRO9DKxqM5HV8Rt46NnqMnnUhW6W2tasd7nVr2NEPsTlKMU14g02Q6e6K1w7b2GsQ0GjYm6vslI7PLg==","signatures":[{"sig":"MEYCIQDwKfLl2j2P6DF69gOhtHnzTBOPI+e39MDuNj3zHns0sgIhAJZtBkzCT+Pe0sG6Kk5Abitfg2SeNMM0h4TTYq18FljJ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eddieparc%2fsenpi-accounts@0.4.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":288398},"type":"module","gitHead":"df3fd68e7380d3fbbba2fdc04d4538e05a67d84a","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","prepare":"[ -f tsconfig.build.json ] && npm run build || exit 0","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:4efd9388-d0e7-4181-9818-96806520deff"}},"repository":{"url":"git+https://github.com/eddieparc/senpi-accounts.git","type":"git"},"_npmVersion":"11.16.0","description":"Senpi addon: multi-account subscription providers (Kiro) with cache-preserving routing, usage-aware placement and 429 failover.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"proper-lockfile":"4.1.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.10","typescript":"^5.9.3","@types/node":"^24.13.3","@code-yeongyu/senpi":"^2026.7.29"},"peerDependencies":{"@code-yeongyu/senpi":">=2026.7.28"},"_npmOperationalInternal":{"tmp":"tmp/senpi-accounts_0.4.1_1785723102640_0.8969939811535532","host":"s3://npm-registry-packages-npm-production"}},"0.4.2":{"name":"@eddieparc/senpi-accounts","version":"0.4.2","keywords":["pi-package","senpi","senpi-extension","kiro","multi-account","provider-accounts"],"license":"MIT","_id":"@eddieparc/senpi-accounts@0.4.2","maintainers":[{"name":"eddieparc","email":"jgp3620@gmail.com"}],"homepage":"https://github.com/eddieparc/senpi-accounts#readme","bugs":{"url":"https://github.com/eddieparc/senpi-accounts/issues"},"pi":{"extensions":["./dist/index.js"]},"dist":{"shasum":"a96d8fbd2e58b37d7596cf45c65966d98315580a","tarball":"https://registry.npmjs.org/@eddieparc/senpi-accounts/-/senpi-accounts-0.4.2.tgz","fileCount":73,"integrity":"sha512-/Mw6Tf4zPhXi3BSo46IFbsxtNywto4bt2ycF+lpGUrmvKkwhmQ/L+2rJtMNB4eQBpYTCzxVh5KpRhVVZB+wMgQ==","signatures":[{"sig":"MEUCIQC/bM6cEpdTlZ9kVutOQPVrPxwM0hJGtWuZzrj0QT/c7QIgF3DE63lVoYaCUW3wq6ipSsb3UnT9Ytm6PVGjHMVYcNI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eddieparc%2fsenpi-accounts@0.4.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":293460},"type":"module","gitHead":"f1799552ff941474abc5ffc35d02aa651c2f65f1","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","prepare":"[ -f tsconfig.build.json ] && npm run build || exit 0","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:4efd9388-d0e7-4181-9818-96806520deff"}},"repository":{"url":"git+https://github.com/eddieparc/senpi-accounts.git","type":"git"},"_npmVersion":"11.16.0","description":"Senpi addon: multi-account subscription providers (Kiro) with cache-preserving routing, usage-aware placement and 429 failover.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"proper-lockfile":"4.1.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.10","typescript":"^5.9.3","@types/node":"^24.13.3","@code-yeongyu/senpi":"^2026.7.29"},"peerDependencies":{"@code-yeongyu/senpi":">=2026.7.28"},"_npmOperationalInternal":{"tmp":"tmp/senpi-accounts_0.4.2_1785731904529_0.8659255138600062","host":"s3://npm-registry-packages-npm-production"}},"0.4.3":{"name":"@eddieparc/senpi-accounts","version":"0.4.3","keywords":["pi-package","senpi","senpi-extension","kiro","multi-account","provider-accounts"],"license":"MIT","_id":"@eddieparc/senpi-accounts@0.4.3","maintainers":[{"name":"eddieparc","email":"jgp3620@gmail.com"}],"homepage":"https://github.com/eddieparc/senpi-accounts#readme","bugs":{"url":"https://github.com/eddieparc/senpi-accounts/issues"},"pi":{"extensions":["./dist/index.js"]},"dist":{"shasum":"9a44aaf040005b73715914708643d8687854baa3","tarball":"https://registry.npmjs.org/@eddieparc/senpi-accounts/-/senpi-accounts-0.4.3.tgz","fileCount":73,"integrity":"sha512-ano61HJODw9HQgFzhF4qfzWz0V+e1Z/Yora0L8F7EY3McIudVfUcVzJEqPdvvtiAfuk6OLM+8HE78yiP9rgHtw==","signatures":[{"sig":"MEUCIQDQuQ+2M9laBmaxvo7VMsMPyMYIcgVR6x8bmvq+iwE8DAIgDG4vzGyHLCWZ4pAx9r6GiEEWkLYyf+/gFEqgEyolKzY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eddieparc%2fsenpi-accounts@0.4.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":293461},"type":"module","gitHead":"5900908a9b2f62b0d9ea44b5994f54322dd640cc","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","prepare":"[ -f tsconfig.build.json ] && npm run build || exit 0","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:4efd9388-d0e7-4181-9818-96806520deff"}},"repository":{"url":"git+https://github.com/eddieparc/senpi-accounts.git","type":"git"},"_npmVersion":"11.16.0","description":"Senpi addon: multi-account subscription providers (Kiro) with cache-preserving routing, usage-aware placement and 429 failover.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"proper-lockfile":"4.1.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.10","typescript":"^5.9.3","@types/node":"^24.13.3","@code-yeongyu/senpi":"2026.8.3-3"},"peerDependencies":{"@code-yeongyu/senpi":">=2026.8.3-3"},"_npmOperationalInternal":{"tmp":"tmp/senpi-accounts_0.4.3_1785767389303_0.8269470489130994","host":"s3://npm-registry-packages-npm-production"}},"0.4.4":{"name":"@eddieparc/senpi-accounts","version":"0.4.4","keywords":["pi-package","senpi","senpi-extension","kiro","multi-account","provider-accounts"],"license":"MIT","_id":"@eddieparc/senpi-accounts@0.4.4","maintainers":[{"name":"eddieparc","email":"jgp3620@gmail.com"}],"homepage":"https://github.com/eddieparc/senpi-accounts#readme","bugs":{"url":"https://github.com/eddieparc/senpi-accounts/issues"},"pi":{"extensions":["./dist/index.js"]},"dist":{"shasum":"d2fbf62249cd48379c2104119c84ec1c9651d23e","tarball":"https://registry.npmjs.org/@eddieparc/senpi-accounts/-/senpi-accounts-0.4.4.tgz","fileCount":75,"integrity":"sha512-2MkszWGUad+pJMpr+1qEwReFvIA/hiwDw+hOpEh8qKKhDJ5o1EWW46rXPyvyDF71sl5soDbe7TAoUccnY6HuEw==","signatures":[{"sig":"MEUCID5NIvbcu1wayJLZmFGtMl5O2BFFOeKtUQLuf6ioaSmeAiEAktxLtaasXl2mSvvtFmjWY21/e44eKWFEZFW7xOP/sMc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eddieparc%2fsenpi-accounts@0.4.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":298314},"type":"module","gitHead":"13254792ce86f664189c7bb0c913663679a65c4a","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","prepare":"[ -f tsconfig.build.json ] && npm run build || exit 0","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:4efd9388-d0e7-4181-9818-96806520deff"}},"repository":{"url":"git+https://github.com/eddieparc/senpi-accounts.git","type":"git"},"_npmVersion":"11.16.0","description":"Senpi addon: multi-account subscription providers (Kiro) with cache-preserving routing, usage-aware placement and 429 failover.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"proper-lockfile":"4.1.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.10","typescript":"^5.9.3","@types/node":"^24.13.3","@code-yeongyu/senpi":"2026.8.3-3"},"peerDependencies":{"@code-yeongyu/senpi":">=2026.8.3-3"},"_npmOperationalInternal":{"tmp":"tmp/senpi-accounts_0.4.4_1785802900722_0.0022857562570002266","host":"s3://npm-registry-packages-npm-production"}},"0.4.5":{"name":"@eddieparc/senpi-accounts","version":"0.4.5","description":"Senpi addon: multi-account subscription providers (Kiro) with cache-preserving routing, usage-aware placement and 429 failover.","type":"module","license":"MIT","repository":{"type":"git","url":"git+https://github.com/eddieparc/senpi-accounts.git"},"homepage":"https://github.com/eddieparc/senpi-accounts#readme","bugs":{"url":"https://github.com/eddieparc/senpi-accounts/issues"},"keywords":["pi-package","senpi","senpi-extension","kiro","multi-account","provider-accounts"],"publishConfig":{"access":"public"},"pi":{"extensions":["./dist/index.js"]},"scripts":{"build":"tsc -p tsconfig.build.json","test":"vitest run","typecheck":"tsc --noEmit","prepare":"[ -f tsconfig.build.json ] && npm run build || exit 0","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"peerDependencies":{"@code-yeongyu/senpi":">=2026.8.3-3"},"dependencies":{"proper-lockfile":"4.1.2"},"devDependencies":{"@code-yeongyu/senpi":"2026.8.3-3","@types/node":"^24.13.3","typescript":"^5.9.3","vitest":"^4.1.10"},"gitHead":"254b19de0d7db09cc6d4046d9a821b3afe64fbf2","_id":"@eddieparc/senpi-accounts@0.4.5","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-Q8LpgB3E0BIfEGo5dBsmPFTcfP7Mcd8UYd6RPV+jIbAR9457eO/i2DxDtCEk1OUjRNqtElwZktQzZulONM61vA==","shasum":"875a321e49b2b918eda76aeb78842ed09d7772a4","tarball":"https://registry.npmjs.org/@eddieparc/senpi-accounts/-/senpi-accounts-0.4.5.tgz","fileCount":75,"unpackedSize":299242,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@eddieparc%2fsenpi-accounts@0.4.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDrwJzfnn5WwDIHhCimzOwLkuOV0FvJBRs9kB54/70iTgIgb8uq0dMjKgYmtq5RyIKwH8qKdSDNqkIUSw1xK91sJL4="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:4efd9388-d0e7-4181-9818-96806520deff"}},"directories":{},"maintainers":[{"name":"eddieparc","email":"jgp3620@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/senpi-accounts_0.4.5_1787802916542_0.6478976512952217"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-30T15:58:29.006Z","modified":"2026-08-27T03:55:17.058Z","0.2.0":"2026-07-30T15:58:29.424Z","0.2.1":"2026-07-30T16:03:56.038Z","0.2.2":"2026-07-30T17:14:22.881Z","0.2.3":"2026-07-31T00:59:56.299Z","0.2.4":"2026-07-31T01:29:46.428Z","0.3.0":"2026-07-31T04:50:19.490Z","0.4.0":"2026-07-31T06:36:21.009Z","0.4.1":"2026-08-03T02:11:42.772Z","0.4.2":"2026-08-03T04:38:24.679Z","0.4.3":"2026-08-03T14:29:49.446Z","0.4.4":"2026-08-04T00:21:40.918Z","0.4.5":"2026-08-27T03:55:16.733Z"},"bugs":{"url":"https://github.com/eddieparc/senpi-accounts/issues"},"license":"MIT","homepage":"https://github.com/eddieparc/senpi-accounts#readme","keywords":["pi-package","senpi","senpi-extension","kiro","multi-account","provider-accounts"],"repository":{"type":"git","url":"git+https://github.com/eddieparc/senpi-accounts.git"},"description":"Senpi addon: multi-account subscription providers (Kiro) with cache-preserving routing, usage-aware placement and 429 failover.","maintainers":[{"name":"eddieparc","email":"jgp3620@gmail.com"}],"readme":"# senpi-accounts\n\nMulti-account subscription providers for [senpi](https://github.com/code-yeongyu/senpi),\nwith cache-preserving routing, usage-aware placement and automatic 429 failover.\n\nStock senpi is the base layer and is never modified. This addon sits on top of it and\nfills only the gaps stock leaves.\n\n> ### Purpose and scope\n>\n> **This is an open-source project published for learning and research purposes.** It\n> exists to explore how senpi's extension API composes providers, how prompt-cache\n> affinity interacts with account rotation, and how subscription rate limits surface\n> through a provider SDK.\n>\n> It automates nothing you could not do by hand: it signs in with **your own**\n> subscriptions, through each vendor's normal OAuth flow, and stores the resulting\n> tokens in senpi's own `auth.json`. It does not share, pool, resell or redistribute\n> accounts, and it does not bypass any vendor's authentication, billing or rate limits\n> — when a subscription is exhausted this addon simply reports it and stops using that\n> account until the vendor's own reset time.\n>\n> You are responsible for complying with the terms of service of every provider you\n> configure. Review them before using multiple accounts. Provided as-is, without\n> warranty, under the MIT licence.\n\n## What this addon adds\n\n| Capability | Status | Where it comes from |\n|---|---|---|\n| **Kiro** subscription provider (Google / GitHub / AWS Builder ID) | **shipped, live-verified** | this addon |\n| Multi-account pool with pin, rotation, 429 failover and timed failback | **shipped, live-verified** | this addon |\n| Cache-preserving conversation affinity + usage-aware placement | shipped | this addon |\n| Per-account and full logout; `cache-first` / `balanced` / `spread` modes | shipped | this addon |\n| `/usage` dashboard across every subscription | shipped | this addon |\n| **TokenRouter** provider (117 models behind one key) | **shipped, live-verified** | this addon |\n| **OpenGateway** provider (Kimi K3 Ultrafast) | shipped | this addon |\n| **OpenAI Codex account pool** | experimental, enabled | this addon |\n| Anthropic multi-account | stock | `/claude-account` |\n| Alibaba Model Studio workspace | validated API-key login | this addon |\n| Alibaba Token Plan, OpenCode Go | stock | plan/API-key providers |\n\nNothing marked *stock* is reimplemented here; the addon only surfaces it in the usage\ndashboard.\n\n**Kiro is the supported provider in this release.** It is verified against the live API:\nfour models (`claude-opus-5`, `claude-opus-4.7`, `claude-sonnet-4.6`, `claude-haiku-4.5`),\ntwo real accounts, per-account pinning, failover onto a second account when the first is\nrejected, automatic token refresh, and recovery after a cooldown expires.\n\n### Two stock bugs found while building this\n\nBoth were reported upstream rather than worked around here:\n\n- [senpi#503](https://github.com/code-yeongyu/senpi/pull/503) — `/fast` can never succeed.\n  The command is registered only for `openai-codex`, but the catalog generator emits\n  `-fast` priority variants only for the direct `openai` provider. Measured against\n  `chatgpt.com`, `service_tier: \"priority\"` returns HTTP 200 and is then served at normal\n  tier, while senpi bills it at up to 2.5x — so synthesising the missing variants would be\n  a placebo that inflates reported cost. Fast mode is therefore **not** implemented here;\n  the PR corrects the misleading message instead.\n- [senpi#505](https://github.com/code-yeongyu/senpi/pull/505) — Claude multi-account never\n  rotates. Plan exhaustion arrives as prose (\"You've hit your weekly limit\") or as a bare\n  `error_during_execution` with the cause only in `terminal_reason`, and neither was\n  classified as a rate limit, so the exhausted account was never blocked.\n\n## Install\n\nRequires senpi `>= 2026.7.28` (verified against `2026.7.30`).\n\n**One command** — from the npm registry:\n\n```bash\nnpm install @eddieparc/senpi-accounts\n```\n\nThe git route works too and compiles on install:\n\n```bash\nnpm install github:eddieparc/senpi-accounts\n```\n\nnpm runs the package's `prepare` script for a git dependency, so `dist/` is\ncompiled during install. Then point senpi at the built entry:\n\n```text\nsenpi -e ./node_modules/@eddieparc/senpi-accounts\n```\n\nOr use the tarball attached to the\n[v0.2.0 release](https://github.com/eddieparc/senpi-accounts/releases/tag/v0.2.0):\n\n```text\nnpm install ./eddieparc-senpi-accounts-0.2.0.tgz\n```\n\n**From source** — the path this repo is developed against:\n\n```bash\ngit clone https://github.com/eddieparc/senpi-accounts.git\ncd senpi-accounts\nnpm install\nnpm run build\n```\n\nThen either load it per-run (substitute your own checkout path):\n\n```text\nsenpi -e /absolute/path/to/senpi-accounts\n```\n\nor enable it for every session by adding the built entry point to `extensions` in\n`~/.senpi/agent/settings.json`:\n\n```json\n{\n  \"extensions\": [\"/absolute/path/to/senpi-accounts/dist/index.js\"]\n}\n```\n\nPoint at `dist/index.js`, not the repository root. senpi enumerates a bare\ndirectory and would load `dist/` and `src/` as two separate extensions.\n\nVerify it loaded — this should print the Kiro models:\n\n```text\nsenpi -e /absolute/path/to/senpi-accounts --list-models | grep kiro\n```\n\n## Kiro setup\n\n```\n/login kiro\n```\n\n`/login kiro` is a full account manager, not just a one-shot login:\n\n| Action | What it does |\n|---|---|\n| Add an account | Google / GitHub / AWS Builder ID sign-in, then names the slot |\n| Log out of one account | Deletes one account, leaving the rest intact |\n| Log out of every account | Empties the pool, clearing the pin and bindings too |\n| Pin / Clear the pin | Force every request onto one account |\n| Clear a block | Lift a rate-limit or auth block early |\n| Scheduling mode | `cache-first` (default), `balanced` or `spread` |\n| Migration policy | `auto` (default), `ask` or `never` — see [Migration policy](#migration-policy) |\n\nBoth logout paths live inside `/login kiro`, which is the account manager. Full\nlogout asks for confirmation first, and clears the pin and conversation bindings\nalong with the accounts so nothing points at a slot that no longer exists.\n\nThen pick a model:\n\n```\n/model kiro/claude-opus-5\n```\n\nThe built-in catalog follows Kiro CLI 2.15.2 and includes its Claude, GPT-5.6,\nDeepSeek, MiniMax, GLM and Qwen options. Availability still depends on the\nselected account. To replace the catalog without waiting for a package update:\n\n```bash\nexport KIRO_MODELS_OVERRIDE=auto,claude-sonnet-5,gpt-5.6-sol\n```\n\nAutomatic completion probing is intentionally disabled because probes consume\ncredits and one pooled account's entitlement does not describe the whole pool.\n\nFor redacted Kiro protocol and request-failure diagnostics:\n\n```bash\nexport KIRO_DEBUG=1\n```\n\nThe log is written to `$SENPI_CODING_AGENT_DIR/debug/debug.log`. Credentials and\nauthorization values are redacted, and logging is off by default.\n\n### Adding a second or third Kiro account\n\nKiro federates Google sign-in through its own Cognito pool, and Google keeps a\nbrowser-wide SSO cookie. Two consequences:\n\n- Signing out of **Kiro** alone is not enough — Google silently re-authenticates the\n  same identity server-side, before any client-side `prompt=select_account` can apply.\n- Aside browser profiles do **not** help: they share one Google cookie jar, so every\n  profile presents the same default Google account.\n\nSo a second Kiro account needs the Google account switched first. This sequence\nworks:\n\n1. Sign out of Kiro: `https://app.kiro.dev/home` → account menu → **Sign Out**.\n2. Sign in to Google as the target account at `https://accounts.google.com/`.\n   These accounts use a **passkey**, so this step needs a human at the machine\n   (Touch ID); it cannot be automated.\n3. Confirm the switch stuck — `https://app.kiro.dev/signin` should say\n   \"currently signed in via Google as: <target>\".\n4. Run the scripted login; it binds whichever identity Kiro now holds.\n\nAll three Kiro auth methods were exercised and all three resolve to whichever\nidentity the browser/AWS session already holds:\n\n| Method | Result |\n|---|---|\n| Google | Kiro's Cognito session re-federates the current Google account |\n| GitHub | same Cognito session behaviour |\n| AWS Builder ID | device-code flow completes (`요청 승인됨`) but returns the same AWS identity |\n\nSo switching accounts is a browser/AWS session action, not something the addon\ncan drive. The duplicate guard below exists precisely because these flows all\n*succeed* while silently returning the identity you already had.\n\nVerify which identity was actually captured — the login prints the email:\n\n```\nUSAGE 0/0 jgplabs@gmail.com\nSAVED jgplabs\n```\n\nIf it prints the wrong address, the Google session did not switch; repeat step 2.\nAccounts are keyed by name, so a duplicate simply stores the same identity twice and\nyields no extra quota.\n\n### Scripted login\n\nFor CI or headless setup:\n\n```text\nSENPI_CODING_AGENT_DIR=~/.senpi/agent \\\n  npx tsx scripts/login.mts <account-name> [google|github|builder-id]\n```\n\nIt prints the authorize URL, captures the localhost callback automatically, and appends\nthe account to the pool.\n\n## Other subscriptions\n\nAlibaba now has two different key families that cannot share an endpoint:\n\n- Token/Coding Plan keys start with `sk-sp-`. Use stock `alibaba-token-plan`.\n- Workspace pay-as-you-go keys start with `sk-ws-`. Use this addon's\n  `alibaba-model-studio`.\n\nFor a workspace key, copy the **OpenAI compatible** endpoint shown next to the\nkey in Model Studio, then start senpi with it:\n\n```bash\nexport ALIBABA_MODEL_STUDIO_BASE_URL=\"https://<workspace>.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1\"\n```\n\nLogin through the validated provider:\n\n```text\n/login alibaba-model-studio\n```\n\nThe login accepts only `sk-ws-` keys and sends a one-token `qwen-plus` request\nto the configured workspace endpoint before Senpi stores the credential. A\nmalformed, revoked, or endpoint-mismatched key is rejected without echoing it.\n\nStock Token Plan and OpenCode Go remain available separately:\n\n```\n/login alibaba-token-plan     # or set ALIBABA_TOKEN_PLAN_API_KEY\n/login opencode-go            # or set OPENCODE_API_KEY\n```\n\nDo not put a `sk-ws-` key into `alibaba-token-plan`: the stock plan endpoint\nrejects workspace keys with `401 invalid_api_key`. Likewise, do not use a\n`sk-sp-` plan key with `alibaba-model-studio`.\n\n**Anthropic** multi-account is stock; use `/claude-account`. This addon does not\ntouch it.\n\n### TokenRouter\n\nTokenRouter fronts ~117 models behind one OpenAI-compatible endpoint, and stock senpi\nhas no `tokenrouter` provider — so the models are unreachable however the key is stored.\nThis addon registers the provider id, which is what puts TokenRouter in the `/login`\nlist:\n\n```\n/login tokenrouter            # or set TOKENROUTER_API_KEY\n```\n\nIssue the key at [tokenrouter.com](https://www.tokenrouter.com) under Console -> API\nKeys. There is no account pool: TokenRouter meters one account, so rotating keys would\nbuy nothing, and this is a single-credential provider like stock's `opencode-go`.\n\nThe catalog ships `moonshotai/kimi-k3`, `moonshotai/kimi-k3-free`,\n`deepseek/deepseek-v4-pro`, `qwen/qwen3.7-max` and `z-ai/glm-5.2`;\n`TOKENROUTER_MODELS_OVERRIDE=<comma-separated ids>` adds any other id the router serves.\nA catalog is mandatory rather than cosmetic — an extension-registered provider inherits\nno models, and without one `--provider tokenrouter` fails as `Unknown provider`.\n\nTwo measured quirks are encoded in the catalog's `compat` profile rather than left for a\nuser to hit:\n\n| Request senpi sends by default | TokenRouter's answer |\n|---|---|\n| `role: \"developer\"` | `HTTP 400 role 'developer' is not allowed` |\n| `store: false` | `HTTP 200` with a whitespace body and no completion |\n\nBoth made a turn fail as `422 openai_error` while a plain `curl` succeeded, so every\nmodel declares `supportsDeveloperRole: false` and `supportsStore: false`.\n\n**`kimi-k3-free` is slow, not broken.** The free tier queued for 395s on a cold call\nbefore returning a normal `HTTP 200`. senpi bounds the wait to the first stream event at\n90s by default, so a free-tier turn needs that raised:\n\n```json\n{\n  \"retry\": { \"provider\": { \"streamStartTimeoutMs\": 600000, \"streamIdleTimeoutMs\": 600000 } }\n}\n```\n\nPaid `moonshotai/kimi-k3` answers in 6-9s and needs no such setting.\n\n### OpenGateway\n\nOpenGateway is an OpenAI-compatible gateway that stock senpi does not know, so its\nmodels are unreachable no matter where the key is stored. Registering the provider id is\nwhat puts it in the `/login` list, and senpi's own API-key prompt then stores, replaces\nand drops the key:\n\n```\n/login opengateway            # or set OPENGATEWAY_API_KEY\n```\n\nThe catalog ships `moonshotai/kimi-k3-ultrafast`. OpenGateway publishes neither token\nlimits nor pricing, so the limits mirror Kimi K3 elsewhere in senpi and cost stays zero\nrather than inventing billing data. Like TokenRouter this is a single-credential\nprovider: one metered account, so there is no pool to rotate.\n\n**OpenAI Codex** works out of the box as stock `openai-codex`. The addon's\nexisting multi-account `codex-pool` is also registered by default, so it remains\nvisible in `/login` without an environment gate.\n\n`codex-pool` delegates streaming to stock's Codex\nResponses implementation while adding the same account pool, affinity and failover as\nKiro. Manage it with `/login codex-pool`.\n\nIt is marked experimental because it has been verified with only **one** real account\n(rotation was proved using a deliberately invalid second slot, not two live\nsubscriptions), and because it depends on resolving stock's Codex streamer at runtime —\nsenpi is a peer dependency, so that resolution is anchored on the running senpi process.\nIf it cannot be resolved the provider degrades on its own and Kiro is unaffected.\n\n## How routing works\n\nThe scarce resource is not quota alone but the upstream **prompt-prefix cache**. Moving a\nconversation to a different account makes that account's cache cold, which usually costs\nmore than the quota it saves. So:\n\n1. **Affinity first.** A conversation is fingerprinted from its first user message and\n   pinned to one account. Later turns reuse it, keeping the cache warm.\n2. **Quota only when the cache is cold.** For a conversation that has not been placed\n   before, `balanced` mode picks the account with the most headroom using\n   power-of-two-choices, which spreads load without herding onto one account.\n3. **429 failover last.** A rate-limited, quota-exhausted, auth-failed or 5xx account is\n   blocked and the request is replayed on the next account. Timed blocks expire on their\n   own (failback); auth blocks persist until re-login.\n\nHeadroom comes from Kiro's own usage-limits endpoint, read from the `CREDIT` row of\n`usageBreakdownList` — the same numbers the\n[account page](https://app.kiro.dev/settings/account) shows. Snapshots are cached for 30s\nwith a 2s ceiling per refresh, so routing never waits on a quota lookup, and an expired\naccess token is refreshed before probing (a stale token answers HTTP 403, which would\notherwise read as \"headroom unknown\" and quietly drop that account from placement).\n\nMeasured across three live Pro Max accounts, `balanced` mode places cold conversations by\nheadroom and leaves the most-used account untouched; the per-mode figures are in\n[Scheduling modes](#scheduling-modes). When no provider reports a limit, placement\ndegrades to an even\nspread rather than herding onto one account.\n\n### Scheduling modes\n\n| Mode | Behaviour |\n|---|---|\n| `cache-first` (default) | Hold one account per conversation. Maximises cache hits. |\n| `balanced` | Same, but new conversations go to the account with the most quota left. |\n| `spread` | Round-robin every request. Best load spread, ignores the cache. |\n\nMeasured over the three live Pro Max accounts at 70.3% / 90.1% / 98.1% headroom, 300 cold\nconversations each:\n\n| Mode | Placement |\n|---|---|\n| `cache-first` | `jgplabs01` 111, `jgp3620` 98, `jgplabs` 91 — hashed, quota ignored |\n| `balanced` | `jgplabs01` 194, `jgplabs` 106, `jgp3620` **0** — most-used account starved |\n| `spread` | 100 / 100 / 100 — exactly even |\n\nThe same conversation key placed twice returns the same account with `reusedBinding=true`,\nso affinity holds across turns.\n\nThe conversation key is senpi's session id when the runtime supplies one, and a hash of the\nfirst user message otherwise. The session id is preferred because it does not move:\ncompaction replaces the first user message with the summary, which changed a content-derived\nkey mid-conversation and dropped the binding on a conversation whose cache was warm.\n\n### Upstream congestion is not an account fault\n\nKiro's CodeWhisperer backend answers a busy moment with prose and no HTTP status:\n\n```\nEncountered unexpectedly high load when processing the request, please try again.\n```\n\nThat used to block the account for 60s. One request walks the whole pool, so a\ntwenty-second backend hiccup blocked all three accounts and the next request was\nrefused with \"All accounts are blocked (rate limited or awaiting re-login)\" while\nevery subscription still had quota — 22%, 60% and 35% in the observed incident.\n\nCongestion is now **transient**: the same account is retried after a short bounded\ndelay (400ms, doubling, capped at 2s), which also keeps its warm prompt cache. Only\nafter repeated congestion on one account is it sidelined, for seconds rather than a\nminute, and never when it is the last selectable account. A genuine HTTP 5xx still\nblocks immediately.\n\n| Symptom | Treated as | Effect on the account |\n|---|---|---|\n| `429`, rate limit, throttled | account is over its limit | blocked, failover |\n| quota / entitlement / billing | subscription exhausted | blocked, failover |\n| `401` / `403`, bad token | needs re-login | blocked until `/login` |\n| HTTP `5xx`, bad gateway | broken request | blocked briefly, failover |\n| \"high load\", \"try again\", \"at capacity\" | **upstream is busy** | **not blocked; retried** |\n\nThe block window also grows properly now. `blockAccount` always computed\n`base * 2**attempt`, but the attempt counter lived in a map rebuilt on every\nrequest, so it was always 0 and every block lasted exactly 60s. The streak is\npersisted on the account and cleared by a success, so repeated failures back off\n60s → 120s → 240s.\n\nWhen the pool genuinely has nothing left, the error says so in full:\n\n```\nAll 3 account(s) are blocked (server_error); earliest retry in 47s (jgplabs);\nquota is not the limiting factor here.\n```\n\n`/usage` names the reason too, so it can no longer report `available` for an\naccount that placement is refusing to use:\n\n```\nkiro  jgplabs: 22% remaining, available\nkiro  jgplabs01: 60% remaining, blocked 47s (server_error)\nkiro  jgp3620: 35% remaining, needs re-login\n```\n\n### Migration policy\n\nA conversation can lose the account holding its warm prompt cache in two very different\nways, and only one of them is worth telling you about:\n\n| Case | What it means | Policy applies |\n|---|---|---|\n| **Detour** | The account is rate limited, quota blocked or briefly failing. The block is a wall-clock window that expires, so the binding is kept and the conversation returns once it lifts. | No — always allowed |\n| **Permanent rebind** | The bound account has left the pool (logged out, removed). The cache is gone with it. | Yes |\n\n```\n/kiro-account migrate <auto|ask|never>\n```\n\n| Policy | Behaviour on a permanent rebind |\n|---|---|\n| `auto` (default) | Move to another account silently. |\n| `ask` | Move, and report which account the conversation left. |\n| `never` | Refuse: the request fails instead of silently moving to a cold account. |\n\nThe policy is also reachable from the `/login kiro` menu as **Migration policy**, and the\ncurrent value is shown by `/kiro-account list`.\n\nNotices never interrupt a stream: they are emitted after placement and are suppressed in\nnon-interactive modes (`print`, RPC without UI), where no one is watching. A failure inside\nthe notification is swallowed rather than surfaced as a request failure.\n\n`never` is for keeping a conversation and its cache on exactly one account, at the cost of\nthe turn that would have moved it. It does not block a detour, because a detour is\nreversible.\n\n### Interaction with senpi's own fallback\n\nsenpi has a **model-level** fallback (`SelectorCooldowns` + fallback chains). This addon\nis **account-level** and sits underneath it:\n\n```\nrequest\n └─ addon: pick account → on 429 retry on the next account   (senpi never sees this)\n     └─ only when every account is blocked, the error surfaces\n         └─ senpi: suppress the model, fall back to the next model\n```\n\nWhen the pool is fully blocked, the addon raises `AllAccountsBlockedError` carrying\n`retryAfterMs` set to the real unblock time. senpi's cooldown prefers an explicit\n`retryAfterMs` over its keyword heuristics, so the model is suppressed for exactly as long\nas the pool is down instead of senpi's default 30-minute quota bucket.\n\n## Commands\n\n| Command | Purpose |\n|---|---|\n| `/login kiro` | Account manager: add, log out (one or all), pin, unblock, set scheduling mode |\n| `/usage` | Remaining usage across addon and stock subscriptions |\n| `/senpi-accounts` | Provider health, including any degraded provider |\n\n## Reliability\n\nEach provider is an isolated package under `src/providers/`, loaded lazily inside its own\ntry/catch. A provider that fails to load, build or register is reported as degraded and\nskipped; every other provider still registers. Providers never import each other.\n\nCredentials live in senpi's own `auth.json`, written atomically with `0600` permissions.\nA corrupt `auth.json` is never overwritten.\n\n### Keychain (optional, macOS)\n\n`src/core/keychain.ts` can hold pools in the macOS Keychain instead of the filesystem.\nIt is **off by default** because `auth.json` already matches stock's protection, and it\nis only used when `keychainAvailable()` proves a full write/read round-trip succeeds —\npresence of the `security` binary is not enough, since a locked or access-denied keychain\nwould silently drop credentials.\n\nThe probe asks `security default-keychain` before attempting anything. An isolated `HOME`\n(CI, a sandbox, the README doc-check) has no login keychain, and a write in that state\nmakes macOS raise a modal \"keychain could not be found\" dialog that blocks the run until\nsomeone clicks it. Reporting unavailable is the correct answer there, and it costs no\nwrite.\n\n## Publishing\n\nPublished to the npm registry as\n[`@eddieparc/senpi-accounts`](https://www.npmjs.com/package/@eddieparc/senpi-accounts).\nA scoped package defaults to restricted access, which answers `402 Payment Required` on a\nfree account, so `publishConfig.access` is `public` in `package.json` and no flag is\nneeded.\n\nReleases go out from CI over\n[trusted publishing](https://docs.npmjs.com/trusted-publishers): `.github/workflows/release.yml`\nauthenticates to the registry with a short-lived OIDC token, so no npm credential is\nstored anywhere and no publish needs an interactive 2FA approval. Bump the version, then\npush the tag:\n\n```bash\nnpm version patch          # or minor / major\ngit push origin main --follow-tags\n```\n\nThe workflow also accepts a manual `workflow_dispatch` run. Either way `prepublishOnly`\nruns typecheck, the full suite and the build first, so an unverified tree cannot reach the\nregistry, and npm attaches a signed provenance statement because the publish is attributable\nto the workflow that produced it.\n\nPublishing this way depends on three things staying in agreement, and npm only reports a\nmismatch when a publish actually runs:\n\n- the trusted publisher registered on npmjs.com names `eddieparc` / `senpi-accounts` /\n  `release.yml`, case-sensitive and including the extension\n- the workflow keeps `permissions: id-token: write`\n- `repository.url` in `package.json` matches the GitHub repository\n\nRenaming the workflow file therefore breaks releases until the npm setting is renamed to\nmatch.\n\n## Development\n\n```bash\nnpm install\nnpm run typecheck\nnpm test\nnpm run build\n```\n","readmeFilename":"README.md"}