ai-whisper 0.8.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
@@ -105,6 +105,13 @@ The first `mount` creates the collab and starts the broker daemon for the worksp
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?
@@ -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,87 +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
- workspaceRoot: collab2?.workspaceRoot ?? "",
2002
- workflowId: wf?.workflowId ?? null,
2003
- workflowType: wf?.workflowType ?? null,
2004
- workflowStatus: wf?.status ?? null,
2005
- currentPhaseRunId,
2006
- phaseIndex,
2007
- phaseName,
2008
- currentRound: chain?.currentRound ?? null,
2009
- maxRounds: chain?.maxRounds ?? null,
2010
- chainStatus: chain?.status ?? null,
2011
- turn: {
2012
- owner: turn?.owner ?? "none",
2013
- waiting: turn?.waiting ?? null,
2014
- handoffState: turn?.handoffState ?? "idle"
2015
- },
2016
- sessions,
2017
- workflowCreatedAt: wf?.createdAt ?? null,
2018
- specPath: wf ? displayArtifactPath(wf.specPath, collab2?.workspaceRoot ?? "") : null,
2019
- lastActivityAt: runLastAct
2020
- };
2021
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));
2022
2041
  }
2023
2042
  function listWorkflowsForCollab(db, collabId2) {
2024
2043
  const rows = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
@@ -4327,6 +4346,12 @@ function createControlService(db, events) {
4327
4346
  ...now !== void 0 ? { now } : {}
4328
4347
  });
4329
4348
  },
4349
+ listAllWorkflowSummaries(sinceMs, now) {
4350
+ return listAllWorkflowSummaries(db, {
4351
+ sinceMs,
4352
+ ...now !== void 0 ? { now } : {}
4353
+ });
4354
+ },
4330
4355
  listRunCostRows(collabId2, workflowId) {
4331
4356
  return listRunCostRows(db, { collabId: collabId2, workflowId });
4332
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,87 +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
- workspaceRoot: collab?.workspaceRoot ?? "",
2035
- workflowId: wf?.workflowId ?? null,
2036
- workflowType: wf?.workflowType ?? null,
2037
- workflowStatus: wf?.status ?? null,
2038
- currentPhaseRunId,
2039
- phaseIndex,
2040
- phaseName,
2041
- currentRound: chain?.currentRound ?? null,
2042
- maxRounds: chain?.maxRounds ?? null,
2043
- chainStatus: chain?.status ?? null,
2044
- turn: {
2045
- owner: turn?.owner ?? "none",
2046
- waiting: turn?.waiting ?? null,
2047
- handoffState: turn?.handoffState ?? "idle"
2048
- },
2049
- sessions,
2050
- workflowCreatedAt: wf?.createdAt ?? null,
2051
- specPath: wf ? displayArtifactPath(wf.specPath, collab?.workspaceRoot ?? "") : null,
2052
- lastActivityAt: runLastAct
2053
- };
2054
- }
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));
2055
2074
  }
2056
2075
  function listWorkflowsForCollab(db, collabId) {
2057
2076
  const rows = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
@@ -4347,6 +4366,12 @@ function createControlService(db, events) {
4347
4366
  ...now !== void 0 ? { now } : {}
4348
4367
  });
4349
4368
  },
4369
+ listAllWorkflowSummaries(sinceMs, now) {
4370
+ return listAllWorkflowSummaries(db, {
4371
+ sinceMs,
4372
+ ...now !== void 0 ? { now } : {}
4373
+ });
4374
+ },
4350
4375
  listRunCostRows(collabId, workflowId) {
4351
4376
  return listRunCostRows(db, { collabId, workflowId });
4352
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,87 +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
- workspaceRoot: collab?.workspaceRoot ?? "",
2005
- workflowId: wf?.workflowId ?? null,
2006
- workflowType: wf?.workflowType ?? null,
2007
- workflowStatus: wf?.status ?? null,
2008
- currentPhaseRunId,
2009
- phaseIndex,
2010
- phaseName,
2011
- currentRound: chain?.currentRound ?? null,
2012
- maxRounds: chain?.maxRounds ?? null,
2013
- chainStatus: chain?.status ?? null,
2014
- turn: {
2015
- owner: turn?.owner ?? "none",
2016
- waiting: turn?.waiting ?? null,
2017
- handoffState: turn?.handoffState ?? "idle"
2018
- },
2019
- sessions,
2020
- workflowCreatedAt: wf?.createdAt ?? null,
2021
- specPath: wf ? displayArtifactPath(wf.specPath, collab?.workspaceRoot ?? "") : null,
2022
- lastActivityAt: runLastAct
2023
- };
2024
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));
2025
2044
  }
2026
2045
  function listWorkflowsForCollab(db, collabId2) {
2027
2046
  const rows = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
@@ -4317,6 +4336,12 @@ function createControlService(db, events) {
4317
4336
  ...now !== void 0 ? { now } : {}
4318
4337
  });
4319
4338
  },
4339
+ listAllWorkflowSummaries(sinceMs, now) {
4340
+ return listAllWorkflowSummaries(db, {
4341
+ sinceMs,
4342
+ ...now !== void 0 ? { now } : {}
4343
+ });
4344
+ },
4320
4345
  listRunCostRows(collabId2, workflowId) {
4321
4346
  return listRunCostRows(db, { collabId: collabId2, workflowId });
4322
4347
  },
@@ -6092,6 +6117,9 @@ function computeLiveness(snap) {
6092
6117
  let why = null;
6093
6118
  let stuck = false;
6094
6119
  let liveOverride = null;
6120
+ if (terminal === "paused") {
6121
+ return { stuck: false, why: null, liveText: "paused" };
6122
+ }
6095
6123
  if (terminal === "done") {
6096
6124
  return { stuck: false, why: null, liveText: "done" };
6097
6125
  } else if (terminal === "halted" || terminal === "canceled") {
@@ -2305,7 +2305,8 @@ function listActiveCollabSummaries(db, input) {
2305
2305
  GROUP BY c.collab_id
2306
2306
  HAVING MAX(h.last_activity_at) >= ?
2307
2307
  OR EXISTS (SELECT 1 FROM workflows w
2308
- WHERE w.collab_id = c.collab_id AND w.status = 'running')`).all(cutoff);
2308
+ WHERE w.collab_id = c.collab_id
2309
+ AND w.status IN ('running','paused'))`).all(cutoff);
2309
2310
  const out = [];
2310
2311
  const seen = /* @__PURE__ */ new Set();
2311
2312
  for (const e of eligible) {
@@ -2330,87 +2331,105 @@ function listActiveCollabSummaries(db, input) {
2330
2331
  }
2331
2332
  return out;
2332
2333
  }
2334
+ function buildWorkflowSummary(db, collabId, wf) {
2335
+ const collab = db.prepare(`SELECT display_name AS displayName, workspace_root AS workspaceRoot
2336
+ FROM collab WHERE collab_id = ?`).get(collabId);
2337
+ let currentPhaseRunId = null;
2338
+ let phaseIndex = null;
2339
+ let phaseName = null;
2340
+ let chainId = null;
2341
+ if (wf) {
2342
+ const ph = db.prepare(`SELECT phase_run_id AS phaseRunId, phase_index AS phaseIndex,
2343
+ phase_name AS phaseName, chain_id AS chainId
2344
+ FROM workflow_phases WHERE workflow_id = ?
2345
+ ORDER BY (ended_at IS NULL) DESC, started_at DESC
2346
+ LIMIT 1`).get(wf.workflowId);
2347
+ if (ph) {
2348
+ currentPhaseRunId = ph.phaseRunId;
2349
+ phaseIndex = ph.phaseIndex;
2350
+ phaseName = ph.phaseName;
2351
+ chainId = ph.chainId;
2352
+ }
2353
+ }
2354
+ const chain = chainId ? db.prepare(`SELECT status, current_round AS currentRound, max_rounds AS maxRounds
2355
+ FROM relay_chains WHERE chain_id = ?`).get(chainId) : void 0;
2356
+ const turn = db.prepare(`SELECT turn_owner AS owner, waiting_agent AS waiting, handoff_state AS handoffState
2357
+ FROM relay_turn_state WHERE collab_id = ?`).get(collabId);
2358
+ const sessions = db.prepare(`SELECT agentType, healthState FROM (
2359
+ SELECT s.agent_type AS agentType,
2360
+ s.health_state AS healthState,
2361
+ ROW_NUMBER() OVER (
2362
+ PARTITION BY s.agent_type
2363
+ ORDER BY CASE WHEN sb.active_session_id = s.session_id
2364
+ THEN 0 ELSE 1 END ASC,
2365
+ s.registered_at DESC,
2366
+ s.rowid DESC
2367
+ ) AS rn
2368
+ FROM session s
2369
+ LEFT JOIN session_binding sb
2370
+ ON sb.collab_id = s.collab_id
2371
+ AND sb.agent_type = s.agent_type
2372
+ WHERE s.collab_id = ?
2373
+ ) ranked
2374
+ WHERE rn = 1
2375
+ ORDER BY agentType ASC`).all(collabId);
2376
+ const label = wf?.name && wf.name.trim() || collab?.displayName && collab.displayName.trim() || (collab?.workspaceRoot ? basename2(collab.workspaceRoot) : "") || collabId.slice(0, 12);
2377
+ const runLastActRow = wf ? db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
2378
+ FROM relay_handoff
2379
+ WHERE collab_id = ? AND workflow_id = ?`).get(collabId, wf.workflowId) : db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
2380
+ FROM relay_handoff
2381
+ WHERE collab_id = ? AND workflow_id IS NULL`).get(collabId);
2382
+ const runLastAct = runLastActRow?.lastAct ?? "";
2383
+ return {
2384
+ collabId,
2385
+ label,
2386
+ workspaceRoot: collab?.workspaceRoot ?? "",
2387
+ workflowId: wf?.workflowId ?? null,
2388
+ workflowType: wf?.workflowType ?? null,
2389
+ workflowStatus: wf?.status ?? null,
2390
+ currentPhaseRunId,
2391
+ phaseIndex,
2392
+ phaseName,
2393
+ currentRound: chain?.currentRound ?? null,
2394
+ maxRounds: chain?.maxRounds ?? null,
2395
+ chainStatus: chain?.status ?? null,
2396
+ turn: {
2397
+ owner: turn?.owner ?? "none",
2398
+ waiting: turn?.waiting ?? null,
2399
+ handoffState: turn?.handoffState ?? "idle"
2400
+ },
2401
+ sessions,
2402
+ workflowCreatedAt: wf?.createdAt ?? null,
2403
+ specPath: wf ? displayArtifactPath(wf.specPath, collab?.workspaceRoot ?? "") : null,
2404
+ lastActivityAt: runLastAct
2405
+ };
2406
+ }
2333
2407
  function buildCollabSummary(db, collabId) {
2334
- {
2335
- const e = { collabId };
2336
- const collab = db.prepare(`SELECT display_name AS displayName, workspace_root AS workspaceRoot
2337
- FROM collab WHERE collab_id = ?`).get(e.collabId);
2338
- const wf = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
2339
- name, status, current_phase_index AS currentPhaseIndex,
2340
- created_at AS createdAt, spec_path AS specPath
2341
- FROM workflows WHERE collab_id = ?
2342
- ORDER BY (status = 'running') DESC, created_at DESC
2343
- LIMIT 1`).get(e.collabId);
2344
- let currentPhaseRunId = null;
2345
- let phaseIndex = null;
2346
- let phaseName = null;
2347
- let chainId = null;
2348
- if (wf) {
2349
- const ph = db.prepare(`SELECT phase_run_id AS phaseRunId, phase_index AS phaseIndex,
2350
- phase_name AS phaseName, chain_id AS chainId
2351
- FROM workflow_phases WHERE workflow_id = ?
2352
- ORDER BY (ended_at IS NULL) DESC, started_at DESC
2353
- LIMIT 1`).get(wf.workflowId);
2354
- if (ph) {
2355
- currentPhaseRunId = ph.phaseRunId;
2356
- phaseIndex = ph.phaseIndex;
2357
- phaseName = ph.phaseName;
2358
- chainId = ph.chainId;
2359
- }
2360
- }
2361
- const chain = chainId ? db.prepare(`SELECT status, current_round AS currentRound, max_rounds AS maxRounds
2362
- FROM relay_chains WHERE chain_id = ?`).get(chainId) : void 0;
2363
- const turn = db.prepare(`SELECT turn_owner AS owner, waiting_agent AS waiting, handoff_state AS handoffState
2364
- FROM relay_turn_state WHERE collab_id = ?`).get(e.collabId);
2365
- const sessions = db.prepare(`SELECT agentType, healthState FROM (
2366
- SELECT s.agent_type AS agentType,
2367
- s.health_state AS healthState,
2368
- ROW_NUMBER() OVER (
2369
- PARTITION BY s.agent_type
2370
- ORDER BY CASE WHEN sb.active_session_id = s.session_id
2371
- THEN 0 ELSE 1 END ASC,
2372
- s.registered_at DESC,
2373
- s.rowid DESC
2374
- ) AS rn
2375
- FROM session s
2376
- LEFT JOIN session_binding sb
2377
- ON sb.collab_id = s.collab_id
2378
- AND sb.agent_type = s.agent_type
2379
- WHERE s.collab_id = ?
2380
- ) ranked
2381
- WHERE rn = 1
2382
- ORDER BY agentType ASC`).all(e.collabId);
2383
- const label = wf?.name && wf.name.trim() || collab?.displayName && collab.displayName.trim() || (collab?.workspaceRoot ? basename2(collab.workspaceRoot) : "") || e.collabId.slice(0, 12);
2384
- const runLastActRow = wf ? db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
2385
- FROM relay_handoff
2386
- WHERE collab_id = ? AND workflow_id = ?`).get(e.collabId, wf.workflowId) : db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
2387
- FROM relay_handoff
2388
- WHERE collab_id = ? AND workflow_id IS NULL`).get(e.collabId);
2389
- const runLastAct = runLastActRow?.lastAct ?? "";
2390
- return {
2391
- collabId: e.collabId,
2392
- label,
2393
- workspaceRoot: collab?.workspaceRoot ?? "",
2394
- workflowId: wf?.workflowId ?? null,
2395
- workflowType: wf?.workflowType ?? null,
2396
- workflowStatus: wf?.status ?? null,
2397
- currentPhaseRunId,
2398
- phaseIndex,
2399
- phaseName,
2400
- currentRound: chain?.currentRound ?? null,
2401
- maxRounds: chain?.maxRounds ?? null,
2402
- chainStatus: chain?.status ?? null,
2403
- turn: {
2404
- owner: turn?.owner ?? "none",
2405
- waiting: turn?.waiting ?? null,
2406
- handoffState: turn?.handoffState ?? "idle"
2407
- },
2408
- sessions,
2409
- workflowCreatedAt: wf?.createdAt ?? null,
2410
- specPath: wf ? displayArtifactPath(wf.specPath, collab?.workspaceRoot ?? "") : null,
2411
- lastActivityAt: runLastAct
2412
- };
2413
- }
2408
+ const wf = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
2409
+ name, status, current_phase_index AS currentPhaseIndex,
2410
+ created_at AS createdAt, spec_path AS specPath
2411
+ FROM workflows WHERE collab_id = ?
2412
+ ORDER BY (status = 'running') DESC, created_at DESC
2413
+ LIMIT 1`).get(collabId);
2414
+ return buildWorkflowSummary(db, collabId, wf ?? null);
2415
+ }
2416
+ function listAllWorkflowSummaries(db, input) {
2417
+ const nowMs = Date.parse(input.now ?? (/* @__PURE__ */ new Date()).toISOString());
2418
+ const base = Number.isFinite(nowMs) ? nowMs : Date.now();
2419
+ const cutoff = new Date(Math.max(0, base - input.sinceMs)).toISOString();
2420
+ const rows = db.prepare(`SELECT w.workflow_id AS workflowId, w.workflow_type AS workflowType,
2421
+ w.name AS name, w.status AS status,
2422
+ w.current_phase_index AS currentPhaseIndex,
2423
+ w.created_at AS createdAt, w.spec_path AS specPath,
2424
+ w.collab_id AS collabId
2425
+ FROM workflows w
2426
+ LEFT JOIN relay_handoff h ON h.workflow_id = w.workflow_id
2427
+ GROUP BY w.workflow_id
2428
+ HAVING w.status IN ('running','paused')
2429
+ OR MAX(h.last_activity_at) >= ?
2430
+ OR (MAX(h.last_activity_at) IS NULL AND w.created_at >= ?)
2431
+ ORDER BY w.created_at DESC, w.rowid DESC`).all(cutoff, cutoff);
2432
+ return rows.map((r) => buildWorkflowSummary(db, r.collabId, r));
2414
2433
  }
2415
2434
  function listWorkflowsForCollab(db, collabId) {
2416
2435
  const rows = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
@@ -4748,6 +4767,12 @@ function createControlService(db, events) {
4748
4767
  ...now !== void 0 ? { now } : {}
4749
4768
  });
4750
4769
  },
4770
+ listAllWorkflowSummaries(sinceMs, now) {
4771
+ return listAllWorkflowSummaries(db, {
4772
+ sinceMs,
4773
+ ...now !== void 0 ? { now } : {}
4774
+ });
4775
+ },
4751
4776
  listRunCostRows(collabId, workflowId) {
4752
4777
  return listRunCostRows(db, { collabId, workflowId });
4753
4778
  },
@@ -6668,6 +6693,9 @@ function computeLiveness(snap) {
6668
6693
  let why = null;
6669
6694
  let stuck = false;
6670
6695
  let liveOverride = null;
6696
+ if (terminal === "paused") {
6697
+ return { stuck: false, why: null, liveText: "paused" };
6698
+ }
6671
6699
  if (terminal === "done") {
6672
6700
  return { stuck: false, why: null, liveText: "done" };
6673
6701
  } else if (terminal === "halted" || terminal === "canceled") {
@@ -6800,6 +6828,9 @@ function statusGlyph(input) {
6800
6828
  if (input.workflowStatus === null) {
6801
6829
  return { glyph: "\u25CC", color: THEME.muted, key: "idle" };
6802
6830
  }
6831
+ if (input.workflowStatus === "paused") {
6832
+ return { glyph: "\u2016", color: THEME.muted, key: "paused" };
6833
+ }
6803
6834
  if (input.workflowStatus === "done") {
6804
6835
  return { glyph: "\u2713", color: THEME.ok, key: "done" };
6805
6836
  }
@@ -6821,6 +6852,16 @@ var init_dashboard_glyph = __esm({
6821
6852
  // src/runtime/dashboard-view.tsx
6822
6853
  import { Box as Box2, Text as Text2, useInput as useInput2, useStdin as useStdin2 } from "ink";
6823
6854
  import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
6855
+ function ActionStatusLine(props) {
6856
+ if (props.confirm) {
6857
+ return /* @__PURE__ */ jsx3(Text2, { wrap: "truncate", color: THEME.warn, children: `${ACTION_VERB[props.confirm.action]} ${props.confirm.workflowId}? (y/n)` });
6858
+ }
6859
+ if (props.feedback) {
6860
+ const color = props.feedback.kind === "ok" ? THEME.ok : props.feedback.kind === "err" ? THEME.err : THEME.muted;
6861
+ return /* @__PURE__ */ jsx3(Text2, { wrap: "truncate", color, children: props.feedback.text });
6862
+ }
6863
+ return null;
6864
+ }
6824
6865
  function abbreviateWorkflowType(full) {
6825
6866
  const known = TYPE_ABBREVIATION[full];
6826
6867
  if (known) return known;
@@ -6983,7 +7024,7 @@ function FullCard(props) {
6983
7024
  }
6984
7025
  function CompactCard(props) {
6985
7026
  const { pane } = props;
6986
- const statusWord = pane.statusKey === "done" ? "done" : pane.statusKey === "canceled" ? "canceled" : pane.statusKey === "stuck" ? "halted" : pane.statusKey === "idle" ? "idle" : "running";
7027
+ const statusWord = pane.statusKey === "done" ? "done" : pane.statusKey === "canceled" ? "canceled" : pane.statusKey === "stuck" ? "halted" : pane.statusKey === "idle" ? "idle" : pane.statusKey === "paused" ? "paused" : "running";
6987
7028
  const glyph = statusGlyph({
6988
7029
  workflowStatus: pane.statusKey === "idle" ? null : pane.statusKey === "stuck" ? "halted" : pane.statusKey,
6989
7030
  stuck: false
@@ -7045,6 +7086,10 @@ function Wall(props) {
7045
7086
  const paneWidth = Math.floor(props.cols / colsCount);
7046
7087
  let globalIdx = 0;
7047
7088
  return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: props.cols, children: [
7089
+ props.counts ? /* @__PURE__ */ jsx3(Text2, { wrap: "truncate", children: SUMMARY_SEGMENTS.map((seg, i) => {
7090
+ const n = props.counts[seg.key];
7091
+ return /* @__PURE__ */ jsx3(Text2, { color: n > 0 ? seg.color : THEME.muted, children: (i > 0 ? " " : "") + `${seg.glyph} ${n} ${seg.label}` }, seg.key);
7092
+ }) }) : null,
7048
7093
  state.sections.map((sec) => {
7049
7094
  const rows = [];
7050
7095
  for (let i = 0; i < sec.panes.length; i += colsCount) {
@@ -7062,7 +7107,7 @@ function Wall(props) {
7062
7107
  selected,
7063
7108
  width: paneWidth
7064
7109
  },
7065
- pane.collabId
7110
+ pane.workflowId ?? pane.collabId
7066
7111
  ) : /* @__PURE__ */ jsx3(
7067
7112
  CompactCard,
7068
7113
  {
@@ -7070,13 +7115,20 @@ function Wall(props) {
7070
7115
  selected,
7071
7116
  width: paneWidth
7072
7117
  },
7073
- pane.collabId
7118
+ pane.workflowId ?? pane.collabId
7074
7119
  );
7075
7120
  }) }, ri))
7076
7121
  ] }, sec.group);
7077
7122
  }),
7078
- /* @__PURE__ */ jsx3(Text2, { color: THEME.muted, children: `page ${state.page + 1}/${Math.max(1, state.pageCount)} \xB7 ${state.totalRuns} runs \xB7 \u2191\u2193/jk select \xB7 \u21B5 inspect \xB7 [ ] page \xB7 q quit` }),
7079
- /* @__PURE__ */ jsx3(Text2, { color: THEME.muted, children: "\u25CF running \u26A0 stuck/halted \u2713 done \u2716 canceled \u25CC idle" })
7123
+ /* @__PURE__ */ jsx3(Text2, { color: THEME.muted, children: `page ${state.page + 1}/${Math.max(1, state.pageCount)} \xB7 ${props.showAll ? `${state.totalRuns} runs (every run, unmasked)` : `${state.totalRuns} collabs (one latest run each)`} \xB7 \u2191\u2193/jk select \xB7 \u21B5 inspect \xB7 p/r/c act \xB7 [ ] page \xB7 q quit` }),
7124
+ /* @__PURE__ */ jsx3(Text2, { color: THEME.muted, children: "\u25CF running \u2016 paused \u26A0 stuck/halted \u2713 done \u2716 canceled \u25CC idle" }),
7125
+ /* @__PURE__ */ jsx3(
7126
+ ActionStatusLine,
7127
+ {
7128
+ ...props.confirm != null ? { confirm: props.confirm } : {},
7129
+ ...props.feedback != null ? { feedback: props.feedback } : {}
7130
+ }
7131
+ )
7080
7132
  ] });
7081
7133
  }
7082
7134
  function TabBar(props) {
@@ -7113,7 +7165,7 @@ function Inspector(props) {
7113
7165
  ] }),
7114
7166
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7115
7167
  /* @__PURE__ */ jsx3(TabBar, { active: props.section }),
7116
- /* @__PURE__ */ jsx3(Text2, { color: THEME.muted, children: ` 1-4 section${props.section === "live" ? " \xB7 \u2191\u2193/g/G/f scroll" : ""} \xB7 Esc wall \xB7 q quit` })
7168
+ /* @__PURE__ */ jsx3(Text2, { color: THEME.muted, children: ` 1-4 section${props.section === "live" ? " \xB7 \u2191\u2193/g/G/f scroll" : ""} \xB7 p/r/c act \xB7 Esc wall \xB7 q quit` })
7117
7169
  ] }),
7118
7170
  props.section === "live" ? /* @__PURE__ */ jsx3(
7119
7171
  RelayView,
@@ -7127,8 +7179,7 @@ function Inspector(props) {
7127
7179
  s.workflowHistory.length > 0 ? /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
7128
7180
  /* @__PURE__ */ jsx3(Text2, { wrap: "truncate", color: THEME.muted, children: `WORKFLOW HISTORY (${s.workflowHistory.length})` }),
7129
7181
  s.workflowHistory.map((w) => {
7130
- const wfStatus = w.status === "paused" ? null : w.status;
7131
- const g = statusGlyph({ workflowStatus: wfStatus, stuck: false });
7182
+ const g = statusGlyph({ workflowStatus: w.status, stuck: false });
7132
7183
  return /* @__PURE__ */ jsxs2(
7133
7184
  Text2,
7134
7185
  {
@@ -7180,7 +7231,14 @@ function Inspector(props) {
7180
7231
  ] }) : /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
7181
7232
  /* @__PURE__ */ jsx3(Text2, { wrap: "truncate", children: `total ${fmtDur(s.cost.totalMs)} \xB7 in \u2248${s.cost.estInputTokens} \xB7 out \u2248${s.cost.estOutputTokens} (est, not metered)` }),
7182
7233
  s.cost.perPhase.map((p, i) => /* @__PURE__ */ jsx3(Text2, { wrap: "truncate", color: THEME.muted, children: `${p.phaseName} in \u2248${p.estInTokens} out \u2248${p.estOutTokens} ${p.durationMs == null ? "\u2013" : fmtDur(p.durationMs)}` }, i))
7183
- ] })
7234
+ ] }),
7235
+ /* @__PURE__ */ jsx3(
7236
+ ActionStatusLine,
7237
+ {
7238
+ ...props.confirm != null ? { confirm: props.confirm } : {},
7239
+ ...props.feedback != null ? { feedback: props.feedback } : {}
7240
+ }
7241
+ )
7184
7242
  ] });
7185
7243
  }
7186
7244
  function DashInput(props) {
@@ -7196,7 +7254,7 @@ function DashboardApp(props) {
7196
7254
  const { isRawModeSupported } = useStdin2();
7197
7255
  return isRawModeSupported ? /* @__PURE__ */ jsx3(DashInput, { onKey: props.onKey, children: props.node }) : props.node;
7198
7256
  }
7199
- var MIN_PANE_COLS, NARROW_PANE_COLS, BAR_FILLED, BAR_EMPTY, TYPE_ABBREVIATION;
7257
+ var MIN_PANE_COLS, NARROW_PANE_COLS, BAR_FILLED, BAR_EMPTY, SUMMARY_SEGMENTS, ACTION_VERB, TYPE_ABBREVIATION;
7200
7258
  var init_dashboard_view = __esm({
7201
7259
  "src/runtime/dashboard-view.tsx"() {
7202
7260
  "use strict";
@@ -7208,6 +7266,19 @@ var init_dashboard_view = __esm({
7208
7266
  NARROW_PANE_COLS = 48;
7209
7267
  BAR_FILLED = "\u25B0";
7210
7268
  BAR_EMPTY = "\u25B1";
7269
+ SUMMARY_SEGMENTS = [
7270
+ { key: "running", glyph: "\u25CF", color: THEME.accent, label: "running" },
7271
+ { key: "paused", glyph: "\u2016", color: THEME.muted, label: "paused" },
7272
+ { key: "stuck", glyph: "\u26A0", color: THEME.err, label: "stuck" },
7273
+ { key: "done", glyph: "\u2713", color: THEME.ok, label: "done" },
7274
+ { key: "canceled", glyph: "\u2716", color: THEME.err, label: "canceled" },
7275
+ { key: "idle", glyph: "\u25CC", color: THEME.muted, label: "idle" }
7276
+ ];
7277
+ ACTION_VERB = {
7278
+ pause: "Pause",
7279
+ resume: "Resume",
7280
+ cancel: "Cancel"
7281
+ };
7211
7282
  TYPE_ABBREVIATION = {
7212
7283
  "complex-bug-fixing": "bugfix",
7213
7284
  "spec-driven-development": "sdd",
@@ -7237,6 +7308,9 @@ function abbreviateCwd(absPath, home) {
7237
7308
  if (home && (p === home || p.startsWith(home + "/"))) p = "~" + p.slice(home.length);
7238
7309
  return p;
7239
7310
  }
7311
+ function runKey(s) {
7312
+ return s.workflowId ?? s.collabId;
7313
+ }
7240
7314
  function partitionWallGroups(summaries) {
7241
7315
  const active = [];
7242
7316
  const idleManual = [];
@@ -7244,7 +7318,8 @@ function partitionWallGroups(summaries) {
7244
7318
  const doneCanceled = [];
7245
7319
  for (const s of summaries) {
7246
7320
  if (s.workflowStatus === null) idleManual.push(s);
7247
- else if (s.workflowStatus === "running") active.push(s);
7321
+ else if (s.workflowStatus === "running" || s.workflowStatus === "paused")
7322
+ active.push(s);
7248
7323
  else if (s.workflowStatus === "halted") halted.push(s);
7249
7324
  else if (s.workflowStatus === "done" || s.workflowStatus === "canceled")
7250
7325
  doneCanceled.push(s);
@@ -7260,6 +7335,33 @@ function partitionWallGroups(summaries) {
7260
7335
  doneCanceled.sort((a, b) => cmpDesc(recencyKey(a), recencyKey(b)));
7261
7336
  return { active, idleManual, halted, doneCanceled };
7262
7337
  }
7338
+ function summarizeWall(summaries) {
7339
+ const counts = {
7340
+ running: 0,
7341
+ paused: 0,
7342
+ stuck: 0,
7343
+ done: 0,
7344
+ canceled: 0,
7345
+ idle: 0
7346
+ };
7347
+ for (const s of summaries) {
7348
+ const st = s.workflowStatus;
7349
+ if (st === null) counts.idle++;
7350
+ else if (st === "halted") counts.stuck++;
7351
+ else if (st === "running") {
7352
+ if (isStuckRunning(s)) counts.stuck++;
7353
+ else counts.running++;
7354
+ } else if (st === "paused") counts.paused++;
7355
+ else if (st === "done") counts.done++;
7356
+ else if (st === "canceled") counts.canceled++;
7357
+ }
7358
+ return counts;
7359
+ }
7360
+ function actionsForStatus(status) {
7361
+ if (status === "running") return ["pause", "cancel"];
7362
+ if (status === "paused" || status === "halted") return ["resume", "cancel"];
7363
+ return [];
7364
+ }
7263
7365
  function cardKindFor(group) {
7264
7366
  return group === "active" ? "full" : "compact";
7265
7367
  }
@@ -7573,7 +7675,7 @@ function buildWallState(input) {
7573
7675
  label: sec.label,
7574
7676
  cardKind: sec.cardKind,
7575
7677
  panes: sec.cards.map((sum) => {
7576
- const snap = input.snapshots[sum.collabId] ?? {
7678
+ const snap = input.snapshots[runKey(sum)] ?? input.snapshots[sum.collabId] ?? {
7577
7679
  handoffs: [],
7578
7680
  phaseRuns: [],
7579
7681
  totalPhases: 0
@@ -7682,13 +7784,19 @@ function createDashboardRuntime(input) {
7682
7784
  let inspectorSection = "live";
7683
7785
  let wallPage = 0;
7684
7786
  let wallSelected = 0;
7685
- let lastPaneCollabIds = [];
7787
+ let lastPaneRuns = [];
7788
+ let pendingConfirm = null;
7789
+ let actionFeedback = null;
7790
+ let actionFeedbackAtMs = 0;
7791
+ const nowMs = input.nowMs ?? (() => Date.now());
7792
+ const FEEDBACK_TTL_MS = 4e3;
7686
7793
  const viewport = { offset: 0, follow: true };
7687
7794
  let loopResolve;
7688
7795
  const loopDone = new Promise((r) => loopResolve = r);
7689
7796
  const cols = input.stdout.columns ?? 120;
7690
7797
  const rows = input.stdout.rows ?? 40;
7691
7798
  const windowMs = resolveDashboardWindowMs(input.windowMs);
7799
+ const showAll = input.showAll ?? false;
7692
7800
  let pendingSig = "";
7693
7801
  let lastSig = null;
7694
7802
  let renderCount = 0;
@@ -7816,9 +7924,58 @@ function createDashboardRuntime(input) {
7816
7924
  selectedWorkflowId: inspectorWorkflowId
7817
7925
  });
7818
7926
  }
7927
+ function setFeedback(kind, text) {
7928
+ actionFeedback = { kind, text };
7929
+ actionFeedbackAtMs = nowMs();
7930
+ }
7931
+ function expireFeedback() {
7932
+ if (actionFeedback && nowMs() - actionFeedbackAtMs >= FEEDBACK_TTL_MS) {
7933
+ actionFeedback = null;
7934
+ }
7935
+ }
7936
+ function freshStatusFor(collabId, workflowId) {
7937
+ const sums = showAll ? input.broker.control.listAllWorkflowSummaries(windowMs, (/* @__PURE__ */ new Date()).toISOString()) : input.broker.control.listActiveCollabSummaries(windowMs, (/* @__PURE__ */ new Date()).toISOString());
7938
+ const s = sums.find((x) => x.collabId === collabId && x.workflowId === workflowId);
7939
+ return s?.workflowStatus ?? null;
7940
+ }
7941
+ function requestAction(target, action) {
7942
+ if (!target.workflowId) {
7943
+ setFeedback("hint", "no workflow on this card");
7944
+ return;
7945
+ }
7946
+ const status = freshStatusFor(target.collabId, target.workflowId);
7947
+ if (!actionsForStatus(status).includes(action)) {
7948
+ setFeedback("hint", `${action} not available (${status ?? "no workflow"})`);
7949
+ return;
7950
+ }
7951
+ pendingConfirm = { workflowId: target.workflowId, action };
7952
+ }
7953
+ function executeConfirmed() {
7954
+ if (!pendingConfirm) return;
7955
+ const { workflowId, action } = pendingConfirm;
7956
+ pendingConfirm = null;
7957
+ const now = (/* @__PURE__ */ new Date()).toISOString();
7958
+ const c = input.broker.control;
7959
+ try {
7960
+ if (action === "pause") c.pauseWorkflow({ workflowId, now });
7961
+ else if (action === "resume") c.resumeWorkflow({ workflowId, now });
7962
+ else c.cancelWorkflow({ workflowId, now });
7963
+ const verb = action === "pause" ? "paused" : action === "resume" ? "resumed" : "canceled";
7964
+ setFeedback("ok", `${verb} ${workflowId}`);
7965
+ } catch (err) {
7966
+ setFeedback("err", err instanceof Error ? err.message : String(err));
7967
+ }
7968
+ }
7969
+ function actionForKey(key) {
7970
+ if (key === "p") return "pause";
7971
+ if (key === "r") return "resume";
7972
+ if (key === "c") return "cancel";
7973
+ return null;
7974
+ }
7819
7975
  function node() {
7820
7976
  const c = input.broker.control;
7821
7977
  const isoNow = (/* @__PURE__ */ new Date()).toISOString();
7978
+ expireFeedback();
7822
7979
  if (mode === "inspector" && inspectorCollabId) {
7823
7980
  const st = inspectorState();
7824
7981
  if (st) {
@@ -7829,7 +7986,9 @@ function createDashboardRuntime(input) {
7829
7986
  label: inspectorLabel,
7830
7987
  type: inspectorType,
7831
7988
  cols,
7832
- rows
7989
+ rows,
7990
+ confirm: pendingConfirm,
7991
+ feedback: actionFeedback
7833
7992
  })}`;
7834
7993
  return createElement2(Inspector, {
7835
7994
  state: st,
@@ -7839,11 +7998,13 @@ function createDashboardRuntime(input) {
7839
7998
  rows,
7840
7999
  label: inspectorLabel,
7841
8000
  workflowStatus: inspectorWorkflowStatus,
7842
- workflowType: inspectorType
8001
+ workflowType: inspectorType,
8002
+ confirm: pendingConfirm,
8003
+ feedback: actionFeedback
7843
8004
  });
7844
8005
  }
7845
8006
  }
7846
- const summaries = c.listActiveCollabSummaries(windowMs, isoNow);
8007
+ const summaries = showAll ? c.listAllWorkflowSummaries(windowMs, isoNow) : c.listActiveCollabSummaries(windowMs, isoNow);
7847
8008
  const groups = partitionWallGroups(summaries);
7848
8009
  const allocPreview = allocateWallSections({
7849
8010
  groups,
@@ -7859,7 +8020,7 @@ function createDashboardRuntime(input) {
7859
8020
  });
7860
8021
  const phaseRaw = s.workflowId ? c.getWorkflowPhaseRuns(s.workflowId) : [];
7861
8022
  const def = s.workflowType ? getWorkflowDefinition(s.workflowType) : null;
7862
- snapshots[s.collabId] = {
8023
+ snapshots[runKey(s)] = {
7863
8024
  handoffs,
7864
8025
  phaseRuns: toPhaseRuns(phaseRaw),
7865
8026
  totalPhases: def ? def.phases.length : 0
@@ -7884,9 +8045,10 @@ function createDashboardRuntime(input) {
7884
8045
  });
7885
8046
  wallPage = wallState.page;
7886
8047
  wallSelected = wallState.selected;
7887
- lastPaneCollabIds = wallState.panes.map((p) => p.collabId);
7888
- pendingSig = `w:${JSON.stringify({ wallState, cols, rows })}`;
7889
- return createElement2(Wall, { state: wallState, cols, rows });
8048
+ lastPaneRuns = wallState.panes.map((p) => ({ collabId: p.collabId, workflowId: p.workflowId }));
8049
+ const counts = summarizeWall(summaries);
8050
+ pendingSig = `w:${JSON.stringify({ wallState, cols, rows, counts, confirm: pendingConfirm, feedback: actionFeedback })}`;
8051
+ return createElement2(Wall, { state: wallState, cols, rows, showAll, counts, confirm: pendingConfirm, feedback: actionFeedback });
7890
8052
  }
7891
8053
  const inkOptions = {
7892
8054
  stdout: input.stdout,
@@ -7923,6 +8085,12 @@ function createDashboardRuntime(input) {
7923
8085
  }
7924
8086
  }
7925
8087
  function handleKey(ev) {
8088
+ if (pendingConfirm) {
8089
+ if (ev.key === "y" || ev.key === "\r" || ev.key === "\n") executeConfirmed();
8090
+ else if (ev.key === "n" || ev.escape) pendingConfirm = null;
8091
+ rerender();
8092
+ return;
8093
+ }
7926
8094
  if (mode === "wall") {
7927
8095
  if (ev.upArrow || ev.key === "k")
7928
8096
  wallSelected = Math.max(0, wallSelected - 1);
@@ -7930,23 +8098,31 @@ function createDashboardRuntime(input) {
7930
8098
  else if (ev.key === "[") wallPage = Math.max(0, wallPage - 1);
7931
8099
  else if (ev.key === "]") wallPage = wallPage + 1;
7932
8100
  else if (ev.key === "\r" || ev.key === "\n") {
7933
- const collabId = lastPaneCollabIds[wallSelected];
7934
- if (collabId) {
7935
- const sums = input.broker.control.listActiveCollabSummaries(
8101
+ const run = lastPaneRuns[wallSelected];
8102
+ if (run) {
8103
+ const sums = showAll ? input.broker.control.listAllWorkflowSummaries(
8104
+ windowMs,
8105
+ (/* @__PURE__ */ new Date()).toISOString()
8106
+ ) : input.broker.control.listActiveCollabSummaries(
7936
8107
  windowMs,
7937
8108
  (/* @__PURE__ */ new Date()).toISOString()
7938
8109
  );
7939
- const s = sums.find((x) => x.collabId === collabId);
7940
- inspectorCollabId = collabId;
7941
- inspectorWorkflowId = s?.workflowId ?? null;
8110
+ const s = sums.find(
8111
+ (x) => x.collabId === run.collabId && x.workflowId === run.workflowId
8112
+ );
8113
+ inspectorCollabId = run.collabId;
8114
+ inspectorWorkflowId = run.workflowId;
7942
8115
  inspectorType = s?.workflowType ?? null;
7943
- inspectorLabel = s?.label ?? collabId;
8116
+ inspectorLabel = s?.label ?? run.collabId;
7944
8117
  inspectorWorkflowStatus = s?.workflowStatus ?? null;
7945
8118
  inspectorSection = "live";
7946
8119
  viewport.offset = 0;
7947
8120
  viewport.follow = true;
7948
8121
  mode = "inspector";
7949
8122
  }
8123
+ } else if (actionForKey(ev.key)) {
8124
+ const run = lastPaneRuns[wallSelected];
8125
+ if (run) requestAction(run, actionForKey(ev.key));
7950
8126
  } else if (ev.key === "q") stopping = true;
7951
8127
  } else {
7952
8128
  if (ev.key === "1") inspectorSection = "live";
@@ -7955,7 +8131,14 @@ function createDashboardRuntime(input) {
7955
8131
  else if (ev.key === "4") inspectorSection = "cost";
7956
8132
  else if (ev.escape) mode = "wall";
7957
8133
  else if (ev.key === "q") stopping = true;
7958
- else if (inspectorSection === "live") {
8134
+ else if (actionForKey(ev.key)) {
8135
+ if (inspectorCollabId) {
8136
+ requestAction(
8137
+ { collabId: inspectorCollabId, workflowId: inspectorWorkflowId },
8138
+ actionForKey(ev.key)
8139
+ );
8140
+ }
8141
+ } else if (inspectorSection === "live") {
7959
8142
  const visibleH = logViewportHeight(rows);
7960
8143
  const linesLen = inspectorState()?.live.logLines.length ?? 0;
7961
8144
  const tailStart = Math.max(0, linesLen - visibleH);
@@ -8021,7 +8204,10 @@ function createDashboardRuntime(input) {
8021
8204
  }),
8022
8205
  __renderCount: () => renderCount,
8023
8206
  __recycles: () => recycles,
8024
- __clears: () => clearCount
8207
+ __clears: () => clearCount,
8208
+ __inspectorWorkflowId: () => inspectorWorkflowId,
8209
+ __pendingConfirm: () => pendingConfirm,
8210
+ __actionFeedback: () => actionFeedback
8025
8211
  };
8026
8212
  }
8027
8213
  var DEFAULT_WINDOW_MS;
@@ -12870,8 +13056,8 @@ function compareSemver(a, b) {
12870
13056
  var EZIO_PROVENANCE = {
12871
13057
  ezioCliVersion: "0.2.0-beta.5",
12872
13058
  ezioGitSha: "45823b4",
12873
- builtAt: "2026-06-23T19:09:50.748Z",
12874
- whisperVersion: "0.8.0"
13059
+ builtAt: "2026-06-25T03:27:07.318Z",
13060
+ whisperVersion: "0.8.1"
12875
13061
  };
12876
13062
 
12877
13063
  // src/ezio-provenance-types.ts
@@ -16373,10 +16559,12 @@ async function runCollabDashboard(input) {
16373
16559
  runBrokerDaemonSweep: false
16374
16560
  });
16375
16561
  const dashboardId = `dash_${randomBytes4(9).toString("base64url")}`;
16376
- const runtime = input?.__createRuntime?.(broker, dashboardId, stdout) ?? createDashboardRuntime({
16562
+ const showAll = input?.showAll ?? false;
16563
+ const runtime = input?.__createRuntime?.(broker, dashboardId, stdout, { showAll }) ?? createDashboardRuntime({
16377
16564
  broker,
16378
16565
  dashboardId,
16379
16566
  stdout,
16567
+ showAll,
16380
16568
  ...input?.windowMs != null ? { windowMs: input.windowMs } : {}
16381
16569
  });
16382
16570
  let stoppedBySignal = false;
@@ -17473,6 +17661,9 @@ Not attached (stdin/stdout is not a TTY). To view the tmux session, run:
17473
17661
  collab.command("dashboard").description("Full-screen dashboard: live wall of recently-active runs + per-run inspector").option(
17474
17662
  "--window <duration>",
17475
17663
  "Eligible-collab activity window. Accepts ms or Ns/Nm/Nh/Nd (e.g. 45s, 30m, 2h, 1d), or 'all' for no limit. Default: 30m."
17664
+ ).option(
17665
+ "--all",
17666
+ "Show one card per workflow RUN (no per-collab masking). Still respects --window per run; pair with '--window all' for the complete run ledger."
17476
17667
  ).action(async (opts) => {
17477
17668
  const { parseDashboardWindow: parseDashboardWindow2 } = await Promise.resolve().then(() => (init_dashboard(), dashboard_exports));
17478
17669
  const windowMs = opts.window != null ? parseDashboardWindow2(opts.window) : null;
@@ -17482,9 +17673,10 @@ Not attached (stdin/stdout is not a TTY). To view the tmux session, run:
17482
17673
  );
17483
17674
  process.exit(2);
17484
17675
  }
17485
- await runCollabDashboard(
17486
- windowMs != null ? { windowMs } : void 0
17487
- );
17676
+ await runCollabDashboard({
17677
+ ...windowMs != null ? { windowMs } : {},
17678
+ ...opts.all ? { showAll: true } : {}
17679
+ });
17488
17680
  });
17489
17681
  collab.command("stop").description("Stop the active collaboration session").option(
17490
17682
  "--collab <id>",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-whisper",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Terminal-first relay for paired AI coding agents (Claude + Codex), driven by structured workflows.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {