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 +9 -2
- package/dist/bin/broker-daemon.js +105 -79
- package/dist/bin/companion-agent.js +106 -80
- package/dist/bin/relay-monitor.js +108 -79
- package/dist/bin/whisper.js +459 -142
- package/package.json +4 -4
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
|
|
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
|
|
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
|
|
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
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
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
|
|
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
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
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
|
|
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
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
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") {
|