@cortexkit/opencode-antigravity-auth 3.0.5 → 3.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -352
- package/dist/cli.js +9199 -8799
- package/dist/cli.js.map +4 -4
- package/dist/cli.meta.json +1286 -1064
- package/dist/index.js +13641 -14559
- package/dist/index.js.map +4 -4
- package/dist/index.meta.json +1333 -1342
- package/dist/server.js +10618 -11080
- package/dist/server.js.map +4 -4
- package/dist/server.meta.json +1 -1
- package/dist/src/auth-method-labels.d.ts +3 -0
- package/dist/src/auth-method-labels.d.ts.map +1 -0
- package/dist/src/auth-method-labels.js +5 -0
- package/dist/src/auth-method-labels.js.map +1 -0
- package/dist/src/cli.d.ts +3 -1
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +98 -12
- package/dist/src/cli.js.map +1 -1
- package/dist/src/common-auth-embedded/claustrum/consumer.d.ts +33 -3
- package/dist/src/common-auth-embedded/claustrum/consumer.js +96 -1
- package/dist/src/common-auth-embedded/claustrum/custody.d.ts +4 -1
- package/dist/src/common-auth-embedded/claustrum/enrollment.d.ts +6 -1
- package/dist/src/common-auth-embedded/claustrum/enrollment.js +6 -1
- package/dist/src/common-auth-embedded/claustrum/index.d.ts +2 -1
- package/dist/src/common-auth-embedded/claustrum/index.js +5 -3
- package/dist/src/common-auth-embedded/claustrum/insula.d.ts +69 -0
- package/dist/src/common-auth-embedded/claustrum/insula.js +152 -0
- package/dist/src/common-auth-embedded/claustrum/roster.d.ts +13 -0
- package/dist/src/common-auth-embedded/claustrum/roster.js +33 -3
- package/dist/src/common-auth-embedded/fs/refresh-file-lock.js +20 -11
- package/dist/src/common-auth-embedded/quota/codec.d.ts +2 -0
- package/dist/src/common-auth-embedded/quota/codec.js +2 -1
- package/dist/src/common-auth-embedded/quota/format.d.ts +26 -0
- package/dist/src/common-auth-embedded/quota/format.js +78 -42
- package/dist/src/common-auth-embedded/quota/index.d.ts +4 -4
- package/dist/src/common-auth-embedded/quota/index.js +2 -2
- package/dist/src/common-auth-embedded/quota/map.d.ts +11 -0
- package/dist/src/common-auth-embedded/quota/map.js +36 -1
- package/dist/src/common-auth-embedded/quota/merge.d.ts +3 -1
- package/dist/src/common-auth-embedded/quota/merge.js +21 -5
- package/dist/src/common-auth-embedded/quota/projection.d.ts +2 -1
- package/dist/src/common-auth-embedded/quota/projection.js +3 -1
- package/dist/src/common-auth-embedded/setup/command-runner.js +49 -0
- package/dist/src/common-auth-embedded/setup/command.d.ts +3 -0
- package/dist/src/common-auth-embedded/setup/command.js +215 -0
- package/dist/src/common-auth-embedded/setup/config-write.js +60 -0
- package/dist/src/common-auth-embedded/setup/detect.d.ts +6 -0
- package/dist/src/common-auth-embedded/setup/detect.js +224 -0
- package/dist/src/common-auth-embedded/setup/enroll.js +70 -0
- package/dist/src/common-auth-embedded/setup/index.d.ts +5 -0
- package/dist/src/common-auth-embedded/setup/index.js +4 -0
- package/dist/src/common-auth-embedded/setup/paths.js +33 -0
- package/dist/src/common-auth-embedded/setup/process-fence.d.ts +43 -0
- package/dist/src/common-auth-embedded/setup/process-fence.js +270 -0
- package/dist/src/common-auth-embedded/setup/prompts.js +26 -0
- package/dist/src/common-auth-embedded/setup/register.d.ts +11 -0
- package/dist/src/common-auth-embedded/setup/register.js +130 -0
- package/dist/src/common-auth-embedded/setup/types.d.ts +136 -0
- package/dist/src/common-auth-embedded/source-output.json +228 -80
- package/dist/src/common-auth-embedded/store/schema.d.ts +2 -0
- package/dist/src/common-auth-embedded/store/schema.js +3 -2
- package/dist/src/ga/rpc/protocol.d.ts +4 -7
- package/dist/src/ga/rpc/protocol.d.ts.map +1 -1
- package/dist/src/ga/rpc/protocol.js +5 -13
- package/dist/src/ga/rpc/protocol.js.map +1 -1
- package/dist/src/ga/server/auth.d.ts +8 -3
- package/dist/src/ga/server/auth.d.ts.map +1 -1
- package/dist/src/ga/server/auth.js +25 -9
- package/dist/src/ga/server/auth.js.map +1 -1
- package/dist/src/ga/server/index.d.ts +39 -12
- package/dist/src/ga/server/index.d.ts.map +1 -1
- package/dist/src/ga/server/index.js +214 -53
- package/dist/src/ga/server/index.js.map +1 -1
- package/dist/src/ga/server/pool-login.d.ts +22 -0
- package/dist/src/ga/server/pool-login.d.ts.map +1 -0
- package/dist/src/ga/server/pool-login.js +150 -0
- package/dist/src/ga/server/pool-login.js.map +1 -0
- package/dist/src/ga/tui/host-ga.d.ts +2 -5
- package/dist/src/ga/tui/host-ga.d.ts.map +1 -1
- package/dist/src/ga/tui/host-ga.js +17 -49
- package/dist/src/ga/tui/host-ga.js.map +1 -1
- package/dist/src/plugin/accounts.d.ts +1 -1
- package/dist/src/plugin/accounts.d.ts.map +1 -1
- package/dist/src/plugin/accounts.js +1 -0
- package/dist/src/plugin/accounts.js.map +1 -1
- package/dist/src/plugin/background-vault-quota-refresh.d.ts +2 -0
- package/dist/src/plugin/background-vault-quota-refresh.d.ts.map +1 -1
- package/dist/src/plugin/background-vault-quota-refresh.js +125 -10
- package/dist/src/plugin/background-vault-quota-refresh.js.map +1 -1
- package/dist/src/plugin/command-apply.d.ts +2 -2
- package/dist/src/plugin/command-apply.d.ts.map +1 -1
- package/dist/src/plugin/command-apply.js +3 -10
- package/dist/src/plugin/command-apply.js.map +1 -1
- package/dist/src/plugin/commands.d.ts +1 -0
- package/dist/src/plugin/commands.d.ts.map +1 -1
- package/dist/src/plugin/commands.js +2 -2
- package/dist/src/plugin/commands.js.map +1 -1
- package/dist/src/plugin/config/operator-settings-schema.d.ts +0 -4
- package/dist/src/plugin/config/operator-settings-schema.d.ts.map +1 -1
- package/dist/src/plugin/config/operator-settings-schema.js +0 -5
- package/dist/src/plugin/config/operator-settings-schema.js.map +1 -1
- package/dist/src/plugin/config/schema.d.ts +0 -7
- package/dist/src/plugin/config/schema.d.ts.map +1 -1
- package/dist/src/plugin/config/schema.js +0 -43
- package/dist/src/plugin/config/schema.js.map +1 -1
- package/dist/src/plugin/config/writer.d.ts +1 -1
- package/dist/src/plugin/config/writer.js +1 -1
- package/dist/src/plugin/fetch/retry-state.d.ts +19 -3
- package/dist/src/plugin/fetch/retry-state.d.ts.map +1 -1
- package/dist/src/plugin/fetch/retry-state.js +0 -6
- package/dist/src/plugin/fetch/retry-state.js.map +1 -1
- package/dist/src/plugin/fetch-interceptor.d.ts.map +1 -1
- package/dist/src/plugin/fetch-interceptor.js +0 -3
- package/dist/src/plugin/fetch-interceptor.js.map +1 -1
- package/dist/src/plugin/fetch-routing.d.ts +0 -16
- package/dist/src/plugin/fetch-routing.d.ts.map +1 -1
- package/dist/src/plugin/fetch-routing.js +0 -49
- package/dist/src/plugin/fetch-routing.js.map +1 -1
- package/dist/src/plugin/ga-location-services.d.ts +14 -9
- package/dist/src/plugin/ga-location-services.d.ts.map +1 -1
- package/dist/src/plugin/ga-location-services.js +120 -40
- package/dist/src/plugin/ga-location-services.js.map +1 -1
- package/dist/src/plugin/google-origin.d.ts +7 -0
- package/dist/src/plugin/google-origin.d.ts.map +1 -0
- package/dist/src/plugin/google-origin.js +14 -0
- package/dist/src/plugin/google-origin.js.map +1 -0
- package/dist/src/plugin/index.d.ts.map +1 -1
- package/dist/src/plugin/index.js +15 -4
- package/dist/src/plugin/index.js.map +1 -1
- package/dist/src/plugin/oauth-methods.d.ts.map +1 -1
- package/dist/src/plugin/oauth-methods.js +0 -33
- package/dist/src/plugin/oauth-methods.js.map +1 -1
- package/dist/src/plugin/operator-settings.d.ts +1 -1
- package/dist/src/plugin/operator-settings.d.ts.map +1 -1
- package/dist/src/plugin/operator-settings.js +1 -8
- package/dist/src/plugin/operator-settings.js.map +1 -1
- package/dist/src/plugin/quota.d.ts +11 -7
- package/dist/src/plugin/quota.d.ts.map +1 -1
- package/dist/src/plugin/quota.js +128 -102
- package/dist/src/plugin/quota.js.map +1 -1
- package/dist/src/plugin/request.d.ts +5 -3
- package/dist/src/plugin/request.d.ts.map +1 -1
- package/dist/src/plugin/request.js +87 -168
- package/dist/src/plugin/request.js.map +1 -1
- package/dist/src/plugin/server.d.ts.map +1 -1
- package/dist/src/plugin/server.js +60 -53
- package/dist/src/plugin/server.js.map +1 -1
- package/dist/src/plugin/shared/advisory-repository.d.ts +20 -0
- package/dist/src/plugin/shared/advisory-repository.d.ts.map +1 -0
- package/dist/src/plugin/shared/advisory-repository.js +91 -0
- package/dist/src/plugin/shared/advisory-repository.js.map +1 -0
- package/dist/src/plugin/shared/request-services.d.ts +19 -25
- package/dist/src/plugin/shared/request-services.d.ts.map +1 -1
- package/dist/src/plugin/shared/request-services.js +105 -188
- package/dist/src/plugin/shared/request-services.js.map +1 -1
- package/dist/src/plugin/shared/runtime.js +4 -2
- package/dist/src/plugin/shared/runtime.js.map +1 -1
- package/dist/src/plugin/shared/vault-request-credentials.d.ts +4 -1
- package/dist/src/plugin/shared/vault-request-credentials.d.ts.map +1 -1
- package/dist/src/plugin/shared/vault-request-credentials.js +41 -7
- package/dist/src/plugin/shared/vault-request-credentials.js.map +1 -1
- package/dist/src/plugin/storage.d.ts +2 -2
- package/dist/src/plugin/storage.d.ts.map +1 -1
- package/dist/src/plugin/storage.js.map +1 -1
- package/dist/src/plugin/vault-custody.d.ts.map +1 -1
- package/dist/src/plugin/vault-custody.js +147 -35
- package/dist/src/plugin/vault-custody.js.map +1 -1
- package/dist/src/plugin/vault-quota-outcome.d.ts +19 -0
- package/dist/src/plugin/vault-quota-outcome.d.ts.map +1 -0
- package/dist/src/plugin/vault-quota-outcome.js +47 -0
- package/dist/src/plugin/vault-quota-outcome.js.map +1 -0
- package/dist/src/quota-presentation.d.ts +29 -1
- package/dist/src/quota-presentation.d.ts.map +1 -1
- package/dist/src/quota-presentation.js +52 -17
- package/dist/src/quota-presentation.js.map +1 -1
- package/dist/src/setup.d.ts +15 -0
- package/dist/src/setup.d.ts.map +1 -0
- package/dist/src/setup.js +320 -0
- package/dist/src/setup.js.map +1 -0
- package/dist/src/sidebar-projection.d.ts +1 -1
- package/dist/src/sidebar-projection.d.ts.map +1 -1
- package/dist/src/sidebar-state.d.ts +1 -1
- package/dist/src/sidebar-state.d.ts.map +1 -1
- package/dist/src/sidebar-state.js +19 -1
- package/dist/src/sidebar-state.js.map +1 -1
- package/dist/src/tui.d.ts.map +1 -1
- package/dist/src/tui.js +205 -110
- package/dist/src/tui.js.map +1 -1
- package/dist/tui-build-map.json +37 -37
- package/dist/tui-ga-build-map.json +33 -33
- package/dist/types/src/auth-method-labels.d.ts +3 -0
- package/dist/types/src/auth-method-labels.d.ts.map +1 -0
- package/dist/types/src/cli.d.ts +3 -1
- package/dist/types/src/cli.d.ts.map +1 -1
- package/dist/types/src/common-auth-embedded/auth-menu/terminal.d.ts +43 -0
- package/dist/types/src/common-auth-embedded/claustrum/consumer.d.ts +132 -0
- package/dist/types/src/common-auth-embedded/claustrum/custody.d.ts +178 -0
- package/dist/types/src/common-auth-embedded/claustrum/enrollment.d.ts +164 -0
- package/dist/types/src/common-auth-embedded/claustrum/errors.d.ts +16 -0
- package/dist/types/src/common-auth-embedded/claustrum/host-slot.d.ts +39 -0
- package/dist/types/src/common-auth-embedded/claustrum/index.d.ts +19 -0
- package/dist/types/src/common-auth-embedded/claustrum/insula.d.ts +69 -0
- package/dist/types/src/common-auth-embedded/claustrum/interlock.d.ts +27 -0
- package/dist/types/src/common-auth-embedded/claustrum/roster.d.ts +221 -0
- package/dist/types/src/common-auth-embedded/opencode2/errors.d.ts +25 -0
- package/dist/types/src/common-auth-embedded/opencode2/index.d.ts +8 -0
- package/dist/types/src/common-auth-embedded/opencode2/install.d.ts +55 -0
- package/dist/types/src/common-auth-embedded/opencode2/integration.d.ts +112 -0
- package/dist/types/src/common-auth-embedded/opencode2/sse.d.ts +12 -0
- package/dist/types/src/common-auth-embedded/opencode2/types.d.ts +413 -0
- package/dist/types/src/common-auth-embedded/quota/codec.d.ts +2 -0
- package/dist/types/src/common-auth-embedded/quota/format.d.ts +26 -0
- package/dist/types/src/common-auth-embedded/quota/index.d.ts +4 -4
- package/dist/types/src/common-auth-embedded/quota/map.d.ts +11 -0
- package/dist/types/src/common-auth-embedded/quota/merge.d.ts +3 -1
- package/dist/types/src/common-auth-embedded/quota/projection.d.ts +2 -1
- package/dist/types/src/common-auth-embedded/routing/admission.d.ts +93 -0
- package/dist/types/src/common-auth-embedded/routing/index.d.ts +8 -0
- package/dist/types/src/common-auth-embedded/routing/ordered.d.ts +47 -0
- package/dist/types/src/common-auth-embedded/routing/pins.d.ts +22 -0
- package/dist/types/src/common-auth-embedded/routing/sticky.d.ts +158 -0
- package/dist/types/src/common-auth-embedded/setup/command.d.ts +3 -0
- package/dist/types/src/common-auth-embedded/setup/detect.d.ts +6 -0
- package/dist/types/src/common-auth-embedded/setup/index.d.ts +5 -0
- package/dist/types/src/common-auth-embedded/setup/process-fence.d.ts +43 -0
- package/dist/types/src/common-auth-embedded/setup/register.d.ts +11 -0
- package/dist/types/src/common-auth-embedded/setup/types.d.ts +136 -0
- package/dist/types/src/common-auth-embedded/store/schema.d.ts +2 -0
- package/dist/types/src/ga/rpc/protocol.d.ts +4 -7
- package/dist/types/src/ga/rpc/protocol.d.ts.map +1 -1
- package/dist/types/src/ga/server/auth.d.ts +8 -3
- package/dist/types/src/ga/server/auth.d.ts.map +1 -1
- package/dist/types/src/ga/server/index.d.ts +39 -12
- package/dist/types/src/ga/server/index.d.ts.map +1 -1
- package/dist/types/src/ga/server/pool-login.d.ts +22 -0
- package/dist/types/src/ga/server/pool-login.d.ts.map +1 -0
- package/dist/types/src/plugin/accounts.d.ts +1 -1
- package/dist/types/src/plugin/accounts.d.ts.map +1 -1
- package/dist/types/src/plugin/background-vault-quota-refresh.d.ts +2 -0
- package/dist/types/src/plugin/background-vault-quota-refresh.d.ts.map +1 -1
- package/dist/types/src/plugin/command-apply.d.ts +2 -2
- package/dist/types/src/plugin/command-apply.d.ts.map +1 -1
- package/dist/types/src/plugin/commands.d.ts +1 -0
- package/dist/types/src/plugin/commands.d.ts.map +1 -1
- package/dist/types/src/plugin/config/operator-settings-schema.d.ts +0 -4
- package/dist/types/src/plugin/config/operator-settings-schema.d.ts.map +1 -1
- package/dist/types/src/plugin/config/schema.d.ts +0 -7
- package/dist/types/src/plugin/config/schema.d.ts.map +1 -1
- package/dist/types/src/plugin/config/writer.d.ts +1 -1
- package/dist/types/src/plugin/fetch/retry-state.d.ts +19 -3
- package/dist/types/src/plugin/fetch/retry-state.d.ts.map +1 -1
- package/dist/types/src/plugin/fetch-interceptor.d.ts.map +1 -1
- package/dist/types/src/plugin/fetch-routing.d.ts +0 -16
- package/dist/types/src/plugin/fetch-routing.d.ts.map +1 -1
- package/dist/types/src/plugin/ga-location-services.d.ts +14 -9
- package/dist/types/src/plugin/ga-location-services.d.ts.map +1 -1
- package/dist/types/src/plugin/google-origin.d.ts +7 -0
- package/dist/types/src/plugin/google-origin.d.ts.map +1 -0
- package/dist/types/src/plugin/index.d.ts.map +1 -1
- package/dist/types/src/plugin/oauth-methods.d.ts.map +1 -1
- package/dist/types/src/plugin/operator-settings.d.ts +1 -1
- package/dist/types/src/plugin/operator-settings.d.ts.map +1 -1
- package/dist/types/src/plugin/quota.d.ts +11 -7
- package/dist/types/src/plugin/quota.d.ts.map +1 -1
- package/dist/types/src/plugin/request.d.ts +5 -3
- package/dist/types/src/plugin/request.d.ts.map +1 -1
- package/dist/types/src/plugin/server.d.ts.map +1 -1
- package/dist/types/src/plugin/shared/advisory-repository.d.ts +20 -0
- package/dist/types/src/plugin/shared/advisory-repository.d.ts.map +1 -0
- package/dist/types/src/plugin/shared/request-services.d.ts +19 -25
- package/dist/types/src/plugin/shared/request-services.d.ts.map +1 -1
- package/dist/types/src/plugin/shared/vault-request-credentials.d.ts +4 -1
- package/dist/types/src/plugin/shared/vault-request-credentials.d.ts.map +1 -1
- package/dist/types/src/plugin/storage.d.ts +2 -2
- package/dist/types/src/plugin/storage.d.ts.map +1 -1
- package/dist/types/src/plugin/vault-custody.d.ts.map +1 -1
- package/dist/types/src/plugin/vault-quota-outcome.d.ts +19 -0
- package/dist/types/src/plugin/vault-quota-outcome.d.ts.map +1 -0
- package/dist/types/src/setup.d.ts +15 -0
- package/dist/types/src/setup.d.ts.map +1 -0
- package/dist/types/src/sidebar-state.d.ts +1 -1
- package/dist/types/src/sidebar-state.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/common-auth-embedded/claustrum/consumer.d.ts +33 -3
- package/src/common-auth-embedded/claustrum/consumer.js +96 -1
- package/src/common-auth-embedded/claustrum/custody.d.ts +4 -1
- package/src/common-auth-embedded/claustrum/enrollment.d.ts +6 -1
- package/src/common-auth-embedded/claustrum/enrollment.js +6 -1
- package/src/common-auth-embedded/claustrum/index.d.ts +2 -1
- package/src/common-auth-embedded/claustrum/index.js +5 -3
- package/src/common-auth-embedded/claustrum/insula.d.ts +69 -0
- package/src/common-auth-embedded/claustrum/insula.js +152 -0
- package/src/common-auth-embedded/claustrum/roster.d.ts +13 -0
- package/src/common-auth-embedded/claustrum/roster.js +33 -3
- package/src/common-auth-embedded/fs/refresh-file-lock.js +20 -11
- package/src/common-auth-embedded/quota/codec.d.ts +2 -0
- package/src/common-auth-embedded/quota/codec.js +2 -1
- package/src/common-auth-embedded/quota/format.d.ts +26 -0
- package/src/common-auth-embedded/quota/format.js +78 -42
- package/src/common-auth-embedded/quota/index.d.ts +4 -4
- package/src/common-auth-embedded/quota/index.js +2 -2
- package/src/common-auth-embedded/quota/map.d.ts +11 -0
- package/src/common-auth-embedded/quota/map.js +36 -1
- package/src/common-auth-embedded/quota/merge.d.ts +3 -1
- package/src/common-auth-embedded/quota/merge.js +21 -5
- package/src/common-auth-embedded/quota/projection.d.ts +2 -1
- package/src/common-auth-embedded/quota/projection.js +3 -1
- package/src/common-auth-embedded/setup/command-runner.js +49 -0
- package/src/common-auth-embedded/setup/command.d.ts +3 -0
- package/src/common-auth-embedded/setup/command.js +215 -0
- package/src/common-auth-embedded/setup/config-write.js +60 -0
- package/src/common-auth-embedded/setup/detect.d.ts +6 -0
- package/src/common-auth-embedded/setup/detect.js +224 -0
- package/src/common-auth-embedded/setup/enroll.js +70 -0
- package/src/common-auth-embedded/setup/index.d.ts +5 -0
- package/src/common-auth-embedded/setup/index.js +4 -0
- package/src/common-auth-embedded/setup/paths.js +33 -0
- package/src/common-auth-embedded/setup/process-fence.d.ts +43 -0
- package/src/common-auth-embedded/setup/process-fence.js +270 -0
- package/src/common-auth-embedded/setup/prompts.js +26 -0
- package/src/common-auth-embedded/setup/register.d.ts +11 -0
- package/src/common-auth-embedded/setup/register.js +130 -0
- package/src/common-auth-embedded/setup/types.d.ts +136 -0
- package/src/common-auth-embedded/source-output.json +228 -80
- package/src/common-auth-embedded/store/schema.d.ts +2 -0
- package/src/common-auth-embedded/store/schema.js +3 -2
- package/src/sidebar-state.ts +19 -2
- package/src/tui-compiled/common-auth-embedded/quota/codec.js +2 -1
- package/src/tui-compiled/common-auth-embedded/quota/format.js +78 -42
- package/src/tui-compiled/common-auth-embedded/quota/index.js +2 -2
- package/src/tui-compiled/common-auth-embedded/quota/map.js +36 -1
- package/src/tui-compiled/common-auth-embedded/quota/merge.js +21 -5
- package/src/tui-compiled/common-auth-embedded/quota/projection.js +3 -1
- package/src/tui-compiled/quota-presentation.js +42 -9
- package/src/tui-compiled/sidebar-state.js +15 -1
- package/src/tui-compiled/tui.js +516 -334
- package/src/tui-ga-compiled/host-ga.js +11 -38
- package/src/tui-ga-compiled/shared/1ff34afa7c42d196-projection.js +3 -1
- package/src/tui-ga-compiled/shared/77138df80c7ae006-map.js +36 -1
- package/src/tui-ga-compiled/shared/98cc0c186c46c42d-quota-presentation.js +42 -9
- package/src/tui-ga-compiled/shared/aef2402f8fc342f0-format.js +78 -42
- package/src/tui-ga-compiled/shared/bf17cbee28e58197-index.js +2 -2
- package/src/tui-ga-compiled/shared/ca21dc417b36dc5d-codec.js +2 -1
- package/src/tui-ga-compiled/shared/ecc214300932dfb6-merge.js +21 -5
- package/src/tui-ga-raw/host-ga.tsx +31 -62
- package/src/tui-ga-raw/shared/1ff34afa7c42d196-projection.js +3 -1
- package/src/tui-ga-raw/shared/77138df80c7ae006-map.js +36 -1
- package/src/tui-ga-raw/shared/98cc0c186c46c42d-quota-presentation.js +42 -9
- package/src/tui-ga-raw/shared/aef2402f8fc342f0-format.js +78 -42
- package/src/tui-ga-raw/shared/bf17cbee28e58197-index.js +2 -2
- package/src/tui-ga-raw/shared/ca21dc417b36dc5d-codec.js +2 -1
- package/src/tui-ga-raw/shared/ecc214300932dfb6-merge.js +21 -5
- package/src/tui-raw/common-auth-embedded/quota/codec.js +2 -1
- package/src/tui-raw/common-auth-embedded/quota/format.js +78 -42
- package/src/tui-raw/common-auth-embedded/quota/index.js +2 -2
- package/src/tui-raw/common-auth-embedded/quota/map.js +36 -1
- package/src/tui-raw/common-auth-embedded/quota/merge.js +21 -5
- package/src/tui-raw/common-auth-embedded/quota/projection.js +3 -1
- package/src/tui-raw/quota-presentation.js +42 -9
- package/src/tui-raw/sidebar-state.js +15 -1
- package/src/tui-raw/tui.tsx +423 -218
- package/src/tui.tsx +423 -218
- package/dist/src/tui/vault-setup.d.ts +0 -98
- package/dist/src/tui/vault-setup.d.ts.map +0 -1
- package/dist/src/tui/vault-setup.js +0 -198
- package/dist/src/tui/vault-setup.js.map +0 -1
- package/dist/types/src/plugin/transform/model-resolver.d.ts +0 -2
- package/dist/types/src/plugin/transform/model-resolver.d.ts.map +0 -1
- package/dist/types/src/quota-presentation.d.ts +0 -18
- package/dist/types/src/quota-presentation.d.ts.map +0 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// scope, orders the result the way the primitives expect, and carries each
|
|
7
7
|
// entry's (scope, label) so a decision names the limit it judged rather than
|
|
8
8
|
// the position it occupied.
|
|
9
|
-
import { ALL_SCOPE, } from "./77138df80c7ae006-map.js";
|
|
9
|
+
import { ALL_SCOPE, readQuotaCounters, } from "./77138df80c7ae006-map.js";
|
|
10
10
|
function project(entry) {
|
|
11
11
|
if (entry.kind === 'retired') {
|
|
12
12
|
return {
|
|
@@ -94,11 +94,13 @@ export function projectQuota(map, scope = ALL_SCOPE) {
|
|
|
94
94
|
? Math.min(...stamped.map((limit) => limit.checkedAt))
|
|
95
95
|
: undefined;
|
|
96
96
|
const budget = map?.budget?.kind === 'reading' ? projectBudget(map.budget) : undefined;
|
|
97
|
+
const counters = readQuotaCounters(map?.counters);
|
|
97
98
|
return {
|
|
98
99
|
scope,
|
|
99
100
|
limits,
|
|
100
101
|
...(checkedAt === undefined ? {} : { checkedAt }),
|
|
101
102
|
...(budget === undefined ? {} : { budget }),
|
|
103
|
+
...(counters === undefined ? {} : { counters }),
|
|
102
104
|
};
|
|
103
105
|
}
|
|
104
106
|
/**
|
|
@@ -83,6 +83,40 @@ export function isCreditBudgetEntry(value) {
|
|
|
83
83
|
optional(value, 'remaining', isFiniteNumber) &&
|
|
84
84
|
optional(value, 'unit', isString));
|
|
85
85
|
}
|
|
86
|
+
function isQuotaCounter(value) {
|
|
87
|
+
return (isRecord(value) &&
|
|
88
|
+
isFiniteNumber(value.value) &&
|
|
89
|
+
Number.isInteger(value.value) &&
|
|
90
|
+
value.value >= 0 &&
|
|
91
|
+
isFiniteNumber(value.checkedAt));
|
|
92
|
+
}
|
|
93
|
+
export function isQuotaCounters(value) {
|
|
94
|
+
return isRecord(value) && Object.values(value).every(isQuotaCounter);
|
|
95
|
+
}
|
|
96
|
+
/** Keep usable counters without letting one malformed count hide a quota map. */
|
|
97
|
+
export function readQuotaCounters(value) {
|
|
98
|
+
if (!isRecord(value))
|
|
99
|
+
return undefined;
|
|
100
|
+
const entries = Object.entries(value).filter(([, entry]) => isQuotaCounter(entry));
|
|
101
|
+
return entries.length === 0
|
|
102
|
+
? undefined
|
|
103
|
+
: Object.fromEntries(entries);
|
|
104
|
+
}
|
|
105
|
+
/** Decode persisted quota, dropping malformed counters but not limit evidence. */
|
|
106
|
+
export function decodeQuotaMap(value) {
|
|
107
|
+
// A valid map is returned as the same object, so stored quota keeps the
|
|
108
|
+
// identity it had before counters existed; only a map with a malformed
|
|
109
|
+
// counter is copied without it.
|
|
110
|
+
if (isQuotaMap(value))
|
|
111
|
+
return value;
|
|
112
|
+
if (!isRecord(value))
|
|
113
|
+
return undefined;
|
|
114
|
+
const { counters: rawCounters, ...rest } = value;
|
|
115
|
+
if (!isQuotaMap(rest))
|
|
116
|
+
return undefined;
|
|
117
|
+
const counters = readQuotaCounters(rawCounters);
|
|
118
|
+
return { ...rest, ...(counters === undefined ? {} : { counters }) };
|
|
119
|
+
}
|
|
86
120
|
/**
|
|
87
121
|
* True when `value` is a well-formed quota map. Unrecognised top-level keys
|
|
88
122
|
* are tolerated (and preserved by merge) so a newer writer's additions
|
|
@@ -101,5 +135,6 @@ export function isQuotaMap(value) {
|
|
|
101
135
|
return false;
|
|
102
136
|
seen.add(key);
|
|
103
137
|
}
|
|
104
|
-
return optional(value, 'budget', isCreditBudgetEntry)
|
|
138
|
+
return (optional(value, 'budget', isCreditBudgetEntry) &&
|
|
139
|
+
optional(value, 'counters', isQuotaCounters));
|
|
105
140
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
formatQuota,
|
|
3
3
|
NO_QUOTA_READING,
|
|
4
|
-
|
|
5
|
-
quotaWindowName
|
|
4
|
+
quotaWindowParts
|
|
6
5
|
} from "./bf17cbee28e58197-index.js";
|
|
7
6
|
|
|
8
7
|
export { NO_QUOTA_READING };
|
|
@@ -23,20 +22,54 @@ function projectReading(label, reading) {
|
|
|
23
22
|
export function formatQuotaReading(label, reading, now) {
|
|
24
23
|
return formatQuota(projectReading(label, reading), { now });
|
|
25
24
|
}
|
|
25
|
+
export function quotaWindowText(reading, now) {
|
|
26
|
+
const part = quotaWindowParts(projectReading("", reading), {
|
|
27
|
+
now,
|
|
28
|
+
form: "full",
|
|
29
|
+
staleAfterMs: Number.POSITIVE_INFINITY
|
|
30
|
+
}).windows[0];
|
|
31
|
+
if (!part)
|
|
32
|
+
return {
|
|
33
|
+
name: "",
|
|
34
|
+
figure: NO_QUOTA_READING,
|
|
35
|
+
reset: "",
|
|
36
|
+
remaining: null,
|
|
37
|
+
resetSinceReading: !1
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
name: part.name,
|
|
41
|
+
figure: part.figure,
|
|
42
|
+
reset: part.resetIn ?? "",
|
|
43
|
+
remaining: part.remainingPercent ?? null,
|
|
44
|
+
resetSinceReading: part.resetSinceReading
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export function quotaReadingAge(readings, now) {
|
|
48
|
+
const limits = readings.flatMap((reading, index) => projectReading(`reading ${index}`, reading)?.limits ?? []);
|
|
49
|
+
if (limits.length === 0)
|
|
50
|
+
return "";
|
|
51
|
+
return quotaWindowParts({
|
|
52
|
+
scope: "all",
|
|
53
|
+
limits,
|
|
54
|
+
checkedAt: Math.min(...limits.map((limit) => limit.checkedAt))
|
|
55
|
+
}, { now, form: "compact" }).age ?? "";
|
|
56
|
+
}
|
|
26
57
|
export function quotaReadingParts(label, reading, now) {
|
|
27
|
-
const
|
|
28
|
-
|
|
58
|
+
const parts = quotaWindowParts(projectReading(label, reading), {
|
|
59
|
+
now,
|
|
60
|
+
form: "full"
|
|
61
|
+
}), part = parts.windows[0];
|
|
62
|
+
if (!part)
|
|
29
63
|
return {
|
|
30
64
|
name: label,
|
|
31
65
|
figure: NO_QUOTA_READING,
|
|
32
66
|
detail: "",
|
|
33
67
|
remaining: null
|
|
34
68
|
};
|
|
35
|
-
const full = quotaTextParts(projected, { now }), compact = quotaTextParts(projected, { now, form: "compact" }), name = quotaWindowName(limit), first = compact[0] ?? "", figure = first.startsWith(`${name} `) ? first.slice(name.length + 1) : first, reset = (full[0] ?? "").slice(first.length).replace(/^, /, "");
|
|
36
69
|
return {
|
|
37
|
-
name,
|
|
38
|
-
figure,
|
|
39
|
-
detail: [
|
|
40
|
-
remaining:
|
|
70
|
+
name: part.name,
|
|
71
|
+
figure: part.figure,
|
|
72
|
+
detail: [part.resetIn ? `resets ${part.resetIn}` : "", parts.age].filter(Boolean).join(" \xB7 "),
|
|
73
|
+
remaining: part.remainingPercent ?? null
|
|
41
74
|
};
|
|
42
75
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// The one quota wording every surface shows: the command menu's dialogs on
|
|
2
2
|
// OpenCode and Pi, the terminal auth menu, and the plugins' sidebars. Each of
|
|
3
|
-
// them calls `formatQuota`
|
|
4
|
-
//
|
|
3
|
+
// them calls `formatQuota`, `quotaTextParts`, or `quotaWindowParts`, so the
|
|
4
|
+
// wording cannot drift between plugins or between a dialog and a sidebar.
|
|
5
5
|
//
|
|
6
6
|
// The rules: a window is named by its length (`5h`, `7d`), or, for a window
|
|
7
7
|
// that binds only one model family, by the label the plugin stored it under.
|
|
@@ -22,18 +22,23 @@ export const NO_QUOTA_READING = 'no quota reading yet';
|
|
|
22
22
|
*/
|
|
23
23
|
export const NO_LIMITS_REPORTED = 'no limits reported';
|
|
24
24
|
/**
|
|
25
|
-
* A
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* A time span in at most its two largest units: `45m`, `2h29m`, `5h`, `3d23h`,
|
|
26
|
+
* `7d`. Every unit is rounded down, so a reset is never shown later than it is;
|
|
27
|
+
* the one exception is a span under a minute, which reads `1m` rather than
|
|
28
|
+
* zero. A zero second unit is left out.
|
|
28
29
|
*/
|
|
29
30
|
function shortSpan(ms) {
|
|
30
|
-
const minutes = Math.max(1, Math.
|
|
31
|
+
const minutes = Math.max(1, Math.floor(ms / 60_000));
|
|
31
32
|
if (minutes < 60)
|
|
32
33
|
return `${minutes}m`;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
if (minutes < 1440) {
|
|
35
|
+
const hours = Math.floor(minutes / 60);
|
|
36
|
+
const rest = minutes % 60;
|
|
37
|
+
return rest === 0 ? `${hours}h` : `${hours}h${rest}m`;
|
|
38
|
+
}
|
|
39
|
+
const days = Math.floor(minutes / 1440);
|
|
40
|
+
const hours = Math.floor((minutes % 1440) / 60);
|
|
41
|
+
return hours === 0 ? `${days}d` : `${days}d${hours}h`;
|
|
37
42
|
}
|
|
38
43
|
/** A stored window length in minutes as its exact name: `5h`, `7d`, `90m`. */
|
|
39
44
|
function lengthName(minutes) {
|
|
@@ -55,17 +60,20 @@ export function quotaWindowName(limit) {
|
|
|
55
60
|
return limit.label;
|
|
56
61
|
return lengthName(limit.windowMinutes);
|
|
57
62
|
}
|
|
63
|
+
function clampPercent(remaining) {
|
|
64
|
+
return Math.min(100, Math.max(0, remaining));
|
|
65
|
+
}
|
|
58
66
|
function percentLeft(remaining) {
|
|
59
|
-
return `${Math.round(
|
|
67
|
+
return `${Math.round(clampPercent(remaining))}% left`;
|
|
60
68
|
}
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
function resetDetails(resetsAt, checkedAt, now) {
|
|
70
|
+
const at = resetsAt === undefined ? Number.NaN : Date.parse(resetsAt);
|
|
71
|
+
return {
|
|
72
|
+
...(Number.isFinite(at) && at > now
|
|
73
|
+
? { resetIn: shortSpan(at - now) }
|
|
74
|
+
: {}),
|
|
75
|
+
resetSinceReading: Number.isFinite(at) && at > checkedAt && at <= now,
|
|
76
|
+
};
|
|
69
77
|
}
|
|
70
78
|
/** Shortest window first, so `5h` reads before `7d`; unknown lengths last. */
|
|
71
79
|
function displayOrder(left, right) {
|
|
@@ -85,42 +93,70 @@ function displayOrder(left, right) {
|
|
|
85
93
|
return left.label < right.label ? -1 : left.label > right.label ? 1 : 0;
|
|
86
94
|
}
|
|
87
95
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* was reported; `formatQuota` turns that into a sentence. A caller printing
|
|
92
|
-
* one line per window (the terminal auth menu) uses these directly.
|
|
96
|
+
* Structured quota wording for layouts that need one row per window. The
|
|
97
|
+
* windows use the same filtering and order as `quotaTextParts`; future resets
|
|
98
|
+
* and the optional age keep the shared formatter's wording.
|
|
93
99
|
*/
|
|
94
|
-
export function
|
|
100
|
+
export function quotaWindowParts(quota, options) {
|
|
95
101
|
if (!quota)
|
|
96
|
-
return [];
|
|
102
|
+
return { windows: [] };
|
|
97
103
|
const { now } = options;
|
|
98
|
-
const full = (options.form ?? 'full') === 'full';
|
|
99
|
-
const parts = [];
|
|
100
|
-
const times = [];
|
|
101
104
|
const readings = quota.limits
|
|
102
105
|
.filter((limit) => limit.kind === 'reading' && limit.remainingPercent !== undefined)
|
|
103
106
|
.sort(displayOrder);
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
107
|
+
const windows = readings.map((limit) => {
|
|
108
|
+
const remainingPercent = clampPercent(limit.remainingPercent ?? 0);
|
|
109
|
+
return {
|
|
110
|
+
kind: 'window',
|
|
111
|
+
name: quotaWindowName(limit),
|
|
112
|
+
figure: percentLeft(limit.remainingPercent ?? 0),
|
|
113
|
+
remainingPercent,
|
|
114
|
+
checkedAt: limit.checkedAt,
|
|
115
|
+
...resetDetails(limit.resetsAt, limit.checkedAt, now),
|
|
116
|
+
};
|
|
117
|
+
});
|
|
108
118
|
const budget = quota.budget;
|
|
109
119
|
if (budget) {
|
|
110
|
-
|
|
120
|
+
const remainingPercent = budget.remainingPercent;
|
|
111
121
|
const figure = budget.reached
|
|
112
122
|
? 'credits spent'
|
|
113
|
-
:
|
|
114
|
-
? `credits ${percentLeft(
|
|
123
|
+
: remainingPercent !== undefined
|
|
124
|
+
? `credits ${percentLeft(remainingPercent)}`
|
|
115
125
|
: 'credits available';
|
|
116
|
-
|
|
126
|
+
windows.push({
|
|
127
|
+
kind: 'budget',
|
|
128
|
+
name: 'credits',
|
|
129
|
+
figure,
|
|
130
|
+
...(remainingPercent === undefined
|
|
131
|
+
? {}
|
|
132
|
+
: { remainingPercent: clampPercent(remainingPercent) }),
|
|
133
|
+
checkedAt: budget.checkedAt,
|
|
134
|
+
...resetDetails(budget.resetsAt, budget.checkedAt, now),
|
|
135
|
+
});
|
|
117
136
|
}
|
|
118
|
-
if (
|
|
119
|
-
const age = now - Math.min(...
|
|
120
|
-
if (age > (options.staleAfterMs ?? QUOTA_STALE_AFTER_MS))
|
|
121
|
-
|
|
137
|
+
if (windows.length > 0) {
|
|
138
|
+
const age = now - Math.min(...windows.map((part) => part.checkedAt));
|
|
139
|
+
if (age > (options.staleAfterMs ?? QUOTA_STALE_AFTER_MS)) {
|
|
140
|
+
return { windows, age: `checked ${shortSpan(age)} ago` };
|
|
141
|
+
}
|
|
122
142
|
}
|
|
123
|
-
return
|
|
143
|
+
return { windows };
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* The pieces of a quota text, in order: one per reported window
|
|
147
|
+
* (`5h 58% left, resets 2h`), then the credit budget when there is one, then
|
|
148
|
+
* `checked 3h ago` when the oldest piece shown is stale. Empty when nothing
|
|
149
|
+
* was reported; `formatQuota` turns that into a sentence. A caller printing
|
|
150
|
+
* one line per window (the terminal auth menu) uses these directly.
|
|
151
|
+
*/
|
|
152
|
+
export function quotaTextParts(quota, options) {
|
|
153
|
+
const parts = quotaWindowParts(quota, options);
|
|
154
|
+
const full = (options.form ?? 'full') === 'full';
|
|
155
|
+
const text = parts.windows.map((part) => {
|
|
156
|
+
const reset = full && part.resetIn ? `, resets ${part.resetIn}` : '';
|
|
157
|
+
return `${part.kind === 'budget' ? '' : `${part.name} `}${part.figure}${reset}`;
|
|
158
|
+
});
|
|
159
|
+
return parts.age === undefined ? text : [...text, parts.age];
|
|
124
160
|
}
|
|
125
161
|
/**
|
|
126
162
|
* A row's quota as one line: `5h 58% left · 7d 90% left` in the compact
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { quotaCodec } from "./ca21dc417b36dc5d-codec.js";
|
|
2
|
-
export { formatQuota, NO_LIMITS_REPORTED, NO_QUOTA_READING, QUOTA_STALE_AFTER_MS, quotaTextParts, quotaWindowName, } from "./aef2402f8fc342f0-format.js";
|
|
3
|
-
export { ALL_SCOPE, DEFAULT_REQUIRED_LABELS, emptyQuotaMap, isQuotaMap, } from "./77138df80c7ae006-map.js";
|
|
2
|
+
export { formatQuota, NO_LIMITS_REPORTED, NO_QUOTA_READING, QUOTA_STALE_AFTER_MS, quotaTextParts, quotaWindowName, quotaWindowParts, } from "./aef2402f8fc342f0-format.js";
|
|
3
|
+
export { ALL_SCOPE, DEFAULT_REQUIRED_LABELS, decodeQuotaMap, emptyQuotaMap, isQuotaMap, } from "./77138df80c7ae006-map.js";
|
|
4
4
|
export { isQuotaObservation, mergeQuotaObservation, QuotaCodecError, } from "./ecc214300932dfb6-merge.js";
|
|
5
5
|
export { budgetExhaustedResetAt, futureResetAt, projectQuota, readsExhausted, } from "./1ff34afa7c42d196-projection.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isQuotaMap } from "./77138df80c7ae006-map.js";
|
|
1
|
+
import { decodeQuotaMap, isQuotaMap } from "./77138df80c7ae006-map.js";
|
|
2
2
|
import { mergeQuotaObservation } from "./ecc214300932dfb6-merge.js";
|
|
3
3
|
/**
|
|
4
4
|
* The quota codec the account-pool store (the `/store` subpath) takes when it
|
|
@@ -8,5 +8,6 @@ import { mergeQuotaObservation } from "./ecc214300932dfb6-merge.js";
|
|
|
8
8
|
*/
|
|
9
9
|
export const quotaCodec = Object.freeze({
|
|
10
10
|
validate: isQuotaMap,
|
|
11
|
+
decode: decodeQuotaMap,
|
|
11
12
|
merge: mergeQuotaObservation,
|
|
12
13
|
});
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// no entry gets an absence record. A pair outside the coverage is never
|
|
12
12
|
// touched, so a header-shaped partial observation (which covers only what it
|
|
13
13
|
// carries) cannot erase a family limit or the budget.
|
|
14
|
-
import { ALL_SCOPE, entryTime,
|
|
14
|
+
import { ALL_SCOPE, decodeQuotaMap, entryTime, isQuotaCounters, limitKey, } from "./77138df80c7ae006-map.js";
|
|
15
15
|
/** Thrown by `mergeQuotaObservation` when either argument is malformed. */
|
|
16
16
|
export class QuotaCodecError extends TypeError {
|
|
17
17
|
constructor(message) {
|
|
@@ -83,7 +83,8 @@ export function isQuotaObservation(value) {
|
|
|
83
83
|
}
|
|
84
84
|
if (!coverage.every(isObservedPair))
|
|
85
85
|
return false;
|
|
86
|
-
return value.budget === undefined || isObservedBudget(value.budget)
|
|
86
|
+
return ((value.budget === undefined || isObservedBudget(value.budget)) &&
|
|
87
|
+
(value.counters === undefined || isQuotaCounters(value.counters)));
|
|
87
88
|
}
|
|
88
89
|
function compareEntries(left, right) {
|
|
89
90
|
if (left.scope !== right.scope)
|
|
@@ -99,6 +100,16 @@ function mergeBudget(stored, observed, checkedAt) {
|
|
|
99
100
|
return stored;
|
|
100
101
|
return { ...observed, checkedAt };
|
|
101
102
|
}
|
|
103
|
+
function mergeCounters(stored, observed) {
|
|
104
|
+
const counters = new Map(Object.entries(stored ?? {}));
|
|
105
|
+
for (const [name, counter] of Object.entries(observed ?? {})) {
|
|
106
|
+
const existing = counters.get(name);
|
|
107
|
+
if (existing === undefined || counter.checkedAt >= existing.checkedAt) {
|
|
108
|
+
counters.set(name, counter);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return counters.size === 0 ? undefined : Object.fromEntries(counters);
|
|
112
|
+
}
|
|
102
113
|
/**
|
|
103
114
|
* Applies `observation` to `stored` (undefined for a row with no map yet) and
|
|
104
115
|
* returns the new map. Pure: neither argument is modified. Throws
|
|
@@ -106,13 +117,16 @@ function mergeBudget(stored, observed, checkedAt) {
|
|
|
106
117
|
* write rather than persisting a map it could not read back.
|
|
107
118
|
*/
|
|
108
119
|
export function mergeQuotaObservation(stored, observation) {
|
|
109
|
-
|
|
120
|
+
// Decode the stored map the way reads do, so a malformed counter that reads
|
|
121
|
+
// already hide is dropped here too instead of refusing every later write.
|
|
122
|
+
const decoded = stored === undefined ? undefined : decodeQuotaMap(stored);
|
|
123
|
+
if (stored !== undefined && decoded === undefined) {
|
|
110
124
|
throw new QuotaCodecError('stored quota map is malformed');
|
|
111
125
|
}
|
|
112
126
|
if (!isQuotaObservation(observation)) {
|
|
113
127
|
throw new QuotaCodecError('quota observation is malformed');
|
|
114
128
|
}
|
|
115
|
-
const base =
|
|
129
|
+
const base = decoded ?? { limits: [] };
|
|
116
130
|
const at = observation.checkedAt;
|
|
117
131
|
const entries = new Map();
|
|
118
132
|
for (const entry of base.limits) {
|
|
@@ -152,11 +166,13 @@ export function mergeQuotaObservation(stored, observation) {
|
|
|
152
166
|
: { scope, label: pair.label, kind: 'retired', retiredAt: at });
|
|
153
167
|
}
|
|
154
168
|
// Keys this module does not recognise are carried over untouched.
|
|
155
|
-
const { limits: _limits, budget: _budget, ...unknownKeys } = base;
|
|
169
|
+
const { limits: _limits, budget: _budget, counters: _counters, ...unknownKeys } = base;
|
|
156
170
|
const budget = mergeBudget(base.budget, observation.budget, at);
|
|
171
|
+
const counters = mergeCounters(base.counters, observation.counters);
|
|
157
172
|
return {
|
|
158
173
|
...unknownKeys,
|
|
159
174
|
limits: [...entries.values()].sort(compareEntries),
|
|
160
175
|
...(budget === undefined ? {} : { budget }),
|
|
176
|
+
...(counters === undefined ? {} : { counters }),
|
|
161
177
|
};
|
|
162
178
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isQuotaMap } from "./map.js";
|
|
1
|
+
import { decodeQuotaMap, isQuotaMap } from "./map.js";
|
|
2
2
|
import { mergeQuotaObservation } from "./merge.js";
|
|
3
3
|
/**
|
|
4
4
|
* The quota codec the account-pool store (the `/store` subpath) takes when it
|
|
@@ -8,5 +8,6 @@ import { mergeQuotaObservation } from "./merge.js";
|
|
|
8
8
|
*/
|
|
9
9
|
export const quotaCodec = Object.freeze({
|
|
10
10
|
validate: isQuotaMap,
|
|
11
|
+
decode: decodeQuotaMap,
|
|
11
12
|
merge: mergeQuotaObservation,
|
|
12
13
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// The one quota wording every surface shows: the command menu's dialogs on
|
|
2
2
|
// OpenCode and Pi, the terminal auth menu, and the plugins' sidebars. Each of
|
|
3
|
-
// them calls `formatQuota`
|
|
4
|
-
//
|
|
3
|
+
// them calls `formatQuota`, `quotaTextParts`, or `quotaWindowParts`, so the
|
|
4
|
+
// wording cannot drift between plugins or between a dialog and a sidebar.
|
|
5
5
|
//
|
|
6
6
|
// The rules: a window is named by its length (`5h`, `7d`), or, for a window
|
|
7
7
|
// that binds only one model family, by the label the plugin stored it under.
|
|
@@ -22,18 +22,23 @@ export const NO_QUOTA_READING = 'no quota reading yet';
|
|
|
22
22
|
*/
|
|
23
23
|
export const NO_LIMITS_REPORTED = 'no limits reported';
|
|
24
24
|
/**
|
|
25
|
-
* A
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* A time span in at most its two largest units: `45m`, `2h29m`, `5h`, `3d23h`,
|
|
26
|
+
* `7d`. Every unit is rounded down, so a reset is never shown later than it is;
|
|
27
|
+
* the one exception is a span under a minute, which reads `1m` rather than
|
|
28
|
+
* zero. A zero second unit is left out.
|
|
28
29
|
*/
|
|
29
30
|
function shortSpan(ms) {
|
|
30
|
-
const minutes = Math.max(1, Math.
|
|
31
|
+
const minutes = Math.max(1, Math.floor(ms / 60_000));
|
|
31
32
|
if (minutes < 60)
|
|
32
33
|
return `${minutes}m`;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
if (minutes < 1440) {
|
|
35
|
+
const hours = Math.floor(minutes / 60);
|
|
36
|
+
const rest = minutes % 60;
|
|
37
|
+
return rest === 0 ? `${hours}h` : `${hours}h${rest}m`;
|
|
38
|
+
}
|
|
39
|
+
const days = Math.floor(minutes / 1440);
|
|
40
|
+
const hours = Math.floor((minutes % 1440) / 60);
|
|
41
|
+
return hours === 0 ? `${days}d` : `${days}d${hours}h`;
|
|
37
42
|
}
|
|
38
43
|
/** A stored window length in minutes as its exact name: `5h`, `7d`, `90m`. */
|
|
39
44
|
function lengthName(minutes) {
|
|
@@ -55,17 +60,20 @@ export function quotaWindowName(limit) {
|
|
|
55
60
|
return limit.label;
|
|
56
61
|
return lengthName(limit.windowMinutes);
|
|
57
62
|
}
|
|
63
|
+
function clampPercent(remaining) {
|
|
64
|
+
return Math.min(100, Math.max(0, remaining));
|
|
65
|
+
}
|
|
58
66
|
function percentLeft(remaining) {
|
|
59
|
-
return `${Math.round(
|
|
67
|
+
return `${Math.round(clampPercent(remaining))}% left`;
|
|
60
68
|
}
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
function resetDetails(resetsAt, checkedAt, now) {
|
|
70
|
+
const at = resetsAt === undefined ? Number.NaN : Date.parse(resetsAt);
|
|
71
|
+
return {
|
|
72
|
+
...(Number.isFinite(at) && at > now
|
|
73
|
+
? { resetIn: shortSpan(at - now) }
|
|
74
|
+
: {}),
|
|
75
|
+
resetSinceReading: Number.isFinite(at) && at > checkedAt && at <= now,
|
|
76
|
+
};
|
|
69
77
|
}
|
|
70
78
|
/** Shortest window first, so `5h` reads before `7d`; unknown lengths last. */
|
|
71
79
|
function displayOrder(left, right) {
|
|
@@ -85,42 +93,70 @@ function displayOrder(left, right) {
|
|
|
85
93
|
return left.label < right.label ? -1 : left.label > right.label ? 1 : 0;
|
|
86
94
|
}
|
|
87
95
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* was reported; `formatQuota` turns that into a sentence. A caller printing
|
|
92
|
-
* one line per window (the terminal auth menu) uses these directly.
|
|
96
|
+
* Structured quota wording for layouts that need one row per window. The
|
|
97
|
+
* windows use the same filtering and order as `quotaTextParts`; future resets
|
|
98
|
+
* and the optional age keep the shared formatter's wording.
|
|
93
99
|
*/
|
|
94
|
-
export function
|
|
100
|
+
export function quotaWindowParts(quota, options) {
|
|
95
101
|
if (!quota)
|
|
96
|
-
return [];
|
|
102
|
+
return { windows: [] };
|
|
97
103
|
const { now } = options;
|
|
98
|
-
const full = (options.form ?? 'full') === 'full';
|
|
99
|
-
const parts = [];
|
|
100
|
-
const times = [];
|
|
101
104
|
const readings = quota.limits
|
|
102
105
|
.filter((limit) => limit.kind === 'reading' && limit.remainingPercent !== undefined)
|
|
103
106
|
.sort(displayOrder);
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
107
|
+
const windows = readings.map((limit) => {
|
|
108
|
+
const remainingPercent = clampPercent(limit.remainingPercent ?? 0);
|
|
109
|
+
return {
|
|
110
|
+
kind: 'window',
|
|
111
|
+
name: quotaWindowName(limit),
|
|
112
|
+
figure: percentLeft(limit.remainingPercent ?? 0),
|
|
113
|
+
remainingPercent,
|
|
114
|
+
checkedAt: limit.checkedAt,
|
|
115
|
+
...resetDetails(limit.resetsAt, limit.checkedAt, now),
|
|
116
|
+
};
|
|
117
|
+
});
|
|
108
118
|
const budget = quota.budget;
|
|
109
119
|
if (budget) {
|
|
110
|
-
|
|
120
|
+
const remainingPercent = budget.remainingPercent;
|
|
111
121
|
const figure = budget.reached
|
|
112
122
|
? 'credits spent'
|
|
113
|
-
:
|
|
114
|
-
? `credits ${percentLeft(
|
|
123
|
+
: remainingPercent !== undefined
|
|
124
|
+
? `credits ${percentLeft(remainingPercent)}`
|
|
115
125
|
: 'credits available';
|
|
116
|
-
|
|
126
|
+
windows.push({
|
|
127
|
+
kind: 'budget',
|
|
128
|
+
name: 'credits',
|
|
129
|
+
figure,
|
|
130
|
+
...(remainingPercent === undefined
|
|
131
|
+
? {}
|
|
132
|
+
: { remainingPercent: clampPercent(remainingPercent) }),
|
|
133
|
+
checkedAt: budget.checkedAt,
|
|
134
|
+
...resetDetails(budget.resetsAt, budget.checkedAt, now),
|
|
135
|
+
});
|
|
117
136
|
}
|
|
118
|
-
if (
|
|
119
|
-
const age = now - Math.min(...
|
|
120
|
-
if (age > (options.staleAfterMs ?? QUOTA_STALE_AFTER_MS))
|
|
121
|
-
|
|
137
|
+
if (windows.length > 0) {
|
|
138
|
+
const age = now - Math.min(...windows.map((part) => part.checkedAt));
|
|
139
|
+
if (age > (options.staleAfterMs ?? QUOTA_STALE_AFTER_MS)) {
|
|
140
|
+
return { windows, age: `checked ${shortSpan(age)} ago` };
|
|
141
|
+
}
|
|
122
142
|
}
|
|
123
|
-
return
|
|
143
|
+
return { windows };
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* The pieces of a quota text, in order: one per reported window
|
|
147
|
+
* (`5h 58% left, resets 2h`), then the credit budget when there is one, then
|
|
148
|
+
* `checked 3h ago` when the oldest piece shown is stale. Empty when nothing
|
|
149
|
+
* was reported; `formatQuota` turns that into a sentence. A caller printing
|
|
150
|
+
* one line per window (the terminal auth menu) uses these directly.
|
|
151
|
+
*/
|
|
152
|
+
export function quotaTextParts(quota, options) {
|
|
153
|
+
const parts = quotaWindowParts(quota, options);
|
|
154
|
+
const full = (options.form ?? 'full') === 'full';
|
|
155
|
+
const text = parts.windows.map((part) => {
|
|
156
|
+
const reset = full && part.resetIn ? `, resets ${part.resetIn}` : '';
|
|
157
|
+
return `${part.kind === 'budget' ? '' : `${part.name} `}${part.figure}${reset}`;
|
|
158
|
+
});
|
|
159
|
+
return parts.age === undefined ? text : [...text, parts.age];
|
|
124
160
|
}
|
|
125
161
|
/**
|
|
126
162
|
* A row's quota as one line: `5h 58% left · 7d 90% left` in the compact
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { quotaCodec } from "./codec.js";
|
|
2
|
-
export { formatQuota, NO_LIMITS_REPORTED, NO_QUOTA_READING, QUOTA_STALE_AFTER_MS, quotaTextParts, quotaWindowName, } from "./format.js";
|
|
3
|
-
export { ALL_SCOPE, DEFAULT_REQUIRED_LABELS, emptyQuotaMap, isQuotaMap, } from "./map.js";
|
|
2
|
+
export { formatQuota, NO_LIMITS_REPORTED, NO_QUOTA_READING, QUOTA_STALE_AFTER_MS, quotaTextParts, quotaWindowName, quotaWindowParts, } from "./format.js";
|
|
3
|
+
export { ALL_SCOPE, DEFAULT_REQUIRED_LABELS, decodeQuotaMap, emptyQuotaMap, isQuotaMap, } from "./map.js";
|
|
4
4
|
export { isQuotaObservation, mergeQuotaObservation, QuotaCodecError, } from "./merge.js";
|
|
5
5
|
export { budgetExhaustedResetAt, futureResetAt, projectQuota, readsExhausted, } from "./projection.js";
|
|
@@ -83,6 +83,40 @@ export function isCreditBudgetEntry(value) {
|
|
|
83
83
|
optional(value, 'remaining', isFiniteNumber) &&
|
|
84
84
|
optional(value, 'unit', isString));
|
|
85
85
|
}
|
|
86
|
+
function isQuotaCounter(value) {
|
|
87
|
+
return (isRecord(value) &&
|
|
88
|
+
isFiniteNumber(value.value) &&
|
|
89
|
+
Number.isInteger(value.value) &&
|
|
90
|
+
value.value >= 0 &&
|
|
91
|
+
isFiniteNumber(value.checkedAt));
|
|
92
|
+
}
|
|
93
|
+
export function isQuotaCounters(value) {
|
|
94
|
+
return isRecord(value) && Object.values(value).every(isQuotaCounter);
|
|
95
|
+
}
|
|
96
|
+
/** Keep usable counters without letting one malformed count hide a quota map. */
|
|
97
|
+
export function readQuotaCounters(value) {
|
|
98
|
+
if (!isRecord(value))
|
|
99
|
+
return undefined;
|
|
100
|
+
const entries = Object.entries(value).filter(([, entry]) => isQuotaCounter(entry));
|
|
101
|
+
return entries.length === 0
|
|
102
|
+
? undefined
|
|
103
|
+
: Object.fromEntries(entries);
|
|
104
|
+
}
|
|
105
|
+
/** Decode persisted quota, dropping malformed counters but not limit evidence. */
|
|
106
|
+
export function decodeQuotaMap(value) {
|
|
107
|
+
// A valid map is returned as the same object, so stored quota keeps the
|
|
108
|
+
// identity it had before counters existed; only a map with a malformed
|
|
109
|
+
// counter is copied without it.
|
|
110
|
+
if (isQuotaMap(value))
|
|
111
|
+
return value;
|
|
112
|
+
if (!isRecord(value))
|
|
113
|
+
return undefined;
|
|
114
|
+
const { counters: rawCounters, ...rest } = value;
|
|
115
|
+
if (!isQuotaMap(rest))
|
|
116
|
+
return undefined;
|
|
117
|
+
const counters = readQuotaCounters(rawCounters);
|
|
118
|
+
return { ...rest, ...(counters === undefined ? {} : { counters }) };
|
|
119
|
+
}
|
|
86
120
|
/**
|
|
87
121
|
* True when `value` is a well-formed quota map. Unrecognised top-level keys
|
|
88
122
|
* are tolerated (and preserved by merge) so a newer writer's additions
|
|
@@ -101,5 +135,6 @@ export function isQuotaMap(value) {
|
|
|
101
135
|
return false;
|
|
102
136
|
seen.add(key);
|
|
103
137
|
}
|
|
104
|
-
return optional(value, 'budget', isCreditBudgetEntry)
|
|
138
|
+
return (optional(value, 'budget', isCreditBudgetEntry) &&
|
|
139
|
+
optional(value, 'counters', isQuotaCounters));
|
|
105
140
|
}
|