ai-whisper 0.7.0 → 0.8.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/README.md CHANGED
@@ -99,12 +99,19 @@ whisper collab mount claude
99
99
  whisper collab mount codex
100
100
  ```
101
101
 
102
- The first `mount` creates the collab and starts the broker daemon for the workspace; the second binds the other agent. From either session, start a workflow against a spec or goal file (`spec-driven-development` for a spec, `ralph-loop` for an open-ended goal). Watch it run with:
102
+ The first `mount` creates the collab and starts the broker daemon for the workspace; the second binds the other agent. From either session, start a workflow against a spec or goal file `spec-driven-development` for a spec, `ralph-loop` for an open-ended goal, plus `complex-bug-fixing` and `deliberation` (see [Workflows](docs/workflows.md)). Watch it run with:
103
103
 
104
104
  ```bash
105
105
  whisper collab dashboard
106
106
  ```
107
107
 
108
+ - `whisper collab dashboard` — live wall of recently-active collabs + per-run inspector.
109
+ Add `--all` to show every workflow run (no per-collab masking); combine with
110
+ `--window all` for the full run ledger.
111
+ - From the dashboard you can pause/resume/cancel a workflow run in place
112
+ (`p`/`r`/`c`, each confirmed), and a header bar shows live counts of running /
113
+ paused / stuck / done / canceled / idle runs.
114
+
108
115
  > Running from a repo checkout instead of a packaged install? Build first (`pnpm build`) and invoke the CLI as `node packages/cli/dist/bin/whisper.js ...` wherever these examples say `whisper ...`.
109
116
 
110
117
  ## What happens if it fails?
@@ -121,7 +128,7 @@ For the full mental model, read [Concepts](docs/concepts.md).
121
128
 
122
129
  ## Learn more
123
130
 
124
- - [Workflows](docs/workflows.md) — how to use the workflows well: choosing between `spec-driven-development` and `ralph-loop`, and authoring the spec or goal that drives the run.
131
+ - [Workflows](docs/workflows.md) — how to use the four workflows well: choosing between `spec-driven-development`, `ralph-loop`, `complex-bug-fixing`, and `deliberation`, and authoring the spec, goal, bug report, or seed that drives the run.
125
132
  - [Concepts](docs/concepts.md) — the mental model: baton handoff, real mounted sessions, supervised autonomy, workflow-first execution.
126
133
  - [Relay & handoff flows](docs/relay-handoff-flows.md) — the complete handoff state machine, capture-status table, hotkey reference, per-step verdicts, and troubleshooting.
127
134
  - [Evaluator configuration](docs/evaluator-configuration.md) — required credentials and options for the LLM evaluator that gates workflows.
@@ -1913,7 +1913,8 @@ function listActiveCollabSummaries(db, input) {
1913
1913
  GROUP BY c.collab_id
1914
1914
  HAVING MAX(h.last_activity_at) >= ?
1915
1915
  OR EXISTS (SELECT 1 FROM workflows w
1916
- WHERE w.collab_id = c.collab_id AND w.status = 'running')`).all(cutoff);
1916
+ WHERE w.collab_id = c.collab_id
1917
+ AND w.status IN ('running','paused'))`).all(cutoff);
1917
1918
  const out = [];
1918
1919
  const seen = /* @__PURE__ */ new Set();
1919
1920
  for (const e of eligible) {
@@ -1938,86 +1939,105 @@ function listActiveCollabSummaries(db, input) {
1938
1939
  }
1939
1940
  return out;
1940
1941
  }
1941
- function buildCollabSummary(db, collabId2) {
1942
- {
1943
- const e = { collabId: collabId2 };
1944
- const collab2 = db.prepare(`SELECT display_name AS displayName, workspace_root AS workspaceRoot
1945
- FROM collab WHERE collab_id = ?`).get(e.collabId);
1946
- const wf = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
1947
- name, status, current_phase_index AS currentPhaseIndex,
1948
- created_at AS createdAt, spec_path AS specPath
1949
- FROM workflows WHERE collab_id = ?
1950
- ORDER BY (status = 'running') DESC, created_at DESC
1951
- LIMIT 1`).get(e.collabId);
1952
- let currentPhaseRunId = null;
1953
- let phaseIndex = null;
1954
- let phaseName = null;
1955
- let chainId = null;
1956
- if (wf) {
1957
- const ph = db.prepare(`SELECT phase_run_id AS phaseRunId, phase_index AS phaseIndex,
1958
- phase_name AS phaseName, chain_id AS chainId
1959
- FROM workflow_phases WHERE workflow_id = ?
1960
- ORDER BY (ended_at IS NULL) DESC, started_at DESC
1961
- LIMIT 1`).get(wf.workflowId);
1962
- if (ph) {
1963
- currentPhaseRunId = ph.phaseRunId;
1964
- phaseIndex = ph.phaseIndex;
1965
- phaseName = ph.phaseName;
1966
- chainId = ph.chainId;
1967
- }
1942
+ function buildWorkflowSummary(db, collabId2, wf) {
1943
+ const collab2 = db.prepare(`SELECT display_name AS displayName, workspace_root AS workspaceRoot
1944
+ FROM collab WHERE collab_id = ?`).get(collabId2);
1945
+ let currentPhaseRunId = null;
1946
+ let phaseIndex = null;
1947
+ let phaseName = null;
1948
+ let chainId = null;
1949
+ if (wf) {
1950
+ const ph = db.prepare(`SELECT phase_run_id AS phaseRunId, phase_index AS phaseIndex,
1951
+ phase_name AS phaseName, chain_id AS chainId
1952
+ FROM workflow_phases WHERE workflow_id = ?
1953
+ ORDER BY (ended_at IS NULL) DESC, started_at DESC
1954
+ LIMIT 1`).get(wf.workflowId);
1955
+ if (ph) {
1956
+ currentPhaseRunId = ph.phaseRunId;
1957
+ phaseIndex = ph.phaseIndex;
1958
+ phaseName = ph.phaseName;
1959
+ chainId = ph.chainId;
1968
1960
  }
1969
- const chain = chainId ? db.prepare(`SELECT status, current_round AS currentRound, max_rounds AS maxRounds
1970
- FROM relay_chains WHERE chain_id = ?`).get(chainId) : void 0;
1971
- const turn = db.prepare(`SELECT turn_owner AS owner, waiting_agent AS waiting, handoff_state AS handoffState
1972
- FROM relay_turn_state WHERE collab_id = ?`).get(e.collabId);
1973
- const sessions = db.prepare(`SELECT agentType, healthState FROM (
1974
- SELECT s.agent_type AS agentType,
1975
- s.health_state AS healthState,
1976
- ROW_NUMBER() OVER (
1977
- PARTITION BY s.agent_type
1978
- ORDER BY CASE WHEN sb.active_session_id = s.session_id
1979
- THEN 0 ELSE 1 END ASC,
1980
- s.registered_at DESC,
1981
- s.rowid DESC
1982
- ) AS rn
1983
- FROM session s
1984
- LEFT JOIN session_binding sb
1985
- ON sb.collab_id = s.collab_id
1986
- AND sb.agent_type = s.agent_type
1987
- WHERE s.collab_id = ?
1988
- ) ranked
1989
- WHERE rn = 1
1990
- ORDER BY agentType ASC`).all(e.collabId);
1991
- const label = wf?.name && wf.name.trim() || collab2?.displayName && collab2.displayName.trim() || (collab2?.workspaceRoot ? basename2(collab2.workspaceRoot) : "") || e.collabId.slice(0, 12);
1992
- const runLastActRow = wf ? db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
1993
- FROM relay_handoff
1994
- WHERE collab_id = ? AND workflow_id = ?`).get(e.collabId, wf.workflowId) : db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
1995
- FROM relay_handoff
1996
- WHERE collab_id = ? AND workflow_id IS NULL`).get(e.collabId);
1997
- const runLastAct = runLastActRow?.lastAct ?? "";
1998
- return {
1999
- collabId: e.collabId,
2000
- label,
2001
- workflowId: wf?.workflowId ?? null,
2002
- workflowType: wf?.workflowType ?? null,
2003
- workflowStatus: wf?.status ?? null,
2004
- currentPhaseRunId,
2005
- phaseIndex,
2006
- phaseName,
2007
- currentRound: chain?.currentRound ?? null,
2008
- maxRounds: chain?.maxRounds ?? null,
2009
- chainStatus: chain?.status ?? null,
2010
- turn: {
2011
- owner: turn?.owner ?? "none",
2012
- waiting: turn?.waiting ?? null,
2013
- handoffState: turn?.handoffState ?? "idle"
2014
- },
2015
- sessions,
2016
- workflowCreatedAt: wf?.createdAt ?? null,
2017
- specPath: wf ? displayArtifactPath(wf.specPath, collab2?.workspaceRoot ?? "") : null,
2018
- lastActivityAt: runLastAct
2019
- };
2020
1961
  }
1962
+ const chain = chainId ? db.prepare(`SELECT status, current_round AS currentRound, max_rounds AS maxRounds
1963
+ FROM relay_chains WHERE chain_id = ?`).get(chainId) : void 0;
1964
+ const turn = db.prepare(`SELECT turn_owner AS owner, waiting_agent AS waiting, handoff_state AS handoffState
1965
+ FROM relay_turn_state WHERE collab_id = ?`).get(collabId2);
1966
+ const sessions = db.prepare(`SELECT agentType, healthState FROM (
1967
+ SELECT s.agent_type AS agentType,
1968
+ s.health_state AS healthState,
1969
+ ROW_NUMBER() OVER (
1970
+ PARTITION BY s.agent_type
1971
+ ORDER BY CASE WHEN sb.active_session_id = s.session_id
1972
+ THEN 0 ELSE 1 END ASC,
1973
+ s.registered_at DESC,
1974
+ s.rowid DESC
1975
+ ) AS rn
1976
+ FROM session s
1977
+ LEFT JOIN session_binding sb
1978
+ ON sb.collab_id = s.collab_id
1979
+ AND sb.agent_type = s.agent_type
1980
+ WHERE s.collab_id = ?
1981
+ ) ranked
1982
+ WHERE rn = 1
1983
+ ORDER BY agentType ASC`).all(collabId2);
1984
+ const label = wf?.name && wf.name.trim() || collab2?.displayName && collab2.displayName.trim() || (collab2?.workspaceRoot ? basename2(collab2.workspaceRoot) : "") || collabId2.slice(0, 12);
1985
+ const runLastActRow = wf ? db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
1986
+ FROM relay_handoff
1987
+ WHERE collab_id = ? AND workflow_id = ?`).get(collabId2, wf.workflowId) : db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
1988
+ FROM relay_handoff
1989
+ WHERE collab_id = ? AND workflow_id IS NULL`).get(collabId2);
1990
+ const runLastAct = runLastActRow?.lastAct ?? "";
1991
+ return {
1992
+ collabId: collabId2,
1993
+ label,
1994
+ workspaceRoot: collab2?.workspaceRoot ?? "",
1995
+ workflowId: wf?.workflowId ?? null,
1996
+ workflowType: wf?.workflowType ?? null,
1997
+ workflowStatus: wf?.status ?? null,
1998
+ currentPhaseRunId,
1999
+ phaseIndex,
2000
+ phaseName,
2001
+ currentRound: chain?.currentRound ?? null,
2002
+ maxRounds: chain?.maxRounds ?? null,
2003
+ chainStatus: chain?.status ?? null,
2004
+ turn: {
2005
+ owner: turn?.owner ?? "none",
2006
+ waiting: turn?.waiting ?? null,
2007
+ handoffState: turn?.handoffState ?? "idle"
2008
+ },
2009
+ sessions,
2010
+ workflowCreatedAt: wf?.createdAt ?? null,
2011
+ specPath: wf ? displayArtifactPath(wf.specPath, collab2?.workspaceRoot ?? "") : null,
2012
+ lastActivityAt: runLastAct
2013
+ };
2014
+ }
2015
+ function buildCollabSummary(db, collabId2) {
2016
+ const wf = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
2017
+ name, status, current_phase_index AS currentPhaseIndex,
2018
+ created_at AS createdAt, spec_path AS specPath
2019
+ FROM workflows WHERE collab_id = ?
2020
+ ORDER BY (status = 'running') DESC, created_at DESC
2021
+ LIMIT 1`).get(collabId2);
2022
+ return buildWorkflowSummary(db, collabId2, wf ?? null);
2023
+ }
2024
+ function listAllWorkflowSummaries(db, input) {
2025
+ const nowMs = Date.parse(input.now ?? (/* @__PURE__ */ new Date()).toISOString());
2026
+ const base = Number.isFinite(nowMs) ? nowMs : Date.now();
2027
+ const cutoff = new Date(Math.max(0, base - input.sinceMs)).toISOString();
2028
+ const rows = db.prepare(`SELECT w.workflow_id AS workflowId, w.workflow_type AS workflowType,
2029
+ w.name AS name, w.status AS status,
2030
+ w.current_phase_index AS currentPhaseIndex,
2031
+ w.created_at AS createdAt, w.spec_path AS specPath,
2032
+ w.collab_id AS collabId
2033
+ FROM workflows w
2034
+ LEFT JOIN relay_handoff h ON h.workflow_id = w.workflow_id
2035
+ GROUP BY w.workflow_id
2036
+ HAVING w.status IN ('running','paused')
2037
+ OR MAX(h.last_activity_at) >= ?
2038
+ OR (MAX(h.last_activity_at) IS NULL AND w.created_at >= ?)
2039
+ ORDER BY w.created_at DESC, w.rowid DESC`).all(cutoff, cutoff);
2040
+ return rows.map((r) => buildWorkflowSummary(db, r.collabId, r));
2021
2041
  }
2022
2042
  function listWorkflowsForCollab(db, collabId2) {
2023
2043
  const rows = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
@@ -4326,6 +4346,12 @@ function createControlService(db, events) {
4326
4346
  ...now !== void 0 ? { now } : {}
4327
4347
  });
4328
4348
  },
4349
+ listAllWorkflowSummaries(sinceMs, now) {
4350
+ return listAllWorkflowSummaries(db, {
4351
+ sinceMs,
4352
+ ...now !== void 0 ? { now } : {}
4353
+ });
4354
+ },
4329
4355
  listRunCostRows(collabId2, workflowId) {
4330
4356
  return listRunCostRows(db, { collabId: collabId2, workflowId });
4331
4357
  },
@@ -1946,7 +1946,8 @@ function listActiveCollabSummaries(db, input) {
1946
1946
  GROUP BY c.collab_id
1947
1947
  HAVING MAX(h.last_activity_at) >= ?
1948
1948
  OR EXISTS (SELECT 1 FROM workflows w
1949
- WHERE w.collab_id = c.collab_id AND w.status = 'running')`).all(cutoff);
1949
+ WHERE w.collab_id = c.collab_id
1950
+ AND w.status IN ('running','paused'))`).all(cutoff);
1950
1951
  const out = [];
1951
1952
  const seen = /* @__PURE__ */ new Set();
1952
1953
  for (const e of eligible) {
@@ -1971,86 +1972,105 @@ function listActiveCollabSummaries(db, input) {
1971
1972
  }
1972
1973
  return out;
1973
1974
  }
1975
+ function buildWorkflowSummary(db, collabId, wf) {
1976
+ const collab = db.prepare(`SELECT display_name AS displayName, workspace_root AS workspaceRoot
1977
+ FROM collab WHERE collab_id = ?`).get(collabId);
1978
+ let currentPhaseRunId = null;
1979
+ let phaseIndex = null;
1980
+ let phaseName = null;
1981
+ let chainId = null;
1982
+ if (wf) {
1983
+ const ph = db.prepare(`SELECT phase_run_id AS phaseRunId, phase_index AS phaseIndex,
1984
+ phase_name AS phaseName, chain_id AS chainId
1985
+ FROM workflow_phases WHERE workflow_id = ?
1986
+ ORDER BY (ended_at IS NULL) DESC, started_at DESC
1987
+ LIMIT 1`).get(wf.workflowId);
1988
+ if (ph) {
1989
+ currentPhaseRunId = ph.phaseRunId;
1990
+ phaseIndex = ph.phaseIndex;
1991
+ phaseName = ph.phaseName;
1992
+ chainId = ph.chainId;
1993
+ }
1994
+ }
1995
+ const chain = chainId ? db.prepare(`SELECT status, current_round AS currentRound, max_rounds AS maxRounds
1996
+ FROM relay_chains WHERE chain_id = ?`).get(chainId) : void 0;
1997
+ const turn = db.prepare(`SELECT turn_owner AS owner, waiting_agent AS waiting, handoff_state AS handoffState
1998
+ FROM relay_turn_state WHERE collab_id = ?`).get(collabId);
1999
+ const sessions = db.prepare(`SELECT agentType, healthState FROM (
2000
+ SELECT s.agent_type AS agentType,
2001
+ s.health_state AS healthState,
2002
+ ROW_NUMBER() OVER (
2003
+ PARTITION BY s.agent_type
2004
+ ORDER BY CASE WHEN sb.active_session_id = s.session_id
2005
+ THEN 0 ELSE 1 END ASC,
2006
+ s.registered_at DESC,
2007
+ s.rowid DESC
2008
+ ) AS rn
2009
+ FROM session s
2010
+ LEFT JOIN session_binding sb
2011
+ ON sb.collab_id = s.collab_id
2012
+ AND sb.agent_type = s.agent_type
2013
+ WHERE s.collab_id = ?
2014
+ ) ranked
2015
+ WHERE rn = 1
2016
+ ORDER BY agentType ASC`).all(collabId);
2017
+ const label = wf?.name && wf.name.trim() || collab?.displayName && collab.displayName.trim() || (collab?.workspaceRoot ? basename2(collab.workspaceRoot) : "") || collabId.slice(0, 12);
2018
+ const runLastActRow = wf ? db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
2019
+ FROM relay_handoff
2020
+ WHERE collab_id = ? AND workflow_id = ?`).get(collabId, wf.workflowId) : db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
2021
+ FROM relay_handoff
2022
+ WHERE collab_id = ? AND workflow_id IS NULL`).get(collabId);
2023
+ const runLastAct = runLastActRow?.lastAct ?? "";
2024
+ return {
2025
+ collabId,
2026
+ label,
2027
+ workspaceRoot: collab?.workspaceRoot ?? "",
2028
+ workflowId: wf?.workflowId ?? null,
2029
+ workflowType: wf?.workflowType ?? null,
2030
+ workflowStatus: wf?.status ?? null,
2031
+ currentPhaseRunId,
2032
+ phaseIndex,
2033
+ phaseName,
2034
+ currentRound: chain?.currentRound ?? null,
2035
+ maxRounds: chain?.maxRounds ?? null,
2036
+ chainStatus: chain?.status ?? null,
2037
+ turn: {
2038
+ owner: turn?.owner ?? "none",
2039
+ waiting: turn?.waiting ?? null,
2040
+ handoffState: turn?.handoffState ?? "idle"
2041
+ },
2042
+ sessions,
2043
+ workflowCreatedAt: wf?.createdAt ?? null,
2044
+ specPath: wf ? displayArtifactPath(wf.specPath, collab?.workspaceRoot ?? "") : null,
2045
+ lastActivityAt: runLastAct
2046
+ };
2047
+ }
1974
2048
  function buildCollabSummary(db, collabId) {
1975
- {
1976
- const e = { collabId };
1977
- const collab = db.prepare(`SELECT display_name AS displayName, workspace_root AS workspaceRoot
1978
- FROM collab WHERE collab_id = ?`).get(e.collabId);
1979
- const wf = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
1980
- name, status, current_phase_index AS currentPhaseIndex,
1981
- created_at AS createdAt, spec_path AS specPath
1982
- FROM workflows WHERE collab_id = ?
1983
- ORDER BY (status = 'running') DESC, created_at DESC
1984
- LIMIT 1`).get(e.collabId);
1985
- let currentPhaseRunId = null;
1986
- let phaseIndex = null;
1987
- let phaseName = null;
1988
- let chainId = null;
1989
- if (wf) {
1990
- const ph = db.prepare(`SELECT phase_run_id AS phaseRunId, phase_index AS phaseIndex,
1991
- phase_name AS phaseName, chain_id AS chainId
1992
- FROM workflow_phases WHERE workflow_id = ?
1993
- ORDER BY (ended_at IS NULL) DESC, started_at DESC
1994
- LIMIT 1`).get(wf.workflowId);
1995
- if (ph) {
1996
- currentPhaseRunId = ph.phaseRunId;
1997
- phaseIndex = ph.phaseIndex;
1998
- phaseName = ph.phaseName;
1999
- chainId = ph.chainId;
2000
- }
2001
- }
2002
- const chain = chainId ? db.prepare(`SELECT status, current_round AS currentRound, max_rounds AS maxRounds
2003
- FROM relay_chains WHERE chain_id = ?`).get(chainId) : void 0;
2004
- const turn = db.prepare(`SELECT turn_owner AS owner, waiting_agent AS waiting, handoff_state AS handoffState
2005
- FROM relay_turn_state WHERE collab_id = ?`).get(e.collabId);
2006
- const sessions = db.prepare(`SELECT agentType, healthState FROM (
2007
- SELECT s.agent_type AS agentType,
2008
- s.health_state AS healthState,
2009
- ROW_NUMBER() OVER (
2010
- PARTITION BY s.agent_type
2011
- ORDER BY CASE WHEN sb.active_session_id = s.session_id
2012
- THEN 0 ELSE 1 END ASC,
2013
- s.registered_at DESC,
2014
- s.rowid DESC
2015
- ) AS rn
2016
- FROM session s
2017
- LEFT JOIN session_binding sb
2018
- ON sb.collab_id = s.collab_id
2019
- AND sb.agent_type = s.agent_type
2020
- WHERE s.collab_id = ?
2021
- ) ranked
2022
- WHERE rn = 1
2023
- ORDER BY agentType ASC`).all(e.collabId);
2024
- const label = wf?.name && wf.name.trim() || collab?.displayName && collab.displayName.trim() || (collab?.workspaceRoot ? basename2(collab.workspaceRoot) : "") || e.collabId.slice(0, 12);
2025
- const runLastActRow = wf ? db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
2026
- FROM relay_handoff
2027
- WHERE collab_id = ? AND workflow_id = ?`).get(e.collabId, wf.workflowId) : db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
2028
- FROM relay_handoff
2029
- WHERE collab_id = ? AND workflow_id IS NULL`).get(e.collabId);
2030
- const runLastAct = runLastActRow?.lastAct ?? "";
2031
- return {
2032
- collabId: e.collabId,
2033
- label,
2034
- workflowId: wf?.workflowId ?? null,
2035
- workflowType: wf?.workflowType ?? null,
2036
- workflowStatus: wf?.status ?? null,
2037
- currentPhaseRunId,
2038
- phaseIndex,
2039
- phaseName,
2040
- currentRound: chain?.currentRound ?? null,
2041
- maxRounds: chain?.maxRounds ?? null,
2042
- chainStatus: chain?.status ?? null,
2043
- turn: {
2044
- owner: turn?.owner ?? "none",
2045
- waiting: turn?.waiting ?? null,
2046
- handoffState: turn?.handoffState ?? "idle"
2047
- },
2048
- sessions,
2049
- workflowCreatedAt: wf?.createdAt ?? null,
2050
- specPath: wf ? displayArtifactPath(wf.specPath, collab?.workspaceRoot ?? "") : null,
2051
- lastActivityAt: runLastAct
2052
- };
2053
- }
2049
+ const wf = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
2050
+ name, status, current_phase_index AS currentPhaseIndex,
2051
+ created_at AS createdAt, spec_path AS specPath
2052
+ FROM workflows WHERE collab_id = ?
2053
+ ORDER BY (status = 'running') DESC, created_at DESC
2054
+ LIMIT 1`).get(collabId);
2055
+ return buildWorkflowSummary(db, collabId, wf ?? null);
2056
+ }
2057
+ function listAllWorkflowSummaries(db, input) {
2058
+ const nowMs = Date.parse(input.now ?? (/* @__PURE__ */ new Date()).toISOString());
2059
+ const base = Number.isFinite(nowMs) ? nowMs : Date.now();
2060
+ const cutoff = new Date(Math.max(0, base - input.sinceMs)).toISOString();
2061
+ const rows = db.prepare(`SELECT w.workflow_id AS workflowId, w.workflow_type AS workflowType,
2062
+ w.name AS name, w.status AS status,
2063
+ w.current_phase_index AS currentPhaseIndex,
2064
+ w.created_at AS createdAt, w.spec_path AS specPath,
2065
+ w.collab_id AS collabId
2066
+ FROM workflows w
2067
+ LEFT JOIN relay_handoff h ON h.workflow_id = w.workflow_id
2068
+ GROUP BY w.workflow_id
2069
+ HAVING w.status IN ('running','paused')
2070
+ OR MAX(h.last_activity_at) >= ?
2071
+ OR (MAX(h.last_activity_at) IS NULL AND w.created_at >= ?)
2072
+ ORDER BY w.created_at DESC, w.rowid DESC`).all(cutoff, cutoff);
2073
+ return rows.map((r) => buildWorkflowSummary(db, r.collabId, r));
2054
2074
  }
2055
2075
  function listWorkflowsForCollab(db, collabId) {
2056
2076
  const rows = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
@@ -4346,6 +4366,12 @@ function createControlService(db, events) {
4346
4366
  ...now !== void 0 ? { now } : {}
4347
4367
  });
4348
4368
  },
4369
+ listAllWorkflowSummaries(sinceMs, now) {
4370
+ return listAllWorkflowSummaries(db, {
4371
+ sinceMs,
4372
+ ...now !== void 0 ? { now } : {}
4373
+ });
4374
+ },
4349
4375
  listRunCostRows(collabId, workflowId) {
4350
4376
  return listRunCostRows(db, { collabId, workflowId });
4351
4377
  },
@@ -1916,7 +1916,8 @@ function listActiveCollabSummaries(db, input) {
1916
1916
  GROUP BY c.collab_id
1917
1917
  HAVING MAX(h.last_activity_at) >= ?
1918
1918
  OR EXISTS (SELECT 1 FROM workflows w
1919
- WHERE w.collab_id = c.collab_id AND w.status = 'running')`).all(cutoff);
1919
+ WHERE w.collab_id = c.collab_id
1920
+ AND w.status IN ('running','paused'))`).all(cutoff);
1920
1921
  const out = [];
1921
1922
  const seen = /* @__PURE__ */ new Set();
1922
1923
  for (const e of eligible) {
@@ -1941,86 +1942,105 @@ function listActiveCollabSummaries(db, input) {
1941
1942
  }
1942
1943
  return out;
1943
1944
  }
1944
- function buildCollabSummary(db, collabId2) {
1945
- {
1946
- const e = { collabId: collabId2 };
1947
- const collab = db.prepare(`SELECT display_name AS displayName, workspace_root AS workspaceRoot
1948
- FROM collab WHERE collab_id = ?`).get(e.collabId);
1949
- const wf = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
1950
- name, status, current_phase_index AS currentPhaseIndex,
1951
- created_at AS createdAt, spec_path AS specPath
1952
- FROM workflows WHERE collab_id = ?
1953
- ORDER BY (status = 'running') DESC, created_at DESC
1954
- LIMIT 1`).get(e.collabId);
1955
- let currentPhaseRunId = null;
1956
- let phaseIndex = null;
1957
- let phaseName = null;
1958
- let chainId = null;
1959
- if (wf) {
1960
- const ph = db.prepare(`SELECT phase_run_id AS phaseRunId, phase_index AS phaseIndex,
1961
- phase_name AS phaseName, chain_id AS chainId
1962
- FROM workflow_phases WHERE workflow_id = ?
1963
- ORDER BY (ended_at IS NULL) DESC, started_at DESC
1964
- LIMIT 1`).get(wf.workflowId);
1965
- if (ph) {
1966
- currentPhaseRunId = ph.phaseRunId;
1967
- phaseIndex = ph.phaseIndex;
1968
- phaseName = ph.phaseName;
1969
- chainId = ph.chainId;
1970
- }
1945
+ function buildWorkflowSummary(db, collabId2, wf) {
1946
+ const collab = db.prepare(`SELECT display_name AS displayName, workspace_root AS workspaceRoot
1947
+ FROM collab WHERE collab_id = ?`).get(collabId2);
1948
+ let currentPhaseRunId = null;
1949
+ let phaseIndex = null;
1950
+ let phaseName = null;
1951
+ let chainId = null;
1952
+ if (wf) {
1953
+ const ph = db.prepare(`SELECT phase_run_id AS phaseRunId, phase_index AS phaseIndex,
1954
+ phase_name AS phaseName, chain_id AS chainId
1955
+ FROM workflow_phases WHERE workflow_id = ?
1956
+ ORDER BY (ended_at IS NULL) DESC, started_at DESC
1957
+ LIMIT 1`).get(wf.workflowId);
1958
+ if (ph) {
1959
+ currentPhaseRunId = ph.phaseRunId;
1960
+ phaseIndex = ph.phaseIndex;
1961
+ phaseName = ph.phaseName;
1962
+ chainId = ph.chainId;
1971
1963
  }
1972
- const chain = chainId ? db.prepare(`SELECT status, current_round AS currentRound, max_rounds AS maxRounds
1973
- FROM relay_chains WHERE chain_id = ?`).get(chainId) : void 0;
1974
- const turn = db.prepare(`SELECT turn_owner AS owner, waiting_agent AS waiting, handoff_state AS handoffState
1975
- FROM relay_turn_state WHERE collab_id = ?`).get(e.collabId);
1976
- const sessions = db.prepare(`SELECT agentType, healthState FROM (
1977
- SELECT s.agent_type AS agentType,
1978
- s.health_state AS healthState,
1979
- ROW_NUMBER() OVER (
1980
- PARTITION BY s.agent_type
1981
- ORDER BY CASE WHEN sb.active_session_id = s.session_id
1982
- THEN 0 ELSE 1 END ASC,
1983
- s.registered_at DESC,
1984
- s.rowid DESC
1985
- ) AS rn
1986
- FROM session s
1987
- LEFT JOIN session_binding sb
1988
- ON sb.collab_id = s.collab_id
1989
- AND sb.agent_type = s.agent_type
1990
- WHERE s.collab_id = ?
1991
- ) ranked
1992
- WHERE rn = 1
1993
- ORDER BY agentType ASC`).all(e.collabId);
1994
- const label = wf?.name && wf.name.trim() || collab?.displayName && collab.displayName.trim() || (collab?.workspaceRoot ? basename2(collab.workspaceRoot) : "") || e.collabId.slice(0, 12);
1995
- const runLastActRow = wf ? db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
1996
- FROM relay_handoff
1997
- WHERE collab_id = ? AND workflow_id = ?`).get(e.collabId, wf.workflowId) : db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
1998
- FROM relay_handoff
1999
- WHERE collab_id = ? AND workflow_id IS NULL`).get(e.collabId);
2000
- const runLastAct = runLastActRow?.lastAct ?? "";
2001
- return {
2002
- collabId: e.collabId,
2003
- label,
2004
- workflowId: wf?.workflowId ?? null,
2005
- workflowType: wf?.workflowType ?? null,
2006
- workflowStatus: wf?.status ?? null,
2007
- currentPhaseRunId,
2008
- phaseIndex,
2009
- phaseName,
2010
- currentRound: chain?.currentRound ?? null,
2011
- maxRounds: chain?.maxRounds ?? null,
2012
- chainStatus: chain?.status ?? null,
2013
- turn: {
2014
- owner: turn?.owner ?? "none",
2015
- waiting: turn?.waiting ?? null,
2016
- handoffState: turn?.handoffState ?? "idle"
2017
- },
2018
- sessions,
2019
- workflowCreatedAt: wf?.createdAt ?? null,
2020
- specPath: wf ? displayArtifactPath(wf.specPath, collab?.workspaceRoot ?? "") : null,
2021
- lastActivityAt: runLastAct
2022
- };
2023
1964
  }
1965
+ const chain = chainId ? db.prepare(`SELECT status, current_round AS currentRound, max_rounds AS maxRounds
1966
+ FROM relay_chains WHERE chain_id = ?`).get(chainId) : void 0;
1967
+ const turn = db.prepare(`SELECT turn_owner AS owner, waiting_agent AS waiting, handoff_state AS handoffState
1968
+ FROM relay_turn_state WHERE collab_id = ?`).get(collabId2);
1969
+ const sessions = db.prepare(`SELECT agentType, healthState FROM (
1970
+ SELECT s.agent_type AS agentType,
1971
+ s.health_state AS healthState,
1972
+ ROW_NUMBER() OVER (
1973
+ PARTITION BY s.agent_type
1974
+ ORDER BY CASE WHEN sb.active_session_id = s.session_id
1975
+ THEN 0 ELSE 1 END ASC,
1976
+ s.registered_at DESC,
1977
+ s.rowid DESC
1978
+ ) AS rn
1979
+ FROM session s
1980
+ LEFT JOIN session_binding sb
1981
+ ON sb.collab_id = s.collab_id
1982
+ AND sb.agent_type = s.agent_type
1983
+ WHERE s.collab_id = ?
1984
+ ) ranked
1985
+ WHERE rn = 1
1986
+ ORDER BY agentType ASC`).all(collabId2);
1987
+ const label = wf?.name && wf.name.trim() || collab?.displayName && collab.displayName.trim() || (collab?.workspaceRoot ? basename2(collab.workspaceRoot) : "") || collabId2.slice(0, 12);
1988
+ const runLastActRow = wf ? db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
1989
+ FROM relay_handoff
1990
+ WHERE collab_id = ? AND workflow_id = ?`).get(collabId2, wf.workflowId) : db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
1991
+ FROM relay_handoff
1992
+ WHERE collab_id = ? AND workflow_id IS NULL`).get(collabId2);
1993
+ const runLastAct = runLastActRow?.lastAct ?? "";
1994
+ return {
1995
+ collabId: collabId2,
1996
+ label,
1997
+ workspaceRoot: collab?.workspaceRoot ?? "",
1998
+ workflowId: wf?.workflowId ?? null,
1999
+ workflowType: wf?.workflowType ?? null,
2000
+ workflowStatus: wf?.status ?? null,
2001
+ currentPhaseRunId,
2002
+ phaseIndex,
2003
+ phaseName,
2004
+ currentRound: chain?.currentRound ?? null,
2005
+ maxRounds: chain?.maxRounds ?? null,
2006
+ chainStatus: chain?.status ?? null,
2007
+ turn: {
2008
+ owner: turn?.owner ?? "none",
2009
+ waiting: turn?.waiting ?? null,
2010
+ handoffState: turn?.handoffState ?? "idle"
2011
+ },
2012
+ sessions,
2013
+ workflowCreatedAt: wf?.createdAt ?? null,
2014
+ specPath: wf ? displayArtifactPath(wf.specPath, collab?.workspaceRoot ?? "") : null,
2015
+ lastActivityAt: runLastAct
2016
+ };
2017
+ }
2018
+ function buildCollabSummary(db, collabId2) {
2019
+ const wf = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
2020
+ name, status, current_phase_index AS currentPhaseIndex,
2021
+ created_at AS createdAt, spec_path AS specPath
2022
+ FROM workflows WHERE collab_id = ?
2023
+ ORDER BY (status = 'running') DESC, created_at DESC
2024
+ LIMIT 1`).get(collabId2);
2025
+ return buildWorkflowSummary(db, collabId2, wf ?? null);
2026
+ }
2027
+ function listAllWorkflowSummaries(db, input) {
2028
+ const nowMs = Date.parse(input.now ?? (/* @__PURE__ */ new Date()).toISOString());
2029
+ const base = Number.isFinite(nowMs) ? nowMs : Date.now();
2030
+ const cutoff = new Date(Math.max(0, base - input.sinceMs)).toISOString();
2031
+ const rows = db.prepare(`SELECT w.workflow_id AS workflowId, w.workflow_type AS workflowType,
2032
+ w.name AS name, w.status AS status,
2033
+ w.current_phase_index AS currentPhaseIndex,
2034
+ w.created_at AS createdAt, w.spec_path AS specPath,
2035
+ w.collab_id AS collabId
2036
+ FROM workflows w
2037
+ LEFT JOIN relay_handoff h ON h.workflow_id = w.workflow_id
2038
+ GROUP BY w.workflow_id
2039
+ HAVING w.status IN ('running','paused')
2040
+ OR MAX(h.last_activity_at) >= ?
2041
+ OR (MAX(h.last_activity_at) IS NULL AND w.created_at >= ?)
2042
+ ORDER BY w.created_at DESC, w.rowid DESC`).all(cutoff, cutoff);
2043
+ return rows.map((r) => buildWorkflowSummary(db, r.collabId, r));
2024
2044
  }
2025
2045
  function listWorkflowsForCollab(db, collabId2) {
2026
2046
  const rows = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
@@ -4316,6 +4336,12 @@ function createControlService(db, events) {
4316
4336
  ...now !== void 0 ? { now } : {}
4317
4337
  });
4318
4338
  },
4339
+ listAllWorkflowSummaries(sinceMs, now) {
4340
+ return listAllWorkflowSummaries(db, {
4341
+ sinceMs,
4342
+ ...now !== void 0 ? { now } : {}
4343
+ });
4344
+ },
4319
4345
  listRunCostRows(collabId2, workflowId) {
4320
4346
  return listRunCostRows(db, { collabId: collabId2, workflowId });
4321
4347
  },
@@ -6091,6 +6117,9 @@ function computeLiveness(snap) {
6091
6117
  let why = null;
6092
6118
  let stuck = false;
6093
6119
  let liveOverride = null;
6120
+ if (terminal === "paused") {
6121
+ return { stuck: false, why: null, liveText: "paused" };
6122
+ }
6094
6123
  if (terminal === "done") {
6095
6124
  return { stuck: false, why: null, liveText: "done" };
6096
6125
  } else if (terminal === "halted" || terminal === "canceled") {