feat: workspaces own their sessions; desktop parity; sidebar and settings cleanup
Workspace sessions (docs/plans/desktop-parity, phases 1-5 and 7): - sessions.lane_id: a workspace lists only the sessions its panes held, stamped by bindRunSession (first writer wins, nested `claude -p` excluded); GET /api/sessions?lane=&archived= - session row state dot, double-click rename, archive (sessions.archived_at, hides only); the activity bar's duplicate Sessions tab removed - Fork beside Resume (--fork-session, Claude only), Ctrl/Cmd+click a live session opens it in a second pane, a diff line's comment is pasted into the workspace's last-focused pane (lib/panePaste.ts) dashboard_runs stability: - a pane's previous run is archived as <pane>@<started_at> instead of being overwritten by INSERT OR REPLACE - a run is flagged abandoned only once its tmux session is gone, at boot and on the run-heal beat (panes outlive a server restart) UI: - sidebar: no footer, language or theme block; small collapse button in the brand corner; version + update check in the connection details modal, a status-bar dot while a release is out; language in Settings -> General - one Switch component for every switch, the themed Checkbox for every checkbox (no native checkboxes) Also: AI Tools catalog trimmed to 10 built-ins (custom-file prompt modes tested through fixtures), and the workspace plans under docs/plans/ (the multi-user server plan lives in the AgentHub-Server repo).
This commit is contained in:
+12
-7
@@ -539,14 +539,18 @@ function startBackgroundServices() {
|
||||
}
|
||||
}
|
||||
// A codex/antigravity pane that exits fires no hook, so release its lane on
|
||||
// a beat instead (one `tmux has-session` per lane with a run). Off with
|
||||
// DASHBOARD_RUN_HEAL_MS=0.
|
||||
// a beat instead (one `tmux has-session` per lane with a run), and end the
|
||||
// run record of any pane that is gone. Off with DASHBOARD_RUN_HEAL_MS=0.
|
||||
const HEAL_MS = Number(process.env.DASHBOARD_RUN_HEAL_MS ?? 10_000);
|
||||
if (Number.isFinite(HEAL_MS) && HEAL_MS > 0) {
|
||||
const { healAllRunIds } = require("./routes/lanes");
|
||||
const { reconcileOrphans } = require("./lib/dashboard-runs");
|
||||
const { hasSession } = require("./lib/tmux");
|
||||
const healTimer = setInterval(() => {
|
||||
try {
|
||||
healAllRunIds();
|
||||
// A pane that quit (Ctrl+C, `exit`) ends its run record too.
|
||||
reconcileOrphans(hasSession);
|
||||
} catch (err) {
|
||||
console.warn("run heal failed:", err.message);
|
||||
}
|
||||
@@ -587,13 +591,14 @@ function startBackgroundServices() {
|
||||
} catch (err) {
|
||||
console.warn("remote source sync failed to start:", err.message);
|
||||
}
|
||||
// Flip any dashboard_runs rows the previous process left flagged
|
||||
// running/spawning — those handles died with the previous server, so
|
||||
// there's no way to attach to them anymore. Marking them abandoned
|
||||
// keeps the Run history honest and unblocks Resume on conversation rows.
|
||||
// Flip the dashboard_runs rows still flagged running/spawning whose tmux
|
||||
// pane is gone (a reboot, a pane that quit while no server was up). A pane
|
||||
// that is still there survived the restart and stays running — tmux, not
|
||||
// this process, owns it.
|
||||
try {
|
||||
const { reconcileOrphans } = require("./lib/dashboard-runs");
|
||||
const reconciled = reconcileOrphans();
|
||||
const { hasSession } = require("./lib/tmux");
|
||||
const reconciled = reconcileOrphans(hasSession);
|
||||
if (reconciled > 0) {
|
||||
console.log(`[runs] reconciled ${reconciled} orphan run(s) → abandoned`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user