pi-provider-antigravity 0.12.0 → 0.13.0
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/dist/index.js +145 -91
- package/dist/index.js.map +4 -4
- package/package.json +7 -8
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { createHash, randomBytes } from "node:crypto";
|
|
|
6
6
|
|
|
7
7
|
// src/protocol.ts
|
|
8
8
|
var DEFAULT_ENDPOINT = "https://daily-cloudcode-pa.googleapis.com";
|
|
9
|
-
var DEFAULT_USER_AGENT = "antigravity/cli/1.2.
|
|
9
|
+
var DEFAULT_USER_AGENT = "antigravity/cli/1.2.5 (aidev_client; os_type=linux; arch=amd64; cl=982839923; auth_method=consumer)";
|
|
10
10
|
var PROVIDER_ID = "antigravity";
|
|
11
11
|
var AntigravityHttpError = class extends Error {
|
|
12
12
|
status;
|
|
@@ -254,7 +254,24 @@ function parseStoredCredentials(rawApiKey) {
|
|
|
254
254
|
return { token: rawApiKey, projectId: FALLBACK_PROJECT_ID };
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
// src/
|
|
257
|
+
// src/model-identity.ts
|
|
258
|
+
function classifyModelFamily(modelId) {
|
|
259
|
+
const bare = ((modelId || "").split("/").pop() || "").toLowerCase();
|
|
260
|
+
if (bare.startsWith("gemini-")) return "gemini";
|
|
261
|
+
if (bare.startsWith("claude-")) return "claude";
|
|
262
|
+
if (bare.startsWith("gpt-")) return "gpt";
|
|
263
|
+
return "unknown";
|
|
264
|
+
}
|
|
265
|
+
function isCompatibleFamily(msgModel, targetModelId) {
|
|
266
|
+
if (!msgModel || !targetModelId) return true;
|
|
267
|
+
if (msgModel === targetModelId) return true;
|
|
268
|
+
const msgFamily = classifyModelFamily(msgModel);
|
|
269
|
+
if (msgFamily !== "unknown" && msgFamily === classifyModelFamily(targetModelId)) return true;
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// src/model-catalog.ts
|
|
274
|
+
var PRIVATE_SNAPSHOT_KEY = "pi-provider-antigravity";
|
|
258
275
|
var CANONICAL_TIER_SUFFIXES = Object.freeze({
|
|
259
276
|
low: "-low",
|
|
260
277
|
medium: "-medium",
|
|
@@ -305,23 +322,6 @@ function tierCandidateOrder(effort) {
|
|
|
305
322
|
const fallbacks = TIER_FALLBACKS[effort] ?? DEFAULT_TIER_ORDER;
|
|
306
323
|
return [.../* @__PURE__ */ new Set([...canonical, ...fallbacks])];
|
|
307
324
|
}
|
|
308
|
-
function classifyModelFamily(modelId) {
|
|
309
|
-
const bare = ((modelId || "").split("/").pop() || "").toLowerCase();
|
|
310
|
-
if (bare.startsWith("gemini-")) return "gemini";
|
|
311
|
-
if (bare.startsWith("claude-")) return "claude";
|
|
312
|
-
if (bare.startsWith("gpt-")) return "gpt";
|
|
313
|
-
return "unknown";
|
|
314
|
-
}
|
|
315
|
-
function isCompatibleFamily(msgModel, targetModelId) {
|
|
316
|
-
if (!msgModel || !targetModelId) return true;
|
|
317
|
-
if (msgModel === targetModelId) return true;
|
|
318
|
-
const msgFamily = classifyModelFamily(msgModel);
|
|
319
|
-
if (msgFamily !== "unknown" && msgFamily === classifyModelFamily(targetModelId)) return true;
|
|
320
|
-
return extractBaseModelId(msgModel) === extractBaseModelId(targetModelId);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// src/model-catalog.ts
|
|
324
|
-
var PRIVATE_SNAPSHOT_KEY = "pi-provider-antigravity";
|
|
325
325
|
function buildThinkingMap(models) {
|
|
326
326
|
return Object.fromEntries(
|
|
327
327
|
models.map((m) => [
|
|
@@ -696,21 +696,7 @@ import * as fs from "node:fs";
|
|
|
696
696
|
import * as os from "node:os";
|
|
697
697
|
import * as path from "node:path";
|
|
698
698
|
import { SettingsList } from "@earendil-works/pi-tui";
|
|
699
|
-
var ANSI_FG_RESET = "\x1B[39m";
|
|
700
699
|
var PROVIDER_CONFIG_FILE = "pi-provider-antigravity.json";
|
|
701
|
-
var FOOTER_MODE_NOTES = Object.freeze({
|
|
702
|
-
smart: "Picks whichever window runs out first (5h or weekly), weighting the weekly pool by a ratio learned from your usage",
|
|
703
|
-
all: "Lists every window of the pool backing the current model (5h or weekly)"
|
|
704
|
-
});
|
|
705
|
-
var FOOTER_MODE_OPTIONS = Object.freeze([
|
|
706
|
-
"off",
|
|
707
|
-
"smart",
|
|
708
|
-
"all"
|
|
709
|
-
]);
|
|
710
|
-
function normalizeFooterMode(value) {
|
|
711
|
-
const v = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
712
|
-
return FOOTER_MODE_OPTIONS.includes(v) ? v : void 0;
|
|
713
|
-
}
|
|
714
700
|
function defaultConfigFile(env = process.env) {
|
|
715
701
|
const dir = (env.PI_CODING_AGENT_DIR || "").trim() || path.join(os.homedir(), ".pi", "agent");
|
|
716
702
|
return path.join(dir, PROVIDER_CONFIG_FILE);
|
|
@@ -761,9 +747,6 @@ function updateProviderConfig(file, mutate) {
|
|
|
761
747
|
return false;
|
|
762
748
|
}
|
|
763
749
|
}
|
|
764
|
-
function resolveFooterMode(config) {
|
|
765
|
-
return normalizeFooterMode(config?.settings?.quotaFooter) ?? "off";
|
|
766
|
-
}
|
|
767
750
|
function loadSubsystemState(subsystem, file = defaultConfigFile()) {
|
|
768
751
|
const state = loadProviderConfig(file)?.states?.[subsystem];
|
|
769
752
|
return state && typeof state === "object" && !Array.isArray(state) ? state : void 0;
|
|
@@ -776,28 +759,33 @@ function saveSubsystemState(subsystem, state, file = defaultConfigFile()) {
|
|
|
776
759
|
config.states = states;
|
|
777
760
|
});
|
|
778
761
|
}
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
{
|
|
788
|
-
key: "quotaFooter",
|
|
789
|
-
label: "Quota footer",
|
|
790
|
-
description: "Show remaining quota in Pi's status footer",
|
|
791
|
-
options: FOOTER_MODE_OPTIONS,
|
|
792
|
-
defaultValue: "off",
|
|
793
|
-
optionNotes: FOOTER_MODE_NOTES,
|
|
794
|
-
onChange: async (ctx, quotaStatus) => {
|
|
795
|
-
if (!quotaStatus) return;
|
|
796
|
-
if (quotaStatus.mode() !== "off") await quotaStatus.refresh(ctx, { ignoreMode: true });
|
|
797
|
-
quotaStatus.paint(ctx);
|
|
762
|
+
var SettingsRegistry = class {
|
|
763
|
+
fields = [];
|
|
764
|
+
register(field) {
|
|
765
|
+
const existingIndex = this.fields.findIndex((f) => f.key === field.key);
|
|
766
|
+
if (existingIndex >= 0) {
|
|
767
|
+
this.fields[existingIndex] = field;
|
|
768
|
+
} else {
|
|
769
|
+
this.fields.push(field);
|
|
798
770
|
}
|
|
799
771
|
}
|
|
800
|
-
|
|
772
|
+
unregister(key) {
|
|
773
|
+
this.fields = this.fields.filter((f) => f.key !== key);
|
|
774
|
+
}
|
|
775
|
+
getFields() {
|
|
776
|
+
return [...this.fields];
|
|
777
|
+
}
|
|
778
|
+
clear() {
|
|
779
|
+
this.fields = [];
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
var defaultSettingsRegistry = new SettingsRegistry();
|
|
783
|
+
function registerSettingField(field) {
|
|
784
|
+
defaultSettingsRegistry.register(field);
|
|
785
|
+
}
|
|
786
|
+
function getRegisteredSettingFields() {
|
|
787
|
+
return defaultSettingsRegistry.getFields();
|
|
788
|
+
}
|
|
801
789
|
function fieldDisplayValue(config, field) {
|
|
802
790
|
const raw = config?.settings?.[field.key];
|
|
803
791
|
if (typeof raw === "string" && raw.trim()) return raw.trim();
|
|
@@ -810,25 +798,17 @@ function saveSettingValue(field, value, file) {
|
|
|
810
798
|
config.settings = settings;
|
|
811
799
|
});
|
|
812
800
|
}
|
|
813
|
-
async function applySettingValue(field, value, file, ctx
|
|
801
|
+
async function applySettingValue(field, value, file, ctx) {
|
|
814
802
|
if (!saveSettingValue(field, value, file)) {
|
|
815
803
|
return false;
|
|
816
804
|
}
|
|
817
|
-
await field.onChange?.(ctx,
|
|
805
|
+
await field.onChange?.(ctx, value);
|
|
818
806
|
return true;
|
|
819
807
|
}
|
|
820
808
|
function writeFailedMessage(file) {
|
|
821
809
|
return `Failed to write ${file}. If the file is not valid JSON, fix or delete it.`;
|
|
822
810
|
}
|
|
823
|
-
function
|
|
824
|
-
if (!coord) return void 0;
|
|
825
|
-
const normalized = normalizeFooterMode(mode);
|
|
826
|
-
if (!normalized || normalized === "off") return void 0;
|
|
827
|
-
const { colored } = coord.renderFooter(modelId, normalized, style);
|
|
828
|
-
if (!colored) return void 0;
|
|
829
|
-
return ANSI_FG_RESET + colored;
|
|
830
|
-
}
|
|
831
|
-
function buildSettingsItems(config, fields = SETTINGS_FIELDS) {
|
|
811
|
+
function buildSettingsItems(config, fields = getRegisteredSettingFields()) {
|
|
832
812
|
return fields.map((f) => ({
|
|
833
813
|
id: f.key,
|
|
834
814
|
label: f.label,
|
|
@@ -851,29 +831,37 @@ async function settingsListTheme(theme) {
|
|
|
851
831
|
};
|
|
852
832
|
}
|
|
853
833
|
}
|
|
854
|
-
|
|
834
|
+
function resolveFields(registryOrFields) {
|
|
835
|
+
if (!registryOrFields) return getRegisteredSettingFields();
|
|
836
|
+
if ("getFields" in registryOrFields && typeof registryOrFields.getFields === "function") {
|
|
837
|
+
return registryOrFields.getFields();
|
|
838
|
+
}
|
|
839
|
+
return registryOrFields;
|
|
840
|
+
}
|
|
841
|
+
async function openSettings(ctx, registryOrFields) {
|
|
842
|
+
const fields = resolveFields(registryOrFields);
|
|
855
843
|
const file = defaultConfigFile();
|
|
856
844
|
if (ctx.mode === "tui" && ctx.hasUI) {
|
|
857
|
-
await openSettingsDialog(ctx,
|
|
845
|
+
await openSettingsDialog(ctx, fields, file);
|
|
858
846
|
return;
|
|
859
847
|
}
|
|
860
848
|
const config = loadProviderConfig(file);
|
|
861
849
|
if (!ctx.hasUI) {
|
|
862
|
-
const text =
|
|
850
|
+
const text = fields.map((f) => `${f.label}: ${fieldDisplayValue(config, f)}`).join("\n") + `
|
|
863
851
|
Edit ${file} to change.`;
|
|
864
852
|
if (ctx.hasUI) ctx.ui.notify(text, "info");
|
|
865
853
|
else console.log(text);
|
|
866
854
|
return;
|
|
867
855
|
}
|
|
868
|
-
let field =
|
|
856
|
+
let field = fields[0];
|
|
869
857
|
if (!field) return;
|
|
870
|
-
if (
|
|
871
|
-
const labels =
|
|
858
|
+
if (fields.length > 1) {
|
|
859
|
+
const labels = fields.map(
|
|
872
860
|
(f) => `${f.label} (current: ${fieldDisplayValue(config, f)})`
|
|
873
861
|
);
|
|
874
862
|
const choice = await ctx.ui.select("Antigravity settings", labels);
|
|
875
863
|
if (!choice) return;
|
|
876
|
-
const found =
|
|
864
|
+
const found = fields[labels.indexOf(choice)];
|
|
877
865
|
if (!found) return;
|
|
878
866
|
field = found;
|
|
879
867
|
}
|
|
@@ -882,39 +870,43 @@ Edit ${file} to change.`;
|
|
|
882
870
|
[...field.options]
|
|
883
871
|
);
|
|
884
872
|
if (!picked || !field.options.includes(picked)) return;
|
|
885
|
-
if (await applySettingValue(field, picked, file, ctx
|
|
873
|
+
if (await applySettingValue(field, picked, file, ctx)) {
|
|
886
874
|
ctx.ui.notify(`${field.label} set to ${picked}.`, "info");
|
|
887
875
|
} else {
|
|
888
876
|
ctx.ui.notify(writeFailedMessage(file), "error");
|
|
889
877
|
}
|
|
890
878
|
}
|
|
891
|
-
async function openSettingsDialog(ctx,
|
|
892
|
-
|
|
879
|
+
async function openSettingsDialog(ctx, fields, file) {
|
|
880
|
+
for (const field of fields) {
|
|
881
|
+
if (field.prepare) await field.prepare(ctx);
|
|
882
|
+
}
|
|
893
883
|
await ctx.ui.custom(async (tui, theme, _kb, done) => {
|
|
894
884
|
const config = loadProviderConfig(file);
|
|
895
|
-
const items = buildSettingsItems(config);
|
|
896
|
-
const
|
|
897
|
-
|
|
898
|
-
const item = items.find((i) => i.id === "quotaFooter");
|
|
885
|
+
const items = buildSettingsItems(config, fields);
|
|
886
|
+
const paintPreview = (field, value) => {
|
|
887
|
+
const item = items.find((i) => i.id === field.key);
|
|
899
888
|
if (!item) return;
|
|
900
|
-
const base =
|
|
901
|
-
const sample =
|
|
889
|
+
const base = field.description ?? "";
|
|
890
|
+
const sample = field.renderPreview?.(value, ctx, theme);
|
|
902
891
|
const head = sample && base ? `${base}: ${sample}` : sample ?? base;
|
|
903
|
-
const note =
|
|
892
|
+
const note = field.optionNotes?.[value];
|
|
904
893
|
item.description = note ? `${head}
|
|
905
894
|
${note}` : head;
|
|
906
895
|
};
|
|
907
|
-
|
|
896
|
+
for (const field of fields) {
|
|
897
|
+
const current = fieldDisplayValue(config, field);
|
|
898
|
+
paintPreview(field, current);
|
|
899
|
+
}
|
|
908
900
|
const list = new SettingsList(
|
|
909
901
|
items,
|
|
910
902
|
Math.min(items.length, 10),
|
|
911
903
|
await settingsListTheme(theme),
|
|
912
904
|
(id, newValue) => {
|
|
913
|
-
const field =
|
|
905
|
+
const field = fields.find((f) => f.key === id);
|
|
914
906
|
if (!field) return;
|
|
915
907
|
list.invalidate();
|
|
916
908
|
tui.requestRender();
|
|
917
|
-
void applySettingValue(field, newValue, file, ctx
|
|
909
|
+
void applySettingValue(field, newValue, file, ctx).then((saved) => {
|
|
918
910
|
if (!saved) {
|
|
919
911
|
list.updateValue(field.key, fieldDisplayValue(loadProviderConfig(file), field));
|
|
920
912
|
ctx.ui.notify(writeFailedMessage(file), "error");
|
|
@@ -922,7 +914,7 @@ ${note}` : head;
|
|
|
922
914
|
tui.requestRender();
|
|
923
915
|
return;
|
|
924
916
|
}
|
|
925
|
-
paintPreview(newValue);
|
|
917
|
+
paintPreview(field, newValue);
|
|
926
918
|
list.invalidate();
|
|
927
919
|
tui.requestRender();
|
|
928
920
|
});
|
|
@@ -945,6 +937,22 @@ ${note}` : head;
|
|
|
945
937
|
}
|
|
946
938
|
|
|
947
939
|
// src/quota-status.ts
|
|
940
|
+
var FOOTER_MODE_NOTES = Object.freeze({
|
|
941
|
+
smart: "Picks whichever window runs out first (5h or weekly), weighting the weekly pool by a ratio learned from your usage",
|
|
942
|
+
all: "Lists every window of the pool backing the current model (5h or weekly)"
|
|
943
|
+
});
|
|
944
|
+
var FOOTER_MODE_OPTIONS = Object.freeze([
|
|
945
|
+
"off",
|
|
946
|
+
"smart",
|
|
947
|
+
"all"
|
|
948
|
+
]);
|
|
949
|
+
function normalizeFooterMode(value) {
|
|
950
|
+
const v = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
951
|
+
return FOOTER_MODE_OPTIONS.includes(v) ? v : void 0;
|
|
952
|
+
}
|
|
953
|
+
function resolveFooterMode(config) {
|
|
954
|
+
return normalizeFooterMode(config?.settings?.quotaFooter) ?? "off";
|
|
955
|
+
}
|
|
948
956
|
function renderProgressBar(fraction, width = 10) {
|
|
949
957
|
const clamped = Math.max(0, Math.min(1, fraction));
|
|
950
958
|
const filled = Math.round(clamped * width);
|
|
@@ -1113,7 +1121,7 @@ function formatQuotaWindowPart(bucket) {
|
|
|
1113
1121
|
var ANSI_RED = "\x1B[31m";
|
|
1114
1122
|
var ANSI_YELLOW = "\x1B[33m";
|
|
1115
1123
|
var ANSI_DIM = "\x1B[90m";
|
|
1116
|
-
var
|
|
1124
|
+
var ANSI_FG_RESET = "\x1B[39m";
|
|
1117
1125
|
var QUOTA_WARN_PCT = 30;
|
|
1118
1126
|
var QUOTA_ALERT_PCT = 10;
|
|
1119
1127
|
function resolveColorizer(style) {
|
|
@@ -1121,7 +1129,7 @@ function resolveColorizer(style) {
|
|
|
1121
1129
|
if (style && typeof style.fg === "function") return (tone, text) => style.fg(tone, text);
|
|
1122
1130
|
return (tone, text) => {
|
|
1123
1131
|
const code = tone === "error" ? ANSI_RED : tone === "warning" ? ANSI_YELLOW : ANSI_DIM;
|
|
1124
|
-
return `${code}${text}${
|
|
1132
|
+
return `${code}${text}${ANSI_FG_RESET}`;
|
|
1125
1133
|
};
|
|
1126
1134
|
}
|
|
1127
1135
|
function colorizeQuotaFooter(footer, style) {
|
|
@@ -1140,9 +1148,51 @@ function colorizeQuotaFooterBoth(footer, style) {
|
|
|
1140
1148
|
const sep = color("dim", " \xB7 ");
|
|
1141
1149
|
return footer.split(" \xB7 ").map((part) => colorizeQuotaFooter(part, style) ?? part).join(sep);
|
|
1142
1150
|
}
|
|
1151
|
+
function previewQuotaFooterText(coord, modelId, mode, style) {
|
|
1152
|
+
if (!coord) return void 0;
|
|
1153
|
+
const normalized = normalizeFooterMode(mode);
|
|
1154
|
+
if (!normalized || normalized === "off") return void 0;
|
|
1155
|
+
const { colored } = coord.renderFooter(modelId, normalized, style);
|
|
1156
|
+
if (!colored) return void 0;
|
|
1157
|
+
return ANSI_FG_RESET + colored;
|
|
1158
|
+
}
|
|
1143
1159
|
var QUOTA_STATUS_KEY = "pi-provider-antigravity-footer-usage";
|
|
1144
1160
|
var QUOTA_REFRESH_INTERVAL_MS = 5 * 60 * 1e3;
|
|
1145
1161
|
var MAX_OBSERVATION_AGE_MS = 60 * 60 * 1e3;
|
|
1162
|
+
function fileQuotaStatusStore(file = defaultConfigFile()) {
|
|
1163
|
+
return {
|
|
1164
|
+
loadMode: () => resolveFooterMode(loadProviderConfig(file)),
|
|
1165
|
+
loadQuotaState: () => loadSubsystemState("quota", file),
|
|
1166
|
+
saveQuotaState: (state) => saveSubsystemState("quota", state, file)
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
function createQuotaFooterField(quotaStatus) {
|
|
1170
|
+
return {
|
|
1171
|
+
key: "quotaFooter",
|
|
1172
|
+
label: "Quota footer",
|
|
1173
|
+
description: "Show remaining quota in Pi's status footer",
|
|
1174
|
+
options: FOOTER_MODE_OPTIONS,
|
|
1175
|
+
defaultValue: "off",
|
|
1176
|
+
optionNotes: FOOTER_MODE_NOTES,
|
|
1177
|
+
renderPreview: (mode, ctx, theme) => {
|
|
1178
|
+
if (mode === "off") return "hidden";
|
|
1179
|
+
const activeTheme = theme || ctx.ui?.theme;
|
|
1180
|
+
return previewQuotaFooterText(quotaStatus, ctx.model?.id, mode, activeTheme);
|
|
1181
|
+
},
|
|
1182
|
+
prepare: async (ctx) => {
|
|
1183
|
+
await quotaStatus.ensurePreview(ctx);
|
|
1184
|
+
},
|
|
1185
|
+
onChange: async (ctx, _value) => {
|
|
1186
|
+
if (quotaStatus.mode() !== "off") {
|
|
1187
|
+
await quotaStatus.refresh(ctx, { ignoreMode: true });
|
|
1188
|
+
}
|
|
1189
|
+
quotaStatus.paint(ctx);
|
|
1190
|
+
}
|
|
1191
|
+
};
|
|
1192
|
+
}
|
|
1193
|
+
function registerQuotaSettings(quotaStatus) {
|
|
1194
|
+
registerSettingField(createQuotaFooterField(quotaStatus));
|
|
1195
|
+
}
|
|
1146
1196
|
function isFiniteNumber(value) {
|
|
1147
1197
|
return typeof value === "number" && Number.isFinite(value);
|
|
1148
1198
|
}
|
|
@@ -2063,7 +2113,10 @@ var SUBCOMMANDS = Object.freeze([
|
|
|
2063
2113
|
name: "settings",
|
|
2064
2114
|
description: "Configure provider settings",
|
|
2065
2115
|
aliases: Object.freeze(["setting"]),
|
|
2066
|
-
run: async ({ ctx, quotaStatus }) =>
|
|
2116
|
+
run: async ({ ctx, quotaStatus }) => {
|
|
2117
|
+
if (quotaStatus) registerQuotaSettings(quotaStatus);
|
|
2118
|
+
await openSettings(ctx);
|
|
2119
|
+
}
|
|
2067
2120
|
},
|
|
2068
2121
|
{
|
|
2069
2122
|
name: "websearch",
|
|
@@ -2214,6 +2267,7 @@ async function runAntigravitySubcommand(args, ctx, quotaStatus, catalog) {
|
|
|
2214
2267
|
var PROVIDER_NAME = "Antigravity";
|
|
2215
2268
|
function index_default(pi) {
|
|
2216
2269
|
const quotaStatus = new QuotaStatusCoordinator();
|
|
2270
|
+
registerQuotaSettings(quotaStatus);
|
|
2217
2271
|
const catalog = createModelCatalog();
|
|
2218
2272
|
pi.registerProvider(PROVIDER_ID, {
|
|
2219
2273
|
name: PROVIDER_NAME,
|