pi-antigravity-rotator 2.3.1 → 2.3.2

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/src/rotator.ts CHANGED
@@ -44,6 +44,7 @@ import { logger } from "./logger.js";
44
44
  import { getUpdateInfo } from "./version-check.js";
45
45
  import { getNotifications } from "./notification-poller.js";
46
46
  import { getConfiguredAdminToken } from "./admin-auth.js";
47
+ import { getProxyExposureWarning } from "./exposure.js";
47
48
  import {
48
49
  getCachedState,
49
50
  setCachedState,
@@ -876,7 +877,7 @@ export class AccountRotator {
876
877
  const state = this.modelState.get(modelKey);
877
878
  if (state) {
878
879
  state.requestsOnActiveAccount++;
879
- this.saveState();
880
+ this.scheduleStateSave();
880
881
  }
881
882
  }
882
883
 
@@ -2165,7 +2166,7 @@ export class AccountRotator {
2165
2166
  account.dailyRequestCount++;
2166
2167
  this.projectRequests[account.config.projectId] =
2167
2168
  (this.projectRequests[account.config.projectId] ?? 0) + 1;
2168
- this.saveState();
2169
+ this.scheduleStateSave();
2169
2170
  }
2170
2171
 
2171
2172
  getSafetyJitterMs(account: AccountRuntime): number {
@@ -2655,6 +2656,11 @@ export class AccountRotator {
2655
2656
  }
2656
2657
  }
2657
2658
 
2659
+ const adminWarning = getConfiguredAdminToken()
2660
+ ? null
2661
+ : `Admin routes are exposed on ${this.config.bindHost}:${this.config.proxyPort} because PI_ROTATOR_ADMIN_TOKEN is not configured.`;
2662
+ const proxyWarning = getProxyExposureWarning(this.config);
2663
+
2658
2664
  return {
2659
2665
  version: updateInfo.currentVersion,
2660
2666
  proxyPort: this.config.proxyPort,
@@ -2676,9 +2682,7 @@ export class AccountRotator {
2676
2682
  },
2677
2683
  security: {
2678
2684
  adminTokenConfigured: !!getConfiguredAdminToken(),
2679
- warning: getConfiguredAdminToken()
2680
- ? null
2681
- : `Admin routes are exposed on ${this.config.bindHost}:${this.config.proxyPort} because PI_ROTATOR_ADMIN_TOKEN is not configured.`,
2685
+ warning: [adminWarning, proxyWarning].filter(Boolean).join(" ") || null,
2682
2686
  bindHost: this.config.bindHost || "0.0.0.0",
2683
2687
  },
2684
2688
  routingDiagnostics,
@@ -2905,7 +2909,7 @@ export class AccountRotator {
2905
2909
  }
2906
2910
 
2907
2911
  setAccountTier(email: string, tier: string): boolean {
2908
- const validTiers = ["unknown", "free", "pro", "ultra"];
2912
+ const validTiers = ["unknown", "free", "plus", "pro", "ultra"];
2909
2913
  if (!validTiers.includes(tier)) return false;
2910
2914
  const account = this.accounts.find((a) => a.config.email === email);
2911
2915
  if (!account) return false;
@@ -370,6 +370,10 @@ function renderAccounts(data) {
370
370
  "FREE</div>" +
371
371
  '<div class="tier-option" onclick="setAccountTier(\'' +
372
372
  jsString(a.email) +
373
+ "', 'plus')\">" +
374
+ "PLUS</div>" +
375
+ '<div class="tier-option" onclick="setAccountTier(\'' +
376
+ jsString(a.email) +
373
377
  "', 'pro')\">" +
374
378
  "PRO</div>" +
375
379
  '<div class="tier-option" onclick="setAccountTier(\'' +
@@ -836,8 +840,9 @@ function renderAttentionPanel(data) {
836
840
  "Security warning",
837
841
  security.warning,
838
842
  [
839
- "Set PI_ROTATOR_ADMIN_TOKEN to protect dashboard and admin APIs.",
840
- "For local-only usage, prefer bindHost 127.0.0.1.",
843
+ "Dashboard and admin APIs require the admin token.",
844
+ "Native and /v1 proxy routes do not require a token.",
845
+ "For local-only usage, set bindHost to 127.0.0.1 or bind the Docker port to 127.0.0.1.",
841
846
  ],
842
847
  "warning",
843
848
  ),
package/src/telemetry.ts CHANGED
@@ -9,8 +9,10 @@
9
9
  // - Flag events: HTTP status, matched patterns, model, pool state,
10
10
  // request velocity — everything needed to improve the anti-flag algorithm
11
11
  //
12
- // What we NEVER collect:
13
- // - Emails, tokens, IPs, project IDs, request bodies, error message text
12
+ // What we NEVER include in telemetry payloads or event files:
13
+ // - Emails, tokens, project IDs, request bodies, error message text
14
+ // Source IPs are not part of the JSON telemetry payload, but the receiver and
15
+ // network path can observe them for transport and rate limiting.
14
16
  //
15
17
  // Docs: https://github.com/tuxevil/pi-antigravity-rotator#telemetry
16
18
 
@@ -129,8 +131,8 @@ function printTelemetryNotice(): void {
129
131
  console.log();
130
132
  console.log(" ╭──────────────────────────────────────────────────────────╮");
131
133
  console.log(" │ Anonymous telemetry is enabled to help improve the │");
132
- console.log(" │ rotator. No emails, tokens, IPs, or personal data is │");
133
- console.log(" │ collected — only aggregate usage stats. │");
134
+ console.log(" │ rotator. No emails, tokens, project IDs, request bodies │");
135
+ console.log(" │ or error text are sent — only aggregate usage stats. │");
134
136
  console.log(" │ │");
135
137
  console.log(" │ Flag events help us improve the anti-flag algorithm │");
136
138
  console.log(" │ for everyone. Consider keeping telemetry on! │");
@@ -182,7 +184,7 @@ export interface TelemetryPayload {
182
184
  // This is the most important telemetry signal — it drives anti-flag
183
185
  // algorithm improvements that benefit all users.
184
186
  //
185
- // NO PII: no email, no error text, no IP, no projectId.
187
+ // NO PII in the payload: no email, no error text, no projectId, no request body.
186
188
  // Only structured, anonymous context about what happened.
187
189
  export interface FlagEventData {
188
190
  // What triggered it
package/src/types.ts CHANGED
@@ -150,14 +150,6 @@ export interface ModelSpecConfig {
150
150
  isThinking: boolean;
151
151
  }
152
152
 
153
- // Per-model thinking/output spec used by the compat layer.
154
- // Operators can override defaults via the `modelSpecs` field in accounts.json.
155
- export interface ModelSpecConfig {
156
- maxOutputTokens: number;
157
- thinkingBudget: number; // -1 = adaptive (model decides), >=0 = fixed
158
- isThinking: boolean;
159
- }
160
-
161
153
  // Per-model quota info for an account
162
154
  export interface ModelQuota {
163
155
  modelKey: string;
@@ -619,9 +611,10 @@ export const CLIENT_SECRET = atob(
619
611
  );
620
612
  export const TOKEN_URL = "https://oauth2.googleapis.com/token";
621
613
 
614
+ // Production default: use the daily Cloud Code Assist endpoint. The proxy
615
+ // forwarder supports cascading if additional verified endpoints are added here.
622
616
  export const ANTIGRAVITY_ENDPOINTS = [
623
617
  "https://daily-cloudcode-pa.googleapis.com",
624
- // "https://cloudcode-pa.googleapis.com",
625
618
  ] as const;
626
619
 
627
620
  export const QUOTA_API_URL =
@@ -26,6 +26,7 @@ let cachedInfo: UpdateInfo = {
26
26
  updateAvailable: false,
27
27
  checkedAt: 0,
28
28
  };
29
+ let initialCheckTimer: ReturnType<typeof setTimeout> | null = null;
29
30
  let checkTimer: ReturnType<typeof setInterval> | null = null;
30
31
 
31
32
  /**
@@ -123,18 +124,26 @@ export function getUpdateInfo(): UpdateInfo {
123
124
  */
124
125
  export function startVersionChecker(): void {
125
126
  // Initial delayed check
126
- setTimeout(() => {
127
- void checkForUpdate();
128
- }, 10_000);
127
+ if (!initialCheckTimer) {
128
+ initialCheckTimer = setTimeout(() => {
129
+ initialCheckTimer = null;
130
+ void checkForUpdate();
131
+ }, 10_000);
132
+ if (initialCheckTimer.unref) {
133
+ initialCheckTimer.unref();
134
+ }
135
+ }
129
136
 
130
137
  // Periodic check
131
- checkTimer = setInterval(() => {
132
- void checkForUpdate();
133
- }, CHECK_INTERVAL_MS);
134
-
135
- // Don't keep process alive just for version checking
136
- if (checkTimer.unref) {
137
- checkTimer.unref();
138
+ if (!checkTimer) {
139
+ checkTimer = setInterval(() => {
140
+ void checkForUpdate();
141
+ }, CHECK_INTERVAL_MS);
142
+
143
+ // Don't keep process alive just for version checking
144
+ if (checkTimer.unref) {
145
+ checkTimer.unref();
146
+ }
138
147
  }
139
148
  }
140
149
 
@@ -142,6 +151,10 @@ export function startVersionChecker(): void {
142
151
  * Stop periodic version checking.
143
152
  */
144
153
  export function stopVersionChecker(): void {
154
+ if (initialCheckTimer) {
155
+ clearTimeout(initialCheckTimer);
156
+ initialCheckTimer = null;
157
+ }
145
158
  if (checkTimer) {
146
159
  clearInterval(checkTimer);
147
160
  checkTimer = null;
@@ -113,7 +113,8 @@ curl -H "Authorization: Bearer YOUR_STATS_TOKEN" https://telemetry.yourdomain.co
113
113
 
114
114
  ## Security
115
115
 
116
- - **No PII is stored**: no emails, tokens, IPs, project IDs
116
+ - **No PII is stored in telemetry event files**: no emails, tokens, project IDs, request bodies, or error text
117
+ - Source IPs are used transiently for in-memory rate limiting and may be visible to your network, host, or reverse-proxy logs. The receiver does not write IPs into telemetry JSONL event files.
117
118
  - Email-pattern detection in validation: payloads containing `@` email patterns are rejected
118
119
  - Payloads capped at 4KB
119
120
  - Rate limited: 12 req/min per IP