@herbertgao/pi-extensions 2026.9.3 → 2026.9.4
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 +2 -1
- package/THIRD_PARTY_NOTICES.md +25 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +3 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +16 -11
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +20 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +12 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +98 -0
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/pi-antigravity/LICENSE +21 -0
- package/node_modules/pi-antigravity/README.md +194 -0
- package/node_modules/pi-antigravity/package.json +67 -0
- package/node_modules/pi-antigravity/src/auth/index.ts +14 -0
- package/node_modules/pi-antigravity/src/auth/oauth.ts +442 -0
- package/node_modules/pi-antigravity/src/client/client.ts +561 -0
- package/node_modules/pi-antigravity/src/client/index.ts +1 -0
- package/node_modules/pi-antigravity/src/diagnostics/diagnostics.ts +96 -0
- package/node_modules/pi-antigravity/src/diagnostics/index.ts +1 -0
- package/node_modules/pi-antigravity/src/image/image.ts +336 -0
- package/node_modules/pi-antigravity/src/image/index.ts +1 -0
- package/node_modules/pi-antigravity/src/index.ts +280 -0
- package/node_modules/pi-antigravity/src/models/discovery.ts +154 -0
- package/node_modules/pi-antigravity/src/models/grouping.ts +424 -0
- package/node_modules/pi-antigravity/src/models/index.ts +3 -0
- package/node_modules/pi-antigravity/src/models/models.ts +500 -0
- package/node_modules/pi-antigravity/src/stream/index.ts +1 -0
- package/node_modules/pi-antigravity/src/stream/stream.ts +1460 -0
- package/node_modules/pi-antigravity/src/types/enums.ts +42 -0
- package/node_modules/pi-antigravity/src/types/index.ts +2 -0
- package/node_modules/pi-antigravity/src/types/types.ts +292 -0
- package/node_modules/pi-antigravity/src/usage/index.ts +1 -0
- package/node_modules/pi-antigravity/src/usage/usage.ts +371 -0
- package/node_modules/pi-antigravity/src/utils/http.ts +91 -0
- package/node_modules/pi-antigravity/src/utils/index.ts +3 -0
- package/node_modules/pi-antigravity/src/utils/security.ts +73 -0
- package/node_modules/pi-antigravity/src/utils/util.ts +132 -0
- package/node_modules/pi-antigravity/tsconfig.json +21 -0
- package/package.json +5 -2
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { antigravityEnv } from "./util.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Node's built-in fetch keeps an idle socket for only 4 seconds unless the server
|
|
5
|
+
* advertises a longer `Keep-Alive: timeout=`. The Cloud Code Assist endpoint sends no
|
|
6
|
+
* such header, and interactive coding turns are almost always more than 4 seconds
|
|
7
|
+
* apart, so without a dedicated pool every message pays a fresh DNS + TCP + TLS
|
|
8
|
+
* handshake. A long-lived dispatcher removes that per-turn setup cost.
|
|
9
|
+
*
|
|
10
|
+
* The dispatcher is scoped to this provider's requests rather than installed with
|
|
11
|
+
* `setGlobalDispatcher`, so it never changes HTTP behaviour for the rest of the host
|
|
12
|
+
* process or for other extensions.
|
|
13
|
+
*
|
|
14
|
+
* Node 22+ global `fetch` cannot take an npm `undici.Agent` (handler mismatch).
|
|
15
|
+
* Those runtimes already pool connections natively, so we skip the custom Agent.
|
|
16
|
+
*/
|
|
17
|
+
const KEEP_ALIVE_TIMEOUT_MS = 60_000;
|
|
18
|
+
const KEEP_ALIVE_MAX_TIMEOUT_MS = 5 * 60_000;
|
|
19
|
+
const CONNECT_TIMEOUT_MS = 10_000;
|
|
20
|
+
const PREWARM_TIMEOUT_MS = 5_000;
|
|
21
|
+
|
|
22
|
+
/** `dispatcher` is an undici extension to RequestInit that Node's fetch honours. */
|
|
23
|
+
type DispatcherInit = RequestInit & { dispatcher?: unknown };
|
|
24
|
+
|
|
25
|
+
let dispatcherPromise: Promise<unknown> | undefined;
|
|
26
|
+
|
|
27
|
+
function hasProxyConfiguration(): boolean {
|
|
28
|
+
return ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "http_proxy", "https_proxy", "all_proxy"].some(
|
|
29
|
+
(name) => Boolean(process.env[name]?.trim()),
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function getDispatcher(): Promise<unknown> {
|
|
34
|
+
dispatcherPromise ??= (async () => {
|
|
35
|
+
// Pi configures a proxy-aware global dispatcher. Passing a private Agent here
|
|
36
|
+
// would bypass it and make Antigravity requests connect directly instead.
|
|
37
|
+
if (antigravityEnv("NO_KEEPALIVE") === "1" || hasProxyConfiguration()) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
const nodeMajor = Number(process.versions.node?.split(".")[0]);
|
|
41
|
+
if (!Number.isNaN(nodeMajor) && nodeMajor >= 22) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const { Agent } = await import("undici");
|
|
46
|
+
return new Agent({
|
|
47
|
+
keepAliveTimeout: KEEP_ALIVE_TIMEOUT_MS,
|
|
48
|
+
keepAliveMaxTimeout: KEEP_ALIVE_MAX_TIMEOUT_MS,
|
|
49
|
+
connections: 8,
|
|
50
|
+
connect: { timeout: CONNECT_TIMEOUT_MS },
|
|
51
|
+
// HTTP/2 is opt-in: the endpoint negotiates it, but moving SSE onto h2 is a
|
|
52
|
+
// transport change we do not want to force on every user.
|
|
53
|
+
allowH2: antigravityEnv("HTTP2") === "1",
|
|
54
|
+
});
|
|
55
|
+
} catch {
|
|
56
|
+
// undici unavailable — fall back to Node's default fetch behaviour.
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
})();
|
|
60
|
+
return dispatcherPromise;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** fetch() bound to this provider's keep-alive connection pool when available. */
|
|
64
|
+
export async function antigravityFetch(
|
|
65
|
+
input: string | URL,
|
|
66
|
+
init: RequestInit = {},
|
|
67
|
+
): Promise<Response> {
|
|
68
|
+
const dispatcher = await getDispatcher();
|
|
69
|
+
if (!dispatcher) return fetch(input, init);
|
|
70
|
+
return fetch(input, { ...init, dispatcher } as DispatcherInit);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Open the TLS connection when the extension loads so the first message of a session
|
|
75
|
+
* does not pay the handshake either. Best-effort: failures are ignored.
|
|
76
|
+
*/
|
|
77
|
+
export function prewarmConnection(url: string): void {
|
|
78
|
+
if (antigravityEnv("NO_PREWARM") === "1") return;
|
|
79
|
+
void (async () => {
|
|
80
|
+
try {
|
|
81
|
+
const res = await antigravityFetch(url, {
|
|
82
|
+
method: "HEAD",
|
|
83
|
+
signal: AbortSignal.timeout(PREWARM_TIMEOUT_MS),
|
|
84
|
+
});
|
|
85
|
+
// Release the socket back to the pool even though HEAD carries no body.
|
|
86
|
+
await res.arrayBuffer();
|
|
87
|
+
} catch {
|
|
88
|
+
// Warm-up only; the real request will establish the connection instead.
|
|
89
|
+
}
|
|
90
|
+
})();
|
|
91
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { antigravityEnv } from "./util.js";
|
|
2
|
+
|
|
3
|
+
const LOOPBACK_HOSTS = new Set(["127.0.0.1", "::1", "localhost"]);
|
|
4
|
+
const ALLOWED_API_HOST_SUFFIXES = [".googleapis.com", ".sandbox.googleapis.com"];
|
|
5
|
+
|
|
6
|
+
/** Only loopback binds are allowed so OAuth codes cannot be stolen off-machine. */
|
|
7
|
+
export function resolveCallbackHost(raw = antigravityEnv("CALLBACK_HOST")): string {
|
|
8
|
+
const host = (raw || "127.0.0.1").trim().toLowerCase();
|
|
9
|
+
if (!LOOPBACK_HOSTS.has(host)) {
|
|
10
|
+
throw new Error(
|
|
11
|
+
`Unsafe ANTIGRAVITY_CALLBACK_HOST="${host}". Only loopback hosts are allowed: 127.0.0.1, ::1, localhost.`,
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
return host === "localhost" ? "127.0.0.1" : host;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Prevent token exfiltration via poisoned BASE_URL (SSRF / credential leak). */
|
|
18
|
+
export function assertSafeApiBaseUrl(raw: string): string {
|
|
19
|
+
let url: URL;
|
|
20
|
+
try {
|
|
21
|
+
url = new URL(raw);
|
|
22
|
+
} catch {
|
|
23
|
+
throw new Error(`Invalid ANTIGRAVITY_BASE_URL: ${raw}`);
|
|
24
|
+
}
|
|
25
|
+
if (url.protocol !== "https:") {
|
|
26
|
+
throw new Error(`ANTIGRAVITY_BASE_URL must use https (got ${url.protocol})`);
|
|
27
|
+
}
|
|
28
|
+
if (url.username || url.password) {
|
|
29
|
+
throw new Error("ANTIGRAVITY_BASE_URL must not include credentials");
|
|
30
|
+
}
|
|
31
|
+
const host = url.hostname.toLowerCase();
|
|
32
|
+
const allowed =
|
|
33
|
+
host === "googleapis.com" || ALLOWED_API_HOST_SUFFIXES.some((suffix) => host.endsWith(suffix));
|
|
34
|
+
if (!allowed) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`ANTIGRAVITY_BASE_URL host "${host}" is not allowed. Use a *.googleapis.com endpoint.`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
const path = url.pathname.replace(/\/+$/, "");
|
|
40
|
+
return `${url.origin}${path === "/" ? "" : path}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Redact bearer tokens, refresh tokens, and similar secrets from diagnostics/errors. */
|
|
44
|
+
export function redactSecrets(text: string): string {
|
|
45
|
+
return text
|
|
46
|
+
.replace(/\bya29\.[A-Za-z0-9._~+/-]+=*/g, "[redacted-access-token]")
|
|
47
|
+
.replace(/\b1\/[A-Za-z0-9_-]{20,}/g, "[redacted-refresh-token]")
|
|
48
|
+
.replace(/\bBearer\s+[A-Za-z0-9._~+/-]+=*/gi, "Bearer [redacted]")
|
|
49
|
+
.replace(
|
|
50
|
+
/("?(?:access_token|refresh_token|id_token|token|client_secret|code_verifier|authorization)"?\s*[:=]\s*")[^"]*(")/gi,
|
|
51
|
+
"$1[redacted]$2",
|
|
52
|
+
)
|
|
53
|
+
.replace(
|
|
54
|
+
/("?(?:access_token|refresh_token|id_token|token|client_secret|code_verifier|authorization)"?\s*[:=]\s*)[^\s&,}]+/gi,
|
|
55
|
+
"$1[redacted]",
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function maskEmail(email: string | undefined): string | undefined {
|
|
60
|
+
if (!email || typeof email !== "string") return undefined;
|
|
61
|
+
const parts = email.split("@");
|
|
62
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) return "[redacted-email]";
|
|
63
|
+
const name = parts[0];
|
|
64
|
+
const domain = parts[1];
|
|
65
|
+
const lastChar = name.at(-1) || "";
|
|
66
|
+
const maskedName = name.length > 2 ? `${name[0]}***${lastChar}` : `${name[0]}***`;
|
|
67
|
+
return `${maskedName}@${domain}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function safeError(error: unknown): string {
|
|
71
|
+
const raw = error instanceof Error ? error.message : String(error);
|
|
72
|
+
return redactSecrets(raw);
|
|
73
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { getModelEnum } from "../models/models.js";
|
|
3
|
+
|
|
4
|
+
export function antigravityEnv(name: string): string | undefined {
|
|
5
|
+
return process.env[`ANTIGRAVITY_${name}`] || process.env[`NOAGY_${name}`];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
9
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function asString(value: unknown): string | undefined {
|
|
13
|
+
return typeof value === "string" && value ? value : undefined;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function sanitizeText(text: unknown): string {
|
|
17
|
+
return String(text ?? "").replace(/[\uD800-\uDFFF]/g, "\uFFFD");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function escapeHtml(text: string): string {
|
|
21
|
+
return text
|
|
22
|
+
.replace(/&/g, "&")
|
|
23
|
+
.replace(/</g, "<")
|
|
24
|
+
.replace(/>/g, ">")
|
|
25
|
+
.replace(/"/g, """)
|
|
26
|
+
.replace(/'/g, "'");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function escapeRegExp(text: string): string {
|
|
30
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function nowRequestId(): string {
|
|
34
|
+
return antigravityRequestEnvelope("unknown", false).requestId;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Deterministic RFC 4122 v5 UUID from seed (survives restarts for the same session seed). */
|
|
38
|
+
export function stableUuid(seed: string): string {
|
|
39
|
+
const bytes = createHash("sha1").update(seed).digest().subarray(0, 16);
|
|
40
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x50;
|
|
41
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
42
|
+
const hex = [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
43
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type AntigravityEnvelopeOptions = {
|
|
47
|
+
isClaude?: boolean;
|
|
48
|
+
isNonGemini?: boolean;
|
|
49
|
+
step?: number;
|
|
50
|
+
lastStepIndex?: string;
|
|
51
|
+
requestIndex?: number;
|
|
52
|
+
userTurnIndex?: number;
|
|
53
|
+
trajectoryId?: string;
|
|
54
|
+
conversationId?: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const sessionTrajectoryMap = new Map<string, { conversationId: string; trajectoryId: string }>();
|
|
58
|
+
|
|
59
|
+
/** Stable conversationId and trajectoryId within a multi-turn conversation session. */
|
|
60
|
+
export function resolveSessionTrajectory(context?: {
|
|
61
|
+
messages?: Array<{ role?: string; timestamp?: number; content?: unknown }>;
|
|
62
|
+
}): { conversationId: string; trajectoryId: string } {
|
|
63
|
+
const firstMsg = context?.messages?.[0];
|
|
64
|
+
if (!firstMsg) {
|
|
65
|
+
return { conversationId: crypto.randomUUID(), trajectoryId: crypto.randomUUID() };
|
|
66
|
+
}
|
|
67
|
+
const contentSeed =
|
|
68
|
+
typeof firstMsg.content === "string"
|
|
69
|
+
? firstMsg.content.slice(0, 64)
|
|
70
|
+
: Array.isArray(firstMsg.content)
|
|
71
|
+
? JSON.stringify(firstMsg.content[0] ?? "").slice(0, 64)
|
|
72
|
+
: "";
|
|
73
|
+
const seed = `${firstMsg.role || "user"}:${firstMsg.timestamp || ""}:${contentSeed}`;
|
|
74
|
+
let entry = sessionTrajectoryMap.get(seed);
|
|
75
|
+
if (!entry) {
|
|
76
|
+
entry = {
|
|
77
|
+
conversationId: stableUuid(`antigravity:conv:${seed}`),
|
|
78
|
+
trajectoryId: stableUuid(`antigravity:traj:${seed}`),
|
|
79
|
+
};
|
|
80
|
+
sessionTrajectoryMap.set(seed, entry);
|
|
81
|
+
if (sessionTrajectoryMap.size > 64) {
|
|
82
|
+
const oldestKey = sessionTrajectoryMap.keys().next().value;
|
|
83
|
+
if (oldestKey !== undefined) sessionTrajectoryMap.delete(oldestKey);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return entry;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function clearSessionTrajectoryMap(): void {
|
|
90
|
+
sessionTrajectoryMap.clear();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function antigravityRequestEnvelope(
|
|
94
|
+
wireModelId: string,
|
|
95
|
+
optionsOrIsClaude: boolean | AntigravityEnvelopeOptions = false,
|
|
96
|
+
): { requestId: string; sessionId: string; labels: Record<string, string> } {
|
|
97
|
+
const options: AntigravityEnvelopeOptions =
|
|
98
|
+
typeof optionsOrIsClaude === "boolean" ? { isClaude: optionsOrIsClaude } : optionsOrIsClaude;
|
|
99
|
+
|
|
100
|
+
const isClaude = Boolean(options.isClaude);
|
|
101
|
+
const isNonGemini = Boolean(options.isNonGemini || isClaude);
|
|
102
|
+
const step = Math.max(1, options.step ?? 1);
|
|
103
|
+
const lastStepIndex = options.lastStepIndex ?? String(Math.max(0, step - 1));
|
|
104
|
+
const requestIndex = options.requestIndex ?? options.userTurnIndex ?? Math.max(0, step - 1);
|
|
105
|
+
const agentId = options.conversationId || crypto.randomUUID();
|
|
106
|
+
const trajectoryId = options.trajectoryId || crypto.randomUUID();
|
|
107
|
+
const bytes = crypto.getRandomValues(new Uint8Array(8));
|
|
108
|
+
const sessionId = String(new DataView(bytes.buffer, bytes.byteOffset, 8).getBigInt64(0, true));
|
|
109
|
+
|
|
110
|
+
const claudeLabel = isClaude ? "true" : "false";
|
|
111
|
+
const nonGeminiLabel = isNonGemini ? "true" : "false";
|
|
112
|
+
|
|
113
|
+
const labels: Record<string, string> = {
|
|
114
|
+
last_step_index: lastStepIndex,
|
|
115
|
+
request_id: `${trajectoryId}-${requestIndex}`,
|
|
116
|
+
trajectory_id: trajectoryId,
|
|
117
|
+
used_claude: claudeLabel,
|
|
118
|
+
used_claude_conservative: claudeLabel,
|
|
119
|
+
used_non_gemini_model: nonGeminiLabel,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const modelEnum = getModelEnum(wireModelId);
|
|
123
|
+
if (modelEnum) {
|
|
124
|
+
labels.model_enum = modelEnum;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
requestId: `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`,
|
|
129
|
+
sessionId,
|
|
130
|
+
labels,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"noEmit": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"noUnusedLocals": true,
|
|
14
|
+
"noUnusedParameters": true,
|
|
15
|
+
"noFallthroughCasesInSwitch": true,
|
|
16
|
+
"noImplicitOverride": true,
|
|
17
|
+
"forceConsistentCasingInFileNames": true,
|
|
18
|
+
"types": ["node"]
|
|
19
|
+
},
|
|
20
|
+
"include": ["src/**/*.ts"]
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herbertgao/pi-extensions",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.4",
|
|
4
4
|
"description": "Aggregate installer for HerbertGao-maintained Pi extensions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"extensions",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@effect/platform-node": "4.0.0-beta.103",
|
|
45
45
|
"@effect/platform-node-shared": "4.0.0-beta.103",
|
|
46
46
|
"@herbertgao/pi-bark": "0.1.0",
|
|
47
|
-
"@herbertgao/pi-cc-extensions": "0.9.
|
|
47
|
+
"@herbertgao/pi-cc-extensions": "0.9.1",
|
|
48
48
|
"@herbertgao/pi-subagents": "0.17.1",
|
|
49
49
|
"@herbertgao/resume-from": "0.2.0",
|
|
50
50
|
"@herbertgao/sol-pi": "0.2.0",
|
|
@@ -90,6 +90,7 @@
|
|
|
90
90
|
"nanoid": "^5.0.0",
|
|
91
91
|
"open": "^10.2.0",
|
|
92
92
|
"p-limit": "^6.1.0",
|
|
93
|
+
"pi-antigravity": "0.7.2",
|
|
93
94
|
"pi-footer": "0.5.1",
|
|
94
95
|
"pi-lens": "4.1.6",
|
|
95
96
|
"pi-mcp-adapter": "2.32.1",
|
|
@@ -133,6 +134,7 @@
|
|
|
133
134
|
"@tifan/pi-preferred-thinking",
|
|
134
135
|
"@tifan/pi-recap",
|
|
135
136
|
"@tifan/pi-rename",
|
|
137
|
+
"pi-antigravity",
|
|
136
138
|
"pi-footer",
|
|
137
139
|
"pi-lens",
|
|
138
140
|
"pi-mcp-adapter",
|
|
@@ -166,6 +168,7 @@
|
|
|
166
168
|
"./node_modules/pi-mcp-adapter/index.ts",
|
|
167
169
|
"./node_modules/pi-lens/dist/index.js",
|
|
168
170
|
"./node_modules/pi-web-access/index.ts",
|
|
171
|
+
"./node_modules/pi-antigravity/src/index.ts",
|
|
169
172
|
"./node_modules/remote-pi/dist/index.js",
|
|
170
173
|
"./node_modules/@czottmann/pi-automode/extensions/auto-mode.ts",
|
|
171
174
|
"./node_modules/pi-footer/src/index.ts"
|