my-durable 0.0.17 → 0.0.18
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/apps/dpi-tui/src/app.ts +27 -3
- package/apps/dpi-tui/src/views.ts +4 -0
- package/package.json +1 -1
package/apps/dpi-tui/src/app.ts
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
type OverlayHandle,
|
|
13
13
|
type TuiInputListenerResult,
|
|
14
14
|
} from "@earendil-works/pi-tui";
|
|
15
|
-
import { DpiClient, follow, type AgentHandle, type ConnectionState } from "../../dpi-sdk/src/client.ts";
|
|
15
|
+
import { DpiClient, follow, type AgentHandle, type ConnectionState, type GitStatus } from "../../dpi-sdk/src/client.ts";
|
|
16
16
|
import { isDpiError } from "../../dpi-sdk/src/errors.ts";
|
|
17
17
|
import { AgentModel, SessionModel } from "../../dpi-sdk/src/models.ts";
|
|
18
18
|
import { sumUsage } from "../../dpi-sdk/src/transcript.ts";
|
|
@@ -152,6 +152,26 @@ export class App {
|
|
|
152
152
|
private overlays: Array<{ handle: OverlayHandle; onClose?: () => void }> = [];
|
|
153
153
|
private ticker?: ReturnType<typeof setInterval>;
|
|
154
154
|
private sessions: SessionSummary[] = [];
|
|
155
|
+
/** Ambient git for the panel: cwd → {at, status}, 30s TTL, fetched as the
|
|
156
|
+
* cursor moves — the herd and agent header always show ⎇ branch ±dirty. */
|
|
157
|
+
private gitCache = new Map<string, { at: number; s: GitStatus }>();
|
|
158
|
+
|
|
159
|
+
private refreshGit(cwd: string | undefined) {
|
|
160
|
+
if (!cwd) return;
|
|
161
|
+
const hit = this.gitCache.get(cwd);
|
|
162
|
+
if (hit && Date.now() - hit.at < 30_000) return;
|
|
163
|
+
void this.client
|
|
164
|
+
.gitStatus(cwd)
|
|
165
|
+
.then((s) => {
|
|
166
|
+
this.gitCache.set(cwd, { at: Date.now(), s });
|
|
167
|
+
this.requestRender();
|
|
168
|
+
})
|
|
169
|
+
.catch(() => {});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private gitOf(cwd: string | undefined): GitStatus | undefined {
|
|
173
|
+
return cwd ? this.gitCache.get(cwd)?.s : undefined;
|
|
174
|
+
}
|
|
155
175
|
private devicesCache: DeviceRow[] = [];
|
|
156
176
|
private deviceOnline = false;
|
|
157
177
|
private events: { at: string; glyph: string; text: string }[] = [];
|
|
@@ -972,7 +992,8 @@ export class App {
|
|
|
972
992
|
}).slice(0, h);
|
|
973
993
|
if (!wide) return table;
|
|
974
994
|
const selected = this.sessions.find((s) => s.id === (this.selectedId ?? this.sessionId));
|
|
975
|
-
|
|
995
|
+
if (selected?.cwd) this.refreshGit(selected.cwd);
|
|
996
|
+
const panel = renderHerdPanel(panelW, h, selected, this.contextLeft(), this.device.name, this.gitOf(selected?.cwd));
|
|
976
997
|
return joinPanel(table, panel, tableW, w, h);
|
|
977
998
|
}
|
|
978
999
|
|
|
@@ -1000,8 +1021,11 @@ export class App {
|
|
|
1000
1021
|
const ctx = this.contextLeft();
|
|
1001
1022
|
const barW = Math.min(40, Math.max(12, Math.round(w * 0.3)));
|
|
1002
1023
|
const filled = ctx === undefined ? 0 : Math.round((ctx / 100) * barW);
|
|
1024
|
+
const g = this.gitOf(session?.cwd);
|
|
1025
|
+
if (session?.cwd) this.refreshGit(session.cwd);
|
|
1026
|
+
const gitChip = g?.repo ? ` ${c.muted("⎇")} ${c.text(g.branch ?? g.head ?? "")}${(g.staged ?? 0) + (g.unstaged ?? 0) + (g.untracked ?? 0) ? c.warn(` ±${(g.staged ?? 0) + (g.unstaged ?? 0) + (g.untracked ?? 0)}`) : ""}` : "";
|
|
1003
1027
|
lines.push(
|
|
1004
|
-
`${c.muted(this.device.id)} ${c.muted("›")} ${c.text(session?.name ?? "—")} ${c.muted("›")} ${c.bold(`#${this.agentId ?? 1}`)} ` +
|
|
1028
|
+
`${c.muted(this.device.id)} ${c.muted("›")} ${c.text(session?.name ?? "—")} ${c.muted("›")} ${c.bold(`#${this.agentId ?? 1}`)}${gitChip} ` +
|
|
1005
1029
|
`${STATE_COLOR[state](STATE_GLYPH[state] + " " + (this.busy() ? "working" : "idle"))} ` +
|
|
1006
1030
|
`${c.muted("ctx")} ${ctx === undefined ? c.muted("—") : c.accent(rep("█", filled)) + c.muted(rep("░", barW - filled)) + " " + c.muted(`${ctx}%`)}`,
|
|
1007
1031
|
);
|
|
@@ -285,6 +285,7 @@ export function renderHerdPanel(
|
|
|
285
285
|
s: SessionSummary | undefined,
|
|
286
286
|
ctxLeft?: number,
|
|
287
287
|
device?: string,
|
|
288
|
+
git?: { repo: boolean; branch?: string; head?: string; staged?: number; unstaged?: number; untracked?: number; ahead?: number; behind?: number; worktreeOf?: string },
|
|
288
289
|
): string[] {
|
|
289
290
|
// No session selected: a blank panel next to the divider is what made the
|
|
290
291
|
// wide layout look broken — herdr's panel always carries a device header.
|
|
@@ -308,6 +309,9 @@ export function renderHerdPanel(
|
|
|
308
309
|
c.muted(" OVERVIEW"),
|
|
309
310
|
` ${c.bold(s.name)}`,
|
|
310
311
|
` ${c.muted(basename(s.cwd))} ${c.muted("·")} ${c.text(basename(s.model) || s.model)}`,
|
|
312
|
+
git?.repo
|
|
313
|
+
? ` ${c.muted("⎇")} ${c.text(git.branch ?? git.head ?? "?")}${c.muted("±")}${c.text(String((git.staged ?? 0) + (git.unstaged ?? 0) + (git.untracked ?? 0)))}${git.ahead ? c.text(` ↑${git.ahead}`) : ""}${git.behind ? c.text(` ↓${git.behind}`) : ""}${git.worktreeOf ? c.muted(" · worktree") : ""}`
|
|
314
|
+
: "",
|
|
311
315
|
"",
|
|
312
316
|
` ${c.muted("state")} ${STATE_COLOR[sessionState(s)](sessionState(s))}`,
|
|
313
317
|
` ${c.muted("agents")} ${agents.length ? agents[0] : "—"}`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-durable",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"description": "Durable Pi \u2014 the durable agent network: hub web UI, device backend daemon, TUI admin and the shared SDK, packaged as one runnable monorepo install",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|