@narumitw/pi-statusline 0.50.0 → 0.50.1
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 +29 -209
- package/dist/chunks/{chunk-74QZGJ7L.js → chunk-J2ZSGEDQ.js} +18 -97
- package/dist/chunks/chunk-J2ZSGEDQ.js.map +7 -0
- package/dist/chunks/{commands-C2G2G7C6.js → commands-PPT3AJTL.js} +14 -58
- package/dist/chunks/commands-PPT3AJTL.js.map +7 -0
- package/dist/index.ts +21 -76
- package/dist/index.ts.map +2 -2
- package/docs/configuration.md +194 -0
- package/package.json +51 -51
- package/src/ansi.ts +18 -24
- package/src/command-contract.ts +6 -6
- package/src/commands.ts +759 -818
- package/src/directory.ts +27 -31
- package/src/extension-status.ts +186 -219
- package/src/git-status.ts +103 -111
- package/src/information-profiles.ts +12 -31
- package/src/powerline.ts +120 -127
- package/src/presets/candy.ts +1 -7
- package/src/presets/create-ramp.ts +21 -23
- package/src/presets/custom.ts +7 -7
- package/src/presets/forest.ts +1 -7
- package/src/presets/index.ts +30 -32
- package/src/presets/mono.ts +1 -7
- package/src/presets/neon.ts +1 -7
- package/src/presets/ocean.ts +1 -7
- package/src/presets/sunset.ts +1 -7
- package/src/presets/tokyo-night.ts +9 -9
- package/src/presets/types.ts +5 -5
- package/src/render.ts +277 -306
- package/src/settings.ts +516 -568
- package/src/statusline.ts +347 -372
- package/src/types.ts +34 -42
- package/src/usage.ts +40 -40
- package/dist/chunks/chunk-74QZGJ7L.js.map +0 -7
- package/dist/chunks/commands-C2G2G7C6.js.map +0 -7
package/src/statusline.ts
CHANGED
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
|
-
import {
|
|
3
|
-
type ExtensionAPI,
|
|
4
|
-
type ExtensionContext,
|
|
5
|
-
getAgentDir,
|
|
6
|
-
} from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { type ExtensionAPI, type ExtensionContext, getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
7
3
|
import { getCapabilities } from "@earendil-works/pi-tui";
|
|
8
4
|
import { completeStatuslineArguments } from "./command-contract.js";
|
|
9
5
|
import type { StatuslineCommandOptions } from "./commands.js";
|
|
10
6
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
buildExtensionStatusIconAliases,
|
|
8
|
+
type ExtensionStatusIconAliasMap,
|
|
9
|
+
findDuplicateExtensions,
|
|
10
|
+
readInstalledExtensionPackages,
|
|
15
11
|
} from "./extension-status.js";
|
|
16
12
|
import { type GitStatusSummary, gitStatusSummaryEqual, readGitStatus } from "./git-status.js";
|
|
17
13
|
import { type RuntimeState, renderExtensionStatusline, renderStatusline } from "./render.js";
|
|
18
14
|
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
consumeStatuslineSettingsNotice,
|
|
16
|
+
type LoadedStatuslineSettings,
|
|
17
|
+
loadStatuslineSettings,
|
|
18
|
+
loadStatuslineSettingsForAgent,
|
|
19
|
+
settingsFilePath,
|
|
24
20
|
} from "./settings.js";
|
|
25
21
|
import type { PalettePreset } from "./types.js";
|
|
26
22
|
|
|
@@ -33,376 +29,355 @@ type StatuslineCommands = typeof import("./commands.js");
|
|
|
33
29
|
let statuslineCommandsPromise: Promise<StatuslineCommands> | undefined;
|
|
34
30
|
|
|
35
31
|
function loadStatuslineCommands(): Promise<StatuslineCommands> {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
32
|
+
if (!statuslineCommandsPromise) {
|
|
33
|
+
statuslineCommandsPromise = import("./commands.js").catch((error) => {
|
|
34
|
+
statuslineCommandsPromise = undefined;
|
|
35
|
+
throw error;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return statuslineCommandsPromise;
|
|
43
39
|
}
|
|
44
40
|
|
|
45
41
|
export default function statusline(pi: ExtensionAPI) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
pi.on("tool_execution_start", (event, ctx) => {
|
|
354
|
-
if (!ownsRuntime(ctx)) return;
|
|
355
|
-
const currentCount = runtime.activeTools.get(event.toolName) ?? 0;
|
|
356
|
-
runtime.activeTools.set(event.toolName, currentCount + 1);
|
|
357
|
-
refresh();
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
pi.on("tool_execution_end", (event, ctx) => {
|
|
361
|
-
if (!ownsRuntime(ctx)) return;
|
|
362
|
-
const currentCount = runtime.activeTools.get(event.toolName) ?? 0;
|
|
363
|
-
if (currentCount <= 1) runtime.activeTools.delete(event.toolName);
|
|
364
|
-
else runtime.activeTools.set(event.toolName, currentCount - 1);
|
|
365
|
-
|
|
366
|
-
scheduleGitStatusRefreshForContext(ctx);
|
|
367
|
-
refresh();
|
|
368
|
-
});
|
|
42
|
+
let loaded: LoadedStatuslineSettings | undefined;
|
|
43
|
+
let previewPalettePreset: PalettePreset | undefined;
|
|
44
|
+
let activeSessionManager: ExtensionContext["sessionManager"] | undefined;
|
|
45
|
+
const runtime: RuntimeState = {
|
|
46
|
+
turnCount: 0,
|
|
47
|
+
activeTools: new Map(),
|
|
48
|
+
isStreaming: false,
|
|
49
|
+
thinkingLevel: "off",
|
|
50
|
+
duplicateExtensions: [],
|
|
51
|
+
extensionStatusIconAliases: EMPTY_EXTENSION_STATUS_ICON_ALIASES,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
let sessionGeneration = 0;
|
|
55
|
+
let menuController = new AbortController();
|
|
56
|
+
let gitStatusRequestId = 0;
|
|
57
|
+
let activeGitStatusTarget: { cwd: string; generation: number } | undefined;
|
|
58
|
+
let gitStatusRefreshInFlight = false;
|
|
59
|
+
let gitStatusAbortController: AbortController | undefined;
|
|
60
|
+
let gitStatusDebounceTimer: ReturnType<typeof setTimeout> | undefined;
|
|
61
|
+
let pendingGitStatusRefresh: { cwd: string; generation: number; requestId: number } | undefined;
|
|
62
|
+
|
|
63
|
+
const refresh = () => runtime.requestRender?.();
|
|
64
|
+
const ownsRuntime = (ctx: ExtensionContext) => ctx.sessionManager === activeSessionManager;
|
|
65
|
+
|
|
66
|
+
const setGitStatus = (summary: GitStatusSummary | undefined) => {
|
|
67
|
+
if (gitStatusSummaryEqual(runtime.gitStatus, summary)) return;
|
|
68
|
+
runtime.gitStatus = summary;
|
|
69
|
+
refresh();
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const clearGitStatusDebounce = () => {
|
|
73
|
+
if (!gitStatusDebounceTimer) return;
|
|
74
|
+
clearTimeout(gitStatusDebounceTimer);
|
|
75
|
+
gitStatusDebounceTimer = undefined;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const abortGitStatusRefresh = (reason: string) => {
|
|
79
|
+
gitStatusAbortController?.abort(new DOMException(reason, "AbortError"));
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const isActiveGitStatusTarget = (cwd: string, generation: number) =>
|
|
83
|
+
activeGitStatusTarget?.cwd === cwd &&
|
|
84
|
+
activeGitStatusTarget.generation === generation &&
|
|
85
|
+
generation === sessionGeneration;
|
|
86
|
+
|
|
87
|
+
const isCurrentGitStatusRequest = (cwd: string, generation: number, requestId: number) =>
|
|
88
|
+
isActiveGitStatusTarget(cwd, generation) && requestId === gitStatusRequestId;
|
|
89
|
+
|
|
90
|
+
const runGitStatusRefresh = (cwd: string, generation: number, requestId: number) => {
|
|
91
|
+
if (!isCurrentGitStatusRequest(cwd, generation, requestId)) return;
|
|
92
|
+
if (gitStatusRefreshInFlight) {
|
|
93
|
+
pendingGitStatusRefresh = { cwd, generation, requestId };
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
gitStatusRefreshInFlight = true;
|
|
98
|
+
const abortController = new AbortController();
|
|
99
|
+
gitStatusAbortController = abortController;
|
|
100
|
+
void (async () => {
|
|
101
|
+
try {
|
|
102
|
+
const summary = await readGitStatus(pi, cwd, abortController.signal);
|
|
103
|
+
if (isCurrentGitStatusRequest(cwd, generation, requestId)) setGitStatus(summary);
|
|
104
|
+
} catch {
|
|
105
|
+
if (isCurrentGitStatusRequest(cwd, generation, requestId)) setGitStatus(undefined);
|
|
106
|
+
} finally {
|
|
107
|
+
gitStatusRefreshInFlight = false;
|
|
108
|
+
if (gitStatusAbortController === abortController) gitStatusAbortController = undefined;
|
|
109
|
+
const pending = pendingGitStatusRefresh;
|
|
110
|
+
pendingGitStatusRefresh = undefined;
|
|
111
|
+
if (pending) runGitStatusRefresh(pending.cwd, pending.generation, pending.requestId);
|
|
112
|
+
}
|
|
113
|
+
})();
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const refreshGitStatus = (cwd: string, generation = sessionGeneration) => {
|
|
117
|
+
if (!isActiveGitStatusTarget(cwd, generation)) return;
|
|
118
|
+
runGitStatusRefresh(cwd, generation, ++gitStatusRequestId);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const scheduleGitStatusRefresh = (cwd: string, generation = sessionGeneration) => {
|
|
122
|
+
if (!isActiveGitStatusTarget(cwd, generation)) return;
|
|
123
|
+
const requestId = ++gitStatusRequestId;
|
|
124
|
+
clearGitStatusDebounce();
|
|
125
|
+
gitStatusDebounceTimer = setTimeout(() => {
|
|
126
|
+
gitStatusDebounceTimer = undefined;
|
|
127
|
+
runGitStatusRefresh(cwd, generation, requestId);
|
|
128
|
+
}, GIT_STATUS_EVENT_DEBOUNCE_MS);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const scheduleGitStatusRefreshForContext = (ctx: ExtensionContext) => {
|
|
132
|
+
if (!activeGitStatusTarget || activeGitStatusTarget.cwd !== ctx.cwd) return;
|
|
133
|
+
scheduleGitStatusRefresh(activeGitStatusTarget.cwd, activeGitStatusTarget.generation);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const installFooter = (ctx: ExtensionContext) => {
|
|
137
|
+
const generation = ++sessionGeneration;
|
|
138
|
+
menuController.abort(new DOMException("Statusline session context replaced", "AbortError"));
|
|
139
|
+
menuController = new AbortController();
|
|
140
|
+
const cwd = ctx.cwd;
|
|
141
|
+
activeSessionManager = ctx.sessionManager;
|
|
142
|
+
runtime.homeDir = homedir();
|
|
143
|
+
previewPalettePreset = undefined;
|
|
144
|
+
abortGitStatusRefresh("Statusline session context replaced");
|
|
145
|
+
clearGitStatusDebounce();
|
|
146
|
+
activeGitStatusTarget = ctx.mode === "tui" ? { cwd, generation } : undefined;
|
|
147
|
+
runtime.gitStatus = undefined;
|
|
148
|
+
runtime.duplicateExtensions = [];
|
|
149
|
+
runtime.extensionStatusIconAliases = EMPTY_EXTENSION_STATUS_ICON_ALIASES;
|
|
150
|
+
ctx.ui.setStatus(STATUSLINE_KEY, undefined);
|
|
151
|
+
if (!activeGitStatusTarget || !loaded) return;
|
|
152
|
+
const installedPackages = readInstalledExtensionPackages(cwd);
|
|
153
|
+
runtime.duplicateExtensions = findDuplicateExtensions(installedPackages);
|
|
154
|
+
runtime.extensionStatusIconAliases = buildExtensionStatusIconAliases(installedPackages);
|
|
155
|
+
ctx.ui.setFooter((tui, theme, footerData) => {
|
|
156
|
+
runtime.requestRender = () => tui.requestRender();
|
|
157
|
+
|
|
158
|
+
const refreshFooterGitStatus = () => refreshGitStatus(cwd, generation);
|
|
159
|
+
const branchUnsubscribe = footerData.onBranchChange(() => {
|
|
160
|
+
runtime.gitStatus = undefined;
|
|
161
|
+
abortGitStatusRefresh("Statusline Git branch changed");
|
|
162
|
+
clearGitStatusDebounce();
|
|
163
|
+
refreshFooterGitStatus();
|
|
164
|
+
tui.requestRender();
|
|
165
|
+
});
|
|
166
|
+
const clock = setInterval(() => {
|
|
167
|
+
clearGitStatusDebounce();
|
|
168
|
+
refreshFooterGitStatus();
|
|
169
|
+
tui.requestRender();
|
|
170
|
+
}, GIT_STATUS_REFRESH_INTERVAL_MS);
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
dispose() {
|
|
174
|
+
branchUnsubscribe();
|
|
175
|
+
clearInterval(clock);
|
|
176
|
+
if (isActiveGitStatusTarget(cwd, generation)) {
|
|
177
|
+
activeGitStatusTarget = undefined;
|
|
178
|
+
abortGitStatusRefresh("Statusline footer disposed");
|
|
179
|
+
clearGitStatusDebounce();
|
|
180
|
+
pendingGitStatusRefresh = undefined;
|
|
181
|
+
runtime.gitStatus = undefined;
|
|
182
|
+
runtime.duplicateExtensions = [];
|
|
183
|
+
runtime.extensionStatusIconAliases = EMPTY_EXTENSION_STATUS_ICON_ALIASES;
|
|
184
|
+
runtime.requestRender = undefined;
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
invalidate() {},
|
|
188
|
+
render(width: number): string[] {
|
|
189
|
+
if (!loaded) return [];
|
|
190
|
+
const config = previewPalettePreset
|
|
191
|
+
? { ...loaded.config, palettePreset: previewPalettePreset }
|
|
192
|
+
: loaded.config;
|
|
193
|
+
const trueColor = getCapabilities().trueColor;
|
|
194
|
+
const mainLine = renderStatusline(width, ctx, footerData, theme, config, runtime, trueColor);
|
|
195
|
+
const lines = mainLine ? mainLine.split("\n") : [];
|
|
196
|
+
lines.push(...renderExtensionStatusline(width, footerData, theme, config, runtime, mainLine, trueColor));
|
|
197
|
+
return lines;
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
});
|
|
201
|
+
refreshGitStatus(cwd, generation);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const agentDir = getAgentDir();
|
|
205
|
+
const configPath = settingsFilePath(agentDir);
|
|
206
|
+
const commandOptions: StatuslineCommandOptions = {
|
|
207
|
+
settingsPath: configPath,
|
|
208
|
+
getLoaded: () => loaded ?? loadStatuslineSettings(configPath),
|
|
209
|
+
getMenuOwner: () => {
|
|
210
|
+
const generation = sessionGeneration;
|
|
211
|
+
return {
|
|
212
|
+
signal: menuController.signal,
|
|
213
|
+
isCurrent: () => generation === sessionGeneration && !menuController.signal.aborted,
|
|
214
|
+
};
|
|
215
|
+
},
|
|
216
|
+
apply(next, ctx) {
|
|
217
|
+
if (ctx.sessionManager !== activeSessionManager) return;
|
|
218
|
+
previewPalettePreset = undefined;
|
|
219
|
+
loaded = next;
|
|
220
|
+
refresh();
|
|
221
|
+
},
|
|
222
|
+
preview(palettePreset, ctx) {
|
|
223
|
+
if (ctx.sessionManager !== activeSessionManager) return;
|
|
224
|
+
previewPalettePreset = palettePreset;
|
|
225
|
+
refresh();
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
pi.registerCommand("statusline", {
|
|
229
|
+
description: "Open or inspect the statusline settings",
|
|
230
|
+
getArgumentCompletions: completeStatuslineArguments,
|
|
231
|
+
handler: async (args, ctx) => {
|
|
232
|
+
const commands = await loadStatuslineCommands();
|
|
233
|
+
if (ctx.sessionManager !== activeSessionManager) return;
|
|
234
|
+
await commands.handleStatuslineCommand(args, ctx, commandOptions);
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
pi.on("session_start", (_event, ctx) => {
|
|
239
|
+
runtime.turnCount = 0;
|
|
240
|
+
runtime.activeTools.clear();
|
|
241
|
+
runtime.isStreaming = false;
|
|
242
|
+
runtime.uiPrompt = undefined;
|
|
243
|
+
loaded = loadStatuslineSettingsForAgent(agentDir);
|
|
244
|
+
const settingsNotice = consumeStatuslineSettingsNotice();
|
|
245
|
+
if (settingsNotice) ctx.ui.notify(settingsNotice, "warning");
|
|
246
|
+
if (loaded.diagnostics.length > 0) {
|
|
247
|
+
ctx.ui.notify(formatSettingsDiagnostics(loaded), "warning");
|
|
248
|
+
}
|
|
249
|
+
runtime.thinkingLevel = pi.getThinkingLevel();
|
|
250
|
+
installFooter(ctx);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
pi.on("session_tree", (_event, ctx) => {
|
|
254
|
+
installFooter(ctx);
|
|
255
|
+
refresh();
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
pi.on("session_shutdown", (_event, ctx) => {
|
|
259
|
+
if (!ownsRuntime(ctx)) return;
|
|
260
|
+
sessionGeneration += 1;
|
|
261
|
+
menuController.abort(new DOMException("Statusline session shut down", "AbortError"));
|
|
262
|
+
activeSessionManager = undefined;
|
|
263
|
+
previewPalettePreset = undefined;
|
|
264
|
+
activeGitStatusTarget = undefined;
|
|
265
|
+
abortGitStatusRefresh("Statusline session shut down");
|
|
266
|
+
clearGitStatusDebounce();
|
|
267
|
+
pendingGitStatusRefresh = undefined;
|
|
268
|
+
runtime.gitStatus = undefined;
|
|
269
|
+
runtime.activeTools.clear();
|
|
270
|
+
runtime.isStreaming = false;
|
|
271
|
+
runtime.uiPrompt = undefined;
|
|
272
|
+
runtime.duplicateExtensions = [];
|
|
273
|
+
runtime.extensionStatusIconAliases = EMPTY_EXTENSION_STATUS_ICON_ALIASES;
|
|
274
|
+
ctx.ui.setFooter(undefined);
|
|
275
|
+
ctx.ui.setStatus(STATUSLINE_KEY, undefined);
|
|
276
|
+
runtime.requestRender = undefined;
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
pi.on("model_select", () => refresh());
|
|
280
|
+
|
|
281
|
+
pi.on("thinking_level_select", (event) => {
|
|
282
|
+
runtime.thinkingLevel = event.level;
|
|
283
|
+
refresh();
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
pi.on("agent_start", (_event, ctx) => {
|
|
287
|
+
if (!ownsRuntime(ctx)) return;
|
|
288
|
+
runtime.isStreaming = true;
|
|
289
|
+
refresh();
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
pi.on("agent_end", (_event, ctx) => {
|
|
293
|
+
if (!ownsRuntime(ctx)) return;
|
|
294
|
+
runtime.activeTools.clear();
|
|
295
|
+
scheduleGitStatusRefreshForContext(ctx);
|
|
296
|
+
refresh();
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
pi.on("agent_settled", (_event, ctx) => {
|
|
300
|
+
if (!ownsRuntime(ctx)) return;
|
|
301
|
+
runtime.isStreaming = false;
|
|
302
|
+
runtime.activeTools.clear();
|
|
303
|
+
refresh();
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
pi.on("ui_prompt_start", (event, ctx) => {
|
|
307
|
+
if (!ownsRuntime(ctx)) return;
|
|
308
|
+
runtime.uiPrompt = { kind: event.kind, title: event.title };
|
|
309
|
+
refresh();
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
pi.on("ui_prompt_end", (_event, ctx) => {
|
|
313
|
+
if (!ownsRuntime(ctx)) return;
|
|
314
|
+
runtime.uiPrompt = undefined;
|
|
315
|
+
refresh();
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
pi.on("turn_start", (_event, ctx) => {
|
|
319
|
+
if (!ownsRuntime(ctx)) return;
|
|
320
|
+
runtime.turnCount += 1;
|
|
321
|
+
runtime.isStreaming = true;
|
|
322
|
+
refresh();
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
pi.on("turn_end", (_event, ctx) => {
|
|
326
|
+
if (!ownsRuntime(ctx)) return;
|
|
327
|
+
scheduleGitStatusRefreshForContext(ctx);
|
|
328
|
+
refresh();
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
pi.on("tool_execution_start", (event, ctx) => {
|
|
332
|
+
if (!ownsRuntime(ctx)) return;
|
|
333
|
+
const currentCount = runtime.activeTools.get(event.toolName) ?? 0;
|
|
334
|
+
runtime.activeTools.set(event.toolName, currentCount + 1);
|
|
335
|
+
refresh();
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
pi.on("tool_execution_end", (event, ctx) => {
|
|
339
|
+
if (!ownsRuntime(ctx)) return;
|
|
340
|
+
const currentCount = runtime.activeTools.get(event.toolName) ?? 0;
|
|
341
|
+
if (currentCount <= 1) runtime.activeTools.delete(event.toolName);
|
|
342
|
+
else runtime.activeTools.set(event.toolName, currentCount - 1);
|
|
343
|
+
|
|
344
|
+
scheduleGitStatusRefreshForContext(ctx);
|
|
345
|
+
refresh();
|
|
346
|
+
});
|
|
369
347
|
}
|
|
370
348
|
|
|
371
349
|
function formatSettingsDiagnostics(loaded: LoadedStatuslineSettings): string {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
`pi-statusline settings: ${details.join("; ")}`,
|
|
376
|
-
...(remaining > 0 ? [`+${remaining} more`] : []),
|
|
377
|
-
].join(" ");
|
|
350
|
+
const details = loaded.diagnostics.slice(0, 5).map((item) => item.message);
|
|
351
|
+
const remaining = loaded.diagnostics.length - details.length;
|
|
352
|
+
return [`pi-statusline settings: ${details.join("; ")}`, ...(remaining > 0 ? [`+${remaining} more`] : [])].join(" ");
|
|
378
353
|
}
|
|
379
354
|
|
|
380
355
|
export {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
356
|
+
buildExtensionStatusIconAliases,
|
|
357
|
+
type ExtensionStatusIconAliasMap,
|
|
358
|
+
extensionColor,
|
|
359
|
+
formatExtensionStatus,
|
|
360
|
+
npmPackageName,
|
|
361
|
+
simplifyExtensionStatusText,
|
|
362
|
+
splitExtensionStatusIcon,
|
|
363
|
+
stripExtensionStatusPrefix,
|
|
364
|
+
wrapExtensionStatusline,
|
|
390
365
|
} from "./extension-status.js";
|
|
391
366
|
export {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
367
|
+
formatGitBranchText,
|
|
368
|
+
formatGitBranchValue,
|
|
369
|
+
formatGitStatusSummary,
|
|
370
|
+
type GitStatusSummary,
|
|
371
|
+
parseGitRoot,
|
|
372
|
+
parseGitStatusPorcelain,
|
|
373
|
+
readGitStatus,
|
|
399
374
|
} from "./git-status.js";
|
|
400
375
|
export {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
376
|
+
contextColor,
|
|
377
|
+
formatCount,
|
|
378
|
+
formatToolActivity,
|
|
379
|
+
prContextFromStatuses,
|
|
380
|
+
prLinkFromStatuses,
|
|
381
|
+
shortenModel,
|
|
407
382
|
} from "./render.js";
|
|
408
383
|
export { normalizeStatuslineSettings, readStatuslineSettings } from "./settings.js";
|