ai-whisper 0.5.4 → 0.5.6
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 +5 -4
- package/dist/bin/broker-daemon.js +201 -28
- package/dist/bin/companion-agent.js +596 -76
- package/dist/bin/relay-monitor.js +214 -30
- package/dist/bin/turn-event-shim.js +85 -0
- package/dist/bin/whisper.js +1475 -131
- package/package.json +6 -4
- package/dist/.tsbuildinfo +0 -1
- package/dist/bin/broker-daemon.d.ts +0 -3
- package/dist/bin/broker-daemon.d.ts.map +0 -1
- package/dist/bin/companion-agent.d.ts +0 -3
- package/dist/bin/companion-agent.d.ts.map +0 -1
- package/dist/bin/relay-monitor.d.ts +0 -3
- package/dist/bin/relay-monitor.d.ts.map +0 -1
- package/dist/bin/whisper.d.ts +0 -3
- package/dist/bin/whisper.d.ts.map +0 -1
- package/dist/commands/collab/dashboard.d.ts +0 -18
- package/dist/commands/collab/dashboard.d.ts.map +0 -1
- package/dist/commands/collab/inspect.d.ts +0 -23
- package/dist/commands/collab/inspect.d.ts.map +0 -1
- package/dist/commands/collab/mount.d.ts +0 -55
- package/dist/commands/collab/mount.d.ts.map +0 -1
- package/dist/commands/collab/reconnect.d.ts +0 -45
- package/dist/commands/collab/reconnect.d.ts.map +0 -1
- package/dist/commands/collab/recover.d.ts +0 -33
- package/dist/commands/collab/recover.d.ts.map +0 -1
- package/dist/commands/collab/relay-monitor.d.ts +0 -21
- package/dist/commands/collab/relay-monitor.d.ts.map +0 -1
- package/dist/commands/collab/start.d.ts +0 -53
- package/dist/commands/collab/start.d.ts.map +0 -1
- package/dist/commands/collab/status.d.ts +0 -6
- package/dist/commands/collab/status.d.ts.map +0 -1
- package/dist/commands/collab/stop.d.ts +0 -13
- package/dist/commands/collab/stop.d.ts.map +0 -1
- package/dist/commands/collab/tell.d.ts +0 -27
- package/dist/commands/collab/tell.d.ts.map +0 -1
- package/dist/commands/skill/install.d.ts +0 -13
- package/dist/commands/skill/install.d.ts.map +0 -1
- package/dist/commands/workflow/cancel.d.ts +0 -14
- package/dist/commands/workflow/cancel.d.ts.map +0 -1
- package/dist/commands/workflow/inspect.d.ts +0 -41
- package/dist/commands/workflow/inspect.d.ts.map +0 -1
- package/dist/commands/workflow/list.d.ts +0 -28
- package/dist/commands/workflow/list.d.ts.map +0 -1
- package/dist/commands/workflow/pause.d.ts +0 -14
- package/dist/commands/workflow/pause.d.ts.map +0 -1
- package/dist/commands/workflow/resume.d.ts +0 -17
- package/dist/commands/workflow/resume.d.ts.map +0 -1
- package/dist/commands/workflow/start.d.ts +0 -66
- package/dist/commands/workflow/start.d.ts.map +0 -1
- package/dist/commands/workflow/types.d.ts +0 -2
- package/dist/commands/workflow/types.d.ts.map +0 -1
- package/dist/create-cli.d.ts +0 -4
- package/dist/create-cli.d.ts.map +0 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.d.ts.map +0 -1
- package/dist/runtime/action-inference.d.ts +0 -3
- package/dist/runtime/action-inference.d.ts.map +0 -1
- package/dist/runtime/artifact-input.d.ts +0 -2
- package/dist/runtime/artifact-input.d.ts.map +0 -1
- package/dist/runtime/assistant-turn-capture.d.ts +0 -14
- package/dist/runtime/assistant-turn-capture.d.ts.map +0 -1
- package/dist/runtime/bracketed-paste-detector.d.ts +0 -16
- package/dist/runtime/bracketed-paste-detector.d.ts.map +0 -1
- package/dist/runtime/broker-artifact-service.d.ts +0 -48
- package/dist/runtime/broker-artifact-service.d.ts.map +0 -1
- package/dist/runtime/broker-connect.d.ts +0 -9
- package/dist/runtime/broker-connect.d.ts.map +0 -1
- package/dist/runtime/broker-daemon.d.ts +0 -25
- package/dist/runtime/broker-daemon.d.ts.map +0 -1
- package/dist/runtime/busy-indicator.d.ts +0 -11
- package/dist/runtime/busy-indicator.d.ts.map +0 -1
- package/dist/runtime/capture-handback-text.d.ts +0 -56
- package/dist/runtime/capture-handback-text.d.ts.map +0 -1
- package/dist/runtime/clipboard-change-count.d.ts +0 -12
- package/dist/runtime/clipboard-change-count.d.ts.map +0 -1
- package/dist/runtime/clipboard-handback-capture.d.ts +0 -13
- package/dist/runtime/clipboard-handback-capture.d.ts.map +0 -1
- package/dist/runtime/collab-resolver.d.ts +0 -36
- package/dist/runtime/collab-resolver.d.ts.map +0 -1
- package/dist/runtime/companion-agent-loop.d.ts +0 -13
- package/dist/runtime/companion-agent-loop.d.ts.map +0 -1
- package/dist/runtime/context-injector.d.ts +0 -20
- package/dist/runtime/context-injector.d.ts.map +0 -1
- package/dist/runtime/context-policy.d.ts +0 -3
- package/dist/runtime/context-policy.d.ts.map +0 -1
- package/dist/runtime/current-tty.d.ts +0 -2
- package/dist/runtime/current-tty.d.ts.map +0 -1
- package/dist/runtime/dashboard-glyph.d.ts +0 -12
- package/dist/runtime/dashboard-glyph.d.ts.map +0 -1
- package/dist/runtime/dashboard-state.d.ts +0 -183
- package/dist/runtime/dashboard-state.d.ts.map +0 -1
- package/dist/runtime/dashboard-view.d.ts +0 -34
- package/dist/runtime/dashboard-view.d.ts.map +0 -1
- package/dist/runtime/dashboard.d.ts +0 -46
- package/dist/runtime/dashboard.d.ts.map +0 -1
- package/dist/runtime/evaluator-config.d.ts +0 -21
- package/dist/runtime/evaluator-config.d.ts.map +0 -1
- package/dist/runtime/evaluator-observer.d.ts +0 -8
- package/dist/runtime/evaluator-observer.d.ts.map +0 -1
- package/dist/runtime/id-factory.d.ts +0 -6
- package/dist/runtime/id-factory.d.ts.map +0 -1
- package/dist/runtime/launcher.d.ts +0 -39
- package/dist/runtime/launcher.d.ts.map +0 -1
- package/dist/runtime/live-session-broker-executor.d.ts +0 -8
- package/dist/runtime/live-session-broker-executor.d.ts.map +0 -1
- package/dist/runtime/live-session.d.ts +0 -33
- package/dist/runtime/live-session.d.ts.map +0 -1
- package/dist/runtime/load-dot-env.d.ts +0 -6
- package/dist/runtime/load-dot-env.d.ts.map +0 -1
- package/dist/runtime/local-multiline-composer.d.ts +0 -23
- package/dist/runtime/local-multiline-composer.d.ts.map +0 -1
- package/dist/runtime/mount-session-main.d.ts +0 -67
- package/dist/runtime/mount-session-main.d.ts.map +0 -1
- package/dist/runtime/mounted-turn-owned-relay.d.ts +0 -170
- package/dist/runtime/mounted-turn-owned-relay.d.ts.map +0 -1
- package/dist/runtime/on-demand-processing.d.ts +0 -23
- package/dist/runtime/on-demand-processing.d.ts.map +0 -1
- package/dist/runtime/operator-inspect-captures.d.ts +0 -6
- package/dist/runtime/operator-inspect-captures.d.ts.map +0 -1
- package/dist/runtime/operator-inspect-verdicts.d.ts +0 -6
- package/dist/runtime/operator-inspect-verdicts.d.ts.map +0 -1
- package/dist/runtime/operator-inspect.d.ts +0 -138
- package/dist/runtime/operator-inspect.d.ts.map +0 -1
- package/dist/runtime/paths.d.ts +0 -2
- package/dist/runtime/paths.d.ts.map +0 -1
- package/dist/runtime/port-allocator.d.ts +0 -7
- package/dist/runtime/port-allocator.d.ts.map +0 -1
- package/dist/runtime/port-utils.d.ts +0 -3
- package/dist/runtime/port-utils.d.ts.map +0 -1
- package/dist/runtime/process-start-time.d.ts +0 -7
- package/dist/runtime/process-start-time.d.ts.map +0 -1
- package/dist/runtime/provider-submit-strategy.d.ts +0 -14
- package/dist/runtime/provider-submit-strategy.d.ts.map +0 -1
- package/dist/runtime/providers.d.ts +0 -18
- package/dist/runtime/providers.d.ts.map +0 -1
- package/dist/runtime/record-evaluator-status.d.ts +0 -9
- package/dist/runtime/record-evaluator-status.d.ts.map +0 -1
- package/dist/runtime/recovery-guard.d.ts +0 -12
- package/dist/runtime/recovery-guard.d.ts.map +0 -1
- package/dist/runtime/relay-directive.d.ts +0 -4
- package/dist/runtime/relay-directive.d.ts.map +0 -1
- package/dist/runtime/relay-line-buffer.d.ts +0 -22
- package/dist/runtime/relay-line-buffer.d.ts.map +0 -1
- package/dist/runtime/relay-monitor.d.ts +0 -26
- package/dist/runtime/relay-monitor.d.ts.map +0 -1
- package/dist/runtime/relay-orchestrator-evaluator.d.ts +0 -160
- package/dist/runtime/relay-orchestrator-evaluator.d.ts.map +0 -1
- package/dist/runtime/relay-orchestrator.d.ts +0 -116
- package/dist/runtime/relay-orchestrator.d.ts.map +0 -1
- package/dist/runtime/relay-pane-writer.d.ts +0 -28
- package/dist/runtime/relay-pane-writer.d.ts.map +0 -1
- package/dist/runtime/relay-service.d.ts +0 -76
- package/dist/runtime/relay-service.d.ts.map +0 -1
- package/dist/runtime/relay-view-input.d.ts +0 -17
- package/dist/runtime/relay-view-input.d.ts.map +0 -1
- package/dist/runtime/relay-view-state.d.ts +0 -87
- package/dist/runtime/relay-view-state.d.ts.map +0 -1
- package/dist/runtime/relay-view.d.ts +0 -16
- package/dist/runtime/relay-view.d.ts.map +0 -1
- package/dist/runtime/reply-wait.d.ts +0 -21
- package/dist/runtime/reply-wait.d.ts.map +0 -1
- package/dist/runtime/runtime-debug-log.d.ts +0 -7
- package/dist/runtime/runtime-debug-log.d.ts.map +0 -1
- package/dist/runtime/state-root.d.ts +0 -3
- package/dist/runtime/state-root.d.ts.map +0 -1
- package/dist/runtime/terminal-input-normalizer.d.ts +0 -11
- package/dist/runtime/terminal-input-normalizer.d.ts.map +0 -1
- package/dist/runtime/theme.d.ts +0 -16
- package/dist/runtime/theme.d.ts.map +0 -1
- package/dist/runtime/version-check.d.ts +0 -17
- package/dist/runtime/version-check.d.ts.map +0 -1
- package/dist/runtime/wait-for-broker-ready.d.ts +0 -13
- package/dist/runtime/wait-for-broker-ready.d.ts.map +0 -1
- package/dist/runtime/workspace-id.d.ts +0 -3
- package/dist/runtime/workspace-id.d.ts.map +0 -1
- package/dist/skills/ai-whisper-bugfix/SKILL.md +0 -163
- package/dist/skills/ai-whisper-code-review/SKILL.md +0 -79
- package/dist/skills/ai-whisper-ralph/SKILL.md +0 -163
- package/dist/skills/ai-whisper-sdd/SKILL.md +0 -155
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ai-whisper
|
|
2
2
|
|
|
3
|
-
ai-whisper
|
|
3
|
+
ai-whisper pairs two coding agents — mount any two of Claude, Codex, and ezio — into a terminal-native pair that hand work back and forth under a single baton, so one agent implements while the other reviews, and a structured workflow drives the loop to a finished, reviewed deliverable without a human babysitting every round.
|
|
4
4
|
|
|
5
5
|
## Magic moment
|
|
6
6
|
|
|
@@ -52,10 +52,11 @@ It is **not** for:
|
|
|
52
52
|
|
|
53
53
|
## Prerequisites
|
|
54
54
|
|
|
55
|
-
ai-whisper drives the *real* Claude and Codex CLIs, so you
|
|
55
|
+
You pair any two of three agents — `claude`, `codex`, and `ezio`. ai-whisper drives the *real* Claude and Codex CLIs, so install and authenticate whichever of those two you plan to mount first; `ezio` is protocol-native and ships with ai-whisper, so it needs no separate CLI.
|
|
56
56
|
|
|
57
57
|
- **[Claude Code CLI](https://claude.com/claude-code)** — the `claude` command, signed in.
|
|
58
58
|
- **[Codex CLI](https://github.com/openai/codex)** — the `codex` command, signed in.
|
|
59
|
+
- **ezio** *(optional)* — bundled with ai-whisper; mount it with `whisper collab mount ezio`, no separate install.
|
|
59
60
|
- **Node.js 22+**.
|
|
60
61
|
- **An LLM evaluator with credentials** — workflows are gated by it and refuse to start without it. See [Evaluator configuration](docs/evaluator-configuration.md).
|
|
61
62
|
- **tmux** *(optional)* — only for `whisper collab start`, which auto-arranges both agents into panes. The mount flow below does not need it.
|
|
@@ -110,9 +111,9 @@ A run that stops short usually **escalates** — it does not crash. When the eva
|
|
|
110
111
|
|
|
111
112
|
## Core concepts
|
|
112
113
|
|
|
113
|
-
ai-whisper is **not a swarm**. The agents never type at once — work moves by a single baton, one owner at a time. Mounted sessions are *real*
|
|
114
|
+
ai-whisper is **not a swarm**. The agents never type at once — work moves by a single baton, one owner at a time. Mounted sessions are *real* agent sessions in your terminal — Claude or Codex CLIs, or ezio — and those sessions are the source of truth. Autonomy is supervised: every handoff, verdict, and round is inspectable, and runs are resumable rather than fire-and-forget. Work is organized as structured workflows — explicit loops and state transitions, not a free-form chat.
|
|
114
115
|
|
|
115
|
-
Claude and
|
|
116
|
+
Claude, Codex, and ezio are supported today — you mount any two of them; the architecture is provider-agnostic by design, so other coding-agent CLIs can be added behind the same relay.
|
|
116
117
|
|
|
117
118
|
For the full mental model, read [Concepts](docs/concepts.md).
|
|
118
119
|
|
|
@@ -106,6 +106,26 @@ var attachTargetModes = [
|
|
|
106
106
|
"mount_current_tty"
|
|
107
107
|
];
|
|
108
108
|
|
|
109
|
+
// ../shared/dist/repo-relative-path.js
|
|
110
|
+
import { basename, isAbsolute, relative } from "node:path";
|
|
111
|
+
function repoRelativePath(absPath, root) {
|
|
112
|
+
if (!absPath)
|
|
113
|
+
return "";
|
|
114
|
+
if (!root || !isAbsolute(absPath) || !isAbsolute(root))
|
|
115
|
+
return absPath;
|
|
116
|
+
const rel = relative(root, absPath);
|
|
117
|
+
if (rel === "" || rel.startsWith("..") || isAbsolute(rel))
|
|
118
|
+
return absPath;
|
|
119
|
+
return rel;
|
|
120
|
+
}
|
|
121
|
+
function displayArtifactPath(absPath, root) {
|
|
122
|
+
const trimmed = (absPath ?? "").trim();
|
|
123
|
+
if (!trimmed)
|
|
124
|
+
return null;
|
|
125
|
+
const rel = repoRelativePath(trimmed, root).trim();
|
|
126
|
+
return rel || basename(trimmed).trim() || null;
|
|
127
|
+
}
|
|
128
|
+
|
|
109
129
|
// ../shared/dist/broker-status.js
|
|
110
130
|
import { z as z3 } from "zod";
|
|
111
131
|
var brokerStatusSchema = z3.object({
|
|
@@ -1255,8 +1275,78 @@ function deleteEvaluatorDiagnosticsOlderThan(db, cutoffIso) {
|
|
|
1255
1275
|
return result.changes;
|
|
1256
1276
|
}
|
|
1257
1277
|
|
|
1278
|
+
// ../broker/dist/storage/repositories/relay-turn-event-diagnostics-repository.js
|
|
1279
|
+
var insertSeq = 0;
|
|
1280
|
+
function insertTurnEventDiagnostic(db, input) {
|
|
1281
|
+
const eventId = `tevt_${input.receivedAt.replace(/[^0-9]/g, "")}_${(input.handoffId ?? input.workspaceId).slice(-8)}_${input.action}_${process.pid}_${(insertSeq++).toString(36)}`;
|
|
1282
|
+
db.prepare(`INSERT INTO relay_turn_event_diagnostics (
|
|
1283
|
+
event_id, received_at, provider, workspace_id, cwd,
|
|
1284
|
+
session_or_thread_id, turn_id, workflow_active, collab_id, workflow_id,
|
|
1285
|
+
chain_id, handoff_id, input_correlated, containment_score,
|
|
1286
|
+
fidelity_verdict, defer_count, action, message_len, message_sample
|
|
1287
|
+
) VALUES (
|
|
1288
|
+
@eventId, @receivedAt, @provider, @workspaceId, @cwd,
|
|
1289
|
+
@sessionOrThreadId, @turnId, @workflowActive, @collabId, @workflowId,
|
|
1290
|
+
@chainId, @handoffId, @inputCorrelated, @containmentScore,
|
|
1291
|
+
@fidelityVerdict, @deferCount, @action, @messageLen, @messageSample
|
|
1292
|
+
)`).run({
|
|
1293
|
+
eventId,
|
|
1294
|
+
receivedAt: input.receivedAt,
|
|
1295
|
+
provider: input.provider,
|
|
1296
|
+
workspaceId: input.workspaceId,
|
|
1297
|
+
cwd: input.cwd,
|
|
1298
|
+
sessionOrThreadId: input.sessionOrThreadId,
|
|
1299
|
+
turnId: input.turnId,
|
|
1300
|
+
workflowActive: input.workflowActive ? 1 : 0,
|
|
1301
|
+
collabId: input.collabId,
|
|
1302
|
+
workflowId: input.workflowId,
|
|
1303
|
+
chainId: input.chainId,
|
|
1304
|
+
handoffId: input.handoffId,
|
|
1305
|
+
inputCorrelated: input.inputCorrelated === null ? null : input.inputCorrelated ? 1 : 0,
|
|
1306
|
+
containmentScore: input.containmentScore,
|
|
1307
|
+
fidelityVerdict: input.fidelityVerdict,
|
|
1308
|
+
deferCount: input.deferCount,
|
|
1309
|
+
action: input.action,
|
|
1310
|
+
messageLen: input.messageLen,
|
|
1311
|
+
messageSample: input.messageSample
|
|
1312
|
+
});
|
|
1313
|
+
return { eventId };
|
|
1314
|
+
}
|
|
1315
|
+
function rowToRecord4(r) {
|
|
1316
|
+
return {
|
|
1317
|
+
eventId: r.event_id,
|
|
1318
|
+
receivedAt: r.received_at,
|
|
1319
|
+
provider: r.provider,
|
|
1320
|
+
workspaceId: r.workspace_id,
|
|
1321
|
+
cwd: r.cwd,
|
|
1322
|
+
sessionOrThreadId: r.session_or_thread_id,
|
|
1323
|
+
turnId: r.turn_id,
|
|
1324
|
+
workflowActive: r.workflow_active === 1,
|
|
1325
|
+
collabId: r.collab_id,
|
|
1326
|
+
workflowId: r.workflow_id,
|
|
1327
|
+
chainId: r.chain_id,
|
|
1328
|
+
handoffId: r.handoff_id,
|
|
1329
|
+
inputCorrelated: r.input_correlated === null ? null : r.input_correlated === 1,
|
|
1330
|
+
containmentScore: r.containment_score,
|
|
1331
|
+
fidelityVerdict: r.fidelity_verdict,
|
|
1332
|
+
deferCount: r.defer_count,
|
|
1333
|
+
action: r.action,
|
|
1334
|
+
messageLen: r.message_len,
|
|
1335
|
+
messageSample: r.message_sample
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
function listTurnEventDiagnosticsByCollab(db, collabId2, limit) {
|
|
1339
|
+
const sql = "SELECT * FROM relay_turn_event_diagnostics WHERE collab_id = ? ORDER BY received_at DESC" + (limit !== null ? " LIMIT ?" : "");
|
|
1340
|
+
const rows = limit !== null ? db.prepare(sql).all(collabId2, limit) : db.prepare(sql).all(collabId2);
|
|
1341
|
+
return rows.map(rowToRecord4);
|
|
1342
|
+
}
|
|
1343
|
+
function deleteTurnEventDiagnosticsOlderThan(db, cutoffIso) {
|
|
1344
|
+
const info = db.prepare("DELETE FROM relay_turn_event_diagnostics WHERE received_at < ?").run(cutoffIso);
|
|
1345
|
+
return info.changes;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1258
1348
|
// ../broker/dist/storage/repositories/relay-handoff-repository.js
|
|
1259
|
-
function
|
|
1349
|
+
function rowToRecord5(row) {
|
|
1260
1350
|
return {
|
|
1261
1351
|
handoffId: row.handoff_id,
|
|
1262
1352
|
collabId: row.collab_id,
|
|
@@ -1293,7 +1383,7 @@ function queryRelayHandoff(db, handoffId) {
|
|
|
1293
1383
|
FROM relay_handoff h
|
|
1294
1384
|
JOIN collab c ON c.collab_id = h.collab_id
|
|
1295
1385
|
WHERE h.handoff_id = ?`).get(handoffId);
|
|
1296
|
-
return row ?
|
|
1386
|
+
return row ? rowToRecord5(row) : null;
|
|
1297
1387
|
}
|
|
1298
1388
|
function createRelayHandoffTxn(db, input) {
|
|
1299
1389
|
return db.transaction(() => {
|
|
@@ -1445,7 +1535,7 @@ function queryLatestHandedBackHandoff(db, collabId2) {
|
|
|
1445
1535
|
WHERE h.collab_id = ? AND h.status = 'handed_back'
|
|
1446
1536
|
ORDER BY h.resolved_at DESC
|
|
1447
1537
|
LIMIT 1`).get(collabId2);
|
|
1448
|
-
return row ?
|
|
1538
|
+
return row ? rowToRecord5(row) : null;
|
|
1449
1539
|
}
|
|
1450
1540
|
function failRelayHandoffOnDisconnectTxn(db, input) {
|
|
1451
1541
|
db.transaction(() => {
|
|
@@ -1516,7 +1606,7 @@ function listRelayHandoffsPendingOrchestration(db, collabId2) {
|
|
|
1516
1606
|
AND h.status = 'handed_back'
|
|
1517
1607
|
AND h.orchestrator_status = 'idle'
|
|
1518
1608
|
AND (w.status IS NULL OR w.status <> 'paused')`).all(collabId2);
|
|
1519
|
-
return rows.map(
|
|
1609
|
+
return rows.map(rowToRecord5);
|
|
1520
1610
|
}
|
|
1521
1611
|
function createLoopRelayHandoffTxn(db, input) {
|
|
1522
1612
|
return db.transaction(() => {
|
|
@@ -1712,7 +1802,7 @@ function getHandoffWithWorkflowMetaById(db, handoffId) {
|
|
|
1712
1802
|
WHERE h.handoff_id = ?`).get(handoffId);
|
|
1713
1803
|
if (!row)
|
|
1714
1804
|
return null;
|
|
1715
|
-
const base =
|
|
1805
|
+
const base = rowToRecord5(row);
|
|
1716
1806
|
return {
|
|
1717
1807
|
...base,
|
|
1718
1808
|
handoffStep: row.handoff_step,
|
|
@@ -1811,7 +1901,7 @@ function cleanupOrchestrationOnShutdownTxn(db, input) {
|
|
|
1811
1901
|
}
|
|
1812
1902
|
|
|
1813
1903
|
// ../broker/dist/storage/repositories/dashboard-repository.js
|
|
1814
|
-
import { basename } from "node:path";
|
|
1904
|
+
import { basename as basename2 } from "node:path";
|
|
1815
1905
|
function listActiveCollabSummaries(db, input) {
|
|
1816
1906
|
const nowMs = Date.parse(input.now ?? (/* @__PURE__ */ new Date()).toISOString());
|
|
1817
1907
|
const base = Number.isFinite(nowMs) ? nowMs : Date.now();
|
|
@@ -1855,7 +1945,7 @@ function buildCollabSummary(db, collabId2) {
|
|
|
1855
1945
|
FROM collab WHERE collab_id = ?`).get(e.collabId);
|
|
1856
1946
|
const wf = db.prepare(`SELECT workflow_id AS workflowId, workflow_type AS workflowType,
|
|
1857
1947
|
name, status, current_phase_index AS currentPhaseIndex,
|
|
1858
|
-
created_at AS createdAt
|
|
1948
|
+
created_at AS createdAt, spec_path AS specPath
|
|
1859
1949
|
FROM workflows WHERE collab_id = ?
|
|
1860
1950
|
ORDER BY (status = 'running') DESC, created_at DESC
|
|
1861
1951
|
LIMIT 1`).get(e.collabId);
|
|
@@ -1898,7 +1988,7 @@ function buildCollabSummary(db, collabId2) {
|
|
|
1898
1988
|
) ranked
|
|
1899
1989
|
WHERE rn = 1
|
|
1900
1990
|
ORDER BY agentType ASC`).all(e.collabId);
|
|
1901
|
-
const label = wf?.name && wf.name.trim() || collab2?.displayName && collab2.displayName.trim() || (collab2?.workspaceRoot ?
|
|
1991
|
+
const label = wf?.name && wf.name.trim() || collab2?.displayName && collab2.displayName.trim() || (collab2?.workspaceRoot ? basename2(collab2.workspaceRoot) : "") || e.collabId.slice(0, 12);
|
|
1902
1992
|
const runLastActRow = wf ? db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
|
|
1903
1993
|
FROM relay_handoff
|
|
1904
1994
|
WHERE collab_id = ? AND workflow_id = ?`).get(e.collabId, wf.workflowId) : db.prepare(`SELECT COALESCE(MAX(last_activity_at), '') AS lastAct
|
|
@@ -1924,6 +2014,7 @@ function buildCollabSummary(db, collabId2) {
|
|
|
1924
2014
|
},
|
|
1925
2015
|
sessions,
|
|
1926
2016
|
workflowCreatedAt: wf?.createdAt ?? null,
|
|
2017
|
+
specPath: wf ? displayArtifactPath(wf.specPath, collab2?.workspaceRoot ?? "") : null,
|
|
1927
2018
|
lastActivityAt: runLastAct
|
|
1928
2019
|
};
|
|
1929
2020
|
}
|
|
@@ -1966,7 +2057,7 @@ function listRunCostRows(db, input) {
|
|
|
1966
2057
|
import { randomUUID } from "node:crypto";
|
|
1967
2058
|
|
|
1968
2059
|
// ../broker/dist/storage/repositories/workflow-phase-repository.js
|
|
1969
|
-
function
|
|
2060
|
+
function rowToRecord6(row) {
|
|
1970
2061
|
return {
|
|
1971
2062
|
phaseRunId: row.phase_run_id,
|
|
1972
2063
|
workflowId: row.workflow_id,
|
|
@@ -1985,7 +2076,7 @@ function insertWorkflowPhaseRun(db, input) {
|
|
|
1985
2076
|
}
|
|
1986
2077
|
function listPhaseRunsForWorkflow(db, workflowId) {
|
|
1987
2078
|
const rows = db.prepare("SELECT * FROM workflow_phases WHERE workflow_id = ? ORDER BY started_at ASC").all(workflowId);
|
|
1988
|
-
return rows.map(
|
|
2079
|
+
return rows.map(rowToRecord6);
|
|
1989
2080
|
}
|
|
1990
2081
|
function closeWorkflowPhaseRun(db, input) {
|
|
1991
2082
|
db.prepare("UPDATE workflow_phases SET ended_at = ?, outcome = ? WHERE phase_run_id = ?").run(input.now, input.outcome, input.phaseRunId);
|
|
@@ -1998,7 +2089,7 @@ function hasOpenPhaseRunForIndex(db, input) {
|
|
|
1998
2089
|
}
|
|
1999
2090
|
|
|
2000
2091
|
// ../broker/dist/storage/repositories/relay-chain-repository.js
|
|
2001
|
-
function
|
|
2092
|
+
function rowToRecord7(row) {
|
|
2002
2093
|
return {
|
|
2003
2094
|
chainId: row.chain_id,
|
|
2004
2095
|
collabId: row.collab_id,
|
|
@@ -2018,7 +2109,7 @@ function insertRelayChain(db, input) {
|
|
|
2018
2109
|
}
|
|
2019
2110
|
function getRelayChain(db, chainId) {
|
|
2020
2111
|
const row = db.prepare("SELECT * FROM relay_chains WHERE chain_id = ?").get(chainId);
|
|
2021
|
-
return row ?
|
|
2112
|
+
return row ? rowToRecord7(row) : null;
|
|
2022
2113
|
}
|
|
2023
2114
|
function incrementChainRound(db, input) {
|
|
2024
2115
|
db.prepare("UPDATE relay_chains SET current_round = current_round + 1, updated_at = ? WHERE chain_id = ?").run(input.now, input.chainId);
|
|
@@ -2375,11 +2466,11 @@ function derivePlanPath(specPath, dateIso) {
|
|
|
2375
2466
|
if (!/^\d{4}-\d{2}-\d{2}/.test(dateIso)) {
|
|
2376
2467
|
throw new Error(`derivePlanPath: dateIso must start with YYYY-MM-DD, got "${dateIso}"`);
|
|
2377
2468
|
}
|
|
2378
|
-
const
|
|
2379
|
-
if (!
|
|
2469
|
+
const basename3 = specPath.split("/").pop() ?? "";
|
|
2470
|
+
if (!basename3.endsWith("-design.md")) {
|
|
2380
2471
|
throw new Error(`derivePlanPath: specPath must end with "-design.md", got "${specPath}"`);
|
|
2381
2472
|
}
|
|
2382
|
-
const withoutExt =
|
|
2473
|
+
const withoutExt = basename3.replace(/\.md$/, "");
|
|
2383
2474
|
const slug = withoutExt.replace(/-design$/, "").replace(/^\d{4}-\d{2}-\d{2}-/, "");
|
|
2384
2475
|
const date = dateIso.slice(0, 10);
|
|
2385
2476
|
return `docs/superpowers/plans/${date}-${slug}.md`;
|
|
@@ -4170,6 +4261,15 @@ function createControlService(db, events) {
|
|
|
4170
4261
|
sweepEvaluatorDiagnostics(input) {
|
|
4171
4262
|
return deleteEvaluatorDiagnosticsOlderThan(db, input.cutoffIso);
|
|
4172
4263
|
},
|
|
4264
|
+
recordTurnEventDiagnostic(input) {
|
|
4265
|
+
return insertTurnEventDiagnostic(db, input);
|
|
4266
|
+
},
|
|
4267
|
+
listTurnEventDiagnosticsByCollab(collabId2, limit) {
|
|
4268
|
+
return listTurnEventDiagnosticsByCollab(db, collabId2, limit);
|
|
4269
|
+
},
|
|
4270
|
+
sweepTurnEventDiagnostics(input) {
|
|
4271
|
+
return deleteTurnEventDiagnosticsOlderThan(db, input.cutoffIso);
|
|
4272
|
+
},
|
|
4173
4273
|
cleanupOrchestration(input) {
|
|
4174
4274
|
return cleanupOrchestrationOnShutdownTxn(db, input);
|
|
4175
4275
|
}
|
|
@@ -4310,7 +4410,7 @@ function sweepStaleCaptureLease(db, options = {}) {
|
|
|
4310
4410
|
}
|
|
4311
4411
|
|
|
4312
4412
|
// ../broker/dist/storage/apply-migrations.js
|
|
4313
|
-
var CURRENT_SCHEMA_VERSION =
|
|
4413
|
+
var CURRENT_SCHEMA_VERSION = 6;
|
|
4314
4414
|
var initMigrationSql = `
|
|
4315
4415
|
CREATE TABLE IF NOT EXISTS broker_state (
|
|
4316
4416
|
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
@@ -4825,6 +4925,37 @@ function runMigrationBody(db) {
|
|
|
4825
4925
|
if (!brokerDaemonColumns.some((column) => column.name === "evaluator_status")) {
|
|
4826
4926
|
db.exec("ALTER TABLE broker_daemon ADD COLUMN evaluator_status TEXT");
|
|
4827
4927
|
}
|
|
4928
|
+
db.exec(`
|
|
4929
|
+
CREATE TABLE IF NOT EXISTS relay_turn_event_diagnostics (
|
|
4930
|
+
event_id TEXT PRIMARY KEY,
|
|
4931
|
+
received_at TEXT NOT NULL,
|
|
4932
|
+
provider TEXT NOT NULL,
|
|
4933
|
+
workspace_id TEXT NOT NULL,
|
|
4934
|
+
cwd TEXT NOT NULL,
|
|
4935
|
+
session_or_thread_id TEXT,
|
|
4936
|
+
turn_id TEXT,
|
|
4937
|
+
workflow_active INTEGER NOT NULL DEFAULT 0,
|
|
4938
|
+
collab_id TEXT,
|
|
4939
|
+
workflow_id TEXT,
|
|
4940
|
+
chain_id TEXT,
|
|
4941
|
+
handoff_id TEXT,
|
|
4942
|
+
input_correlated INTEGER,
|
|
4943
|
+
containment_score REAL,
|
|
4944
|
+
fidelity_verdict TEXT NOT NULL DEFAULT 'n/a',
|
|
4945
|
+
defer_count INTEGER NOT NULL DEFAULT 0,
|
|
4946
|
+
action TEXT NOT NULL,
|
|
4947
|
+
message_len INTEGER NOT NULL DEFAULT 0,
|
|
4948
|
+
message_sample TEXT
|
|
4949
|
+
);
|
|
4950
|
+
CREATE INDEX IF NOT EXISTS idx_relay_turn_event_diag_collab_received
|
|
4951
|
+
ON relay_turn_event_diagnostics (collab_id, received_at DESC);
|
|
4952
|
+
CREATE INDEX IF NOT EXISTS idx_relay_turn_event_diag_handoff
|
|
4953
|
+
ON relay_turn_event_diagnostics (handoff_id);
|
|
4954
|
+
CREATE INDEX IF NOT EXISTS idx_relay_turn_event_diag_action
|
|
4955
|
+
ON relay_turn_event_diagnostics (action);
|
|
4956
|
+
CREATE INDEX IF NOT EXISTS idx_relay_turn_event_diag_received
|
|
4957
|
+
ON relay_turn_event_diagnostics (received_at);
|
|
4958
|
+
`);
|
|
4828
4959
|
}
|
|
4829
4960
|
|
|
4830
4961
|
// ../broker/dist/storage/open-database.js
|
|
@@ -4975,8 +5106,12 @@ function createDaemonHeartbeat(input) {
|
|
|
4975
5106
|
}
|
|
4976
5107
|
|
|
4977
5108
|
// ../broker/dist/runtime/diagnostics-sweep.js
|
|
5109
|
+
import { readdirSync, unlinkSync, statSync as statSync2 } from "node:fs";
|
|
5110
|
+
import { join as join2 } from "node:path";
|
|
4978
5111
|
var DEFAULT_INTERVAL_MS = 60 * 60 * 1e3;
|
|
4979
5112
|
var DEFAULT_RETENTION_DAYS = 30;
|
|
5113
|
+
var DEFAULT_EVENT_LOG_RETENTION_DAYS = 3;
|
|
5114
|
+
var TURN_EVENT_FILE_RE = /^turn-events-(\d{4}-\d{2}-\d{2})\.jsonl$/;
|
|
4980
5115
|
function resolveIntervalMs(override) {
|
|
4981
5116
|
if (override !== void 0)
|
|
4982
5117
|
return override;
|
|
@@ -4993,6 +5128,38 @@ function resolveRetentionDays(override) {
|
|
|
4993
5128
|
return Number(envVal);
|
|
4994
5129
|
return DEFAULT_RETENTION_DAYS;
|
|
4995
5130
|
}
|
|
5131
|
+
function resolveEventLogRetentionDays(override) {
|
|
5132
|
+
if (override !== void 0)
|
|
5133
|
+
return override;
|
|
5134
|
+
const raw = process.env["AI_WHISPER_EVENT_LOG_RETENTION_DAYS"];
|
|
5135
|
+
if (raw && Number.isFinite(Number(raw)) && Number(raw) > 0)
|
|
5136
|
+
return Number(raw);
|
|
5137
|
+
return DEFAULT_EVENT_LOG_RETENTION_DAYS;
|
|
5138
|
+
}
|
|
5139
|
+
function sweepTurnEventLogs(logsDir, cutoffDate) {
|
|
5140
|
+
let entries;
|
|
5141
|
+
try {
|
|
5142
|
+
entries = readdirSync(logsDir);
|
|
5143
|
+
} catch {
|
|
5144
|
+
return [];
|
|
5145
|
+
}
|
|
5146
|
+
const removed = [];
|
|
5147
|
+
for (const name of entries) {
|
|
5148
|
+
const m = TURN_EVENT_FILE_RE.exec(name);
|
|
5149
|
+
if (!m)
|
|
5150
|
+
continue;
|
|
5151
|
+
if (m[1] < cutoffDate) {
|
|
5152
|
+
const full = join2(logsDir, name);
|
|
5153
|
+
try {
|
|
5154
|
+
statSync2(full);
|
|
5155
|
+
unlinkSync(full);
|
|
5156
|
+
removed.push(full);
|
|
5157
|
+
} catch {
|
|
5158
|
+
}
|
|
5159
|
+
}
|
|
5160
|
+
}
|
|
5161
|
+
return removed;
|
|
5162
|
+
}
|
|
4996
5163
|
function createDiagnosticsSweep(deps) {
|
|
4997
5164
|
const intervalMs = resolveIntervalMs(deps.intervalMs);
|
|
4998
5165
|
const retentionDays = resolveRetentionDays(deps.retentionDays);
|
|
@@ -5002,6 +5169,12 @@ function createDiagnosticsSweep(deps) {
|
|
|
5002
5169
|
const cutoffIso = cutoff.toISOString();
|
|
5003
5170
|
deps.broker.control.sweepCaptureDiagnostics({ cutoffIso });
|
|
5004
5171
|
deps.broker.control.sweepEvaluatorDiagnostics({ cutoffIso });
|
|
5172
|
+
const eventRetentionDays = resolveEventLogRetentionDays(deps.eventLogRetentionDays);
|
|
5173
|
+
const eventCutoff = new Date(Date.now() - eventRetentionDays * 864e5);
|
|
5174
|
+
deps.broker.control.sweepTurnEventDiagnostics({ cutoffIso: eventCutoff.toISOString() });
|
|
5175
|
+
if (deps.logsDir) {
|
|
5176
|
+
sweepTurnEventLogs(deps.logsDir, eventCutoff.toISOString().slice(0, 10));
|
|
5177
|
+
}
|
|
5005
5178
|
}
|
|
5006
5179
|
return {
|
|
5007
5180
|
start() {
|
|
@@ -5020,15 +5193,15 @@ function createDiagnosticsSweep(deps) {
|
|
|
5020
5193
|
|
|
5021
5194
|
// ../broker/dist/runtime/ralph-setup.js
|
|
5022
5195
|
import { mkdirSync, writeFileSync, existsSync as existsSync2 } from "node:fs";
|
|
5023
|
-
import { join as
|
|
5196
|
+
import { join as join3 } from "node:path";
|
|
5024
5197
|
function ensureRalphWorkspace(workspaceRoot, workflowId) {
|
|
5025
5198
|
const dir = ralphRunDir(workspaceRoot, workflowId);
|
|
5026
5199
|
mkdirSync(dir, { recursive: true });
|
|
5027
|
-
const ignorePath =
|
|
5200
|
+
const ignorePath = join3(workspaceRoot, ".ai-whisper", ".gitignore");
|
|
5028
5201
|
if (!existsSync2(ignorePath)) {
|
|
5029
5202
|
writeFileSync(ignorePath, "*\n");
|
|
5030
5203
|
}
|
|
5031
|
-
const ralphIgnorePath =
|
|
5204
|
+
const ralphIgnorePath = join3(workspaceRoot, ".ai-whisper", "ralph", ".gitignore");
|
|
5032
5205
|
if (!existsSync2(ralphIgnorePath)) {
|
|
5033
5206
|
writeFileSync(ralphIgnorePath, "*\n");
|
|
5034
5207
|
}
|
|
@@ -5037,15 +5210,15 @@ function ensureRalphWorkspace(workspaceRoot, workflowId) {
|
|
|
5037
5210
|
|
|
5038
5211
|
// ../broker/dist/runtime/bugfix-setup.js
|
|
5039
5212
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, existsSync as existsSync3 } from "node:fs";
|
|
5040
|
-
import { join as
|
|
5213
|
+
import { join as join4 } from "node:path";
|
|
5041
5214
|
function ensureBugfixWorkspace(workspaceRoot, workflowId) {
|
|
5042
5215
|
const dir = bugfixRunDir(workspaceRoot, workflowId);
|
|
5043
5216
|
mkdirSync2(dir, { recursive: true });
|
|
5044
|
-
const ignorePath =
|
|
5217
|
+
const ignorePath = join4(workspaceRoot, ".ai-whisper", ".gitignore");
|
|
5045
5218
|
if (!existsSync3(ignorePath)) {
|
|
5046
5219
|
writeFileSync2(ignorePath, "*\n");
|
|
5047
5220
|
}
|
|
5048
|
-
const bugfixIgnorePath =
|
|
5221
|
+
const bugfixIgnorePath = join4(workspaceRoot, ".ai-whisper", "bugfix", ".gitignore");
|
|
5049
5222
|
if (!existsSync3(bugfixIgnorePath)) {
|
|
5050
5223
|
writeFileSync2(bugfixIgnorePath, "*\n");
|
|
5051
5224
|
}
|
|
@@ -6099,8 +6272,8 @@ function writeOwnPidToBrokerDaemon(db, input) {
|
|
|
6099
6272
|
}
|
|
6100
6273
|
|
|
6101
6274
|
// src/runtime/evaluator-config.ts
|
|
6102
|
-
import { readFileSync as readFileSync2, statSync as
|
|
6103
|
-
import { join as
|
|
6275
|
+
import { readFileSync as readFileSync2, statSync as statSync3 } from "node:fs";
|
|
6276
|
+
import { join as join5 } from "node:path";
|
|
6104
6277
|
|
|
6105
6278
|
// src/runtime/state-root.ts
|
|
6106
6279
|
import os from "node:os";
|
|
@@ -6131,7 +6304,7 @@ function warnIfLoosePerms(path2) {
|
|
|
6131
6304
|
if (process.platform === "win32") return;
|
|
6132
6305
|
let mode;
|
|
6133
6306
|
try {
|
|
6134
|
-
mode =
|
|
6307
|
+
mode = statSync3(path2).mode;
|
|
6135
6308
|
} catch {
|
|
6136
6309
|
return;
|
|
6137
6310
|
}
|
|
@@ -6159,15 +6332,15 @@ function loadEvaluatorConfig() {
|
|
|
6159
6332
|
const root = getStateRoot();
|
|
6160
6333
|
let dotenv = {};
|
|
6161
6334
|
try {
|
|
6162
|
-
dotenv = parseDotEnv(readFileSync2(
|
|
6335
|
+
dotenv = parseDotEnv(readFileSync2(join5(root, ".env"), "utf8"));
|
|
6163
6336
|
} catch (err) {
|
|
6164
6337
|
if (err.code !== "ENOENT") throw err;
|
|
6165
6338
|
}
|
|
6166
6339
|
const envGet = (k) => process.env[k] ?? dotenv[k];
|
|
6167
|
-
const authPath =
|
|
6340
|
+
const authPath = join5(root, "auth.json");
|
|
6168
6341
|
warnIfLoosePerms(authPath);
|
|
6169
6342
|
const auth = readJsonFile(authPath, "auth.json");
|
|
6170
|
-
const config = readJsonFile(
|
|
6343
|
+
const config = readJsonFile(join5(root, "config.json"), "config.json");
|
|
6171
6344
|
const evalCfg = config?.evaluator ?? {};
|
|
6172
6345
|
const evalOllama = evalCfg.ollama ?? {};
|
|
6173
6346
|
const provider = (envGet("AI_WHISPER_EVALUATOR_PROVIDER") ?? evalCfg.provider) === "ollama" ? "ollama" : "anthropic";
|