tau-coding-agent 0.1.5 → 0.2.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/README.md +15 -12
- package/extensions/answer.ts +129 -73
- package/extensions/branch-term/README.md +7 -0
- package/extensions/{branch-term.ts → branch-term/index.ts} +113 -104
- package/extensions/btw.ts +90 -4
- package/extensions/caffeinate/README.md +5 -0
- package/extensions/caffeinate/index.ts +144 -0
- package/extensions/fast.ts +292 -0
- package/extensions/ghostty.ts +214 -211
- package/extensions/git-diff-stats.ts +124 -84
- package/extensions/git-pr-status.ts +274 -208
- package/extensions/insights.ts +138 -183
- package/extensions/loop.ts +150 -135
- package/extensions/memory.ts +172 -97
- package/extensions/notify.ts +14 -26
- package/extensions/openai-verbosity.ts +108 -42
- package/extensions/review/fix.ts +15 -6
- package/extensions/review/git.ts +93 -103
- package/extensions/review/index.ts +60 -62
- package/extensions/review/interrupt.ts +117 -0
- package/extensions/review/message-queue.ts +45 -12
- package/extensions/review/models.ts +79 -3
- package/extensions/review/prompts.ts +43 -40
- package/extensions/review/review.ts +161 -166
- package/extensions/review/runner.ts +139 -147
- package/extensions/review/runtime.ts +173 -120
- package/extensions/review/submit-review-tool.ts +1 -5
- package/extensions/review/submit-triage-tool.ts +1 -0
- package/extensions/review/triage.ts +41 -44
- package/extensions/sandbox/bash.ts +775 -0
- package/extensions/sandbox/command.ts +605 -0
- package/extensions/sandbox/config.ts +764 -0
- package/extensions/sandbox/index.ts +138 -2850
- package/extensions/sandbox/macos-sandbox-shell.mjs +202 -0
- package/extensions/sandbox/permissions/dialog.ts +118 -0
- package/extensions/sandbox/permissions/filesystem.ts +559 -0
- package/extensions/sandbox/permissions/mach-lookup.ts +186 -0
- package/extensions/sandbox/permissions/network.ts +164 -0
- package/extensions/sandbox/permissions/unsandboxed.ts +270 -0
- package/extensions/sandbox/runtime.ts +616 -0
- package/extensions/stash.ts +28 -15
- package/extensions/subagent/README.md +73 -0
- package/extensions/subagent/index.ts +822 -0
- package/extensions/subagent/interrupt.ts +117 -0
- package/extensions/subagent/permissions.ts +101 -0
- package/extensions/subagent/rpc.ts +177 -0
- package/extensions/tool-display-mode.ts +267 -64
- package/extensions/usage/anthropic.ts +5 -6
- package/extensions/usage/github-copilot.ts +30 -9
- package/extensions/usage/index.ts +250 -357
- package/extensions/usage/openai-codex.ts +2 -2
- package/extensions/usage/openrouter.ts +10 -2
- package/extensions/websearch/README.md +12 -47
- package/extensions/websearch/config.ts +5 -2
- package/extensions/websearch/index.ts +94 -109
- package/extensions/websearch/output.ts +51 -0
- package/extensions/websearch/providers/anthropic.pi.ts +27 -44
- package/extensions/websearch/providers/gemini.browser.ts +68 -77
- package/extensions/websearch/providers/gemini.pi.ts +17 -17
- package/extensions/websearch/providers/openai-codex.pi.ts +145 -7
- package/extensions/websearch/providers/pi-model.shared.ts +44 -32
- package/extensions/websearch/providers/shared.ts +87 -2
- package/extensions/websearch/types.ts +0 -3
- package/extensions/worktree.ts +132 -172
- package/package.json +10 -5
- package/skills/browser-tools/SKILL.md +29 -234
- package/skills/browser-tools/references/cookies.md +36 -0
- package/skills/browser-tools/references/interaction.md +90 -0
- package/skills/browser-tools/references/logging.md +34 -0
- package/skills/git-clean-history/SKILL.md +6 -6
- package/skills/git-commit/SKILL.md +5 -3
- package/skills/github-pull-request/SKILL.md +60 -0
- package/skills/github-pull-request/references/create.md +40 -0
- package/skills/github-pull-request/references/stewardship.md +60 -0
- package/skills/oracle/SKILL.md +4 -4
- package/skills/oracle/scripts/oracle +64 -51
- package/skills/sentry/SKILL.md +15 -185
- package/skills/sentry/references/events.md +79 -0
- package/skills/sentry/references/issues.md +62 -0
- package/skills/sentry/references/logs.md +46 -0
- package/skills/update-changelog/SKILL.md +27 -121
- package/skills/web-design/SKILL.md +16 -105
- package/themes/tau-dark.json +4 -0
- package/extensions/openai-fast.ts +0 -229
- package/extensions/websearch/providers/openai-codex.browser.ts +0 -77
- package/extensions/websearch/providers/openai-codex.shared.ts +0 -123
package/extensions/ghostty.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - Shows the braille spinner backwards while context is compacting
|
|
7
7
|
* - Shows a ? marker while an extension prompt is waiting for input
|
|
8
8
|
* - Updates title with the current tool name during tool execution
|
|
9
|
-
* -
|
|
9
|
+
* - Includes background Review and Subagent work via their session-scoped lifecycle events
|
|
10
10
|
*
|
|
11
11
|
* Pi now emits native OSC 9;4 progress indicators, so this extension only manages the title.
|
|
12
12
|
*/
|
|
@@ -16,231 +16,214 @@ import path from "node:path";
|
|
|
16
16
|
|
|
17
17
|
const STATUS_SPINNER_INTERVAL_MS = 80;
|
|
18
18
|
const STATUS_SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
19
|
-
const REVIEW_EVENT_START = "review:start";
|
|
20
|
-
const REVIEW_EVENT_END = "review:end";
|
|
21
|
-
|
|
22
|
-
let sessionName: string | undefined;
|
|
23
|
-
let sessionCwd: string | undefined;
|
|
24
|
-
let currentTool: string | undefined;
|
|
25
|
-
let isWorking = false;
|
|
26
|
-
let isCompacting = false;
|
|
27
|
-
let frameIndex = 0;
|
|
28
|
-
let spinnerTimer: ReturnType<typeof setInterval> | undefined;
|
|
29
|
-
let pendingPromptCount = 0;
|
|
30
|
-
let latestCtx: ExtensionContext | undefined;
|
|
31
|
-
let currentSessionKey: string | undefined;
|
|
32
|
-
const activeReviewSessions = new Set<string>();
|
|
33
|
-
|
|
34
|
-
function buildTitle(extra?: string, marker = "π"): string {
|
|
35
|
-
const cwd = sessionCwd ?? process.cwd();
|
|
36
|
-
const segments: string[] = [marker, path.basename(cwd)];
|
|
37
|
-
if (sessionName) segments.push(sessionName);
|
|
38
|
-
if (extra) segments.push(extra);
|
|
39
|
-
return segments.join(" · ");
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function clearSpinnerTimer(): void {
|
|
43
|
-
if (!spinnerTimer) return;
|
|
44
|
-
clearInterval(spinnerTimer);
|
|
45
|
-
spinnerTimer = undefined;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function currentFrame(): string {
|
|
49
|
-
return STATUS_SPINNER_FRAMES[frameIndex % STATUS_SPINNER_FRAMES.length];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function resetFrame(): void {
|
|
53
|
-
frameIndex = 0;
|
|
54
|
-
}
|
|
55
19
|
|
|
56
|
-
function
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
20
|
+
export default function (pi: ExtensionAPI) {
|
|
21
|
+
let sessionName: string | undefined;
|
|
22
|
+
let sessionCwd: string | undefined;
|
|
23
|
+
const activeTools = new Map<string, string>();
|
|
24
|
+
let isWorking = false;
|
|
25
|
+
let isCompacting = false;
|
|
26
|
+
let frameIndex = 0;
|
|
27
|
+
let spinnerTimer: ReturnType<typeof setInterval> | undefined;
|
|
28
|
+
let promptPending = false;
|
|
29
|
+
let latestCtx: ExtensionContext | undefined;
|
|
30
|
+
let currentSessionKey: string | undefined;
|
|
31
|
+
const activeBackgroundSessions = new Map([
|
|
32
|
+
["review", new Set<string>()],
|
|
33
|
+
["subagent", new Set<string>()],
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
function buildTitle(extra?: string, marker = "π"): string {
|
|
37
|
+
const cwd = sessionCwd ?? process.cwd();
|
|
38
|
+
const segments: string[] = [marker, path.basename(cwd)];
|
|
39
|
+
if (sessionName) segments.push(sessionName);
|
|
40
|
+
if (extra) segments.push(extra);
|
|
41
|
+
return segments.join(" · ");
|
|
42
|
+
}
|
|
64
43
|
|
|
65
|
-
function
|
|
66
|
-
|
|
67
|
-
|
|
44
|
+
function clearSpinnerTimer(): void {
|
|
45
|
+
if (!spinnerTimer) return;
|
|
46
|
+
clearInterval(spinnerTimer);
|
|
47
|
+
spinnerTimer = undefined;
|
|
48
|
+
}
|
|
68
49
|
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (typeof payload.sessionKey !== "string") return undefined;
|
|
73
|
-
const sessionKey = payload.sessionKey.trim();
|
|
74
|
-
return sessionKey.length > 0 ? sessionKey : undefined;
|
|
75
|
-
}
|
|
50
|
+
function currentFrame(): string {
|
|
51
|
+
return STATUS_SPINNER_FRAMES[frameIndex % STATUS_SPINNER_FRAMES.length];
|
|
52
|
+
}
|
|
76
53
|
|
|
77
|
-
function
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
54
|
+
function resetFrame(): void {
|
|
55
|
+
frameIndex = 0;
|
|
56
|
+
}
|
|
81
57
|
|
|
82
|
-
function
|
|
83
|
-
|
|
84
|
-
|
|
58
|
+
function advanceFrame(): void {
|
|
59
|
+
const step = isCompacting ? -1 : 1;
|
|
60
|
+
frameIndex = (frameIndex + step + STATUS_SPINNER_FRAMES.length) % STATUS_SPINNER_FRAMES.length;
|
|
61
|
+
}
|
|
85
62
|
|
|
86
|
-
function
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (!isWorking && hasActiveReviewRuns()) return "review";
|
|
90
|
-
return undefined;
|
|
91
|
-
}
|
|
63
|
+
function hasPendingPrompts(): boolean {
|
|
64
|
+
return promptPending;
|
|
65
|
+
}
|
|
92
66
|
|
|
93
|
-
function
|
|
94
|
-
|
|
95
|
-
|
|
67
|
+
function getActiveBackgroundRun(): string | undefined {
|
|
68
|
+
for (const [kind, sessions] of activeBackgroundSessions) {
|
|
69
|
+
if (currentSessionKey && sessions.has(currentSessionKey)) return kind;
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
96
73
|
|
|
97
|
-
function
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
74
|
+
function isBusy(): boolean {
|
|
75
|
+
return isWorking || isCompacting || getActiveBackgroundRun() !== undefined;
|
|
76
|
+
}
|
|
101
77
|
|
|
102
|
-
function
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return;
|
|
78
|
+
function getWorkingExtra(): string | undefined {
|
|
79
|
+
const currentTool = [...activeTools.values()].at(-1);
|
|
80
|
+
if (currentTool) return currentTool;
|
|
81
|
+
if (isCompacting) return "compacting";
|
|
82
|
+
if (!isWorking) return getActiveBackgroundRun();
|
|
83
|
+
return undefined;
|
|
106
84
|
}
|
|
107
85
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return;
|
|
86
|
+
function renderWorkingTitle(ctx: ExtensionContext): void {
|
|
87
|
+
ctx.ui.setTitle(buildTitle(getWorkingExtra(), currentFrame()));
|
|
111
88
|
}
|
|
112
89
|
|
|
113
|
-
ctx
|
|
114
|
-
|
|
90
|
+
function renderPromptTitle(ctx: ExtensionContext): void {
|
|
91
|
+
const extra = isBusy() ? getWorkingExtra() : undefined;
|
|
92
|
+
ctx.ui.setTitle(buildTitle(extra, "?"));
|
|
93
|
+
}
|
|
115
94
|
|
|
116
|
-
function
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
renderWorkingTitle(ctx);
|
|
122
|
-
}, STATUS_SPINNER_INTERVAL_MS);
|
|
123
|
-
}
|
|
95
|
+
function renderActiveTitle(ctx: ExtensionContext): void {
|
|
96
|
+
if (hasPendingPrompts()) {
|
|
97
|
+
renderPromptTitle(ctx);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
124
100
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
resetFrame();
|
|
130
|
-
renderActiveTitle(ctx);
|
|
101
|
+
if (isBusy()) {
|
|
102
|
+
renderWorkingTitle(ctx);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
131
105
|
|
|
132
|
-
|
|
133
|
-
startSpinnerTimer(ctx);
|
|
106
|
+
ctx.ui.setTitle(buildTitle());
|
|
134
107
|
}
|
|
135
|
-
}
|
|
136
108
|
|
|
137
|
-
function
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
109
|
+
function startSpinnerTimer(ctx: ExtensionContext): void {
|
|
110
|
+
clearSpinnerTimer();
|
|
111
|
+
spinnerTimer = setInterval(() => {
|
|
112
|
+
if (!isBusy() || hasPendingPrompts()) return;
|
|
113
|
+
advanceFrame();
|
|
114
|
+
renderWorkingTitle(ctx);
|
|
115
|
+
}, STATUS_SPINNER_INTERVAL_MS);
|
|
116
|
+
}
|
|
141
117
|
|
|
142
|
-
|
|
118
|
+
function startSpinner(ctx: ExtensionContext): void {
|
|
119
|
+
clearSpinnerTimer();
|
|
120
|
+
isWorking = true;
|
|
121
|
+
activeTools.clear();
|
|
122
|
+
resetFrame();
|
|
143
123
|
renderActiveTitle(ctx);
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
124
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
return;
|
|
125
|
+
if (!hasPendingPrompts()) {
|
|
126
|
+
startSpinnerTimer(ctx);
|
|
127
|
+
}
|
|
151
128
|
}
|
|
152
129
|
|
|
153
|
-
|
|
154
|
-
|
|
130
|
+
function stopSpinner(ctx: ExtensionContext): void {
|
|
131
|
+
isWorking = false;
|
|
132
|
+
activeTools.clear();
|
|
133
|
+
clearSpinnerTimer();
|
|
155
134
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
135
|
+
if (hasPendingPrompts()) {
|
|
136
|
+
renderActiveTitle(ctx);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (isBusy()) {
|
|
141
|
+
renderWorkingTitle(ctx);
|
|
142
|
+
startSpinnerTimer(ctx);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
160
145
|
|
|
161
|
-
function handlePromptEnd(ctx: ExtensionContext): void {
|
|
162
|
-
if (hasPendingPrompts()) {
|
|
163
146
|
renderActiveTitle(ctx);
|
|
164
|
-
return;
|
|
165
147
|
}
|
|
166
148
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
return;
|
|
149
|
+
function handlePromptStart(ctx: ExtensionContext): void {
|
|
150
|
+
clearSpinnerTimer();
|
|
151
|
+
renderActiveTitle(ctx);
|
|
171
152
|
}
|
|
172
153
|
|
|
173
|
-
|
|
174
|
-
|
|
154
|
+
function handlePromptEnd(ctx: ExtensionContext): void {
|
|
155
|
+
if (hasPendingPrompts()) {
|
|
156
|
+
renderActiveTitle(ctx);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
175
159
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
signal.addEventListener("abort", () => stopCompaction(ctx), { once: true });
|
|
160
|
+
if (isBusy()) {
|
|
161
|
+
renderWorkingTitle(ctx);
|
|
162
|
+
startSpinnerTimer(ctx);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
182
165
|
|
|
183
|
-
|
|
184
|
-
if (!hasPendingPrompts()) {
|
|
185
|
-
startSpinnerTimer(ctx);
|
|
166
|
+
renderActiveTitle(ctx);
|
|
186
167
|
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function stopCompaction(ctx: ExtensionContext, options?: { render?: boolean }): void {
|
|
190
|
-
if (!isCompacting) return;
|
|
191
168
|
|
|
192
|
-
|
|
169
|
+
function startCompaction(ctx: ExtensionContext, signal: AbortSignal): void {
|
|
170
|
+
isCompacting = true;
|
|
171
|
+
activeTools.clear();
|
|
172
|
+
resetFrame();
|
|
173
|
+
signal.addEventListener("abort", () => stopCompaction(ctx), { once: true });
|
|
193
174
|
|
|
194
|
-
if (options?.render === false) return;
|
|
195
|
-
|
|
196
|
-
if (isBusy()) {
|
|
197
175
|
renderActiveTitle(ctx);
|
|
198
176
|
if (!hasPendingPrompts()) {
|
|
199
177
|
startSpinnerTimer(ctx);
|
|
200
178
|
}
|
|
201
|
-
return;
|
|
202
179
|
}
|
|
203
180
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
181
|
+
function stopCompaction(ctx: ExtensionContext, options?: { render?: boolean }): void {
|
|
182
|
+
if (!isCompacting) return;
|
|
207
183
|
|
|
208
|
-
|
|
209
|
-
renderActiveTitle(ctx);
|
|
210
|
-
}
|
|
184
|
+
isCompacting = false;
|
|
211
185
|
|
|
212
|
-
|
|
213
|
-
activeReviewSessions.add(sessionKey);
|
|
214
|
-
}
|
|
186
|
+
if (options?.render === false) return;
|
|
215
187
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
188
|
+
if (isBusy()) {
|
|
189
|
+
renderActiveTitle(ctx);
|
|
190
|
+
if (!hasPendingPrompts()) {
|
|
191
|
+
startSpinnerTimer(ctx);
|
|
192
|
+
}
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
219
195
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if (!hasPendingPrompts()) {
|
|
223
|
-
startSpinnerTimer(ctx);
|
|
196
|
+
clearSpinnerTimer();
|
|
197
|
+
renderActiveTitle(ctx);
|
|
224
198
|
}
|
|
225
|
-
}
|
|
226
199
|
|
|
227
|
-
function
|
|
228
|
-
if (hasPendingPrompts()) {
|
|
200
|
+
function syncSessionTitle(ctx: ExtensionContext): void {
|
|
229
201
|
renderActiveTitle(ctx);
|
|
230
|
-
return;
|
|
231
202
|
}
|
|
232
203
|
|
|
233
|
-
|
|
204
|
+
function handleBackgroundStart(ctx: ExtensionContext): void {
|
|
234
205
|
renderActiveTitle(ctx);
|
|
235
|
-
|
|
236
|
-
|
|
206
|
+
if (!hasPendingPrompts()) {
|
|
207
|
+
startSpinnerTimer(ctx);
|
|
208
|
+
}
|
|
237
209
|
}
|
|
238
210
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
211
|
+
function handleBackgroundEnd(ctx: ExtensionContext): void {
|
|
212
|
+
if (hasPendingPrompts()) {
|
|
213
|
+
renderActiveTitle(ctx);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (isBusy()) {
|
|
218
|
+
renderActiveTitle(ctx);
|
|
219
|
+
startSpinnerTimer(ctx);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
clearSpinnerTimer();
|
|
224
|
+
renderActiveTitle(ctx);
|
|
225
|
+
}
|
|
242
226
|
|
|
243
|
-
export default function (pi: ExtensionAPI) {
|
|
244
227
|
pi.on("session_start", async (_event, ctx) => {
|
|
245
228
|
if (!ctx.hasUI) return;
|
|
246
229
|
latestCtx = ctx;
|
|
@@ -254,6 +237,13 @@ export default function (pi: ExtensionAPI) {
|
|
|
254
237
|
}
|
|
255
238
|
});
|
|
256
239
|
|
|
240
|
+
pi.on("session_info_changed", (event, ctx) => {
|
|
241
|
+
if (!ctx.hasUI) return;
|
|
242
|
+
latestCtx = ctx;
|
|
243
|
+
sessionName = event.name;
|
|
244
|
+
renderActiveTitle(ctx);
|
|
245
|
+
});
|
|
246
|
+
|
|
257
247
|
pi.on("agent_start", async (_event, ctx) => {
|
|
258
248
|
if (!ctx.hasUI) return;
|
|
259
249
|
latestCtx = ctx;
|
|
@@ -268,16 +258,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
268
258
|
});
|
|
269
259
|
|
|
270
260
|
pi.on("tool_execution_start", async (event, ctx) => {
|
|
271
|
-
currentTool = event.toolName;
|
|
272
261
|
if (!ctx.hasUI) return;
|
|
262
|
+
activeTools.set(event.toolCallId, event.toolName);
|
|
273
263
|
latestCtx = ctx;
|
|
274
264
|
if (!isWorking) return;
|
|
275
265
|
renderActiveTitle(ctx);
|
|
276
266
|
});
|
|
277
267
|
|
|
278
|
-
pi.on("tool_execution_end", async (
|
|
279
|
-
currentTool = undefined;
|
|
268
|
+
pi.on("tool_execution_end", async (event, ctx) => {
|
|
280
269
|
if (!ctx.hasUI) return;
|
|
270
|
+
activeTools.delete(event.toolCallId);
|
|
281
271
|
latestCtx = ctx;
|
|
282
272
|
if (!isWorking) return;
|
|
283
273
|
renderActiveTitle(ctx);
|
|
@@ -295,55 +285,56 @@ export default function (pi: ExtensionAPI) {
|
|
|
295
285
|
stopCompaction(ctx);
|
|
296
286
|
});
|
|
297
287
|
|
|
298
|
-
pi.
|
|
299
|
-
|
|
288
|
+
pi.on("session_compact_failed", async (_event, ctx) => {
|
|
289
|
+
if (!ctx.hasUI) return;
|
|
290
|
+
latestCtx = ctx;
|
|
291
|
+
stopCompaction(ctx);
|
|
292
|
+
});
|
|
300
293
|
|
|
301
|
-
|
|
302
|
-
|
|
294
|
+
pi.on("ui_prompt_start", async (_event, ctx) => {
|
|
295
|
+
promptPending = true;
|
|
296
|
+
latestCtx = ctx;
|
|
297
|
+
if (!ctx.hasUI) return;
|
|
303
298
|
handlePromptStart(ctx);
|
|
304
299
|
});
|
|
305
300
|
|
|
306
|
-
pi.
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const ctx = latestCtx;
|
|
311
|
-
if (!ctx || !ctx.hasUI) return;
|
|
301
|
+
pi.on("ui_prompt_end", async (_event, ctx) => {
|
|
302
|
+
promptPending = false;
|
|
303
|
+
latestCtx = ctx;
|
|
304
|
+
if (!ctx.hasUI) return;
|
|
312
305
|
handlePromptEnd(ctx);
|
|
313
306
|
});
|
|
314
307
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
handleReviewEnd(ctx);
|
|
337
|
-
});
|
|
308
|
+
for (const [kind, sessions] of activeBackgroundSessions) {
|
|
309
|
+
pi.events.on(`${kind}:start`, (data) => {
|
|
310
|
+
const sessionKey = extractSessionKey(data);
|
|
311
|
+
if (!sessionKey) return;
|
|
312
|
+
sessions.add(sessionKey);
|
|
313
|
+
|
|
314
|
+
const ctx = latestCtx;
|
|
315
|
+
if (!ctx || !ctx.hasUI || currentSessionKey !== sessionKey) return;
|
|
316
|
+
handleBackgroundStart(ctx);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
pi.events.on(`${kind}:end`, (data) => {
|
|
320
|
+
const sessionKey = extractSessionKey(data);
|
|
321
|
+
if (!sessionKey) return;
|
|
322
|
+
sessions.delete(sessionKey);
|
|
323
|
+
|
|
324
|
+
const ctx = latestCtx;
|
|
325
|
+
if (!ctx || !ctx.hasUI || currentSessionKey !== sessionKey) return;
|
|
326
|
+
handleBackgroundEnd(ctx);
|
|
327
|
+
});
|
|
328
|
+
}
|
|
338
329
|
|
|
339
330
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
340
331
|
clearSpinnerTimer();
|
|
341
332
|
isWorking = false;
|
|
342
333
|
isCompacting = false;
|
|
343
|
-
|
|
344
|
-
|
|
334
|
+
activeTools.clear();
|
|
335
|
+
promptPending = false;
|
|
345
336
|
const sessionKey = getSessionKey(ctx);
|
|
346
|
-
|
|
337
|
+
for (const sessions of activeBackgroundSessions.values()) sessions.delete(sessionKey);
|
|
347
338
|
if (currentSessionKey === sessionKey) {
|
|
348
339
|
currentSessionKey = undefined;
|
|
349
340
|
sessionCwd = undefined;
|
|
@@ -352,3 +343,15 @@ export default function (pi: ExtensionAPI) {
|
|
|
352
343
|
latestCtx = undefined;
|
|
353
344
|
});
|
|
354
345
|
}
|
|
346
|
+
|
|
347
|
+
function getSessionKey(ctx: ExtensionContext): string {
|
|
348
|
+
return ctx.sessionManager.getSessionFile() ?? `session:${ctx.sessionManager.getSessionId()}`;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function extractSessionKey(data: unknown): string | undefined {
|
|
352
|
+
if (!data || typeof data !== "object") return undefined;
|
|
353
|
+
const payload = data as { sessionKey?: unknown };
|
|
354
|
+
if (typeof payload.sessionKey !== "string") return undefined;
|
|
355
|
+
const sessionKey = payload.sessionKey.trim();
|
|
356
|
+
return sessionKey.length > 0 ? sessionKey : undefined;
|
|
357
|
+
}
|