@yuriteixeira/pi-muxr 0.1.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/LICENSE +21 -0
- package/README.md +126 -0
- package/dist/cli/dashboard-component.d.ts +41 -0
- package/dist/cli/dashboard-component.js +236 -0
- package/dist/cli/dashboard-component.js.map +1 -0
- package/dist/cli/dashboard-icons.d.ts +10 -0
- package/dist/cli/dashboard-icons.js +40 -0
- package/dist/cli/dashboard-icons.js.map +1 -0
- package/dist/cli/dashboard-layout.d.ts +20 -0
- package/dist/cli/dashboard-layout.js +50 -0
- package/dist/cli/dashboard-layout.js.map +1 -0
- package/dist/cli/dashboard-theme.d.ts +43 -0
- package/dist/cli/dashboard-theme.js +56 -0
- package/dist/cli/dashboard-theme.js.map +1 -0
- package/dist/cli/dashboard.d.ts +4 -0
- package/dist/cli/dashboard.js +186 -0
- package/dist/cli/dashboard.js.map +1 -0
- package/dist/cli/format.d.ts +4 -0
- package/dist/cli/format.js +35 -0
- package/dist/cli/format.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +74 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/rows.d.ts +2 -0
- package/dist/cli/rows.js +27 -0
- package/dist/cli/rows.js.map +1 -0
- package/dist/config/config.d.ts +3 -0
- package/dist/config/config.js +37 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/paths.d.ts +5 -0
- package/dist/config/paths.js +22 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/domain/sorting.d.ts +3 -0
- package/dist/domain/sorting.js +28 -0
- package/dist/domain/sorting.js.map +1 -0
- package/dist/domain/status.d.ts +60 -0
- package/dist/domain/status.js +17 -0
- package/dist/domain/status.js.map +1 -0
- package/dist/extension/index.d.ts +1 -0
- package/dist/extension/index.js +2 -0
- package/dist/extension/index.js.map +1 -0
- package/dist/extension/pi-muxr.d.ts +7 -0
- package/dist/extension/pi-muxr.js +262 -0
- package/dist/extension/pi-muxr.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/notifications/desktop.d.ts +2 -0
- package/dist/notifications/desktop.js +29 -0
- package/dist/notifications/desktop.js.map +1 -0
- package/dist/state/dashboard-presence.d.ts +6 -0
- package/dist/state/dashboard-presence.js +23 -0
- package/dist/state/dashboard-presence.js.map +1 -0
- package/dist/state/database.d.ts +3 -0
- package/dist/state/database.js +12 -0
- package/dist/state/database.js.map +1 -0
- package/dist/state/read-statuses.d.ts +3 -0
- package/dist/state/read-statuses.js +5 -0
- package/dist/state/read-statuses.js.map +1 -0
- package/dist/state/rows.d.ts +23 -0
- package/dist/state/rows.js +23 -0
- package/dist/state/rows.js.map +1 -0
- package/dist/state/schema.d.ts +1 -0
- package/dist/state/schema.js +31 -0
- package/dist/state/schema.js.map +1 -0
- package/dist/state/write-status.d.ts +10 -0
- package/dist/state/write-status.js +59 -0
- package/dist/state/write-status.js.map +1 -0
- package/dist/tmux/focus.d.ts +3 -0
- package/dist/tmux/focus.js +19 -0
- package/dist/tmux/focus.js.map +1 -0
- package/dist/tmux/list-panes.d.ts +5 -0
- package/dist/tmux/list-panes.js +21 -0
- package/dist/tmux/list-panes.js.map +1 -0
- package/dist/tmux/sidebar.d.ts +16 -0
- package/dist/tmux/sidebar.js +171 -0
- package/dist/tmux/sidebar.js.map +1 -0
- package/dist/web/assets.d.ts +5 -0
- package/dist/web/assets.js +19 -0
- package/dist/web/assets.js.map +1 -0
- package/dist/web/base16-theme.d.ts +23 -0
- package/dist/web/base16-theme.js +68 -0
- package/dist/web/base16-theme.js.map +1 -0
- package/dist/web/notifications.d.ts +7 -0
- package/dist/web/notifications.js +47 -0
- package/dist/web/notifications.js.map +1 -0
- package/dist/web/page.d.ts +1 -0
- package/dist/web/page.js +155 -0
- package/dist/web/page.js.map +1 -0
- package/dist/web/protocol.d.ts +25 -0
- package/dist/web/protocol.js +2 -0
- package/dist/web/protocol.js.map +1 -0
- package/dist/web/server.d.ts +5 -0
- package/dist/web/server.js +51 -0
- package/dist/web/server.js.map +1 -0
- package/dist/web/terminal-gateway.d.ts +2 -0
- package/dist/web/terminal-gateway.js +110 -0
- package/dist/web/terminal-gateway.js.map +1 -0
- package/dist/web/tmux-session.d.ts +4 -0
- package/dist/web/tmux-session.js +50 -0
- package/dist/web/tmux-session.js.map +1 -0
- package/docs/ARCHITECTURE.md +287 -0
- package/docs/BUILDING.md +78 -0
- package/docs/CONTRIBUTING.md +32 -0
- package/docs/resources/fullscreen.png +0 -0
- package/docs/resources/sidebar.png +0 -0
- package/docs/resources/web.png +0 -0
- package/examples/config.json +13 -0
- package/package.json +76 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./pi-muxr.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/extension/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PiMuxrStatus } from "../domain/status.js";
|
|
2
|
+
export default function piMuxrExtension(pi: any): void;
|
|
3
|
+
export declare function resolveAgentEndStatus(event: unknown, fallbackError: string | null): Pick<PiMuxrStatus, "state" | "severity" | "summary">;
|
|
4
|
+
export declare function summarizeAskUserRequest(input: unknown): string;
|
|
5
|
+
export declare function summarizeAskUserResult(event: any): string;
|
|
6
|
+
export declare function formatToolName(toolName: unknown): string;
|
|
7
|
+
export declare function summarizeToolCall(toolName: unknown, input: unknown): string;
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { loadConfig } from "../config/config.js";
|
|
2
|
+
import { DEFAULT_ACTIONABLE_STATES } from "../domain/status.js";
|
|
3
|
+
import { notifyStatus } from "../notifications/desktop.js";
|
|
4
|
+
import { openDatabase } from "../state/database.js";
|
|
5
|
+
import { hasFreshDashboardPresence } from "../state/dashboard-presence.js";
|
|
6
|
+
import { markNotified, removeStatus, updateHeartbeat, upsertStatus } from "../state/write-status.js";
|
|
7
|
+
import { listTmuxPanes } from "../tmux/list-panes.js";
|
|
8
|
+
export default function piMuxrExtension(pi) {
|
|
9
|
+
const runtime = { config: loadConfig(), db: null, id: null, heartbeatTimer: null, lastError: null, model: null, handledToolCallIds: new Set(), hasToolPreviewInPrompt: false };
|
|
10
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
11
|
+
runtime.config = loadConfig();
|
|
12
|
+
runtime.db = openDatabase(runtime.config.databasePath);
|
|
13
|
+
runtime.model = formatModel(ctx.model);
|
|
14
|
+
runtime.id = createSessionId(ctx);
|
|
15
|
+
writeState(runtime, ctx, "IDLE", "low", startSummary(ctx));
|
|
16
|
+
runtime.heartbeatTimer = setInterval(() => writeHeartbeat(runtime, ctx), runtime.config.heartbeatIntervalMs);
|
|
17
|
+
});
|
|
18
|
+
pi.on("model_select", async (event, ctx) => {
|
|
19
|
+
runtime.model = formatModel(event.model);
|
|
20
|
+
writeState(runtime, ctx, "IDLE", "low", `model: ${runtime.model}`);
|
|
21
|
+
});
|
|
22
|
+
pi.on("agent_start", async (_event, ctx) => {
|
|
23
|
+
runtime.lastError = null;
|
|
24
|
+
runtime.handledToolCallIds.clear();
|
|
25
|
+
runtime.hasToolPreviewInPrompt = false;
|
|
26
|
+
writeState(runtime, ctx, "RUN", "low", "agent started");
|
|
27
|
+
});
|
|
28
|
+
pi.on("turn_start", async (event, ctx) => handleTurnStart(runtime, event, ctx));
|
|
29
|
+
pi.on("tool_call", async (event, ctx) => handleToolCall(runtime, event, ctx));
|
|
30
|
+
pi.on("tool_execution_start", async (event, ctx) => handleToolCall(runtime, event, ctx));
|
|
31
|
+
pi.on("tool_result", async (event, ctx) => handleToolResult(runtime, event, ctx));
|
|
32
|
+
pi.on("agent_end", async (event, ctx) => {
|
|
33
|
+
const status = resolveAgentEndStatus(event, runtime.lastError);
|
|
34
|
+
writeState(runtime, ctx, status.state, status.severity, status.summary);
|
|
35
|
+
runtime.lastError = null;
|
|
36
|
+
});
|
|
37
|
+
pi.on("session_shutdown", async (_event) => {
|
|
38
|
+
if (runtime.heartbeatTimer)
|
|
39
|
+
clearInterval(runtime.heartbeatTimer);
|
|
40
|
+
if (runtime.db && runtime.id)
|
|
41
|
+
removeStatus(runtime.db, runtime.id);
|
|
42
|
+
runtime.db?.close();
|
|
43
|
+
runtime.db = null;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function writeHeartbeat(runtime, _ctx) {
|
|
47
|
+
if (!runtime.db || !runtime.id)
|
|
48
|
+
return;
|
|
49
|
+
updateHeartbeat(runtime.db, runtime.id);
|
|
50
|
+
}
|
|
51
|
+
function handleTurnStart(runtime, event, ctx) {
|
|
52
|
+
if (runtime.hasToolPreviewInPrompt) {
|
|
53
|
+
writeHeartbeat(runtime, ctx);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
writeState(runtime, ctx, "RUN", "low", `turn ${formatTurnIndex(event.turnIndex)} started`);
|
|
57
|
+
}
|
|
58
|
+
function handleToolCall(runtime, event, ctx) {
|
|
59
|
+
const toolCallId = typeof event.toolCallId === "string" ? event.toolCallId : null;
|
|
60
|
+
if (toolCallId && runtime.handledToolCallIds.has(toolCallId))
|
|
61
|
+
return;
|
|
62
|
+
if (toolCallId)
|
|
63
|
+
runtime.handledToolCallIds.add(toolCallId);
|
|
64
|
+
runtime.hasToolPreviewInPrompt = true;
|
|
65
|
+
const input = event.input ?? event.args;
|
|
66
|
+
if (event.toolName === "ask_user") {
|
|
67
|
+
writeState(runtime, ctx, "ASK", "high", summarizeAskUserRequest(input));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
writeState(runtime, ctx, "RUN", "low", summarizeToolCall(event.toolName, input));
|
|
71
|
+
}
|
|
72
|
+
function handleToolResult(runtime, event, ctx) {
|
|
73
|
+
if (event.toolName === "ask_user" && event.isError !== true) {
|
|
74
|
+
runtime.lastError = null;
|
|
75
|
+
writeState(runtime, ctx, "RUN", "low", summarizeAskUserResult(event));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
runtime.lastError = event.isError === true ? `${formatToolName(event.toolName)} ${summarizeResult(event)}` : null;
|
|
79
|
+
}
|
|
80
|
+
export function resolveAgentEndStatus(event, fallbackError) {
|
|
81
|
+
const failure = summarizeAgentEndFailure(event);
|
|
82
|
+
if (failure)
|
|
83
|
+
return { state: "ERROR", severity: "high", summary: failure };
|
|
84
|
+
if (!hasAgentEndMessages(event) && fallbackError)
|
|
85
|
+
return { state: "ERROR", severity: "high", summary: fallbackError };
|
|
86
|
+
return { state: "DONE", severity: "medium", summary: "turn completed" };
|
|
87
|
+
}
|
|
88
|
+
function summarizeAgentEndFailure(event) {
|
|
89
|
+
const messages = getAgentEndMessages(event);
|
|
90
|
+
if (!messages)
|
|
91
|
+
return null;
|
|
92
|
+
const assistant = findLastMessageByRole(messages, "assistant");
|
|
93
|
+
if (isRecord(assistant) && (assistant.stopReason === "error" || assistant.stopReason === "aborted")) {
|
|
94
|
+
return typeof assistant.errorMessage === "string" && assistant.errorMessage.trim() ? truncate(assistant.errorMessage.trim(), 200) : `assistant ${assistant.stopReason}`;
|
|
95
|
+
}
|
|
96
|
+
const lastMessage = messages.at(-1);
|
|
97
|
+
if (isRecord(lastMessage) && lastMessage.role === "toolResult" && lastMessage.isError === true) {
|
|
98
|
+
const toolName = typeof lastMessage.toolName === "string" ? lastMessage.toolName : "tool";
|
|
99
|
+
return `${formatToolName(toolName)} ${summarizeResult(lastMessage)}`;
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
function hasAgentEndMessages(event) {
|
|
104
|
+
return Array.isArray(event?.messages);
|
|
105
|
+
}
|
|
106
|
+
function getAgentEndMessages(event) {
|
|
107
|
+
const messages = event?.messages;
|
|
108
|
+
return Array.isArray(messages) ? messages : null;
|
|
109
|
+
}
|
|
110
|
+
function findLastMessageByRole(messages, role) {
|
|
111
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
112
|
+
const message = messages[index];
|
|
113
|
+
if (isRecord(message) && message.role === role)
|
|
114
|
+
return message;
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
function isRecord(value) {
|
|
119
|
+
return Boolean(value) && typeof value === "object";
|
|
120
|
+
}
|
|
121
|
+
function writeState(runtime, ctx, state, severity, summary) {
|
|
122
|
+
if (!runtime.db || !runtime.id)
|
|
123
|
+
return;
|
|
124
|
+
const now = Date.now();
|
|
125
|
+
const pane = currentPane();
|
|
126
|
+
const status = baseStatus(runtime, ctx, pane, state, severity, summary, now, true);
|
|
127
|
+
const notificationSnapshot = readNotificationSnapshot(runtime.db, status.id);
|
|
128
|
+
upsertStatus(runtime.db, status);
|
|
129
|
+
maybeNotify(runtime, status, notificationSnapshot);
|
|
130
|
+
}
|
|
131
|
+
function baseStatus(runtime, ctx, pane, state, severity, summary, now, event) {
|
|
132
|
+
return {
|
|
133
|
+
id: runtime.id ?? createSessionId(ctx),
|
|
134
|
+
paneId: pane?.paneId ?? process.env.TMUX_PANE ?? null,
|
|
135
|
+
tmuxSession: pane?.sessionName ?? null,
|
|
136
|
+
tmuxWindow: pane?.windowName ?? null,
|
|
137
|
+
tmuxWindowIndex: pane?.windowIndex ?? null,
|
|
138
|
+
pid: process.pid,
|
|
139
|
+
cwd: ctx.cwd ?? process.cwd(),
|
|
140
|
+
piSessionFile: getSessionFile(ctx),
|
|
141
|
+
model: runtime.model ?? formatModel(ctx.model),
|
|
142
|
+
state,
|
|
143
|
+
severity,
|
|
144
|
+
summary,
|
|
145
|
+
lastEventAt: event ? now : now,
|
|
146
|
+
heartbeatAt: now,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function maybeNotify(runtime, status, snapshot) {
|
|
150
|
+
if (!runtime.db || !runtime.config.desktopNotifications)
|
|
151
|
+
return;
|
|
152
|
+
if (!DEFAULT_ACTIONABLE_STATES.includes(status.state))
|
|
153
|
+
return;
|
|
154
|
+
if (snapshot?.state === status.state)
|
|
155
|
+
return;
|
|
156
|
+
if (runtime.config.suppressDesktopNotificationsWhenDashboardOpen && hasFreshDashboardPresence(runtime.db, runtime.config.dashboardPresenceStaleAfterMs))
|
|
157
|
+
return;
|
|
158
|
+
if ((snapshot?.lastNotifiedEventAt ?? 0) >= status.lastEventAt)
|
|
159
|
+
return;
|
|
160
|
+
notifyStatus(status);
|
|
161
|
+
markNotified(runtime.db, status.id, status.lastEventAt);
|
|
162
|
+
}
|
|
163
|
+
function readNotificationSnapshot(db, id) {
|
|
164
|
+
const row = db.prepare("SELECT state, last_notified_event_at FROM sessions WHERE id = ?").get(id);
|
|
165
|
+
if (!row?.state)
|
|
166
|
+
return null;
|
|
167
|
+
return { state: row.state, lastNotifiedEventAt: row.last_notified_event_at ?? null };
|
|
168
|
+
}
|
|
169
|
+
function createSessionId(ctx) {
|
|
170
|
+
const file = getSessionFile(ctx);
|
|
171
|
+
const pane = process.env.TMUX_PANE;
|
|
172
|
+
return [file ?? `pid:${process.pid}`, pane].filter(Boolean).join(":");
|
|
173
|
+
}
|
|
174
|
+
function getSessionFile(ctx) {
|
|
175
|
+
try {
|
|
176
|
+
return ctx.sessionManager?.getSessionFile?.() ?? null;
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function currentPane() {
|
|
183
|
+
const paneId = process.env.TMUX_PANE;
|
|
184
|
+
if (!paneId)
|
|
185
|
+
return null;
|
|
186
|
+
return listTmuxPanes().find((pane) => pane.paneId === paneId) ?? null;
|
|
187
|
+
}
|
|
188
|
+
function formatModel(model) {
|
|
189
|
+
if (!model)
|
|
190
|
+
return null;
|
|
191
|
+
if (typeof model === "string")
|
|
192
|
+
return model;
|
|
193
|
+
if (model.provider && model.id)
|
|
194
|
+
return `${model.provider}/${model.id}`;
|
|
195
|
+
return model.id ?? model.name ?? null;
|
|
196
|
+
}
|
|
197
|
+
function startSummary(ctx) {
|
|
198
|
+
const model = formatModel(ctx.model);
|
|
199
|
+
return model ? `session started (${model})` : "session started";
|
|
200
|
+
}
|
|
201
|
+
function formatTurnIndex(turnIndex) {
|
|
202
|
+
return typeof turnIndex === "number" ? String(turnIndex + 1) : "?";
|
|
203
|
+
}
|
|
204
|
+
export function summarizeAskUserRequest(input) {
|
|
205
|
+
const question = extractAskQuestion(input);
|
|
206
|
+
return question ? `${formatToolName("ask_user")} ${truncate(question, 180)}` : `${formatToolName("ask_user")} waiting for input`;
|
|
207
|
+
}
|
|
208
|
+
export function summarizeAskUserResult(event) {
|
|
209
|
+
if (event.details?.cancelled)
|
|
210
|
+
return `${formatToolName("ask_user")} cancelled`;
|
|
211
|
+
const response = event.details?.response;
|
|
212
|
+
if (response?.kind === "selection" && Array.isArray(response.selections))
|
|
213
|
+
return `${formatToolName("ask_user")} answered: ${truncate(response.selections.join(", "), 160)}`;
|
|
214
|
+
if (response?.kind === "freeform" && typeof response.text === "string")
|
|
215
|
+
return `${formatToolName("ask_user")} answered: ${truncate(response.text, 160)}`;
|
|
216
|
+
return `${formatToolName("ask_user")} answered`;
|
|
217
|
+
}
|
|
218
|
+
function extractAskQuestion(input) {
|
|
219
|
+
if (!input || typeof input !== "object")
|
|
220
|
+
return null;
|
|
221
|
+
const question = input.question;
|
|
222
|
+
return typeof question === "string" && question.trim() ? question.trim() : null;
|
|
223
|
+
}
|
|
224
|
+
export function formatToolName(toolName) {
|
|
225
|
+
return `[${typeof toolName === "string" ? toolName : "tool"}]`;
|
|
226
|
+
}
|
|
227
|
+
export function summarizeToolCall(toolName, input) {
|
|
228
|
+
return `${formatToolName(toolName)}${summarizeToolInput(toolName, input)}`;
|
|
229
|
+
}
|
|
230
|
+
function summarizeToolInput(toolName, input) {
|
|
231
|
+
if (!input || typeof input !== "object")
|
|
232
|
+
return "";
|
|
233
|
+
const record = input;
|
|
234
|
+
if (toolName === "bash" && typeof record.command === "string")
|
|
235
|
+
return ` ${truncate(record.command, 160)}`;
|
|
236
|
+
if (typeof record.path === "string")
|
|
237
|
+
return ` ${truncate(record.path, 160)}`;
|
|
238
|
+
if (typeof record.url === "string")
|
|
239
|
+
return ` ${truncate(record.url, 160)}`;
|
|
240
|
+
if (typeof record.query === "string")
|
|
241
|
+
return ` ${truncate(record.query, 160)}`;
|
|
242
|
+
try {
|
|
243
|
+
return ` ${truncate(JSON.stringify(input), 120)}`;
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
return "";
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function summarizeResult(event) {
|
|
250
|
+
if (typeof event.content === "string")
|
|
251
|
+
return truncate(event.content, 200);
|
|
252
|
+
try {
|
|
253
|
+
return truncate(JSON.stringify(event.content ?? event.details ?? {}), 200);
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
return "tool failed";
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function truncate(value, max) {
|
|
260
|
+
return value.length <= max ? value : `${value.slice(0, max - 1)}…`;
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=pi-muxr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pi-muxr.js","sourceRoot":"","sources":["../../src/extension/pi-muxr.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from "./domain/status.js";
|
|
2
|
+
export * from "./domain/sorting.js";
|
|
3
|
+
export * from "./config/config.js";
|
|
4
|
+
export * from "./config/paths.js";
|
|
5
|
+
export * from "./state/database.js";
|
|
6
|
+
export * from "./state/read-statuses.js";
|
|
7
|
+
export * from "./state/write-status.js";
|
|
8
|
+
export * from "./state/dashboard-presence.js";
|
|
9
|
+
export * from "./tmux/list-panes.js";
|
|
10
|
+
export * from "./tmux/focus.js";
|
|
11
|
+
export * from "./web/server.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "./domain/status.js";
|
|
2
|
+
export * from "./domain/sorting.js";
|
|
3
|
+
export * from "./config/config.js";
|
|
4
|
+
export * from "./config/paths.js";
|
|
5
|
+
export * from "./state/database.js";
|
|
6
|
+
export * from "./state/read-statuses.js";
|
|
7
|
+
export * from "./state/write-status.js";
|
|
8
|
+
export * from "./state/dashboard-presence.js";
|
|
9
|
+
export * from "./tmux/list-panes.js";
|
|
10
|
+
export * from "./tmux/focus.js";
|
|
11
|
+
export * from "./web/server.js";
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { projectName } from "../domain/status.js";
|
|
3
|
+
export function notifyStatus(status) {
|
|
4
|
+
const title = `pi-muxr: ${status.state} in ${projectName(status.cwd)}`;
|
|
5
|
+
const body = `${status.summary}\n${formatLocation(status)}`;
|
|
6
|
+
tryNotify(title, body);
|
|
7
|
+
}
|
|
8
|
+
function tryNotify(title, body) {
|
|
9
|
+
if (process.platform === "darwin") {
|
|
10
|
+
try {
|
|
11
|
+
execFileSync("osascript", ["-e", `display notification ${JSON.stringify(body)} with title ${JSON.stringify(title)}`], { stdio: "ignore" });
|
|
12
|
+
}
|
|
13
|
+
catch { }
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (process.platform === "linux") {
|
|
17
|
+
try {
|
|
18
|
+
execFileSync("notify-send", [title, body], { stdio: "ignore" });
|
|
19
|
+
}
|
|
20
|
+
catch { }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function formatLocation(status) {
|
|
24
|
+
const session = status.tmuxSession ?? "?";
|
|
25
|
+
const windowIndex = status.tmuxWindowIndex ?? "?";
|
|
26
|
+
const pane = status.paneId ?? "?";
|
|
27
|
+
return `${session}:${windowIndex}.${pane}`;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=desktop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop.js","sourceRoot":"","sources":["../../src/notifications/desktop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC/C,MAAM,KAAK,GAAG,YAAY,MAAM,CAAC,KAAK,OAAO,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IACvE,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,OAAO,KAAK,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;IAC5D,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,SAAS,CAAC,KAAa,EAAE,IAAY;IAC5C,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,IAAI,CAAC;YAAC,YAAY,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,wBAAwB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QAC5J,OAAO;IACT,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,IAAI,CAAC;YAAC,YAAY,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACnF,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,MAAoB;IAC1C,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,IAAI,GAAG,CAAC;IAC1C,MAAM,WAAW,GAAG,MAAM,CAAC,eAAe,IAAI,GAAG,CAAC;IAClD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC;IAClC,OAAO,GAAG,OAAO,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Database } from "./database.js";
|
|
2
|
+
export declare function createPresenceId(): string;
|
|
3
|
+
export declare function writeDashboardPresence(db: Database, instanceId: string, tmuxPaneId: string | null, at?: number): void;
|
|
4
|
+
export declare function cleanupDashboardPresence(db: Database, staleAfterMs: number, at?: number): void;
|
|
5
|
+
export declare function hasFreshDashboardPresence(db: Database, staleAfterMs: number, at?: number): boolean;
|
|
6
|
+
export declare function removeDashboardPresence(db: Database, instanceId: string): void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
export function createPresenceId() {
|
|
3
|
+
return randomUUID();
|
|
4
|
+
}
|
|
5
|
+
export function writeDashboardPresence(db, instanceId, tmuxPaneId, at = Date.now()) {
|
|
6
|
+
db.prepare(`
|
|
7
|
+
INSERT INTO dashboard_presence (instance_id, pid, tmux_pane_id, started_at, heartbeat_at)
|
|
8
|
+
VALUES (?, ?, ?, ?, ?)
|
|
9
|
+
ON CONFLICT(instance_id) DO UPDATE SET pid=excluded.pid, tmux_pane_id=excluded.tmux_pane_id, heartbeat_at=excluded.heartbeat_at
|
|
10
|
+
`).run(instanceId, process.pid, tmuxPaneId, at, at);
|
|
11
|
+
}
|
|
12
|
+
export function cleanupDashboardPresence(db, staleAfterMs, at = Date.now()) {
|
|
13
|
+
db.prepare("DELETE FROM dashboard_presence WHERE heartbeat_at < ?").run(at - staleAfterMs);
|
|
14
|
+
}
|
|
15
|
+
export function hasFreshDashboardPresence(db, staleAfterMs, at = Date.now()) {
|
|
16
|
+
cleanupDashboardPresence(db, staleAfterMs, at);
|
|
17
|
+
const row = db.prepare("SELECT 1 FROM dashboard_presence WHERE heartbeat_at >= ? LIMIT 1").get(at - staleAfterMs);
|
|
18
|
+
return Boolean(row);
|
|
19
|
+
}
|
|
20
|
+
export function removeDashboardPresence(db, instanceId) {
|
|
21
|
+
db.prepare("DELETE FROM dashboard_presence WHERE instance_id = ?").run(instanceId);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=dashboard-presence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-presence.js","sourceRoot":"","sources":["../../src/state/dashboard-presence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,MAAM,UAAU,gBAAgB;IAC9B,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,EAAY,EAAE,UAAkB,EAAE,UAAyB,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE;IACjH,EAAE,CAAC,OAAO,CAAC;;;;GAIV,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,EAAY,EAAE,YAAoB,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE;IAC1F,EAAE,CAAC,OAAO,CAAC,uDAAuD,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAC7F,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,EAAY,EAAE,YAAoB,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE;IAC3F,wBAAwB,CAAC,EAAE,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,kEAAkE,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;IAClH,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,EAAY,EAAE,UAAkB;IACtE,EAAE,CAAC,OAAO,CAAC,sDAAsD,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AACrF,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
2
|
+
import { DatabaseSync } from "node:sqlite";
|
|
3
|
+
import { parentDir } from "../config/paths.js";
|
|
4
|
+
import { SCHEMA_SQL } from "./schema.js";
|
|
5
|
+
export function openDatabase(databasePath) {
|
|
6
|
+
mkdirSync(parentDir(databasePath), { recursive: true });
|
|
7
|
+
const db = new DatabaseSync(databasePath);
|
|
8
|
+
db.exec("PRAGMA journal_mode = WAL; PRAGMA busy_timeout = 3000;");
|
|
9
|
+
db.exec(SCHEMA_SQL);
|
|
10
|
+
return db;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/state/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC,MAAM,UAAU,YAAY,CAAC,YAAoB;IAC/C,SAAS,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,YAAY,CAAC,CAAC;IAC1C,EAAE,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;IAClE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACpB,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-statuses.js","sourceRoot":"","sources":["../../src/state/read-statuses.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,MAAM,UAAU,YAAY,CAAC,EAAY;IACvC,OAAO,EAAE,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAY,CAAC,CAAC,CAAC;AACzF,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PiMuxrStatus } from "../domain/status.js";
|
|
2
|
+
type DbSessionRow = {
|
|
3
|
+
id: string;
|
|
4
|
+
pane_id: string | null;
|
|
5
|
+
tmux_session: string | null;
|
|
6
|
+
tmux_window: string | null;
|
|
7
|
+
tmux_window_index: string | null;
|
|
8
|
+
pid: number;
|
|
9
|
+
cwd: string;
|
|
10
|
+
pi_session_file: string | null;
|
|
11
|
+
model: string | null;
|
|
12
|
+
state: PiMuxrStatus["state"];
|
|
13
|
+
severity: PiMuxrStatus["severity"];
|
|
14
|
+
summary: string;
|
|
15
|
+
last_event_at: number;
|
|
16
|
+
heartbeat_at: number;
|
|
17
|
+
read_until_event_at: number | null;
|
|
18
|
+
acknowledged_at: number | null;
|
|
19
|
+
dismissed_until_event_at: number | null;
|
|
20
|
+
last_notified_event_at: number | null;
|
|
21
|
+
};
|
|
22
|
+
export declare function toStatus(row: DbSessionRow): PiMuxrStatus;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function toStatus(row) {
|
|
2
|
+
return {
|
|
3
|
+
id: row.id,
|
|
4
|
+
paneId: row.pane_id,
|
|
5
|
+
tmuxSession: row.tmux_session,
|
|
6
|
+
tmuxWindow: row.tmux_window,
|
|
7
|
+
tmuxWindowIndex: row.tmux_window_index,
|
|
8
|
+
pid: row.pid,
|
|
9
|
+
cwd: row.cwd,
|
|
10
|
+
piSessionFile: row.pi_session_file,
|
|
11
|
+
model: row.model,
|
|
12
|
+
state: row.state,
|
|
13
|
+
severity: row.severity,
|
|
14
|
+
summary: row.summary,
|
|
15
|
+
lastEventAt: row.last_event_at,
|
|
16
|
+
heartbeatAt: row.heartbeat_at,
|
|
17
|
+
readUntilEventAt: row.read_until_event_at,
|
|
18
|
+
acknowledgedAt: row.acknowledged_at,
|
|
19
|
+
dismissedUntilEventAt: row.dismissed_until_event_at,
|
|
20
|
+
lastNotifiedEventAt: row.last_notified_event_at,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=rows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rows.js","sourceRoot":"","sources":["../../src/state/rows.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,QAAQ,CAAC,GAAiB;IACxC,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,MAAM,EAAE,GAAG,CAAC,OAAO;QACnB,WAAW,EAAE,GAAG,CAAC,YAAY;QAC7B,UAAU,EAAE,GAAG,CAAC,WAAW;QAC3B,eAAe,EAAE,GAAG,CAAC,iBAAiB;QACtC,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,aAAa,EAAE,GAAG,CAAC,eAAe;QAClC,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,WAAW,EAAE,GAAG,CAAC,aAAa;QAC9B,WAAW,EAAE,GAAG,CAAC,YAAY;QAC7B,gBAAgB,EAAE,GAAG,CAAC,mBAAmB;QACzC,cAAc,EAAE,GAAG,CAAC,eAAe;QACnC,qBAAqB,EAAE,GAAG,CAAC,wBAAwB;QACnD,mBAAmB,EAAE,GAAG,CAAC,sBAAsB;KAChD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SCHEMA_SQL = "\nCREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n pane_id TEXT,\n tmux_session TEXT,\n tmux_window TEXT,\n tmux_window_index TEXT,\n pid INTEGER NOT NULL,\n cwd TEXT NOT NULL,\n pi_session_file TEXT,\n model TEXT,\n state TEXT NOT NULL,\n severity TEXT NOT NULL,\n summary TEXT NOT NULL,\n last_event_at INTEGER NOT NULL,\n heartbeat_at INTEGER NOT NULL,\n read_until_event_at INTEGER,\n acknowledged_at INTEGER,\n dismissed_until_event_at INTEGER,\n last_notified_event_at INTEGER\n);\n\nCREATE TABLE IF NOT EXISTS dashboard_presence (\n instance_id TEXT PRIMARY KEY,\n pid INTEGER NOT NULL,\n tmux_pane_id TEXT,\n started_at INTEGER NOT NULL,\n heartbeat_at INTEGER NOT NULL\n);\n";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const SCHEMA_SQL = `
|
|
2
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
3
|
+
id TEXT PRIMARY KEY,
|
|
4
|
+
pane_id TEXT,
|
|
5
|
+
tmux_session TEXT,
|
|
6
|
+
tmux_window TEXT,
|
|
7
|
+
tmux_window_index TEXT,
|
|
8
|
+
pid INTEGER NOT NULL,
|
|
9
|
+
cwd TEXT NOT NULL,
|
|
10
|
+
pi_session_file TEXT,
|
|
11
|
+
model TEXT,
|
|
12
|
+
state TEXT NOT NULL,
|
|
13
|
+
severity TEXT NOT NULL,
|
|
14
|
+
summary TEXT NOT NULL,
|
|
15
|
+
last_event_at INTEGER NOT NULL,
|
|
16
|
+
heartbeat_at INTEGER NOT NULL,
|
|
17
|
+
read_until_event_at INTEGER,
|
|
18
|
+
acknowledged_at INTEGER,
|
|
19
|
+
dismissed_until_event_at INTEGER,
|
|
20
|
+
last_notified_event_at INTEGER
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
CREATE TABLE IF NOT EXISTS dashboard_presence (
|
|
24
|
+
instance_id TEXT PRIMARY KEY,
|
|
25
|
+
pid INTEGER NOT NULL,
|
|
26
|
+
tmux_pane_id TEXT,
|
|
27
|
+
started_at INTEGER NOT NULL,
|
|
28
|
+
heartbeat_at INTEGER NOT NULL
|
|
29
|
+
);
|
|
30
|
+
`;
|
|
31
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/state/schema.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BzB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PiMuxrState, PiMuxrStatus } from "../domain/status.js";
|
|
2
|
+
import type { Database } from "./database.js";
|
|
3
|
+
export type StatusInput = Omit<PiMuxrStatus, "readUntilEventAt" | "acknowledgedAt" | "dismissedUntilEventAt" | "lastNotifiedEventAt"> & Partial<Pick<PiMuxrStatus, "readUntilEventAt" | "acknowledgedAt" | "dismissedUntilEventAt" | "lastNotifiedEventAt">>;
|
|
4
|
+
export declare function upsertStatus(db: Database, status: StatusInput): void;
|
|
5
|
+
export declare function removeStatus(db: Database, id: string): void;
|
|
6
|
+
export declare function updateHeartbeat(db: Database, id: string, heartbeatAt?: number): void;
|
|
7
|
+
export declare function markRead(db: Database, id: string, lastEventAt: number): void;
|
|
8
|
+
export declare function dismissStatus(db: Database, id: string, lastEventAt: number, at?: number): void;
|
|
9
|
+
export declare function dismissAllRead(db: Database, actionableStatesOrAt?: PiMuxrState[] | number, at?: number): number;
|
|
10
|
+
export declare function markNotified(db: Database, id: string, lastEventAt: number): void;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { DEFAULT_ACTIONABLE_STATES } from "../domain/status.js";
|
|
2
|
+
export function upsertStatus(db, status) {
|
|
3
|
+
db.prepare(`
|
|
4
|
+
INSERT INTO sessions (id, pane_id, tmux_session, tmux_window, tmux_window_index, pid, cwd, pi_session_file, model, state, severity, summary, last_event_at, heartbeat_at, read_until_event_at, acknowledged_at, dismissed_until_event_at, last_notified_event_at)
|
|
5
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
6
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
7
|
+
pane_id=excluded.pane_id,
|
|
8
|
+
tmux_session=excluded.tmux_session,
|
|
9
|
+
tmux_window=excluded.tmux_window,
|
|
10
|
+
tmux_window_index=excluded.tmux_window_index,
|
|
11
|
+
pid=excluded.pid,
|
|
12
|
+
cwd=excluded.cwd,
|
|
13
|
+
pi_session_file=excluded.pi_session_file,
|
|
14
|
+
model=excluded.model,
|
|
15
|
+
state=excluded.state,
|
|
16
|
+
severity=excluded.severity,
|
|
17
|
+
summary=excluded.summary,
|
|
18
|
+
last_event_at=excluded.last_event_at,
|
|
19
|
+
heartbeat_at=excluded.heartbeat_at,
|
|
20
|
+
read_until_event_at=COALESCE(sessions.read_until_event_at, excluded.read_until_event_at),
|
|
21
|
+
acknowledged_at=COALESCE(sessions.acknowledged_at, excluded.acknowledged_at),
|
|
22
|
+
dismissed_until_event_at=COALESCE(sessions.dismissed_until_event_at, excluded.dismissed_until_event_at),
|
|
23
|
+
last_notified_event_at=COALESCE(sessions.last_notified_event_at, excluded.last_notified_event_at)
|
|
24
|
+
`).run(status.id, status.paneId, status.tmuxSession, status.tmuxWindow, status.tmuxWindowIndex, status.pid, status.cwd, status.piSessionFile, status.model, status.state, status.severity, truncate(status.summary, 500), status.lastEventAt, status.heartbeatAt, status.readUntilEventAt ?? null, status.acknowledgedAt ?? null, status.dismissedUntilEventAt ?? null, status.lastNotifiedEventAt ?? null);
|
|
25
|
+
}
|
|
26
|
+
export function removeStatus(db, id) {
|
|
27
|
+
db.prepare("DELETE FROM sessions WHERE id = ?").run(id);
|
|
28
|
+
}
|
|
29
|
+
export function updateHeartbeat(db, id, heartbeatAt = Date.now()) {
|
|
30
|
+
db.prepare("UPDATE sessions SET heartbeat_at = ? WHERE id = ?").run(heartbeatAt, id);
|
|
31
|
+
}
|
|
32
|
+
export function markRead(db, id, lastEventAt) {
|
|
33
|
+
db.prepare("UPDATE sessions SET read_until_event_at = ? WHERE id = ?").run(lastEventAt, id);
|
|
34
|
+
}
|
|
35
|
+
export function dismissStatus(db, id, lastEventAt, at = Date.now()) {
|
|
36
|
+
db.prepare("UPDATE sessions SET dismissed_until_event_at = ?, acknowledged_at = ? WHERE id = ?").run(lastEventAt, at, id);
|
|
37
|
+
}
|
|
38
|
+
export function dismissAllRead(db, actionableStatesOrAt = DEFAULT_ACTIONABLE_STATES, at = Date.now()) {
|
|
39
|
+
const actionableStates = Array.isArray(actionableStatesOrAt) ? actionableStatesOrAt : DEFAULT_ACTIONABLE_STATES;
|
|
40
|
+
const acknowledgedAt = Array.isArray(actionableStatesOrAt) ? at : actionableStatesOrAt;
|
|
41
|
+
if (actionableStates.length === 0)
|
|
42
|
+
return 0;
|
|
43
|
+
const placeholders = actionableStates.map(() => "?").join(", ");
|
|
44
|
+
const result = db.prepare(`
|
|
45
|
+
UPDATE sessions
|
|
46
|
+
SET dismissed_until_event_at = last_event_at, acknowledged_at = ?
|
|
47
|
+
WHERE state IN (${placeholders})
|
|
48
|
+
AND COALESCE(read_until_event_at, 0) >= last_event_at
|
|
49
|
+
AND COALESCE(dismissed_until_event_at, 0) < last_event_at
|
|
50
|
+
`).run(acknowledgedAt, ...actionableStates);
|
|
51
|
+
return Number(result.changes ?? 0);
|
|
52
|
+
}
|
|
53
|
+
export function markNotified(db, id, lastEventAt) {
|
|
54
|
+
db.prepare("UPDATE sessions SET last_notified_event_at = ? WHERE id = ?").run(lastEventAt, id);
|
|
55
|
+
}
|
|
56
|
+
function truncate(value, max) {
|
|
57
|
+
return value.length <= max ? value : `${value.slice(0, max - 1)}…`;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=write-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-status.js","sourceRoot":"","sources":["../../src/state/write-status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { TmuxPane } from "../domain/status.js";
|
|
2
|
+
export declare function focusPane(pane: Pick<TmuxPane, "sessionName" | "windowIndex" | "paneId">): string[];
|
|
3
|
+
export declare function buildFocusCommands(pane: Pick<TmuxPane, "sessionName" | "windowIndex" | "paneId">): string[];
|