pi-ui-extend 0.1.13 → 0.1.17
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 +1 -1
- package/dist/app/app.d.ts +7 -0
- package/dist/app/app.js +102 -17
- package/dist/app/commands/command-controller.js +2 -0
- package/dist/app/commands/command-host.d.ts +5 -0
- package/dist/app/commands/command-model-actions.d.ts +2 -0
- package/dist/app/commands/command-model-actions.js +40 -4
- package/dist/app/commands/command-navigation-actions.d.ts +9 -0
- package/dist/app/commands/command-navigation-actions.js +62 -0
- package/dist/app/commands/command-registry.d.ts +2 -0
- package/dist/app/commands/command-registry.js +16 -0
- package/dist/app/constants.d.ts +0 -1
- package/dist/app/constants.js +0 -1
- package/dist/app/extensions/extension-ui-controller.d.ts +16 -5
- package/dist/app/extensions/extension-ui-controller.js +99 -61
- package/dist/app/icons.d.ts +1 -0
- package/dist/app/icons.js +2 -0
- package/dist/app/input/input-action-controller.d.ts +2 -0
- package/dist/app/input/input-action-controller.js +8 -1
- package/dist/app/logger.d.ts +25 -0
- package/dist/app/logger.js +90 -0
- package/dist/app/model/model-usage-status.js +30 -15
- package/dist/app/popup/menu-items-controller.d.ts +4 -0
- package/dist/app/popup/menu-items-controller.js +68 -6
- package/dist/app/popup/popup-action-controller.d.ts +2 -1
- package/dist/app/popup/popup-action-controller.js +7 -4
- package/dist/app/popup/popup-menu-controller.d.ts +36 -23
- package/dist/app/popup/popup-menu-controller.js +97 -326
- package/dist/app/rendering/conversation-entry-renderer.js +3 -3
- package/dist/app/rendering/conversation-viewport.d.ts +10 -2
- package/dist/app/rendering/conversation-viewport.js +157 -16
- package/dist/app/rendering/editor-panels.js +22 -9
- package/dist/app/rendering/popup-menu-renderer.d.ts +62 -0
- package/dist/app/rendering/popup-menu-renderer.js +405 -0
- package/dist/app/rendering/render-controller.js +30 -28
- package/dist/app/rendering/render-text.js +5 -2
- package/dist/app/rendering/status-line-renderer.d.ts +8 -1
- package/dist/app/rendering/status-line-renderer.js +217 -117
- package/dist/app/rendering/toast-controller.d.ts +12 -3
- package/dist/app/rendering/toast-controller.js +70 -12
- package/dist/app/runtime.d.ts +2 -1
- package/dist/app/runtime.js +20 -10
- package/dist/app/screen/mouse-controller.d.ts +2 -2
- package/dist/app/screen/mouse-controller.js +27 -48
- package/dist/app/screen/screen-styler.d.ts +1 -1
- package/dist/app/screen/screen-styler.js +9 -7
- package/dist/app/screen/scroll-controller.d.ts +12 -9
- package/dist/app/screen/scroll-controller.js +56 -45
- package/dist/app/screen/status-controller.js +2 -1
- package/dist/app/session/lazy-session-manager.d.ts +11 -0
- package/dist/app/session/lazy-session-manager.js +539 -0
- package/dist/app/session/pix-system-message.d.ts +16 -0
- package/dist/app/session/pix-system-message.js +64 -0
- package/dist/app/session/request-history.d.ts +4 -0
- package/dist/app/session/request-history.js +11 -0
- package/dist/app/session/session-event-controller.d.ts +11 -0
- package/dist/app/session/session-event-controller.js +58 -2
- package/dist/app/session/session-history.d.ts +18 -0
- package/dist/app/session/session-history.js +72 -3
- package/dist/app/session/session-lifecycle-controller.d.ts +6 -2
- package/dist/app/session/session-lifecycle-controller.js +7 -2
- package/dist/app/session/session-search.js +10 -0
- package/dist/app/session/tabs-controller.d.ts +17 -5
- package/dist/app/session/tabs-controller.js +308 -29
- package/dist/app/todo/todo-model.d.ts +4 -2
- package/dist/app/todo/todo-model.js +23 -13
- package/dist/app/types.d.ts +17 -6
- package/dist/app/workspace/workspace-actions-controller.d.ts +2 -0
- package/dist/app/workspace/workspace-actions-controller.js +12 -0
- package/dist/config.d.ts +6 -1
- package/dist/config.js +82 -25
- package/dist/default-pix-config.js +4 -0
- package/dist/fuzzy.d.ts +2 -0
- package/dist/fuzzy.js +27 -7
- package/dist/input-editor.d.ts +9 -0
- package/dist/input-editor.js +52 -0
- package/dist/schemas/pi-tools-suite-schema.d.ts +1 -0
- package/dist/schemas/pi-tools-suite-schema.js +1 -0
- package/dist/schemas/pix-schema.d.ts +3 -1
- package/dist/schemas/pix-schema.js +6 -4
- package/dist/terminal-width.d.ts +2 -0
- package/dist/terminal-width.js +64 -3
- package/dist/theme.js +6 -6
- package/dist/ui.d.ts +8 -0
- package/external/pi-tools-suite/README.md +3 -2
- package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +52 -8
- package/external/pi-tools-suite/src/antigravity-auth/commands.ts +3 -41
- package/external/pi-tools-suite/src/antigravity-auth/constants.ts +0 -2
- package/external/pi-tools-suite/src/antigravity-auth/index.ts +11 -18
- package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +129 -61
- package/external/pi-tools-suite/src/antigravity-auth/status.ts +82 -3
- package/external/pi-tools-suite/src/antigravity-auth/stream.ts +20 -7
- package/external/pi-tools-suite/src/antigravity-auth/types.ts +21 -0
- package/external/pi-tools-suite/src/config.ts +8 -0
- package/external/pi-tools-suite/src/dcp/index.ts +16 -1
- package/external/pi-tools-suite/src/dcp/state.ts +35 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +3 -0
- package/external/pi-tools-suite/src/todo/index.ts +123 -14
- package/external/pi-tools-suite/src/todo/state/persistence.ts +0 -1
- package/external/pi-tools-suite/src/todo/state/state-reducer.ts +26 -43
- package/external/pi-tools-suite/src/todo/todo.ts +12 -23
- package/external/pi-tools-suite/src/todo/tool/response-envelope.ts +34 -16
- package/external/pi-tools-suite/src/todo/tool/types.ts +7 -28
- package/external/pi-tools-suite/src/todo/view/format.ts +2 -3
- package/external/pi-tools-suite/src/tool-descriptions.ts +6 -4
- package/external/pi-tools-suite/src/usage/index.ts +5 -2
- package/external/pi-tools-suite/src/usage/lib/google.ts +53 -40
- package/external/pi-tools-suite/src/usage/lib/types.ts +12 -2
- package/package.json +1 -1
- package/schemas/pi-tools-suite.json +4 -0
- package/schemas/pix.json +11 -2
|
@@ -24,7 +24,7 @@ export const MSG_NO_TODOS = "No todos yet. Ask the agent to add some!";
|
|
|
24
24
|
// ---------------------------------------------------------------------------
|
|
25
25
|
|
|
26
26
|
export type TaskStatus = "pending" | "in_progress" | "deferred" | "completed" | "deleted";
|
|
27
|
-
export type
|
|
27
|
+
export type TodoThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
28
28
|
|
|
29
29
|
export type TaskAction = "create" | "update" | "batch_create" | "batch_update" | "list" | "get" | "delete" | "clear" | "export" | "import";
|
|
30
30
|
|
|
@@ -34,10 +34,9 @@ export interface Task {
|
|
|
34
34
|
description?: string;
|
|
35
35
|
activeForm?: string;
|
|
36
36
|
status: TaskStatus;
|
|
37
|
-
|
|
37
|
+
thinking?: TodoThinkingLevel;
|
|
38
38
|
parentId?: number;
|
|
39
39
|
blockedBy?: number[];
|
|
40
|
-
tags?: string[];
|
|
41
40
|
owner?: string;
|
|
42
41
|
metadata?: Record<string, unknown>;
|
|
43
42
|
}
|
|
@@ -67,20 +66,16 @@ export interface TaskMutationParams {
|
|
|
67
66
|
description?: string;
|
|
68
67
|
activeForm?: string;
|
|
69
68
|
status?: TaskStatus;
|
|
70
|
-
|
|
69
|
+
thinking?: TodoThinkingLevel;
|
|
71
70
|
parentId?: number | null;
|
|
72
71
|
clearParent?: boolean;
|
|
73
72
|
blockedBy?: number[];
|
|
74
73
|
addBlockedBy?: number[];
|
|
75
74
|
removeBlockedBy?: number[];
|
|
76
|
-
tags?: string[];
|
|
77
|
-
addTags?: string[];
|
|
78
|
-
removeTags?: string[];
|
|
79
75
|
owner?: string;
|
|
80
76
|
metadata?: Record<string, unknown>;
|
|
81
77
|
id?: number;
|
|
82
78
|
includeDeleted?: boolean;
|
|
83
|
-
tag?: string;
|
|
84
79
|
blockedOnly?: boolean;
|
|
85
80
|
items?: TaskMutationParams[];
|
|
86
81
|
format?: "json" | "markdown";
|
|
@@ -108,9 +103,9 @@ export const TodoParamsSchema = Type.Object({
|
|
|
108
103
|
description: "Target status (update) or list filter (list)",
|
|
109
104
|
}),
|
|
110
105
|
),
|
|
111
|
-
|
|
112
|
-
StringEnum(["low", "medium", "high", "
|
|
113
|
-
description: "
|
|
106
|
+
thinking: Type.Optional(
|
|
107
|
+
StringEnum(["off", "minimal", "low", "medium", "high", "xhigh"] as const, {
|
|
108
|
+
description: "Per-task thinking level used when todoThinking is enabled and this task is in_progress",
|
|
114
109
|
}),
|
|
115
110
|
),
|
|
116
111
|
parentId: Type.Optional(
|
|
@@ -138,21 +133,6 @@ export const TodoParamsSchema = Type.Object({
|
|
|
138
133
|
description: "Task ids to remove from blockedBy (update only, additive merge)",
|
|
139
134
|
}),
|
|
140
135
|
),
|
|
141
|
-
tags: Type.Optional(
|
|
142
|
-
Type.Array(Type.String(), {
|
|
143
|
-
description: "Tags to set on create/update, replacing the previous tag list",
|
|
144
|
-
}),
|
|
145
|
-
),
|
|
146
|
-
addTags: Type.Optional(
|
|
147
|
-
Type.Array(Type.String(), {
|
|
148
|
-
description: "Tags to add on update without replacing existing tags",
|
|
149
|
-
}),
|
|
150
|
-
),
|
|
151
|
-
removeTags: Type.Optional(
|
|
152
|
-
Type.Array(Type.String(), {
|
|
153
|
-
description: "Tags to remove on update",
|
|
154
|
-
}),
|
|
155
|
-
),
|
|
156
136
|
owner: Type.Optional(Type.String({ description: "Agent/owner assigned to this task" })),
|
|
157
137
|
metadata: Type.Optional(
|
|
158
138
|
Type.Record(Type.String(), Type.Unknown(), {
|
|
@@ -169,7 +149,6 @@ export const TodoParamsSchema = Type.Object({
|
|
|
169
149
|
description: "If true, list action returns deleted (tombstoned) tasks as well. Default: false.",
|
|
170
150
|
}),
|
|
171
151
|
),
|
|
172
|
-
tag: Type.Optional(Type.String({ description: "Tag filter for list/export" })),
|
|
173
152
|
blockedOnly: Type.Optional(Type.Boolean({ description: "If true, list only tasks blocked by another task" })),
|
|
174
153
|
items: Type.Optional(
|
|
175
154
|
Type.Array(Type.Record(Type.String(), Type.Unknown()), {
|
|
@@ -182,7 +161,7 @@ export const TodoParamsSchema = Type.Object({
|
|
|
182
161
|
}),
|
|
183
162
|
),
|
|
184
163
|
content: Type.Optional(Type.String({ description: "Import content for action=import" })),
|
|
185
|
-
replace: Type.Optional(Type.Boolean({ description: "For import, replace existing tasks instead of appending. Default: false." })),
|
|
164
|
+
replace: Type.Optional(Type.Boolean({ description: "For import/create/batch_create, replace existing tasks instead of appending. Use batch_create with replace:true when starting a new plan that supersedes old unfinished todos. Default: false." })),
|
|
186
165
|
});
|
|
187
166
|
|
|
188
167
|
export type TodoParams = Static<typeof TodoParamsSchema>;
|
|
@@ -10,9 +10,8 @@ export { formatStatusLabel };
|
|
|
10
10
|
*/
|
|
11
11
|
export function formatCommandTaskLine(t: Task, glyph: string): string {
|
|
12
12
|
const form = t.status === "in_progress" && t.activeForm ? ` (${t.activeForm})` : "";
|
|
13
|
-
const
|
|
13
|
+
const thinking = t.thinking ? ` {thinking:${t.thinking}}` : "";
|
|
14
14
|
const parent = t.parentId !== undefined ? ` ↳ #${t.parentId}` : "";
|
|
15
15
|
const block = t.blockedBy?.length ? ` ⛓ ${t.blockedBy.map((id) => `#${id}`).join(",")}` : "";
|
|
16
|
-
|
|
17
|
-
return ` ${glyph} #${t.id} ${t.subject}${priority}${form}${parent}${block}${tags}`;
|
|
16
|
+
return ` ${glyph} #${t.id} ${t.subject}${thinking}${form}${parent}${block}`;
|
|
18
17
|
}
|
|
@@ -249,10 +249,11 @@ export const REPO_DISCOVERY_TOOL_NAMES = REPO_DISCOVERY_TOOLS.map((tool) => tool
|
|
|
249
249
|
export const TODO_TOOL_DESCRIPTION: ToolDescription = {
|
|
250
250
|
name: "todo",
|
|
251
251
|
label: "Todo",
|
|
252
|
-
description: "Track and keep in sync non-trivial multi-step work as todos. Actions: create, update, batch_create, batch_update, list, get, delete, clear, export, import. Supports
|
|
253
|
-
promptSnippet: "Track/sync non-trivial multi-step work; resync when requirements
|
|
252
|
+
description: "Track and keep in sync non-trivial multi-step work as todos. Actions: create, update, batch_create, batch_update, list, get, delete, clear, export, import. Supports parent/subtask hierarchy, blockers, deferred out-of-scope items, dependencies, and replace:true on create/batch_create/import for intentionally replacing an obsolete plan; skip trivial or chat-only requests. Resynchronize the plan when requirements are added, canceled, or become obsolete, whether from user input or discovered facts. For multi-step plans, include a final user-facing report todo in the initial create/batch_create plan when possible. Keep exactly one task in_progress and complete it only after verification.",
|
|
253
|
+
promptSnippet: "Track/sync non-trivial multi-step work; include final report item; resync when requirements change; keep one task in_progress",
|
|
254
254
|
promptGuidelines: [
|
|
255
255
|
"Use `todo` for complex work with 3+ steps, explicit user task lists, or new non-trivial requirements. Skip single trivial tasks and purely conversational requests.",
|
|
256
|
+
"For any multi-step implementation/debugging plan, include a final todo item in the initial create/batch_create plan for the user-facing final report. Give that final-report todo explicit description/acceptance criteria covering changed files/behavior, verification commands/results, remaining manual actions, and never substitute a compression/housekeeping note for the final report.",
|
|
256
257
|
"When the user adds, removes, cancels, reprioritizes, or changes the goal, scope, requirements, constraints, or chosen approach, use `todo` before continuing to synchronize the plan: update still-relevant tasks, defer or delete obsolete tasks, add new required tasks, and adjust dependencies/order.",
|
|
257
258
|
"When your own investigation or verification discovers new facts that make the current todo plan stale, incomplete, impossible, unsafe, or no longer the best approach, use `todo` to revise the plan immediately instead of following outdated tasks.",
|
|
258
259
|
"Update todos as part of the workflow, not as end-of-task cleanup: whenever you start, finish, block, split, abandon, or materially change a step, call `todo` immediately before continuing.",
|
|
@@ -260,9 +261,10 @@ export const TODO_TOOL_DESCRIPTION: ToolDescription = {
|
|
|
260
261
|
"If implementation is partial, tests fail, or a blocker remains, keep the task in_progress and add/update a blocker task instead of completing it.",
|
|
261
262
|
"Never use `clear`, `delete`, or batch deletion to hide unfinished, stale, or forgotten todos. Defer obsolete items or update them with the reason; only delete when the user explicitly asks or the item was created by mistake.",
|
|
262
263
|
"Before giving a final response for work that used todos, ensure every visible todo is completed, deferred, or intentionally still in_progress with a blocker/explanation.",
|
|
263
|
-
"Keep subjects short and imperative; put details in description only when needed. Use
|
|
264
|
+
"Keep subjects short and imperative; put details in description only when needed. Use parentId for large plans; use blockedBy on create and addBlockedBy/removeBlockedBy on update for dependencies.",
|
|
264
265
|
"Use batch_create/batch_update for large explicit plans, but still keep exactly one visible task in_progress unless the user asks otherwise.",
|
|
265
|
-
"
|
|
266
|
+
"When starting a new plan that supersedes existing unfinished todos, use batch_create with replace:true instead of appending; only omit replace when intentionally extending the current plan.",
|
|
267
|
+
"list hides deleted tombstones unless includeDeleted:true; pass status or blockedOnly only when you need a filtered list.",
|
|
266
268
|
"Use export/import for handoff or plan migration; import with replace:true only when the user explicitly wants to overwrite the current todo state.",
|
|
267
269
|
"When every visible todo is completed, todo state clears automatically; do not call clear afterward just to remove completed tasks.",
|
|
268
270
|
"Optional project persistence is controlled by `/todos persist on|off|status` or the discoverable `/todos-persist on|off|status` alias; when resuming a persisted plan, ask the user which items are in scope and run `/todos scope <id...>` or `/todos-scope <id...>` so out-of-scope active tasks become deferred.",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
@@ -37,7 +37,10 @@ async function readOpenCodeAuth(): Promise<{ authData: AuthData; error?: string
|
|
|
37
37
|
|
|
38
38
|
async function readPiAuth(): Promise<PiAuthData> {
|
|
39
39
|
try {
|
|
40
|
-
const
|
|
40
|
+
const authPath = process.env.NODE_ENV === "test" && process.env.PI_TOOLS_SUITE_TEST_AUTH_PATH
|
|
41
|
+
? process.env.PI_TOOLS_SUITE_TEST_AUTH_PATH
|
|
42
|
+
: join(homedir(), ".pi", "agent", "auth.json");
|
|
43
|
+
const content = await readFile(authPath, "utf-8");
|
|
41
44
|
return JSON.parse(content) as PiAuthData;
|
|
42
45
|
} catch {
|
|
43
46
|
return {};
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Google Cloud 额度查询模块
|
|
3
3
|
*
|
|
4
|
-
* [输入]: ~/.
|
|
4
|
+
* [输入]: ~/.pi/agent/auth.json 中的 Antigravity 账号信息
|
|
5
5
|
* [输出]: 格式化的额度使用情况(按重置时间自动分组)
|
|
6
6
|
* [定位]: 被 usage.ts 调用,处理 Google Cloud 账号
|
|
7
7
|
* [同步]: usage.ts, types.ts, utils.ts
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
11
10
|
import { readFile } from "node:fs/promises";
|
|
12
11
|
import { homedir } from "node:os";
|
|
13
12
|
import { join } from "node:path";
|
|
@@ -15,7 +14,6 @@ import { join } from "node:path";
|
|
|
15
14
|
import {
|
|
16
15
|
type QueryResult,
|
|
17
16
|
type AntigravityAccount,
|
|
18
|
-
type AntigravityAccountsFile,
|
|
19
17
|
HIGH_USAGE_THRESHOLD,
|
|
20
18
|
} from "./types";
|
|
21
19
|
import { createProgressBar, fetchWithTimeout, safeMax } from "./utils";
|
|
@@ -54,9 +52,16 @@ type PiAntigravityCredential = {
|
|
|
54
52
|
type?: string;
|
|
55
53
|
refresh?: string;
|
|
56
54
|
email?: string;
|
|
55
|
+
clientId?: string;
|
|
56
|
+
clientSecret?: string;
|
|
57
|
+
googleClientId?: string;
|
|
58
|
+
googleClientSecret?: string;
|
|
59
|
+
oauthClient?: { clientId?: string; clientSecret?: string };
|
|
57
60
|
accounts?: AntigravityAccount[];
|
|
58
61
|
};
|
|
59
62
|
|
|
63
|
+
type GoogleOAuthClientCredentials = { clientId: string; clientSecret?: string };
|
|
64
|
+
|
|
60
65
|
// ============================================================================
|
|
61
66
|
// 常量
|
|
62
67
|
// ============================================================================
|
|
@@ -86,18 +91,10 @@ const MODEL_DISPLAY_NAMES: Record<string, string> = {
|
|
|
86
91
|
"claude-opus-4-6-thinking": "Claude Opus",
|
|
87
92
|
};
|
|
88
93
|
|
|
89
|
-
// 获取 Antigravity 账号文件路径
|
|
90
|
-
function getAntigravityAccountsPath(): string {
|
|
91
|
-
const home = homedir();
|
|
92
|
-
const configDir =
|
|
93
|
-
process.platform === "win32"
|
|
94
|
-
? process.env.APPDATA || join(home, "AppData", "Roaming")
|
|
95
|
-
: join(home, ".config");
|
|
96
|
-
return join(configDir, "opencode", "antigravity-accounts.json");
|
|
97
|
-
}
|
|
98
|
-
|
|
99
94
|
function getPiAuthPath(): string {
|
|
100
|
-
return
|
|
95
|
+
return process.env.NODE_ENV === "test" && process.env.PI_TOOLS_SUITE_TEST_AUTH_PATH
|
|
96
|
+
? process.env.PI_TOOLS_SUITE_TEST_AUTH_PATH
|
|
97
|
+
: join(homedir(), ".pi", "agent", "auth.json");
|
|
101
98
|
}
|
|
102
99
|
|
|
103
100
|
function splitPiRefresh(refresh: string): AntigravityAccount | null {
|
|
@@ -113,15 +110,37 @@ function splitPiRefresh(refresh: string): AntigravityAccount | null {
|
|
|
113
110
|
};
|
|
114
111
|
}
|
|
115
112
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
113
|
+
function getAccountRefreshToken(account: AntigravityAccount): string | undefined {
|
|
114
|
+
if (account.refreshToken) return account.refreshToken;
|
|
115
|
+
if (!account.refresh) return undefined;
|
|
116
|
+
return splitPiRefresh(account.refresh)?.refreshToken;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function stringProperty(source: unknown, keys: string[]): string | undefined {
|
|
120
|
+
if (!source || typeof source !== "object") return undefined;
|
|
121
|
+
const record = source as Record<string, unknown>;
|
|
122
|
+
for (const key of keys) {
|
|
123
|
+
const value = record[key];
|
|
124
|
+
if (typeof value === "string" && value) return value;
|
|
123
125
|
}
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
124
128
|
|
|
129
|
+
function getGoogleOAuthClientCredentials(...sources: unknown[]): GoogleOAuthClientCredentials | undefined {
|
|
130
|
+
for (const source of sources) {
|
|
131
|
+
const nested = source && typeof source === "object"
|
|
132
|
+
? (source as Record<string, unknown>).oauthClient
|
|
133
|
+
: undefined;
|
|
134
|
+
const nestedClientId = stringProperty(nested, ["clientId", "client_id", "id"]);
|
|
135
|
+
const nestedClientSecret = stringProperty(nested, ["clientSecret", "client_secret", "secret"]);
|
|
136
|
+
const clientId = nestedClientId ?? stringProperty(source, ["clientId", "client_id", "googleClientId", "google_client_id", "oauthClientId", "oauth_client_id"]);
|
|
137
|
+
const clientSecret = nestedClientSecret ?? stringProperty(source, ["clientSecret", "client_secret", "googleClientSecret", "google_client_secret", "oauthClientSecret", "oauth_client_secret"]);
|
|
138
|
+
if (clientId) return { clientId, ...(clientSecret ? { clientSecret } : {}) };
|
|
139
|
+
}
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function readAntigravityAccounts(): Promise<AntigravityAccount[]> {
|
|
125
144
|
try {
|
|
126
145
|
const content = await readFile(getPiAuthPath(), "utf-8");
|
|
127
146
|
const credential = (JSON.parse(content) as Record<string, PiAntigravityCredential>)[
|
|
@@ -129,8 +148,11 @@ async function readAntigravityAccounts(): Promise<AntigravityAccount[]> {
|
|
|
129
148
|
];
|
|
130
149
|
|
|
131
150
|
if (!credential) return [];
|
|
151
|
+
const credentialClient = getGoogleOAuthClientCredentials(credential);
|
|
132
152
|
const accounts = Array.isArray(credential.accounts)
|
|
133
|
-
? credential.accounts
|
|
153
|
+
? credential.accounts
|
|
154
|
+
.filter((account) => getAccountRefreshToken(account))
|
|
155
|
+
.map((account) => ({ ...credentialClient, ...account }))
|
|
134
156
|
: [];
|
|
135
157
|
const primaryAccount =
|
|
136
158
|
credential.type === "oauth" && credential.refresh
|
|
@@ -138,6 +160,7 @@ async function readAntigravityAccounts(): Promise<AntigravityAccount[]> {
|
|
|
138
160
|
: null;
|
|
139
161
|
if (primaryAccount) {
|
|
140
162
|
primaryAccount.email = credential.email;
|
|
163
|
+
Object.assign(primaryAccount, credentialClient);
|
|
141
164
|
accounts.unshift(primaryAccount);
|
|
142
165
|
}
|
|
143
166
|
|
|
@@ -156,15 +179,6 @@ async function readAntigravityAccounts(): Promise<AntigravityAccount[]> {
|
|
|
156
179
|
|
|
157
180
|
const GOOGLE_TOKEN_REFRESH_URL = "https://oauth2.googleapis.com/token";
|
|
158
181
|
|
|
159
|
-
const GOOGLE_CLIENT_ID =
|
|
160
|
-
process.env.PIX_ANTIGRAVITY_GOOGLE_CLIENT_ID ??
|
|
161
|
-
process.env.ANTIGRAVITY_GOOGLE_CLIENT_ID ??
|
|
162
|
-
"";
|
|
163
|
-
const GOOGLE_CLIENT_SECRET =
|
|
164
|
-
process.env.PIX_ANTIGRAVITY_GOOGLE_CLIENT_SECRET ??
|
|
165
|
-
process.env.ANTIGRAVITY_GOOGLE_CLIENT_SECRET ??
|
|
166
|
-
"";
|
|
167
|
-
|
|
168
182
|
// ============================================================================
|
|
169
183
|
// 工具函数
|
|
170
184
|
// ============================================================================
|
|
@@ -255,20 +269,19 @@ function extractModelQuotas(data: GoogleQuotaResponse): ModelQuota[] {
|
|
|
255
269
|
* 刷新 Google access token
|
|
256
270
|
*/
|
|
257
271
|
async function refreshAccessToken(
|
|
258
|
-
|
|
272
|
+
account: AntigravityAccount,
|
|
259
273
|
): Promise<{ access_token: string; expires_in: number }> {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
274
|
+
const refreshToken = getAccountRefreshToken(account);
|
|
275
|
+
if (!refreshToken) throw new Error("Missing refresh token, cannot query quota.");
|
|
276
|
+
const clientCredentials = getGoogleOAuthClientCredentials(account);
|
|
277
|
+
if (!clientCredentials) throw new Error(`Antigravity Google OAuth client credentials are missing in Pi auth: ${getPiAuthPath()}.`);
|
|
265
278
|
|
|
266
279
|
const params = new URLSearchParams({
|
|
267
|
-
client_id:
|
|
268
|
-
client_secret: GOOGLE_CLIENT_SECRET,
|
|
280
|
+
client_id: clientCredentials.clientId,
|
|
269
281
|
refresh_token: refreshToken,
|
|
270
282
|
grant_type: "refresh_token",
|
|
271
283
|
});
|
|
284
|
+
if (clientCredentials.clientSecret) params.set("client_secret", clientCredentials.clientSecret);
|
|
272
285
|
|
|
273
286
|
const response = await fetch(GOOGLE_TOKEN_REFRESH_URL, {
|
|
274
287
|
method: "POST",
|
|
@@ -326,7 +339,7 @@ async function fetchAccountQuota(
|
|
|
326
339
|
}> {
|
|
327
340
|
try {
|
|
328
341
|
// 刷新 access token
|
|
329
|
-
const { access_token } = await refreshAccessToken(account
|
|
342
|
+
const { access_token } = await refreshAccessToken(account);
|
|
330
343
|
|
|
331
344
|
// 使用 projectId 或 managedProjectId
|
|
332
345
|
const projectId = account.projectId || account.managedProjectId;
|
|
@@ -73,13 +73,23 @@ export interface CopilotQuotaConfig {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
* Antigravity 账号(来自 ~/.
|
|
76
|
+
* Antigravity 账号(来自 ~/.pi/agent/auth.json)
|
|
77
77
|
*/
|
|
78
78
|
export interface AntigravityAccount {
|
|
79
79
|
email?: string;
|
|
80
|
-
|
|
80
|
+
access?: string;
|
|
81
|
+
refresh?: string;
|
|
82
|
+
expires?: number;
|
|
83
|
+
refreshToken?: string;
|
|
81
84
|
projectId?: string;
|
|
82
85
|
managedProjectId?: string;
|
|
86
|
+
clientId?: string;
|
|
87
|
+
clientSecret?: string;
|
|
88
|
+
googleClientId?: string;
|
|
89
|
+
googleClientSecret?: string;
|
|
90
|
+
oauthClient?: { clientId?: string; clientSecret?: string };
|
|
91
|
+
fingerprint?: { apiClient?: string; [key: string]: unknown };
|
|
92
|
+
fingerprintHistory?: Array<{ fingerprint?: { apiClient?: string; [key: string]: unknown }; [key: string]: unknown }>;
|
|
83
93
|
addedAt: number;
|
|
84
94
|
lastUsed: number;
|
|
85
95
|
rateLimitResetTimes?: Record<string, number>;
|
package/package.json
CHANGED
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
},
|
|
17
17
|
"description": "List of disabled module names (e.g. ['lsp', 'prompt-commands'])."
|
|
18
18
|
},
|
|
19
|
+
"todoThinking": {
|
|
20
|
+
"type": "boolean",
|
|
21
|
+
"description": "Enable per-todo thinking levels and automatic thinking switch/restore when tasks become in-progress/completed."
|
|
22
|
+
},
|
|
19
23
|
"terminalBell": {
|
|
20
24
|
"type": "object",
|
|
21
25
|
"properties": {
|
package/schemas/pix.json
CHANGED
|
@@ -5,6 +5,15 @@
|
|
|
5
5
|
"type": "string",
|
|
6
6
|
"description": "JSON Schema URL used by editors for validation and autocomplete."
|
|
7
7
|
},
|
|
8
|
+
"ignoreContextFiles": {
|
|
9
|
+
"type": "boolean",
|
|
10
|
+
"description": "Disable AGENTS.md / CLAUDE.md discovery for sessions started in this project, equivalent to pi --no-context-files."
|
|
11
|
+
},
|
|
12
|
+
"maxProjectSessions": {
|
|
13
|
+
"type": "number",
|
|
14
|
+
"description": "Maximum number of pi session JSONL files to retain per project. Set to 0 to disable automatic session deletion.",
|
|
15
|
+
"minimum": 0
|
|
16
|
+
},
|
|
8
17
|
"defaultModel": {
|
|
9
18
|
"type": "object",
|
|
10
19
|
"properties": {
|
|
@@ -39,7 +48,7 @@
|
|
|
39
48
|
"const": "xhigh"
|
|
40
49
|
}
|
|
41
50
|
],
|
|
42
|
-
"description": "
|
|
51
|
+
"description": "Default model thinking budget level."
|
|
43
52
|
}
|
|
44
53
|
},
|
|
45
54
|
"description": "Default model selection for new sessions."
|
|
@@ -293,6 +302,6 @@
|
|
|
293
302
|
"$id": "https://unpkg.com/pi-ui-extend/schemas/pix.json",
|
|
294
303
|
"$schema": "https://json-schema.org/draft-07/schema#",
|
|
295
304
|
"title": "Pix Configuration",
|
|
296
|
-
"description": "Configuration for the pix terminal renderer (~/.config/pi/pix.jsonc).",
|
|
305
|
+
"description": "Configuration for the pix terminal renderer (~/.config/pi/pix.jsonc, with project overrides in <cwd>/.pi/pix.jsonc).",
|
|
297
306
|
"additionalProperties": true
|
|
298
307
|
}
|