pi-cockpit 0.1.0 → 0.1.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/package.json +1 -1
- package/src/footer.ts +12 -8
- package/src/index.ts +37 -26
- package/src/stack-widget.ts +4 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-cockpit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Agent cockpit for Pi: a list-mode status stack (live teammates + todo plan) pinned above the editor, plus a Starship-style footer. Renders only via public extension APIs (setWidget/setFooter).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
package/src/footer.ts
CHANGED
|
@@ -27,9 +27,10 @@ export interface FooterParts {
|
|
|
27
27
|
ctxTokens: number;
|
|
28
28
|
ctxWindow: number;
|
|
29
29
|
totals: UsageTotals;
|
|
30
|
-
git?: string;
|
|
31
|
-
agentSummary?: string;
|
|
32
|
-
|
|
30
|
+
git?: string;
|
|
31
|
+
agentSummary?: string;
|
|
32
|
+
bashBgStatus?: string;
|
|
33
|
+
workflowStatus?: string;
|
|
33
34
|
extensionStatuses?: readonly ExtensionStatusSegment[];
|
|
34
35
|
width: number;
|
|
35
36
|
glyphs: IconGlyphs;
|
|
@@ -322,11 +323,14 @@ export function renderFooter(p: FooterParts): string[] {
|
|
|
322
323
|
}
|
|
323
324
|
if (!selected) fittedLeft = fitLeftBeside("");
|
|
324
325
|
|
|
325
|
-
const line1 = alignRight(fittedLeft.join(identitySeparator), right1, width, utils.measure);
|
|
326
|
-
const lines = [utils.clip(line1, width, ell)];
|
|
327
|
-
if (p.
|
|
328
|
-
lines.push(utils.clip(
|
|
329
|
-
}
|
|
326
|
+
const line1 = alignRight(fittedLeft.join(identitySeparator), right1, width, utils.measure);
|
|
327
|
+
const lines = [utils.clip(line1, width, ell)];
|
|
328
|
+
if (p.bashBgStatus) {
|
|
329
|
+
lines.push(utils.clip(p.bashBgStatus, width, ell));
|
|
330
|
+
}
|
|
331
|
+
if (p.workflowStatus) {
|
|
332
|
+
lines.push(utils.clip(theme.fg("muted", p.workflowStatus), width, ell));
|
|
333
|
+
}
|
|
330
334
|
const statuses = visibleStatuses.filter((status) => !controlStatuses.includes(status));
|
|
331
335
|
if (statuses.length > 0) {
|
|
332
336
|
const statusSeparator = ` ${sep} `;
|
package/src/index.ts
CHANGED
|
@@ -2,16 +2,17 @@ import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
|
2
2
|
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext, Theme } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import type { TUI } from "@earendil-works/pi-tui";
|
|
4
4
|
import { Key, matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
5
|
-
import { AgentsStore, type CompletePayload, type MessagePayload, type StartedPayload } from "./agents-store.ts";
|
|
6
|
-
import { statusText, titleFor, workingMessage, type AmbientState } from "./ambient.ts";
|
|
7
|
-
import { BashBgStore } from "./bash-bg-store.ts";
|
|
8
|
-
import { BashBgOverlay } from "./bash-bg-overlay.ts";
|
|
9
|
-
import {
|
|
5
|
+
import { AgentsStore, type CompletePayload, type MessagePayload, type StartedPayload } from "./agents-store.ts";
|
|
6
|
+
import { statusText, titleFor, workingMessage, type AmbientState } from "./ambient.ts";
|
|
7
|
+
import { BashBgStore } from "./bash-bg-store.ts";
|
|
8
|
+
import { BashBgOverlay } from "./bash-bg-overlay.ts";
|
|
9
|
+
import { renderBashBgSummary } from "./bash-bg-widget.ts";
|
|
10
|
+
import { TodoStore } from "./todo-store.ts";
|
|
10
11
|
import { makeTodoWidget, makeAgentWidget, terminalRows } from "./stack-widget.ts";
|
|
11
12
|
import { activeThemeName, ThemePicker } from "./theme-picker.ts";
|
|
12
13
|
import { getUsageTotals, invalidateUsageCache, renderFooter, type PaintTheme, type WidthUtils } from "./footer.ts";
|
|
13
14
|
import { collectExtensionStatuses } from "./extension-status.ts";
|
|
14
|
-
import { ANIMATION_PERIOD_MS, resolveGlyphs } from "./icons.ts";
|
|
15
|
+
import { ANIMATION_PERIOD_MS, resolveGlyphs, spinFrame } from "./icons.ts";
|
|
15
16
|
import { ensureConfigExists, loadConfig, saveConfig } from "./config.ts";
|
|
16
17
|
import { applyRow, buildRows, rowKeyForAccel, type SaveState } from "./settings-view.ts";
|
|
17
18
|
import {
|
|
@@ -180,13 +181,12 @@ export default function (pi: ExtensionAPI): void {
|
|
|
180
181
|
ctx.ui.setWidget(
|
|
181
182
|
AGENT_WIDGET_KEY,
|
|
182
183
|
(tui, theme) => {
|
|
183
|
-
capturedTui = tui;
|
|
184
|
-
return makeAgentWidget({
|
|
185
|
-
getAgents: () => agents.snapshot(),
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
isAnimating,
|
|
184
|
+
capturedTui = tui;
|
|
185
|
+
return makeAgentWidget({
|
|
186
|
+
getAgents: () => agents.snapshot(),
|
|
187
|
+
getConfig: () => config,
|
|
188
|
+
isRunning: () => running,
|
|
189
|
+
isAnimating,
|
|
190
190
|
})(tui, theme);
|
|
191
191
|
},
|
|
192
192
|
{ placement: "belowEditor" },
|
|
@@ -210,10 +210,23 @@ export default function (pi: ExtensionAPI): void {
|
|
|
210
210
|
const component = {
|
|
211
211
|
render(width: number): string[] {
|
|
212
212
|
if (Number.isFinite(width) && width > 0) observedWidth = width;
|
|
213
|
-
const cu = ctx.getContextUsage();
|
|
214
|
-
const branch = footerData.getGitBranch();
|
|
215
|
-
const extensionStatuses = collectExtensionStatuses(footerData.getExtensionStatuses());
|
|
216
|
-
|
|
213
|
+
const cu = ctx.getContextUsage();
|
|
214
|
+
const branch = footerData.getGitBranch();
|
|
215
|
+
const extensionStatuses = collectExtensionStatuses(footerData.getExtensionStatuses());
|
|
216
|
+
const glyphs = resolveGlyphs(config.icons.mode);
|
|
217
|
+
const now = Date.now();
|
|
218
|
+
const bashBgStatus = renderBashBgSummary(
|
|
219
|
+
bashBg.snapshot(),
|
|
220
|
+
width,
|
|
221
|
+
theme,
|
|
222
|
+
FOOTER_UTILS,
|
|
223
|
+
{
|
|
224
|
+
glyphs,
|
|
225
|
+
spin: spinFrame(glyphs, now, isAnimating()),
|
|
226
|
+
now,
|
|
227
|
+
},
|
|
228
|
+
)[0];
|
|
229
|
+
return renderFooter({
|
|
217
230
|
width,
|
|
218
231
|
model: ctx.model?.id ?? "no-model",
|
|
219
232
|
provider: ctx.model?.provider,
|
|
@@ -221,15 +234,13 @@ export default function (pi: ExtensionAPI): void {
|
|
|
221
234
|
cwd: formatCwd(ctx.sessionManager.getCwd()),
|
|
222
235
|
ctxPct: cu?.percent ?? 0,
|
|
223
236
|
ctxTokens: cu?.tokens ?? 0,
|
|
224
|
-
ctxWindow: cu?.contextWindow ?? ctx.model?.contextWindow ?? 0,
|
|
225
|
-
totals: getUsageTotals(ctx.sessionManager.getEntries()),
|
|
226
|
-
git: branch ?? undefined,
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
extensionStatuses: extensionStatuses.filter((status) => status.key !== WORKFLOW_STATUS_KEY),
|
|
232
|
-
glyphs: resolveGlyphs(config.icons.mode),
|
|
237
|
+
ctxWindow: cu?.contextWindow ?? ctx.model?.contextWindow ?? 0,
|
|
238
|
+
totals: getUsageTotals(ctx.sessionManager.getEntries()),
|
|
239
|
+
git: branch ?? undefined,
|
|
240
|
+
bashBgStatus,
|
|
241
|
+
workflowStatus: extensionStatuses.find((status) => status.key === WORKFLOW_STATUS_KEY)?.text,
|
|
242
|
+
extensionStatuses: extensionStatuses.filter((status) => status.key !== WORKFLOW_STATUS_KEY),
|
|
243
|
+
glyphs,
|
|
233
244
|
theme,
|
|
234
245
|
utils: FOOTER_UTILS,
|
|
235
246
|
});
|
package/src/stack-widget.ts
CHANGED
|
@@ -2,11 +2,10 @@ import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
|
2
2
|
import type { TUI } from "@earendil-works/pi-tui";
|
|
3
3
|
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
4
4
|
import { renderAgents, renderTodos, type PaintTheme, type WidthUtils } from "./render.ts";
|
|
5
|
-
import { renderBashBgSummary } from "./bash-bg-widget.ts";
|
|
6
5
|
import { fitLineByPriority, type PrioritizedSegment } from "./layout.ts";
|
|
7
6
|
import { resolveGlyphs, spinFrame } from "./icons.ts";
|
|
8
7
|
import { panelRows } from "./viewport.ts";
|
|
9
|
-
import type { AgentRow,
|
|
8
|
+
import type { AgentRow, CockpitConfig, TodoItem } from "./types.ts";
|
|
10
9
|
|
|
11
10
|
export interface TodoWidgetDeps {
|
|
12
11
|
getTodos: () => TodoItem[];
|
|
@@ -17,7 +16,6 @@ export interface TodoWidgetDeps {
|
|
|
17
16
|
|
|
18
17
|
export interface AgentWidgetDeps {
|
|
19
18
|
getAgents: () => AgentRow[];
|
|
20
|
-
getBashBgJobs: () => BashBgJob[];
|
|
21
19
|
getConfig: () => CockpitConfig;
|
|
22
20
|
isRunning: () => boolean;
|
|
23
21
|
isAnimating?: () => boolean;
|
|
@@ -71,24 +69,17 @@ export function makeAgentWidget(deps: AgentWidgetDeps) {
|
|
|
71
69
|
render(width: number): string[] {
|
|
72
70
|
const cfg = deps.getConfig();
|
|
73
71
|
const agents = deps.getAgents();
|
|
74
|
-
|
|
72
|
+
if (agents.length === 0) return [];
|
|
75
73
|
const g = resolveGlyphs(cfg.icons.mode);
|
|
76
74
|
const now = Date.now();
|
|
77
75
|
const animating = deps.isAnimating?.() ?? true;
|
|
78
76
|
const spin = spinFrame(g, now, animating);
|
|
79
|
-
const bashBgLines = renderBashBgSummary(bashBgJobs, width, paint, UTILS, {
|
|
80
|
-
glyphs: g,
|
|
81
|
-
spin,
|
|
82
|
-
now,
|
|
83
|
-
});
|
|
84
|
-
if (agents.length === 0) return bashBgLines;
|
|
85
77
|
const running = deps.isRunning();
|
|
86
|
-
// The panel budget covers
|
|
87
|
-
// and the background strip are charged to it before the roster is.
|
|
78
|
+
// The panel budget covers the roster header and its rows.
|
|
88
79
|
const panel = panelRows(terminalRows(tui));
|
|
89
80
|
const rosterRows = panel === undefined
|
|
90
81
|
? undefined
|
|
91
|
-
: Math.max(1, panel - 1
|
|
82
|
+
: Math.max(1, panel - 1);
|
|
92
83
|
const opts = { glyphs: g, spin, now, maxRows: rosterRows };
|
|
93
84
|
const dot = theme.fg(running ? "success" : "muted", running ? g.dotRunning : g.dotIdle);
|
|
94
85
|
const failedCount = agents.filter((a) => a.status === "failed").length;
|
|
@@ -111,7 +102,6 @@ export function makeAgentWidget(deps: AgentWidgetDeps) {
|
|
|
111
102
|
// Was the one line in the package pushed without any width clipping.
|
|
112
103
|
lines.push(fitLineByPriority(headerSegs, width, UTILS, theme.fg("dim", g.separator), g.ellipsis));
|
|
113
104
|
lines.push(...renderAgents(agents, cfg.agentsMode, width, paint, UTILS, { ...opts, withHead: false }));
|
|
114
|
-
lines.push(...bashBgLines);
|
|
115
105
|
return lines;
|
|
116
106
|
},
|
|
117
107
|
invalidate(): void {},
|