tau-coding-agent 0.1.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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +42 -0
  3. package/extensions/answer.ts +601 -0
  4. package/extensions/branch-term.ts +405 -0
  5. package/extensions/btw.ts +444 -0
  6. package/extensions/ghostty.ts +301 -0
  7. package/extensions/git-diff-stats.ts +277 -0
  8. package/extensions/git-pr-status.ts +286 -0
  9. package/extensions/insights.ts +2367 -0
  10. package/extensions/interlude.ts +144 -0
  11. package/extensions/loop.ts +529 -0
  12. package/extensions/memory.ts +1889 -0
  13. package/extensions/notify.ts +161 -0
  14. package/extensions/openai-fast.ts +227 -0
  15. package/extensions/openai-verbosity.ts +223 -0
  16. package/extensions/review.ts +4347 -0
  17. package/extensions/sandbox/index.ts +2578 -0
  18. package/extensions/usage/anthropic.ts +198 -0
  19. package/extensions/usage/github-copilot.ts +204 -0
  20. package/extensions/usage/google-gemini-cli.ts +232 -0
  21. package/extensions/usage/index.ts +2310 -0
  22. package/extensions/usage/minimax.ts +208 -0
  23. package/extensions/usage/openai-codex.ts +180 -0
  24. package/extensions/usage/openrouter.ts +168 -0
  25. package/extensions/usage/providers.ts +26 -0
  26. package/extensions/usage/shared.ts +156 -0
  27. package/extensions/usage/types.ts +53 -0
  28. package/extensions/usage/zai.ts +186 -0
  29. package/extensions/websearch/README.md +68 -0
  30. package/extensions/websearch/browser/chromium.ts +330 -0
  31. package/extensions/websearch/browser/discovery.ts +75 -0
  32. package/extensions/websearch/browser/firefox.ts +150 -0
  33. package/extensions/websearch/browser/sqlite.ts +38 -0
  34. package/extensions/websearch/config.ts +76 -0
  35. package/extensions/websearch/index.ts +312 -0
  36. package/extensions/websearch/normalize.ts +155 -0
  37. package/extensions/websearch/providers/anthropic.pi.ts +139 -0
  38. package/extensions/websearch/providers/gemini.browser.ts +185 -0
  39. package/extensions/websearch/providers/gemini.pi.ts +108 -0
  40. package/extensions/websearch/providers/openai-codex.browser.ts +77 -0
  41. package/extensions/websearch/providers/openai-codex.pi.ts +49 -0
  42. package/extensions/websearch/providers/openai-codex.shared.ts +123 -0
  43. package/extensions/websearch/providers/pi-model.shared.ts +86 -0
  44. package/extensions/websearch/providers/search-prompt.shared.ts +17 -0
  45. package/extensions/websearch/providers/shared.ts +76 -0
  46. package/extensions/websearch/types.ts +52 -0
  47. package/extensions/worktree.ts +2223 -0
  48. package/package.json +72 -0
  49. package/skills/browser-tools/SKILL.md +253 -0
  50. package/skills/browser-tools/scripts/browser-content.js +100 -0
  51. package/skills/browser-tools/scripts/browser-cookies.js +33 -0
  52. package/skills/browser-tools/scripts/browser-dismiss-cookies.js +455 -0
  53. package/skills/browser-tools/scripts/browser-eval.js +75 -0
  54. package/skills/browser-tools/scripts/browser-logs-tail.js +89 -0
  55. package/skills/browser-tools/scripts/browser-nav.js +28 -0
  56. package/skills/browser-tools/scripts/browser-net-summary.js +115 -0
  57. package/skills/browser-tools/scripts/browser-pick.js +133 -0
  58. package/skills/browser-tools/scripts/browser-screenshot.js +18 -0
  59. package/skills/browser-tools/scripts/browser-start.js +281 -0
  60. package/skills/browser-tools/scripts/browser-watch.js +321 -0
  61. package/skills/browser-tools/scripts/utils.js +60 -0
  62. package/skills/git-clean-history/SKILL.md +45 -0
  63. package/skills/git-commit/SKILL.md +55 -0
  64. package/skills/oracle/SKILL.md +64 -0
  65. package/skills/oracle/scripts/oracle +249 -0
  66. package/skills/oracle/scripts/oracle-bundle +227 -0
  67. package/skills/sentry/SKILL.md +198 -0
  68. package/skills/sentry/lib/auth.js +99 -0
  69. package/skills/sentry/scripts/fetch-event.js +325 -0
  70. package/skills/sentry/scripts/fetch-issue.js +368 -0
  71. package/skills/sentry/scripts/list-issues.js +245 -0
  72. package/skills/sentry/scripts/search-events.js +291 -0
  73. package/skills/sentry/scripts/search-logs.js +234 -0
  74. package/skills/update-changelog/SKILL.md +135 -0
  75. package/skills/web-design/SKILL.md +117 -0
@@ -0,0 +1,286 @@
1
+ import {
2
+ isBashToolResult,
3
+ type ExtensionAPI,
4
+ type ExtensionContext,
5
+ } from "@mariozechner/pi-coding-agent";
6
+
7
+ const STATUS_KEY = "1-git-pr-status";
8
+
9
+ const REFRESH_DEBOUNCE_MS = 250;
10
+ const PR_LOOKUP_TIMEOUT_MS = 5_000;
11
+ const BRANCH_CHECK_TIMEOUT_MS = 1_000;
12
+ const USER_BASH_SETTLE_DELAY_MS = 2_000;
13
+
14
+ const GIT_BRANCH_CHANGE_COMMAND_PATTERN = /\bgit\s+(checkout|switch)\b/;
15
+ const GH_BRANCH_CHANGE_COMMAND_PATTERN = /\bgh\s+pr\s+checkout\b/;
16
+ const GH_PR_STATE_COMMAND_PATTERN = /\bgh\s+pr\s+(create|close|merge|ready|reopen)\b/;
17
+
18
+ type PullRequestState = "OPEN" | "CLOSED" | "MERGED";
19
+
20
+ type PullRequestStatus = {
21
+ number: number;
22
+ url: string;
23
+ state: PullRequestState;
24
+ };
25
+
26
+ type PullRequestLookupResult =
27
+ | { kind: "found"; pullRequest: PullRequestStatus }
28
+ | { kind: "none" }
29
+ | { kind: "error" };
30
+
31
+ function isBranchChangeCommand(command: string): boolean {
32
+ return (
33
+ GIT_BRANCH_CHANGE_COMMAND_PATTERN.test(command) ||
34
+ GH_BRANCH_CHANGE_COMMAND_PATTERN.test(command)
35
+ );
36
+ }
37
+
38
+ function isPullRequestStateCommand(command: string): boolean {
39
+ return GH_PR_STATE_COMMAND_PATTERN.test(command);
40
+ }
41
+
42
+ function isNoPullRequestError(stderr: string): boolean {
43
+ return stderr.toLowerCase().includes("no pull requests found for branch");
44
+ }
45
+
46
+ async function loadCurrentBranch(pi: ExtensionAPI, cwd: string): Promise<string | undefined> {
47
+ const result = await pi.exec("git", ["branch", "--show-current"], {
48
+ cwd,
49
+ timeout: BRANCH_CHECK_TIMEOUT_MS,
50
+ });
51
+ if (result.killed || result.code !== 0) return undefined;
52
+
53
+ const branch = result.stdout.trim();
54
+ return branch || undefined;
55
+ }
56
+
57
+ async function loadPullRequestStatus(
58
+ pi: ExtensionAPI,
59
+ cwd: string,
60
+ signal?: AbortSignal,
61
+ ): Promise<PullRequestLookupResult> {
62
+ const result = await pi.exec("gh", ["pr", "view", "--json", "number,url,state"], {
63
+ cwd,
64
+ signal,
65
+ timeout: PR_LOOKUP_TIMEOUT_MS,
66
+ });
67
+
68
+ if (result.killed) return { kind: "error" };
69
+ if (result.code !== 0) {
70
+ return isNoPullRequestError(result.stderr) ? { kind: "none" } : { kind: "error" };
71
+ }
72
+
73
+ const output = result.stdout.trim();
74
+ if (!output) return { kind: "error" };
75
+
76
+ try {
77
+ const parsed = JSON.parse(output) as {
78
+ number?: unknown;
79
+ state?: unknown;
80
+ url?: unknown;
81
+ };
82
+
83
+ if (parsed.state !== "OPEN" && parsed.state !== "CLOSED" && parsed.state !== "MERGED")
84
+ return { kind: "error" };
85
+ if (typeof parsed.number !== "number" || !Number.isInteger(parsed.number) || parsed.number <= 0)
86
+ return { kind: "error" };
87
+ if (typeof parsed.url !== "string") return { kind: "error" };
88
+
89
+ const url = parsed.url.trim();
90
+ if (!url) return { kind: "error" };
91
+
92
+ return {
93
+ kind: "found",
94
+ pullRequest: {
95
+ number: parsed.number,
96
+ url,
97
+ state: parsed.state,
98
+ },
99
+ };
100
+ } catch {
101
+ return { kind: "error" };
102
+ }
103
+ }
104
+
105
+ function formatPullRequestStatus(ctx: ExtensionContext, status: PullRequestStatus): string {
106
+ const suffix = status.state === "OPEN" ? "" : ` (${status.state.toLowerCase()})`;
107
+ return ctx.ui.theme.fg("dim", `#${status.number}${suffix}`);
108
+ }
109
+
110
+ export default function gitPrStatusExtension(pi: ExtensionAPI) {
111
+ let ctx: ExtensionContext | undefined;
112
+ let currentBranch: string | undefined;
113
+ let pullRequest: PullRequestStatus | undefined;
114
+ let generation = 0;
115
+ let refreshTimer: NodeJS.Timeout | undefined;
116
+ let branchCheckTimer: NodeJS.Timeout | undefined;
117
+ let refreshInFlight: Promise<void> | null = null;
118
+ let refreshQueued = false;
119
+ let activeRefreshAbortController: AbortController | undefined;
120
+
121
+ function reset(nextCtx?: ExtensionContext): void {
122
+ ctx?.ui.setStatus(STATUS_KEY, undefined);
123
+ ctx = nextCtx;
124
+ currentBranch = undefined;
125
+ pullRequest = undefined;
126
+ generation += 1;
127
+
128
+ if (refreshTimer) clearTimeout(refreshTimer);
129
+ refreshTimer = undefined;
130
+ if (branchCheckTimer) clearTimeout(branchCheckTimer);
131
+ branchCheckTimer = undefined;
132
+ activeRefreshAbortController?.abort();
133
+ activeRefreshAbortController = undefined;
134
+ refreshInFlight = null;
135
+ refreshQueued = false;
136
+
137
+ if (!nextCtx?.hasUI) return;
138
+
139
+ primeCurrentBranch(nextCtx.cwd, generation);
140
+ scheduleRefresh(0);
141
+ }
142
+
143
+ function applyStatus(): void {
144
+ const activeCtx = ctx;
145
+ if (!activeCtx?.hasUI) return;
146
+
147
+ activeCtx.ui.setStatus(
148
+ STATUS_KEY,
149
+ pullRequest ? formatPullRequestStatus(activeCtx, pullRequest) : undefined,
150
+ );
151
+ }
152
+
153
+ function scheduleRefresh(delay = REFRESH_DEBOUNCE_MS): void {
154
+ const activeCtx = ctx;
155
+ if (!activeCtx?.hasUI) return;
156
+
157
+ if (refreshTimer) clearTimeout(refreshTimer);
158
+
159
+ const refreshGeneration = generation;
160
+ const cwd = activeCtx.cwd;
161
+ refreshTimer = setTimeout(() => {
162
+ refreshTimer = undefined;
163
+ void refresh(cwd, refreshGeneration);
164
+ }, delay);
165
+ }
166
+
167
+ async function primeCurrentBranch(cwd: string, branchGeneration: number): Promise<void> {
168
+ const branch = await loadCurrentBranch(pi, cwd);
169
+ if (generation !== branchGeneration) return;
170
+ currentBranch = branch;
171
+ }
172
+
173
+ function scheduleBranchCheck(delay = 0): void {
174
+ const activeCtx = ctx;
175
+ if (!activeCtx?.hasUI) return;
176
+
177
+ if (branchCheckTimer) clearTimeout(branchCheckTimer);
178
+
179
+ const branchGeneration = generation;
180
+ const cwd = activeCtx.cwd;
181
+ branchCheckTimer = setTimeout(() => {
182
+ branchCheckTimer = undefined;
183
+ void checkForBranchChange(cwd, branchGeneration);
184
+ }, delay);
185
+ }
186
+
187
+ async function checkForBranchChange(cwd: string, branchGeneration: number): Promise<void> {
188
+ const nextBranch = await loadCurrentBranch(pi, cwd);
189
+ if (generation !== branchGeneration) return;
190
+ if (nextBranch === currentBranch) return;
191
+
192
+ currentBranch = nextBranch;
193
+ pullRequest = undefined;
194
+ applyStatus();
195
+ scheduleRefresh(0);
196
+ }
197
+
198
+ async function refresh(cwd: string, refreshGeneration: number): Promise<void> {
199
+ if (refreshInFlight) {
200
+ refreshQueued = true;
201
+ return;
202
+ }
203
+
204
+ const abortController = new AbortController();
205
+ activeRefreshAbortController = abortController;
206
+
207
+ const promise = (async () => {
208
+ const result = await loadPullRequestStatus(pi, cwd, abortController.signal);
209
+ if (generation !== refreshGeneration) return;
210
+
211
+ if (result.kind === "found") {
212
+ pullRequest = result.pullRequest;
213
+ applyStatus();
214
+ return;
215
+ }
216
+
217
+ if (result.kind === "none") {
218
+ pullRequest = undefined;
219
+ applyStatus();
220
+ }
221
+ })();
222
+
223
+ refreshInFlight = promise;
224
+
225
+ try {
226
+ await promise;
227
+ } catch {
228
+ if (generation !== refreshGeneration || abortController.signal.aborted) return;
229
+ } finally {
230
+ if (activeRefreshAbortController === abortController) {
231
+ activeRefreshAbortController = undefined;
232
+ }
233
+ if (refreshInFlight === promise) {
234
+ refreshInFlight = null;
235
+ if (refreshQueued) {
236
+ refreshQueued = false;
237
+ scheduleRefresh(0);
238
+ }
239
+ }
240
+ }
241
+ }
242
+
243
+ pi.on("session_start", async (_event, nextCtx) => {
244
+ reset(nextCtx);
245
+ });
246
+
247
+ pi.on("user_bash", (event, nextCtx) => {
248
+ ctx = nextCtx;
249
+
250
+ if (isBranchChangeCommand(event.command)) {
251
+ scheduleBranchCheck(USER_BASH_SETTLE_DELAY_MS);
252
+ return undefined;
253
+ }
254
+
255
+ if (isPullRequestStateCommand(event.command)) {
256
+ scheduleRefresh(USER_BASH_SETTLE_DELAY_MS);
257
+ }
258
+
259
+ return undefined;
260
+ });
261
+
262
+ pi.on("tool_result", async (event, nextCtx) => {
263
+ ctx = nextCtx;
264
+
265
+ if (!isBashToolResult(event)) return;
266
+ if (typeof event.input.command !== "string") return;
267
+
268
+ if (isBranchChangeCommand(event.input.command)) {
269
+ scheduleBranchCheck(0);
270
+ return;
271
+ }
272
+
273
+ if (isPullRequestStateCommand(event.input.command)) {
274
+ scheduleRefresh(0);
275
+ }
276
+ });
277
+
278
+ pi.on("turn_end", async (_event, nextCtx) => {
279
+ ctx = nextCtx;
280
+ scheduleBranchCheck(0);
281
+ });
282
+
283
+ pi.on("session_shutdown", async () => {
284
+ reset(undefined);
285
+ });
286
+ }