fix: event-loop freezes, plugin-install boot crash, tmux attach/scrollbar, Codex transcripts
- GET /api/workflows: one LEAD() window pass in a read worker (read-pool.js, workflow-stats.js); idx_events_session restored, idx_events_tool added - compat-sqlite gains function/pluck/readonly so a plugin install without a better-sqlite3 build boots again; antigravity-usage uses db.js's Database - install-hooks adds no checkout hooks while the agenthub plugin is enabled (events were doubled) - terminal attach runs the live tmux server's own binary; the pane scrollbar gets a visible 2-column style, and claude panes start with CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1 so tmux keeps history to scroll - Codex sessions' conversation in GET /api/sessions/:id/transcript - Codex/Antigravity sessions claimed by their workspace without hooks - UI-audit follow-ups, docs and OpenAPI
This commit is contained in:
@@ -196,6 +196,45 @@ function laneForSession(sessionId) {
|
||||
}
|
||||
}
|
||||
|
||||
// The newest same-tool run in session `s`'s folder that was live when it
|
||||
// started (2 s of slack: agy stamps whole seconds).
|
||||
const runOf = (col, s) => `
|
||||
SELECT r.${col} FROM dashboard_runs r
|
||||
WHERE r.lane_id IS NOT NULL AND r.tool = ${s}.tool AND r.cwd = ${s}.cwd
|
||||
AND julianday(r.started_at) <= julianday(${s}.started_at) + 2.0 / 86400
|
||||
AND julianday(${s}.started_at) <= julianday(COALESCE(r.ended_at, 'now'))
|
||||
ORDER BY r.started_at DESC LIMIT 1`;
|
||||
const claimToolStmt = db.prepare(`
|
||||
UPDATE sessions SET lane_id = (${runOf("lane_id", "sessions")})
|
||||
WHERE lane_id IS NULL AND tool != 'claude' AND (@id IS NULL OR id = @id)
|
||||
AND (${runOf("lane_id", "sessions")}) IS NOT NULL
|
||||
`);
|
||||
const claimRunStmt = db.prepare(`
|
||||
UPDATE dashboard_runs SET session_id = @id
|
||||
WHERE session_id IS NULL
|
||||
AND id = (SELECT (${runOf("id", "s")}) FROM sessions s WHERE s.id = @id AND s.tool != 'claude')
|
||||
`);
|
||||
|
||||
/**
|
||||
* Stamp the workspace (`sessions.lane_id`) of a Codex / Antigravity session
|
||||
* that nothing bound: their panes learn their session only from opt-in hooks
|
||||
* (routes/hooks.js → bindRunSession), so without them a session the poll
|
||||
* imported belonged to no workspace and vanished from it once its tab closed.
|
||||
* Claude is left to `--session-id` + its hooks. `sessionId` null = every one;
|
||||
* a single session also becomes its run's `session_id` while that is empty,
|
||||
* so its live tab shows the session instead of a second "New session".
|
||||
* ponytail: matched by (tool, cwd, time), so an agy started by hand in the
|
||||
* same folder while a pane of that tool is live is counted as the pane's.
|
||||
*/
|
||||
function claimToolSessions(sessionId = null) {
|
||||
try {
|
||||
if (sessionId) claimRunStmt.run({ id: sessionId });
|
||||
return claimToolStmt.run({ id: sessionId }).changes;
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const runningStmt = db.prepare(
|
||||
"SELECT id FROM dashboard_runs WHERE status IN ('running', 'spawning')"
|
||||
);
|
||||
@@ -235,4 +274,5 @@ module.exports = {
|
||||
reconcileOrphans,
|
||||
routerForSession,
|
||||
laneForSession,
|
||||
claimToolSessions,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user