@exla/rudder 0.0.0-stage → 3.4.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/LICENSE +100 -0
- package/README.md +733 -2
- package/assets/rudder.icns +0 -0
- package/assets/sounds/NOTICE.md +8 -0
- package/assets/sounds/ping.mp3 +0 -0
- package/dist/agent-attention.d.ts +5 -0
- package/dist/agent-attention.js +54 -0
- package/dist/agent-attention.js.map +1 -0
- package/dist/analytics.d.ts +36 -0
- package/dist/analytics.js +178 -0
- package/dist/analytics.js.map +1 -0
- package/dist/attach-session.d.ts +91 -0
- package/dist/attach-session.js +290 -0
- package/dist/attach-session.js.map +1 -0
- package/dist/auth.d.ts +36 -0
- package/dist/auth.js +397 -0
- package/dist/auth.js.map +1 -0
- package/dist/backends.d.ts +3 -0
- package/dist/backends.js +638 -0
- package/dist/backends.js.map +1 -0
- package/dist/board/board.css +1 -0
- package/dist/board/board.js +2 -0
- package/dist/board/daemon.d.ts +39 -0
- package/dist/board/daemon.js +1510 -0
- package/dist/board/daemon.js.map +1 -0
- package/dist/brain.d.ts +24 -0
- package/dist/brain.js +244 -0
- package/dist/brain.js.map +1 -0
- package/dist/bus.d.ts +9 -0
- package/dist/bus.js +23 -0
- package/dist/bus.js.map +1 -0
- package/dist/checkout-sync.d.ts +35 -0
- package/dist/checkout-sync.js +247 -0
- package/dist/checkout-sync.js.map +1 -0
- package/dist/cloud.d.ts +51 -0
- package/dist/cloud.js +4672 -0
- package/dist/cloud.js.map +1 -0
- package/dist/codex-binary.d.ts +12 -0
- package/dist/codex-binary.js +184 -0
- package/dist/codex-binary.js.map +1 -0
- package/dist/context-audit.d.ts +21 -0
- package/dist/context-audit.js +109 -0
- package/dist/context-audit.js.map +1 -0
- package/dist/daemon.d.ts +27 -0
- package/dist/daemon.js +203 -0
- package/dist/daemon.js.map +1 -0
- package/dist/effort.d.ts +9 -0
- package/dist/effort.js +72 -0
- package/dist/effort.js.map +1 -0
- package/dist/feedback.d.ts +46 -0
- package/dist/feedback.js +173 -0
- package/dist/feedback.js.map +1 -0
- package/dist/gc.d.ts +3 -0
- package/dist/gc.js +262 -0
- package/dist/gc.js.map +1 -0
- package/dist/git.d.ts +31 -0
- package/dist/git.js +455 -0
- package/dist/git.js.map +1 -0
- package/dist/goal.d.ts +33 -0
- package/dist/goal.js +95 -0
- package/dist/goal.js.map +1 -0
- package/dist/graph.d.ts +93 -0
- package/dist/graph.js +372 -0
- package/dist/graph.js.map +1 -0
- package/dist/handoff.d.ts +110 -0
- package/dist/handoff.js +565 -0
- package/dist/handoff.js.map +1 -0
- package/dist/improve/advisor.d.ts +10 -0
- package/dist/improve/advisor.js +115 -0
- package/dist/improve/advisor.js.map +1 -0
- package/dist/improve/collect.d.ts +49 -0
- package/dist/improve/collect.js +274 -0
- package/dist/improve/collect.js.map +1 -0
- package/dist/improve/gate.d.ts +17 -0
- package/dist/improve/gate.js +60 -0
- package/dist/improve/gate.js.map +1 -0
- package/dist/improve/index.d.ts +9 -0
- package/dist/improve/index.js +376 -0
- package/dist/improve/index.js.map +1 -0
- package/dist/improve/judge.d.ts +32 -0
- package/dist/improve/judge.js +114 -0
- package/dist/improve/judge.js.map +1 -0
- package/dist/improve/mine.d.ts +31 -0
- package/dist/improve/mine.js +192 -0
- package/dist/improve/mine.js.map +1 -0
- package/dist/improve/propose.d.ts +51 -0
- package/dist/improve/propose.js +150 -0
- package/dist/improve/propose.js.map +1 -0
- package/dist/improve/rank.d.ts +16 -0
- package/dist/improve/rank.js +49 -0
- package/dist/improve/rank.js.map +1 -0
- package/dist/improve/schedule.d.ts +1 -0
- package/dist/improve/schedule.js +95 -0
- package/dist/improve/schedule.js.map +1 -0
- package/dist/improve/ship.d.ts +25 -0
- package/dist/improve/ship.js +82 -0
- package/dist/improve/ship.js.map +1 -0
- package/dist/improve/state.d.ts +157 -0
- package/dist/improve/state.js +264 -0
- package/dist/improve/state.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/dist/jj-binary.d.ts +36 -0
- package/dist/jj-binary.js +143 -0
- package/dist/jj-binary.js.map +1 -0
- package/dist/jj.d.ts +163 -0
- package/dist/jj.js +926 -0
- package/dist/jj.js.map +1 -0
- package/dist/logger.d.ts +22 -0
- package/dist/logger.js +110 -0
- package/dist/logger.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.js +1366 -0
- package/dist/main.js.map +1 -0
- package/dist/migration.d.ts +82 -0
- package/dist/migration.js +198 -0
- package/dist/migration.js.map +1 -0
- package/dist/models.d.ts +9 -0
- package/dist/models.js +623 -0
- package/dist/models.js.map +1 -0
- package/dist/move-home.d.ts +82 -0
- package/dist/move-home.js +472 -0
- package/dist/move-home.js.map +1 -0
- package/dist/native/darwin-arm64/rudder-native +0 -0
- package/dist/native/darwin-x64/rudder-native +0 -0
- package/dist/native/linux-x64/rudder-native +0 -0
- package/dist/native-agents.d.ts +8 -0
- package/dist/native-agents.js +178 -0
- package/dist/native-agents.js.map +1 -0
- package/dist/native-binary.d.ts +4 -0
- package/dist/native-binary.js +140 -0
- package/dist/native-binary.js.map +1 -0
- package/dist/onboarding.d.ts +11 -0
- package/dist/onboarding.js +111 -0
- package/dist/onboarding.js.map +1 -0
- package/dist/paste-bridge.d.ts +36 -0
- package/dist/paste-bridge.js +279 -0
- package/dist/paste-bridge.js.map +1 -0
- package/dist/plan-mode.d.ts +2 -0
- package/dist/plan-mode.js +22 -0
- package/dist/plan-mode.js.map +1 -0
- package/dist/planner.d.ts +27 -0
- package/dist/planner.js +587 -0
- package/dist/planner.js.map +1 -0
- package/dist/predict.d.ts +67 -0
- package/dist/predict.js +369 -0
- package/dist/predict.js.map +1 -0
- package/dist/qr.d.ts +13 -0
- package/dist/qr.js +377 -0
- package/dist/qr.js.map +1 -0
- package/dist/report.d.ts +74 -0
- package/dist/report.js +412 -0
- package/dist/report.js.map +1 -0
- package/dist/rudder-md.d.ts +33 -0
- package/dist/rudder-md.js +142 -0
- package/dist/rudder-md.js.map +1 -0
- package/dist/run-manager.d.ts +62 -0
- package/dist/run-manager.js +1400 -0
- package/dist/run-manager.js.map +1 -0
- package/dist/scheduler.d.ts +128 -0
- package/dist/scheduler.js +955 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/state.d.ts +127 -0
- package/dist/state.js +704 -0
- package/dist/state.js.map +1 -0
- package/dist/surfaces.d.ts +91 -0
- package/dist/surfaces.js +460 -0
- package/dist/surfaces.js.map +1 -0
- package/dist/task-summary.d.ts +30 -0
- package/dist/task-summary.js +472 -0
- package/dist/task-summary.js.map +1 -0
- package/dist/types.d.ts +492 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/usage.d.ts +198 -0
- package/dist/usage.js +830 -0
- package/dist/usage.js.map +1 -0
- package/dist/util.d.ts +73 -0
- package/dist/util.js +399 -0
- package/dist/util.js.map +1 -0
- package/dist/version-check.d.ts +16 -0
- package/dist/version-check.js +269 -0
- package/dist/version-check.js.map +1 -0
- package/package.json +68 -4
- package/scripts/copy-native.mjs +89 -0
- package/scripts/postinstall.mjs +34 -0
package/dist/report.js
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fsp from "node:fs/promises";
|
|
3
|
+
import { readJson, nowIso, slugPrefix, } from "./util.js";
|
|
4
|
+
const RUDDER_DIR = ".rudder";
|
|
5
|
+
const RUNS_DIR = "runs";
|
|
6
|
+
/**
|
|
7
|
+
* Load all run records from .rudder/runs/
|
|
8
|
+
*/
|
|
9
|
+
export async function loadAllRuns(repoRoot) {
|
|
10
|
+
const runsPath = path.join(repoRoot, RUDDER_DIR, RUNS_DIR);
|
|
11
|
+
try {
|
|
12
|
+
const entries = await fsp.readdir(runsPath, { withFileTypes: true });
|
|
13
|
+
const runs = [];
|
|
14
|
+
for (const entry of entries) {
|
|
15
|
+
if (!entry.isDirectory())
|
|
16
|
+
continue;
|
|
17
|
+
const runJsonPath = path.join(runsPath, entry.name, "run.json");
|
|
18
|
+
const run = await readJson(runJsonPath);
|
|
19
|
+
if (run) {
|
|
20
|
+
runs.push(run);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return runs.sort((a, b) => {
|
|
24
|
+
const dateA = new Date(b.createdAt);
|
|
25
|
+
const dateB = new Date(a.createdAt);
|
|
26
|
+
return dateA.getTime() - dateB.getTime();
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
if (e.code === "ENOENT") {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
throw e;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Calculate metrics from a run record
|
|
38
|
+
*/
|
|
39
|
+
function runToMetrics(run) {
|
|
40
|
+
const created = new Date(run.createdAt);
|
|
41
|
+
const updated = new Date(run.updatedAt);
|
|
42
|
+
const duration = (updated.getTime() - created.getTime()) / 1000;
|
|
43
|
+
return {
|
|
44
|
+
id: run.id,
|
|
45
|
+
task: run.task,
|
|
46
|
+
taskSummary: run.taskSummary || run.taskSummaryLlm ? "auto-summarized" : undefined,
|
|
47
|
+
backend: run.backend,
|
|
48
|
+
model: run.model,
|
|
49
|
+
status: run.status,
|
|
50
|
+
createdAt: run.createdAt,
|
|
51
|
+
updatedAt: run.updatedAt,
|
|
52
|
+
duration,
|
|
53
|
+
durationReadable: formatDuration(duration),
|
|
54
|
+
inputTokens: run.tokens?.input,
|
|
55
|
+
outputTokens: run.tokens?.output,
|
|
56
|
+
totalTokens: (run.tokens?.input || 0) + (run.tokens?.output || 0) || undefined,
|
|
57
|
+
mergeStatus: run.merge?.status,
|
|
58
|
+
workspacePath: run.workspace?.path,
|
|
59
|
+
inWorkspace: run.workspace?.enabled,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Format duration in seconds to human-readable string
|
|
64
|
+
*/
|
|
65
|
+
function formatDuration(seconds) {
|
|
66
|
+
if (seconds < 60)
|
|
67
|
+
return `${Math.round(seconds)}s`;
|
|
68
|
+
if (seconds < 3600)
|
|
69
|
+
return `${Math.round(seconds / 60)}m`;
|
|
70
|
+
const hours = Math.round(seconds / 3600);
|
|
71
|
+
const mins = Math.round((seconds % 3600) / 60);
|
|
72
|
+
return mins > 0 ? `${hours}h${mins}m` : `${hours}h`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Filter runs based on options
|
|
76
|
+
*/
|
|
77
|
+
function filterRuns(runs, options) {
|
|
78
|
+
let filtered = runs;
|
|
79
|
+
// Status filter
|
|
80
|
+
if (options.status) {
|
|
81
|
+
const statuses = Array.isArray(options.status)
|
|
82
|
+
? options.status
|
|
83
|
+
: [options.status];
|
|
84
|
+
filtered = filtered.filter(r => statuses.includes(r.status));
|
|
85
|
+
}
|
|
86
|
+
// Backend filter
|
|
87
|
+
if (options.backend) {
|
|
88
|
+
const backends = Array.isArray(options.backend)
|
|
89
|
+
? options.backend
|
|
90
|
+
: [options.backend];
|
|
91
|
+
filtered = filtered.filter(r => backends.includes(r.backend));
|
|
92
|
+
}
|
|
93
|
+
// Model filter
|
|
94
|
+
if (options.model) {
|
|
95
|
+
filtered = filtered.filter(r => r.model?.toLowerCase().includes(options.model.toLowerCase()));
|
|
96
|
+
}
|
|
97
|
+
// Date range filter
|
|
98
|
+
if (options.after) {
|
|
99
|
+
filtered = filtered.filter(r => r.createdAt >= options.after);
|
|
100
|
+
}
|
|
101
|
+
if (options.before) {
|
|
102
|
+
filtered = filtered.filter(r => r.createdAt <= options.before);
|
|
103
|
+
}
|
|
104
|
+
// Limit
|
|
105
|
+
if (options.limit) {
|
|
106
|
+
filtered = filtered.slice(0, options.limit);
|
|
107
|
+
}
|
|
108
|
+
return filtered;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Sort runs by specified column
|
|
112
|
+
*/
|
|
113
|
+
function sortRuns(runs, options) {
|
|
114
|
+
const metrics = runs.map(runToMetrics);
|
|
115
|
+
const sortBy = options.sortBy || "created";
|
|
116
|
+
const reverse = options.reverse || false;
|
|
117
|
+
const sortFn = (a, b) => {
|
|
118
|
+
let cmp = 0;
|
|
119
|
+
switch (sortBy) {
|
|
120
|
+
case "created":
|
|
121
|
+
cmp = a.createdAt.localeCompare(b.createdAt);
|
|
122
|
+
break;
|
|
123
|
+
case "updated":
|
|
124
|
+
cmp = a.updatedAt.localeCompare(b.updatedAt);
|
|
125
|
+
break;
|
|
126
|
+
case "duration":
|
|
127
|
+
cmp = (a.duration || 0) - (b.duration || 0);
|
|
128
|
+
break;
|
|
129
|
+
case "tokens":
|
|
130
|
+
cmp = (a.totalTokens || 0) - (b.totalTokens || 0);
|
|
131
|
+
break;
|
|
132
|
+
case "status":
|
|
133
|
+
cmp = a.status.localeCompare(b.status);
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
cmp = 0;
|
|
137
|
+
}
|
|
138
|
+
return reverse ? -cmp : cmp;
|
|
139
|
+
};
|
|
140
|
+
return metrics.sort(sortFn);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Generate summary statistics
|
|
144
|
+
*/
|
|
145
|
+
function generateSummary(runs) {
|
|
146
|
+
const statusCounts = {
|
|
147
|
+
created: 0,
|
|
148
|
+
running: 0,
|
|
149
|
+
steering: 0,
|
|
150
|
+
verifying: 0,
|
|
151
|
+
completed: 0,
|
|
152
|
+
failed: 0,
|
|
153
|
+
cancelled: 0,
|
|
154
|
+
paused: 0,
|
|
155
|
+
orphaned: 0,
|
|
156
|
+
migrated: 0,
|
|
157
|
+
"merge-conflict": 0,
|
|
158
|
+
merged: 0,
|
|
159
|
+
};
|
|
160
|
+
const backendCounts = {
|
|
161
|
+
claude: 0,
|
|
162
|
+
codex: 0,
|
|
163
|
+
acpx: 0,
|
|
164
|
+
opencode: 0,
|
|
165
|
+
};
|
|
166
|
+
let totalDuration = 0;
|
|
167
|
+
let durableRuns = 0;
|
|
168
|
+
let totalTokens = 0;
|
|
169
|
+
let tokensRuns = 0;
|
|
170
|
+
let mergeConflicts = 0;
|
|
171
|
+
let successful = 0;
|
|
172
|
+
for (const run of runs) {
|
|
173
|
+
statusCounts[run.status]++;
|
|
174
|
+
backendCounts[run.backend]++;
|
|
175
|
+
const duration = (new Date(run.updatedAt).getTime() -
|
|
176
|
+
new Date(run.createdAt).getTime()) /
|
|
177
|
+
1000;
|
|
178
|
+
if (run.status === "completed" || run.status === "merged") {
|
|
179
|
+
totalDuration += duration;
|
|
180
|
+
durableRuns++;
|
|
181
|
+
successful++;
|
|
182
|
+
}
|
|
183
|
+
else if (run.status === "failed" ||
|
|
184
|
+
run.status === "cancelled" ||
|
|
185
|
+
run.status === "orphaned") {
|
|
186
|
+
// Counts in denominator but not numerator
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
// In-flight runs might finish, don't count yet
|
|
190
|
+
}
|
|
191
|
+
if (run.tokens) {
|
|
192
|
+
totalTokens += (run.tokens.input || 0) + (run.tokens.output || 0);
|
|
193
|
+
tokensRuns++;
|
|
194
|
+
}
|
|
195
|
+
if (run.hadMergeConflict || run.merge?.status === "conflict") {
|
|
196
|
+
mergeConflicts++;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const timeRange = runs.length > 0
|
|
200
|
+
? {
|
|
201
|
+
earliest: runs[runs.length - 1].createdAt,
|
|
202
|
+
latest: runs[0].createdAt,
|
|
203
|
+
}
|
|
204
|
+
: undefined;
|
|
205
|
+
return {
|
|
206
|
+
totalRuns: runs.length,
|
|
207
|
+
statusCounts,
|
|
208
|
+
backendCounts,
|
|
209
|
+
avgDuration: durableRuns > 0 ? totalDuration / durableRuns : undefined,
|
|
210
|
+
totalTokens: totalTokens > 0 ? totalTokens : undefined,
|
|
211
|
+
avgTokens: tokensRuns > 0 ? totalTokens / tokensRuns : undefined,
|
|
212
|
+
mergeConflictRate: runs.length > 0 ? (mergeConflicts / runs.length) * 100 : undefined,
|
|
213
|
+
successRate: runs.length > 0
|
|
214
|
+
? ((successful / runs.length) * 100)
|
|
215
|
+
: undefined,
|
|
216
|
+
timeRange,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Format as table (default)
|
|
221
|
+
*/
|
|
222
|
+
function formatTable(metrics, summary) {
|
|
223
|
+
const lines = [];
|
|
224
|
+
// Header
|
|
225
|
+
lines.push("ID | Task (first 30) | Backend | Model | Status | Duration | Tokens");
|
|
226
|
+
lines.push("-".repeat(145));
|
|
227
|
+
// Rows
|
|
228
|
+
for (const m of metrics) {
|
|
229
|
+
const taskDisplay = (m.task || "").substring(0, 30).padEnd(24);
|
|
230
|
+
const modelDisplay = (m.model || "").substring(0, 17).padEnd(17);
|
|
231
|
+
const tokens = m.totalTokens ? String(m.totalTokens.toLocaleString()) : "—";
|
|
232
|
+
const row = [
|
|
233
|
+
slugPrefix(m.id, "id", 20).padEnd(20),
|
|
234
|
+
taskDisplay,
|
|
235
|
+
m.backend.padEnd(7),
|
|
236
|
+
modelDisplay,
|
|
237
|
+
m.status.padEnd(16),
|
|
238
|
+
String(m.durationReadable || "—").padEnd(11),
|
|
239
|
+
tokens,
|
|
240
|
+
].join(" | ");
|
|
241
|
+
lines.push(row);
|
|
242
|
+
}
|
|
243
|
+
// Summary
|
|
244
|
+
if (summary) {
|
|
245
|
+
lines.push("");
|
|
246
|
+
lines.push("SUMMARY");
|
|
247
|
+
lines.push("-".repeat(145));
|
|
248
|
+
lines.push(`Total runs: ${summary.totalRuns}`);
|
|
249
|
+
lines.push(`Statuses: ` + Object.entries(summary.statusCounts)
|
|
250
|
+
.filter(([_, count]) => count > 0)
|
|
251
|
+
.map(([status, count]) => `${status}=${count}`)
|
|
252
|
+
.join(", "));
|
|
253
|
+
lines.push(`Backends: ` + Object.entries(summary.backendCounts)
|
|
254
|
+
.filter(([_, count]) => count > 0)
|
|
255
|
+
.map(([backend, count]) => `${backend}=${count}`)
|
|
256
|
+
.join(", "));
|
|
257
|
+
if (summary.avgDuration !== undefined) {
|
|
258
|
+
lines.push(`Avg duration (completed): ${formatDuration(summary.avgDuration)}`);
|
|
259
|
+
}
|
|
260
|
+
if (summary.totalTokens !== undefined) {
|
|
261
|
+
lines.push(`Total tokens: ${summary.totalTokens.toLocaleString()}`);
|
|
262
|
+
}
|
|
263
|
+
if (summary.avgTokens !== undefined) {
|
|
264
|
+
lines.push(`Avg tokens/run: ${Math.round(summary.avgTokens).toLocaleString()}`);
|
|
265
|
+
}
|
|
266
|
+
if (summary.mergeConflictRate !== undefined) {
|
|
267
|
+
lines.push(`Merge conflict rate: ${summary.mergeConflictRate.toFixed(1)}%`);
|
|
268
|
+
}
|
|
269
|
+
if (summary.successRate !== undefined) {
|
|
270
|
+
lines.push(`Success rate: ${summary.successRate.toFixed(1)}%`);
|
|
271
|
+
}
|
|
272
|
+
if (summary.timeRange) {
|
|
273
|
+
lines.push(`Time range: ${summary.timeRange.earliest} to ${summary.timeRange.latest}`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return lines.join("\n");
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Format as JSON
|
|
280
|
+
*/
|
|
281
|
+
function formatJson(metrics, summary) {
|
|
282
|
+
const output = {
|
|
283
|
+
runs: metrics,
|
|
284
|
+
...(summary && { summary }),
|
|
285
|
+
};
|
|
286
|
+
return JSON.stringify(output, null, 2);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Format as Markdown
|
|
290
|
+
*/
|
|
291
|
+
function formatMarkdown(metrics, summary) {
|
|
292
|
+
const lines = [];
|
|
293
|
+
lines.push("# Rudder Runs Report");
|
|
294
|
+
lines.push("");
|
|
295
|
+
lines.push(`Generated: ${nowIso()}`);
|
|
296
|
+
lines.push("");
|
|
297
|
+
if (summary) {
|
|
298
|
+
lines.push("## Summary");
|
|
299
|
+
lines.push("");
|
|
300
|
+
lines.push(`- **Total runs:** ${summary.totalRuns}`);
|
|
301
|
+
if (summary.avgDuration !== undefined) {
|
|
302
|
+
lines.push(`- **Avg duration:** ${formatDuration(summary.avgDuration)}`);
|
|
303
|
+
}
|
|
304
|
+
if (summary.totalTokens !== undefined) {
|
|
305
|
+
lines.push(`- **Total tokens:** ${summary.totalTokens.toLocaleString()}`);
|
|
306
|
+
}
|
|
307
|
+
if (summary.avgTokens !== undefined) {
|
|
308
|
+
lines.push(`- **Avg tokens per run:** ${Math.round(summary.avgTokens).toLocaleString()}`);
|
|
309
|
+
}
|
|
310
|
+
if (summary.successRate !== undefined) {
|
|
311
|
+
lines.push(`- **Success rate:** ${summary.successRate.toFixed(1)}%`);
|
|
312
|
+
}
|
|
313
|
+
if (summary.mergeConflictRate !== undefined) {
|
|
314
|
+
lines.push(`- **Merge conflict rate:** ${summary.mergeConflictRate.toFixed(1)}%`);
|
|
315
|
+
}
|
|
316
|
+
lines.push("");
|
|
317
|
+
lines.push("### Status Breakdown");
|
|
318
|
+
lines.push("");
|
|
319
|
+
for (const [status, count] of Object.entries(summary.statusCounts)) {
|
|
320
|
+
if (count > 0) {
|
|
321
|
+
lines.push(`- ${status}: ${count}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
lines.push("");
|
|
325
|
+
lines.push("### Backend Breakdown");
|
|
326
|
+
lines.push("");
|
|
327
|
+
for (const [backend, count] of Object.entries(summary.backendCounts)) {
|
|
328
|
+
if (count > 0) {
|
|
329
|
+
lines.push(`- ${backend}: ${count}`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
lines.push("");
|
|
333
|
+
}
|
|
334
|
+
lines.push("## Runs");
|
|
335
|
+
lines.push("");
|
|
336
|
+
lines.push("| ID | Task | Backend | Model | Status | Duration | Tokens |");
|
|
337
|
+
lines.push("|---|---|---|---|---|---|---|");
|
|
338
|
+
for (const m of metrics) {
|
|
339
|
+
const id = slugPrefix(m.id, "id", 8);
|
|
340
|
+
const task = (m.task || "").substring(0, 40).replace(/\|/g, "\\|");
|
|
341
|
+
const model = (m.model || "—").substring(0, 20);
|
|
342
|
+
const tokens = m.totalTokens
|
|
343
|
+
? String(m.totalTokens.toLocaleString())
|
|
344
|
+
: "—";
|
|
345
|
+
lines.push(`| ${id} | ${task} | ${m.backend} | ${model} | ${m.status} | ${String(m.durationReadable || "—")} | ${tokens} |`);
|
|
346
|
+
}
|
|
347
|
+
return lines.join("\n");
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Format as CSV
|
|
351
|
+
*/
|
|
352
|
+
function formatCsv(metrics) {
|
|
353
|
+
const lines = [];
|
|
354
|
+
// Header
|
|
355
|
+
lines.push("ID,Task,Backend,Model,Status,CreatedAt,UpdatedAt,Duration(s),InputTokens,OutputTokens,TotalTokens,MergeStatus,InWorkspace");
|
|
356
|
+
// Rows
|
|
357
|
+
for (const m of metrics) {
|
|
358
|
+
const task = (m.task || "").replace(/"/g, '""'); // CSV escape
|
|
359
|
+
const row = [
|
|
360
|
+
m.id,
|
|
361
|
+
`"${task}"`,
|
|
362
|
+
m.backend,
|
|
363
|
+
m.model || "",
|
|
364
|
+
m.status,
|
|
365
|
+
m.createdAt,
|
|
366
|
+
m.updatedAt,
|
|
367
|
+
m.duration?.toFixed(0) || "",
|
|
368
|
+
m.inputTokens || "",
|
|
369
|
+
m.outputTokens || "",
|
|
370
|
+
m.totalTokens || "",
|
|
371
|
+
m.mergeStatus || "",
|
|
372
|
+
m.inWorkspace ? "yes" : "no",
|
|
373
|
+
];
|
|
374
|
+
lines.push(row.join(","));
|
|
375
|
+
}
|
|
376
|
+
return lines.join("\n");
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Generate and output a report
|
|
380
|
+
*/
|
|
381
|
+
export async function generateReport(repoRoot, options = {}) {
|
|
382
|
+
const runs = await loadAllRuns(repoRoot);
|
|
383
|
+
const filtered = filterRuns(runs, options);
|
|
384
|
+
const sorted = sortRuns(filtered, options);
|
|
385
|
+
const summary = options.summary !== false ? generateSummary(filtered) : undefined;
|
|
386
|
+
const format = options.format || "table";
|
|
387
|
+
switch (format) {
|
|
388
|
+
case "json":
|
|
389
|
+
return formatJson(sorted, summary);
|
|
390
|
+
case "markdown":
|
|
391
|
+
return formatMarkdown(sorted, summary);
|
|
392
|
+
case "csv":
|
|
393
|
+
return formatCsv(sorted);
|
|
394
|
+
case "table":
|
|
395
|
+
default:
|
|
396
|
+
return formatTable(sorted, summary);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Print report to stdout
|
|
401
|
+
*/
|
|
402
|
+
export async function printReport(repoRoot, options = {}) {
|
|
403
|
+
try {
|
|
404
|
+
const report = await generateReport(repoRoot, options);
|
|
405
|
+
console.log(report);
|
|
406
|
+
}
|
|
407
|
+
catch (e) {
|
|
408
|
+
console.error(`Failed to generate report: ${e instanceof Error ? e.message : String(e)}`);
|
|
409
|
+
process.exit(1);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export declare function mergeGeneratedRudderMd(existing: string, generated: string): string;
|
|
2
|
+
export declare function latestRudderPlanBlock(text: string): string | null;
|
|
3
|
+
export declare function rudderMdLockPath(repoRoot: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* Generic cross-process advisory lock: mkdir is atomic across processes, so an
|
|
6
|
+
* existing lock dir means "held". Best-effort by design: a lock older than
|
|
7
|
+
* staleMs is treated as a crashed holder and taken over, and if acquisition
|
|
8
|
+
* never succeeds within waitMs the caller proceeds unlocked, so a crashed
|
|
9
|
+
* holder can never deadlock or fail a writer. NOT re-entrant: never nest two
|
|
10
|
+
* sections taking the same lock dir.
|
|
11
|
+
*/
|
|
12
|
+
export declare function withDirLock<T>(lockDir: string, fn: () => Promise<T>, opts?: {
|
|
13
|
+
waitMs?: number;
|
|
14
|
+
staleMs?: number;
|
|
15
|
+
}): Promise<T>;
|
|
16
|
+
/**
|
|
17
|
+
* Cross-process advisory lock around RUDDER.md read-modify-write. The Rust
|
|
18
|
+
* TUI (acquire_rudder_md_lock in gitio.rs takes the same lock dir), CLI
|
|
19
|
+
* invocations, the daemon, and the orchestrator agent all write the file;
|
|
20
|
+
* serializing the merge keeps interleavings from dropping a freshly written
|
|
21
|
+
* DAG or control marker.
|
|
22
|
+
*/
|
|
23
|
+
export declare function withRudderMdLock<T>(repoRoot: string, fn: () => Promise<T>): Promise<T>;
|
|
24
|
+
export declare function integrationLockPath(repoRoot: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Cross-process lock for the INTEGRATION critical section (merging a run/node
|
|
27
|
+
* into the shared workspace @). withSchedulerLock serializes only within one
|
|
28
|
+
* process; a `rudder merge` CLI invocation and a daemon tick are separate
|
|
29
|
+
* processes operating on the same jj workspace, and concurrent merges there
|
|
30
|
+
* stack merge changes on a moving @. Longer windows than the RUDDER.md lock
|
|
31
|
+
* because a merge legitimately takes seconds.
|
|
32
|
+
*/
|
|
33
|
+
export declare function withIntegrationLock<T>(repoRoot: string, fn: () => Promise<T>): Promise<T>;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import fsp from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const RUDDER_GENERATED_START = "<!-- RUDDER_GENERATED_START -->";
|
|
4
|
+
const RUDDER_GENERATED_END = "<!-- RUDDER_GENERATED_END -->";
|
|
5
|
+
const PLAN_START = "RUDDER_PLAN_TASKS_START";
|
|
6
|
+
const PLAN_END = "RUDDER_PLAN_TASKS_END";
|
|
7
|
+
// A well-formed generated block. Non-greedy + global so repeated blocks (from a
|
|
8
|
+
// prior corruption) are each removed instead of swallowing orchestrator content
|
|
9
|
+
// between them.
|
|
10
|
+
const GENERATED_BLOCK_RE = new RegExp(`${RUDDER_GENERATED_START.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${RUDDER_GENERATED_END.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`, "g");
|
|
11
|
+
// Remove every well-formed generated block, then any orphaned single markers a
|
|
12
|
+
// stray literal (e.g. in orchestrator prose) or torn write left behind, so the
|
|
13
|
+
// rebuilt file always carries exactly one marker pair.
|
|
14
|
+
function stripGeneratedMarkers(text) {
|
|
15
|
+
return text
|
|
16
|
+
.replace(GENERATED_BLOCK_RE, "")
|
|
17
|
+
.split(RUDDER_GENERATED_START)
|
|
18
|
+
.join("")
|
|
19
|
+
.split(RUDDER_GENERATED_END)
|
|
20
|
+
.join("");
|
|
21
|
+
}
|
|
22
|
+
export function mergeGeneratedRudderMd(existing, generated) {
|
|
23
|
+
const wrapped = `${RUDDER_GENERATED_START}\n${generated.trimEnd()}\n${RUDDER_GENERATED_END}\n`;
|
|
24
|
+
const startIdx = existing.indexOf(RUDDER_GENERATED_START);
|
|
25
|
+
const endIdx = existing.indexOf(RUDDER_GENERATED_END);
|
|
26
|
+
if (startIdx >= 0 || endIdx >= 0) {
|
|
27
|
+
// The fresh block goes where the first marker sat so it keeps its position
|
|
28
|
+
// relative to orchestrator content; everything before that point cannot
|
|
29
|
+
// contain markers and is preserved verbatim.
|
|
30
|
+
const insertAt = startIdx >= 0 && (endIdx < 0 || startIdx < endIdx) ? startIdx : endIdx;
|
|
31
|
+
const prefix = existing.slice(0, insertAt);
|
|
32
|
+
const suffix = stripGeneratedMarkers(existing.slice(insertAt));
|
|
33
|
+
// suffix.trim() (not trimStart) keeps repeated renders byte-identical:
|
|
34
|
+
// trailing newlines would otherwise accumulate one per merge.
|
|
35
|
+
return [prefix.trimEnd(), wrapped.trimEnd(), suffix.trim()].filter(Boolean).join("\n\n") + "\n";
|
|
36
|
+
}
|
|
37
|
+
const plan = latestRudderPlanBlock(existing);
|
|
38
|
+
return plan ? `${wrapped}\n## Orchestrator-authored plan\n\n${plan}\n` : wrapped;
|
|
39
|
+
}
|
|
40
|
+
export function latestRudderPlanBlock(text) {
|
|
41
|
+
let current = null;
|
|
42
|
+
let latest = null;
|
|
43
|
+
for (const line of text.replace(/\r/g, "").split("\n")) {
|
|
44
|
+
const trimmed = line.trim();
|
|
45
|
+
if (trimmed === PLAN_START) {
|
|
46
|
+
current = [PLAN_START];
|
|
47
|
+
}
|
|
48
|
+
else if (trimmed === PLAN_END) {
|
|
49
|
+
if (current) {
|
|
50
|
+
current.push(PLAN_END);
|
|
51
|
+
latest = current.join("\n");
|
|
52
|
+
}
|
|
53
|
+
current = null;
|
|
54
|
+
}
|
|
55
|
+
else if (current) {
|
|
56
|
+
current.push(line);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return latest;
|
|
60
|
+
}
|
|
61
|
+
const LOCK_RETRY_MS = 50;
|
|
62
|
+
const LOCK_WAIT_MS = 2_000;
|
|
63
|
+
const LOCK_STALE_MS = 10_000;
|
|
64
|
+
export function rudderMdLockPath(repoRoot) {
|
|
65
|
+
return path.join(repoRoot, ".rudder", "rudder-md.lock");
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Generic cross-process advisory lock: mkdir is atomic across processes, so an
|
|
69
|
+
* existing lock dir means "held". Best-effort by design: a lock older than
|
|
70
|
+
* staleMs is treated as a crashed holder and taken over, and if acquisition
|
|
71
|
+
* never succeeds within waitMs the caller proceeds unlocked, so a crashed
|
|
72
|
+
* holder can never deadlock or fail a writer. NOT re-entrant: never nest two
|
|
73
|
+
* sections taking the same lock dir.
|
|
74
|
+
*/
|
|
75
|
+
export async function withDirLock(lockDir, fn, opts) {
|
|
76
|
+
const waitMs = opts?.waitMs ?? LOCK_WAIT_MS;
|
|
77
|
+
const staleMs = opts?.staleMs ?? LOCK_STALE_MS;
|
|
78
|
+
let acquired = false;
|
|
79
|
+
const deadline = Date.now() + waitMs;
|
|
80
|
+
try {
|
|
81
|
+
await fsp.mkdir(path.dirname(lockDir), { recursive: true }).catch(() => undefined);
|
|
82
|
+
for (;;) {
|
|
83
|
+
try {
|
|
84
|
+
// recursive:false so an existing dir (= lock held) throws.
|
|
85
|
+
await fsp.mkdir(lockDir);
|
|
86
|
+
acquired = true;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
const age = await fsp
|
|
91
|
+
.stat(lockDir)
|
|
92
|
+
.then((st) => Date.now() - st.mtimeMs)
|
|
93
|
+
.catch(() => null);
|
|
94
|
+
if (age !== null && age > staleMs) {
|
|
95
|
+
// Holder likely crashed mid-write; take the lock over.
|
|
96
|
+
await fsp.rm(lockDir, { recursive: true, force: true }).catch(() => undefined);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (Date.now() >= deadline) {
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_MS));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Lock machinery must never fail the caller; fall through unlocked.
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
return await fn();
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
if (acquired) {
|
|
114
|
+
await fsp.rm(lockDir, { recursive: true, force: true }).catch(() => undefined);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Cross-process advisory lock around RUDDER.md read-modify-write. The Rust
|
|
120
|
+
* TUI (acquire_rudder_md_lock in gitio.rs takes the same lock dir), CLI
|
|
121
|
+
* invocations, the daemon, and the orchestrator agent all write the file;
|
|
122
|
+
* serializing the merge keeps interleavings from dropping a freshly written
|
|
123
|
+
* DAG or control marker.
|
|
124
|
+
*/
|
|
125
|
+
export async function withRudderMdLock(repoRoot, fn) {
|
|
126
|
+
return withDirLock(rudderMdLockPath(repoRoot), fn);
|
|
127
|
+
}
|
|
128
|
+
export function integrationLockPath(repoRoot) {
|
|
129
|
+
return path.join(repoRoot, ".rudder", "integrate.lock");
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Cross-process lock for the INTEGRATION critical section (merging a run/node
|
|
133
|
+
* into the shared workspace @). withSchedulerLock serializes only within one
|
|
134
|
+
* process; a `rudder merge` CLI invocation and a daemon tick are separate
|
|
135
|
+
* processes operating on the same jj workspace, and concurrent merges there
|
|
136
|
+
* stack merge changes on a moving @. Longer windows than the RUDDER.md lock
|
|
137
|
+
* because a merge legitimately takes seconds.
|
|
138
|
+
*/
|
|
139
|
+
export async function withIntegrationLock(repoRoot, fn) {
|
|
140
|
+
return withDirLock(integrationLockPath(repoRoot), fn, { waitMs: 30_000, staleMs: 120_000 });
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=rudder-md.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rudder-md.js","sourceRoot":"","sources":["../src/rudder-md.ts"],"names":[],"mappings":"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"}
|