tau-coding-agent 0.1.3 → 0.1.5

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.
Files changed (60) hide show
  1. package/README.md +1 -1
  2. package/extensions/answer.ts +49 -43
  3. package/extensions/branch-term.ts +11 -16
  4. package/extensions/btw.ts +8 -8
  5. package/extensions/ghostty.ts +65 -12
  6. package/extensions/git-diff-stats.ts +1 -1
  7. package/extensions/git-pr-status.ts +1 -1
  8. package/extensions/insights.ts +6 -5
  9. package/extensions/loop.ts +39 -11
  10. package/extensions/memory.ts +6 -5
  11. package/extensions/notify.ts +25 -6
  12. package/extensions/openai-fast.ts +6 -4
  13. package/extensions/openai-verbosity.ts +6 -4
  14. package/extensions/review/fix.ts +239 -0
  15. package/extensions/review/git.ts +517 -0
  16. package/extensions/review/index.ts +232 -0
  17. package/extensions/review/message-queue.ts +249 -0
  18. package/extensions/review/models.ts +589 -0
  19. package/extensions/review/prompts.ts +337 -0
  20. package/extensions/review/renderers/inline.ts +126 -0
  21. package/extensions/review/request.ts +504 -0
  22. package/extensions/review/review.ts +1305 -0
  23. package/extensions/review/runner.ts +522 -0
  24. package/extensions/review/runtime.ts +275 -0
  25. package/extensions/review/schema.ts +160 -0
  26. package/extensions/review/submit-review-tool.ts +66 -0
  27. package/extensions/review/submit-triage-tool.ts +59 -0
  28. package/extensions/review/triage.ts +746 -0
  29. package/extensions/sandbox/index.ts +428 -103
  30. package/extensions/{interlude.ts → stash.ts} +13 -11
  31. package/extensions/tool-display-mode.ts +173 -17
  32. package/extensions/usage/anthropic.ts +1 -1
  33. package/extensions/usage/github-copilot.ts +1 -1
  34. package/extensions/usage/index.ts +9 -5
  35. package/extensions/usage/minimax.ts +1 -1
  36. package/extensions/usage/openai-codex.ts +1 -1
  37. package/extensions/usage/openrouter.ts +1 -1
  38. package/extensions/usage/providers.ts +0 -2
  39. package/extensions/usage/types.ts +1 -2
  40. package/extensions/usage/zai.ts +1 -1
  41. package/extensions/websearch/README.md +1 -1
  42. package/extensions/websearch/browser/chromium.ts +42 -31
  43. package/extensions/websearch/browser/discovery.ts +11 -9
  44. package/extensions/websearch/browser/firefox.ts +10 -7
  45. package/extensions/websearch/browser/fs.ts +10 -0
  46. package/extensions/websearch/browser/sqlite.ts +22 -15
  47. package/extensions/websearch/config.ts +2 -2
  48. package/extensions/websearch/index.ts +9 -9
  49. package/extensions/websearch/providers/anthropic.pi.ts +1 -1
  50. package/extensions/websearch/providers/gemini.pi.ts +1 -1
  51. package/extensions/websearch/providers/openai-codex.pi.ts +1 -1
  52. package/extensions/websearch/providers/pi-model.shared.ts +2 -2
  53. package/extensions/worktree.ts +36 -36
  54. package/package.json +7 -7
  55. package/skills/git-clean-history/SKILL.md +1 -0
  56. package/skills/git-commit/SKILL.md +2 -2
  57. package/skills/oracle/scripts/oracle +28 -12
  58. package/themes/tau-dark.json +2 -1
  59. package/extensions/review.ts +0 -4347
  60. package/extensions/usage/google-gemini-cli.ts +0 -232
@@ -1,232 +0,0 @@
1
- import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
2
- import {
3
- clampPercent,
4
- LiveUsageUnavailableError,
5
- makeMeterItem,
6
- parseISODate,
7
- readArray,
8
- readString,
9
- } from "./shared.js";
10
- import type { LiveUsageItem, LiveUsageSnapshot, UsageProviderDefinition } from "./types.js";
11
-
12
- const PROVIDER_ID = "google-gemini-cli";
13
- const QUOTA_URL = "https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota";
14
- const LOAD_CODE_ASSIST_URL = "https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist";
15
-
16
- type GeminiTier = "free-tier" | "legacy-tier" | "standard-tier";
17
-
18
- interface GeminiAuthPayload {
19
- token?: string;
20
- projectId?: string;
21
- }
22
-
23
- interface GeminiQuota {
24
- modelId: string;
25
- percentLeft: number;
26
- resetTime?: Date;
27
- }
28
-
29
- function readAuthPayload(value: string): GeminiAuthPayload {
30
- try {
31
- return JSON.parse(value) as GeminiAuthPayload;
32
- } catch {
33
- throw new LiveUsageUnavailableError("Gemini CLI OAuth login is required for live quota data");
34
- }
35
- }
36
-
37
- function parsePlan(tier: GeminiTier | undefined): string | undefined {
38
- switch (tier) {
39
- case "standard-tier":
40
- return "Paid";
41
- case "free-tier":
42
- return "Free";
43
- case "legacy-tier":
44
- return "Legacy";
45
- default:
46
- return undefined;
47
- }
48
- }
49
-
50
- function parseModelLabel(modelId: string): string {
51
- const value = modelId.trim();
52
- const slash = value.lastIndexOf("/");
53
- return slash === -1 ? value : value.slice(slash + 1);
54
- }
55
-
56
- function isFlashLiteModel(id: string): boolean {
57
- return id.includes("flash-lite");
58
- }
59
-
60
- function isFlashModel(id: string): boolean {
61
- return id.includes("flash") && !isFlashLiteModel(id);
62
- }
63
-
64
- function isProModel(id: string): boolean {
65
- return id.includes("pro");
66
- }
67
-
68
- function makeMeter(key: string, label: string, quota: GeminiQuota): LiveUsageItem {
69
- return makeMeterItem({
70
- key,
71
- label,
72
- usedPercent: clampPercent(100 - quota.percentLeft),
73
- windowLabel: "24h",
74
- resetsAt: quota.resetTime,
75
- });
76
- }
77
-
78
- async function fetchJson(
79
- url: string,
80
- token: string,
81
- body: Record<string, unknown>,
82
- signal?: AbortSignal,
83
- ): Promise<Record<string, unknown>> {
84
- const response = await fetch(url, {
85
- method: "POST",
86
- headers: {
87
- Authorization: `Bearer ${token}`,
88
- "Content-Type": "application/json",
89
- },
90
- body: JSON.stringify(body),
91
- signal,
92
- });
93
-
94
- if (response.status === 401 || response.status === 403) {
95
- throw new Error("Gemini CLI login expired. Re-run /login google-gemini-cli.");
96
- }
97
-
98
- if (!response.ok) {
99
- const bodyText = await response.text().catch(() => "");
100
- throw new Error(
101
- bodyText.trim()
102
- ? `Gemini usage request failed (${response.status}): ${bodyText.trim()}`
103
- : `Gemini usage request failed (${response.status}).`,
104
- );
105
- }
106
-
107
- return (await response.json()) as Record<string, unknown>;
108
- }
109
-
110
- async function loadCodeAssistStatus(
111
- token: string,
112
- signal?: AbortSignal,
113
- ): Promise<{ tier?: GeminiTier }> {
114
- try {
115
- const payload = await fetchJson(
116
- LOAD_CODE_ASSIST_URL,
117
- token,
118
- { metadata: { ideType: "GEMINI_CLI", pluginType: "GEMINI" } },
119
- signal,
120
- );
121
-
122
- const currentTier = payload.currentTier as Record<string, unknown> | undefined;
123
- const tierId = readString(currentTier?.id);
124
-
125
- return {
126
- tier:
127
- tierId === "free-tier" || tierId === "legacy-tier" || tierId === "standard-tier"
128
- ? tierId
129
- : undefined,
130
- };
131
- } catch {
132
- return {};
133
- }
134
- }
135
-
136
- function parseQuotas(payload: Record<string, unknown>): GeminiQuota[] {
137
- const buckets = readArray<Record<string, unknown>>(payload.buckets);
138
- const quotaByModel = new Map<string, GeminiQuota>();
139
-
140
- for (const bucket of buckets) {
141
- const input = bucket as Record<string, unknown> | null | undefined;
142
- const modelId = readString(input?.modelId);
143
- const remainingFraction =
144
- typeof input?.remainingFraction === "number" ? input.remainingFraction : undefined;
145
- if (!modelId || remainingFraction === undefined) continue;
146
-
147
- const percentLeft = clampPercent(remainingFraction * 100);
148
- const resetTime = parseISODate(readString(input?.resetTime));
149
- const quota: GeminiQuota = {
150
- modelId,
151
- percentLeft,
152
- resetTime,
153
- };
154
-
155
- const existing = quotaByModel.get(modelId);
156
- if (!existing || quota.percentLeft < existing.percentLeft) {
157
- quotaByModel.set(modelId, quota);
158
- }
159
- }
160
-
161
- return [...quotaByModel.values()].sort((left, right) =>
162
- left.modelId.localeCompare(right.modelId),
163
- );
164
- }
165
-
166
- function buildItems(quotas: GeminiQuota[]): LiveUsageItem[] {
167
- const lower = quotas.map((quota) => ({ quota, modelId: quota.modelId.toLowerCase() }));
168
- const pro = lower.filter((entry) => isProModel(entry.modelId)).map((entry) => entry.quota);
169
- const flash = lower.filter((entry) => isFlashModel(entry.modelId)).map((entry) => entry.quota);
170
- const flashLite = lower
171
- .filter((entry) => isFlashLiteModel(entry.modelId))
172
- .map((entry) => entry.quota);
173
-
174
- const items: LiveUsageItem[] = [];
175
- const proMin = pro.sort((left, right) => left.percentLeft - right.percentLeft)[0];
176
- const flashMin = flash.sort((left, right) => left.percentLeft - right.percentLeft)[0];
177
- const flashLiteMin = flashLite.sort((left, right) => left.percentLeft - right.percentLeft)[0];
178
-
179
- if (proMin) items.push(makeMeter("pro", "Pro", proMin));
180
- if (flashMin) items.push(makeMeter("flash", "Flash", flashMin));
181
- if (flashLiteMin) items.push(makeMeter("flash-lite", "Flash Lite", flashLiteMin));
182
-
183
- if (items.length > 0) return items;
184
-
185
- for (const quota of quotas.slice(0, 3)) {
186
- items.push(makeMeter(quota.modelId, parseModelLabel(quota.modelId), quota));
187
- }
188
- return items;
189
- }
190
-
191
- async function fetchUsage(ctx: ExtensionContext, signal?: AbortSignal): Promise<LiveUsageSnapshot> {
192
- const apiKey = await ctx.modelRegistry.getApiKeyForProvider(PROVIDER_ID);
193
- if (!apiKey) throw new LiveUsageUnavailableError("no auth configured");
194
-
195
- const auth = readAuthPayload(apiKey);
196
- const token = typeof auth.token === "string" ? auth.token.trim() : "";
197
- if (!token) {
198
- throw new LiveUsageUnavailableError("Gemini CLI OAuth login is required for live quota data");
199
- }
200
-
201
- const authProjectId = typeof auth.projectId === "string" ? auth.projectId.trim() : undefined;
202
- const statusPromise = loadCodeAssistStatus(token, signal);
203
- const quotaPromise = fetchJson(
204
- QUOTA_URL,
205
- token,
206
- authProjectId ? { project: authProjectId } : {},
207
- signal,
208
- );
209
-
210
- const [status, quotaPayload] = await Promise.all([statusPromise, quotaPromise]);
211
- const quotas = parseQuotas(quotaPayload);
212
-
213
- if (quotas.length === 0) {
214
- throw new Error("Gemini did not return any live quota data.");
215
- }
216
-
217
- return {
218
- plan: parsePlan(status.tier),
219
- fetchedAt: new Date(),
220
- items: buildItems(quotas),
221
- };
222
- }
223
-
224
- const googleGeminiCliProvider: UsageProviderDefinition = {
225
- id: PROVIDER_ID,
226
- label: "Gemini CLI",
227
- shortLabel: "gemini",
228
- color: { r: 171, g: 135, b: 234 },
229
- fetchLiveUsage: fetchUsage,
230
- };
231
-
232
- export default googleGeminiCliProvider;