pi-tropos 0.5.0 → 0.7.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 +5 -0
- package/index.ts +4 -0
- package/package.json +1 -1
- package/src/barista.ts +34 -0
- package/src/footer.ts +77 -0
- package/src/sessions.ts +6 -1
package/README.md
CHANGED
|
@@ -21,6 +21,11 @@ Personal pi customization bundle. One package, installable anywhere.
|
|
|
21
21
|
- **`kaapi` theme** — filter-coffee dark: deep espresso base (`#15100D`), latte-foam text
|
|
22
22
|
(`#E8DCCB`), caramel accent (`#D9984A`), matcha success, terracotta error. Warm and
|
|
23
23
|
caffeinated. Select via `/settings` or `"theme": "kaapi"`.
|
|
24
|
+
- **Clean footer** — one line: `project branch` left; `↑in ↓out Rcache Wcache $cost` plus
|
|
25
|
+
the dumbzone gauge right. Zero-valued counters hide; no full paths, no cache-hit %,
|
|
26
|
+
no session titles. Auto-named sessions are sanitized (no markdown table junk).
|
|
27
|
+
- **Barista mascot** — the working spinner becomes a steaming cup of kaapi; every other
|
|
28
|
+
brew cycle it's a boba 🧋. Hidden thinking blocks read "Steeping…".
|
|
24
29
|
- **pi-smritikosh** — semantic codebase search, bundled as a dependency. One install
|
|
25
30
|
gets everything; don't also install `npm:pi-smritikosh` separately or it loads twice.
|
|
26
31
|
|
package/index.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import smritikosh from "pi-smritikosh/index.js";
|
|
3
|
+
import barista from "./src/barista.js";
|
|
3
4
|
import dumbzone from "./src/dumbzone.js";
|
|
5
|
+
import footer from "./src/footer.js";
|
|
4
6
|
import sessions from "./src/sessions.js";
|
|
5
7
|
|
|
6
8
|
export default function (pi: ExtensionAPI) {
|
|
9
|
+
barista(pi);
|
|
7
10
|
dumbzone(pi);
|
|
11
|
+
footer(pi);
|
|
8
12
|
sessions(pi);
|
|
9
13
|
smritikosh(pi);
|
|
10
14
|
}
|
package/package.json
CHANGED
package/src/barista.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barista — kaapi-flavored working mascot.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the default spinner with a steaming coffee cup; every other
|
|
5
|
+
* brew cycle the cup turns into a boba. Hidden thinking blocks are
|
|
6
|
+
* labeled "Steeping…". Purely cosmetic, zero logic.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
10
|
+
|
|
11
|
+
const FRAMES = [
|
|
12
|
+
"☕ ∘ ",
|
|
13
|
+
"☕ ∘ ",
|
|
14
|
+
"☕ ∘ ",
|
|
15
|
+
"☕ ∘",
|
|
16
|
+
"☕ ",
|
|
17
|
+
"☕ ∘ ",
|
|
18
|
+
"☕ ∘ ",
|
|
19
|
+
"☕ ∘ ",
|
|
20
|
+
"☕ ∘",
|
|
21
|
+
"☕ ",
|
|
22
|
+
"🧋 ∘ ",
|
|
23
|
+
"🧋 ∘ ",
|
|
24
|
+
"🧋 ∘ ",
|
|
25
|
+
"🧋 ∘",
|
|
26
|
+
"🧋 ",
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
export default function barista(pi: ExtensionAPI) {
|
|
30
|
+
pi.on("session_start", (_event, ctx) => {
|
|
31
|
+
ctx.ui.setWorkingIndicator({ frames: FRAMES, intervalMs: 160 });
|
|
32
|
+
ctx.ui.setHiddenThinkingLabel("Steeping…");
|
|
33
|
+
});
|
|
34
|
+
}
|
package/src/footer.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Footer — clean one-line status bar.
|
|
3
|
+
*
|
|
4
|
+
* Left: project dir + git branch (dim)
|
|
5
|
+
* Right: token & cost telemetry (dim, zero-values hidden) + extension
|
|
6
|
+
* statuses (e.g. the dumbzone ctx gauge, colored by health)
|
|
7
|
+
*
|
|
8
|
+
* Same data as the default footer, minus the noise: no full path, no
|
|
9
|
+
* cache-hit %, no window size, no session title.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
13
|
+
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
14
|
+
|
|
15
|
+
interface Usage {
|
|
16
|
+
input: number;
|
|
17
|
+
output: number;
|
|
18
|
+
cacheRead: number;
|
|
19
|
+
cacheWrite: number;
|
|
20
|
+
cost: { total: number };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function fmt(n: number) {
|
|
24
|
+
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
|
|
25
|
+
if (n >= 1_000) return `${Math.round(n / 1_000)}k`;
|
|
26
|
+
return `${n}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function telemetry(ctx: ExtensionContext) {
|
|
30
|
+
let input = 0,
|
|
31
|
+
output = 0,
|
|
32
|
+
cacheRead = 0,
|
|
33
|
+
cacheWrite = 0,
|
|
34
|
+
cost = 0;
|
|
35
|
+
for (const e of ctx.sessionManager.getBranch()) {
|
|
36
|
+
if (e.type !== "message" || e.message.role !== "assistant") continue;
|
|
37
|
+
const u = (e.message as { usage?: Usage }).usage;
|
|
38
|
+
if (!u) continue;
|
|
39
|
+
input += u.input;
|
|
40
|
+
output += u.output;
|
|
41
|
+
cacheRead += u.cacheRead ?? 0;
|
|
42
|
+
cacheWrite += u.cacheWrite ?? 0;
|
|
43
|
+
cost += u.cost?.total ?? 0;
|
|
44
|
+
}
|
|
45
|
+
if (input === 0) return "";
|
|
46
|
+
const parts = [`↑${fmt(input)}`, `↓${fmt(output)}`];
|
|
47
|
+
if (cacheRead > 0) parts.push(`R${fmt(cacheRead)}`);
|
|
48
|
+
if (cacheWrite > 0) parts.push(`W${fmt(cacheWrite)}`);
|
|
49
|
+
parts.push(`$${cost.toFixed(2)}`);
|
|
50
|
+
return parts.join(" ");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default function footer(pi: ExtensionAPI) {
|
|
54
|
+
pi.on("session_start", (_event, ctx) => {
|
|
55
|
+
if (!ctx.hasUI) return;
|
|
56
|
+
ctx.ui.setFooter((tui, theme, footerData) => {
|
|
57
|
+
const unsub = footerData.onBranchChange(() => tui.requestRender());
|
|
58
|
+
return {
|
|
59
|
+
dispose: unsub,
|
|
60
|
+
invalidate() {},
|
|
61
|
+
render(width: number): string[] {
|
|
62
|
+
const dir = ctx.cwd.split("/").pop() ?? ctx.cwd;
|
|
63
|
+
const branch = footerData.getGitBranch();
|
|
64
|
+
const left = theme.fg("dim", branch ? `${dir} ${branch}` : dir);
|
|
65
|
+
|
|
66
|
+
const stats = telemetry(ctx);
|
|
67
|
+
const metrics = stats ? theme.fg("dim", stats) : "";
|
|
68
|
+
const statuses = [...footerData.getExtensionStatuses().values()].join(" ");
|
|
69
|
+
const right = [metrics, statuses].filter(Boolean).join(" ");
|
|
70
|
+
|
|
71
|
+
const pad = " ".repeat(Math.max(1, width - visibleWidth(left) - visibleWidth(right)));
|
|
72
|
+
return [truncateToWidth(left + pad + right, width)];
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
package/src/sessions.ts
CHANGED
|
@@ -16,7 +16,12 @@ import type { ExtensionAPI, ExtensionContext, SessionInfo } from "@earendil-work
|
|
|
16
16
|
const TITLE_MAX = 60;
|
|
17
17
|
|
|
18
18
|
function oneLine(text: string, max: number) {
|
|
19
|
-
|
|
19
|
+
// Strip markdown noise (tables, emphasis, headings) so pasted SPEC
|
|
20
|
+
// rows and the like don't become unreadable titles.
|
|
21
|
+
const line = text
|
|
22
|
+
.replace(/[|*#`>\[\]]+/g, " ")
|
|
23
|
+
.replace(/\s+/g, " ")
|
|
24
|
+
.trim();
|
|
20
25
|
return line.length > max ? `${line.slice(0, max - 1)}…` : line;
|
|
21
26
|
}
|
|
22
27
|
|