@vtstech/pi-status 1.0.7 → 1.0.8
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/package.json +2 -2
- package/status.js +107 -38
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vtstech/pi-status",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "System monitor / status bar extension for Pi Coding Agent",
|
|
5
5
|
"main": "status.js",
|
|
6
6
|
"keywords": ["pi-extensions"],
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"url": "https://github.com/VTSTech/pi-coding-agent"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@vtstech/pi-shared": "1.0.
|
|
17
|
+
"@vtstech/pi-shared": "1.0.8"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"@mariozechner/pi-coding-agent": ">=0.66"
|
package/status.js
CHANGED
|
@@ -26,7 +26,11 @@ function status_temp_default(pi) {
|
|
|
26
26
|
let footerModel = "";
|
|
27
27
|
let footerThinking = "";
|
|
28
28
|
let footerCtxPct = "";
|
|
29
|
+
let footerNativeCtx = "";
|
|
30
|
+
let nativeCtxModel = "";
|
|
29
31
|
let isLocalProvider = true;
|
|
32
|
+
let lastUpstream = 0;
|
|
33
|
+
let lastDownstream = 0;
|
|
30
34
|
let securityFlashTool = "";
|
|
31
35
|
let securityFlashUntil = 0;
|
|
32
36
|
let activeTool = "";
|
|
@@ -94,6 +98,44 @@ function status_temp_default(pi) {
|
|
|
94
98
|
}
|
|
95
99
|
return false;
|
|
96
100
|
}
|
|
101
|
+
let nativeCtxPromise = null;
|
|
102
|
+
function getNativeModelCtx(modelId) {
|
|
103
|
+
if (!modelId) return "";
|
|
104
|
+
if (modelId === nativeCtxModel && footerNativeCtx) return footerNativeCtx;
|
|
105
|
+
nativeCtxModel = modelId;
|
|
106
|
+
if (!nativeCtxPromise) {
|
|
107
|
+
nativeCtxPromise = (async () => {
|
|
108
|
+
try {
|
|
109
|
+
const ollamaBase = getOllamaBaseUrl();
|
|
110
|
+
const res = await fetch(`${ollamaBase}/api/show`, {
|
|
111
|
+
method: "POST",
|
|
112
|
+
headers: { "Content-Type": "application/json" },
|
|
113
|
+
body: JSON.stringify({ name: modelId }),
|
|
114
|
+
signal: AbortSignal.timeout(5e3)
|
|
115
|
+
});
|
|
116
|
+
if (!res.ok) return;
|
|
117
|
+
const data = await res.json();
|
|
118
|
+
for (const key of Object.keys(data?.model_info ?? {})) {
|
|
119
|
+
if (key.endsWith(".context_length")) {
|
|
120
|
+
const val = data.model_info[key];
|
|
121
|
+
if (typeof val === "number") {
|
|
122
|
+
footerNativeCtx = val >= 1e3 ? `${(val / 1e3).toFixed(0)}k` : String(val);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const numCtx = data?.model_info?.["num_ctx"];
|
|
128
|
+
if (typeof numCtx === "number") {
|
|
129
|
+
footerNativeCtx = numCtx >= 1e3 ? `${(numCtx / 1e3).toFixed(0)}k` : String(numCtx);
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
} finally {
|
|
133
|
+
nativeCtxPromise = null;
|
|
134
|
+
}
|
|
135
|
+
})();
|
|
136
|
+
}
|
|
137
|
+
return footerNativeCtx;
|
|
138
|
+
}
|
|
97
139
|
function getOllamaLoadedModel() {
|
|
98
140
|
const now = Date.now();
|
|
99
141
|
if (now - ollamaLoadedLastCheck < OLLAMA_LOADED_INTERVAL) return ollamaLoadedCache;
|
|
@@ -126,6 +168,10 @@ function status_temp_default(pi) {
|
|
|
126
168
|
if (payload.reasoning_effort !== void 0) params.push(`think:${payload.reasoning_effort}`);
|
|
127
169
|
return params;
|
|
128
170
|
}
|
|
171
|
+
function fmtTk(n) {
|
|
172
|
+
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
|
|
173
|
+
return String(n);
|
|
174
|
+
}
|
|
129
175
|
function getPwd() {
|
|
130
176
|
const cwd = process.cwd();
|
|
131
177
|
if (cwd.startsWith(os.homedir())) return "~" + cwd.slice(os.homedir().length);
|
|
@@ -179,6 +225,7 @@ function status_temp_default(pi) {
|
|
|
179
225
|
modelsJson = JSON.parse(raw);
|
|
180
226
|
} catch {
|
|
181
227
|
}
|
|
228
|
+
isLocalProvider = modelsJson ? detectLocalProvider(modelsJson) : false;
|
|
182
229
|
if (currentCtx) {
|
|
183
230
|
footerModel = currentCtx.model?.id || "";
|
|
184
231
|
footerThinking = pi.getThinkingLevel?.() ?? "";
|
|
@@ -190,17 +237,10 @@ function status_temp_default(pi) {
|
|
|
190
237
|
footerCtxPct = "";
|
|
191
238
|
}
|
|
192
239
|
const modelId = currentCtx.model?.id || "";
|
|
193
|
-
if (modelId &&
|
|
194
|
-
|
|
195
|
-
const match = (prov.models || []).find((m) => m.id === modelId);
|
|
196
|
-
if (match?.contextLength) {
|
|
197
|
-
footerCtxPct = `${(match.contextLength / 1e3).toFixed(0)}k ctx`;
|
|
198
|
-
break;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
240
|
+
if (modelId && isLocalProvider) {
|
|
241
|
+
getNativeModelCtx(modelId);
|
|
201
242
|
}
|
|
202
243
|
}
|
|
203
|
-
isLocalProvider = modelsJson ? detectLocalProvider(modelsJson) : false;
|
|
204
244
|
refreshBlockedCount();
|
|
205
245
|
}
|
|
206
246
|
pi.on("session_start", async (_event, ctx) => {
|
|
@@ -214,56 +254,68 @@ function status_temp_default(pi) {
|
|
|
214
254
|
const red = (s) => theme?.fg?.("red", s) ?? s;
|
|
215
255
|
const yellow = (s) => theme?.fg?.("yellow", s) ?? s;
|
|
216
256
|
const sep = dim(" \xB7 ");
|
|
257
|
+
const truncateLine = (line, maxW) => {
|
|
258
|
+
const ellipsis = dim("...");
|
|
259
|
+
const visible = line.replace(/\x1b\[[0-9;]*m/g, "");
|
|
260
|
+
if (visible.length > maxW) {
|
|
261
|
+
let vis = 0, cut = 0;
|
|
262
|
+
for (let i = 0; i < line.length && vis < maxW - 3; i++) {
|
|
263
|
+
if (line[i] === "\x1B") {
|
|
264
|
+
while (i < line.length && line[i] !== "m") i++;
|
|
265
|
+
} else {
|
|
266
|
+
vis++;
|
|
267
|
+
}
|
|
268
|
+
cut = i + 1;
|
|
269
|
+
}
|
|
270
|
+
return line.slice(0, cut) + ellipsis;
|
|
271
|
+
}
|
|
272
|
+
return line;
|
|
273
|
+
};
|
|
217
274
|
return {
|
|
218
275
|
render(width) {
|
|
219
276
|
const lines = [];
|
|
220
|
-
const parts = [];
|
|
221
|
-
parts.push(getPwd());
|
|
222
277
|
let branch = "";
|
|
223
278
|
try {
|
|
224
279
|
branch = footerData?.getGitBranch?.() || "";
|
|
225
280
|
} catch {
|
|
226
281
|
}
|
|
227
282
|
if (!branch) branch = getGitBranch();
|
|
228
|
-
|
|
229
|
-
if (footerModel)
|
|
230
|
-
|
|
231
|
-
if (
|
|
283
|
+
const line1Parts = [];
|
|
284
|
+
if (footerModel) line1Parts.push(`conf:${footerModel}`);
|
|
285
|
+
line1Parts.push(getPwd());
|
|
286
|
+
if (footerThinking && footerThinking !== "off") line1Parts.push(dim(footerThinking));
|
|
287
|
+
if (isLocalProvider) {
|
|
288
|
+
line1Parts.push(dim(`CPU ${cpuUsage.toFixed(0)}%`));
|
|
289
|
+
}
|
|
290
|
+
let line1 = truncateLine(line1Parts.join(sep), width);
|
|
291
|
+
lines.push(line1);
|
|
292
|
+
const line2Parts = [];
|
|
293
|
+
if (ollamaLoaded) line2Parts.push(`load:${ollamaLoaded}`);
|
|
294
|
+
if (footerNativeCtx) line2Parts.push(`M:${footerNativeCtx}`);
|
|
295
|
+
if (footerCtxPct) line2Parts.push(`S:${footerCtxPct}`);
|
|
232
296
|
if (isLocalProvider) {
|
|
233
|
-
|
|
234
|
-
parts.push(`RAM ${fmtBytes(memUsed)}/${fmtBytes(memTotal)}`);
|
|
297
|
+
line2Parts.push(`RAM ${fmtBytes(memUsed)}/${fmtBytes(memTotal)}`);
|
|
235
298
|
if (hasSwap && swapUsed > 0) {
|
|
236
|
-
|
|
299
|
+
line2Parts.push(`Swap ${fmtBytes(swapUsed)}/${fmtBytes(swapTotal)}`);
|
|
237
300
|
}
|
|
238
301
|
}
|
|
239
|
-
if (
|
|
240
|
-
|
|
302
|
+
if (lastUpstream > 0 || lastDownstream > 0) {
|
|
303
|
+
line2Parts.push(dim(`\u2191${fmtTk(lastUpstream)} \u2193${fmtTk(lastDownstream)}`));
|
|
304
|
+
}
|
|
305
|
+
if (lastResponseTime !== null) line2Parts.push(`Resp ${fmtDur(lastResponseTime)}`);
|
|
241
306
|
if (lastPayload) {
|
|
242
307
|
const params = extractParams(lastPayload);
|
|
243
|
-
if (params.length > 0)
|
|
308
|
+
if (params.length > 0) line2Parts.push(...params.map((p) => dim(p)));
|
|
244
309
|
}
|
|
245
310
|
const now = Date.now();
|
|
246
311
|
if (securityFlashTool && now < securityFlashUntil) {
|
|
247
|
-
|
|
312
|
+
line2Parts.push(red(`BLOCKED:${securityFlashTool}`));
|
|
248
313
|
}
|
|
249
314
|
if (blockedCount > 0) {
|
|
250
|
-
|
|
315
|
+
line2Parts.push(red(`SEC:${blockedCount}`));
|
|
251
316
|
}
|
|
252
|
-
let
|
|
253
|
-
|
|
254
|
-
if (visible.length > width) {
|
|
255
|
-
let vis = 0, cut = 0;
|
|
256
|
-
for (let i = 0; i < line.length && vis < width - 3; i++) {
|
|
257
|
-
if (line[i] === "\x1B") {
|
|
258
|
-
while (i < line.length && line[i] !== "m") i++;
|
|
259
|
-
} else {
|
|
260
|
-
vis++;
|
|
261
|
-
}
|
|
262
|
-
cut = i + 1;
|
|
263
|
-
}
|
|
264
|
-
line = line.slice(0, cut) + dim("...");
|
|
265
|
-
}
|
|
266
|
-
lines.push(line);
|
|
317
|
+
let line2 = truncateLine(line2Parts.join(sep), width);
|
|
318
|
+
if (line2) lines.push(line2);
|
|
267
319
|
if (activeTool && activeToolStart > 0) {
|
|
268
320
|
const elapsed = performance.now() - activeToolStart;
|
|
269
321
|
lines.push(`${yellow("\u23F3")} ${activeTool}: ${fmtDur(elapsed)}`);
|
|
@@ -296,12 +348,29 @@ function status_temp_default(pi) {
|
|
|
296
348
|
activeTool = "";
|
|
297
349
|
activeToolStart = 0;
|
|
298
350
|
blockedCount = 0;
|
|
351
|
+
lastUpstream = 0;
|
|
352
|
+
lastDownstream = 0;
|
|
299
353
|
});
|
|
300
354
|
pi.on("before_provider_request", (event) => {
|
|
301
355
|
lastPayload = event.payload;
|
|
302
356
|
});
|
|
357
|
+
function captureUsage(event) {
|
|
358
|
+
if (event?.message?.role !== "assistant") return;
|
|
359
|
+
const usage = event?.message?.usage ?? // normalised Pi usage
|
|
360
|
+
event?.usage ?? // alternative path
|
|
361
|
+
null;
|
|
362
|
+
if (!usage) return;
|
|
363
|
+
const inp = usage.input ?? usage.promptTokens ?? usage.prompt_tokens;
|
|
364
|
+
const out = usage.output ?? usage.completionTokens ?? usage.completion_tokens;
|
|
365
|
+
if (inp != null) lastUpstream = inp;
|
|
366
|
+
if (out != null) lastDownstream = out;
|
|
367
|
+
}
|
|
368
|
+
pi.on("message_end", captureUsage);
|
|
369
|
+
pi.on("turn_end", captureUsage);
|
|
303
370
|
pi.on("agent_start", async () => {
|
|
304
371
|
agentStartTime = performance.now();
|
|
372
|
+
lastUpstream = 0;
|
|
373
|
+
lastDownstream = 0;
|
|
305
374
|
});
|
|
306
375
|
pi.on("agent_end", async () => {
|
|
307
376
|
if (agentStartTime !== null) {
|