@prowi/deskcheck 0.1.0
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 +21 -0
- package/README.md +266 -0
- package/build/agents/executor-prompt.d.ts +10 -0
- package/build/agents/executor-prompt.d.ts.map +1 -0
- package/build/agents/executor-prompt.js +65 -0
- package/build/agents/executor-prompt.js.map +1 -0
- package/build/agents/orchestrator.d.ts +52 -0
- package/build/agents/orchestrator.d.ts.map +1 -0
- package/build/agents/orchestrator.js +343 -0
- package/build/agents/orchestrator.js.map +1 -0
- package/build/agents/planner.d.ts +28 -0
- package/build/agents/planner.d.ts.map +1 -0
- package/build/agents/planner.js +138 -0
- package/build/agents/planner.js.map +1 -0
- package/build/cli.d.ts +3 -0
- package/build/cli.d.ts.map +1 -0
- package/build/cli.js +467 -0
- package/build/cli.js.map +1 -0
- package/build/core/config.d.ts +16 -0
- package/build/core/config.d.ts.map +1 -0
- package/build/core/config.js +81 -0
- package/build/core/config.js.map +1 -0
- package/build/core/context-extractor.d.ts +17 -0
- package/build/core/context-extractor.d.ts.map +1 -0
- package/build/core/context-extractor.js +69 -0
- package/build/core/context-extractor.js.map +1 -0
- package/build/core/glob-matcher.d.ts +32 -0
- package/build/core/glob-matcher.d.ts.map +1 -0
- package/build/core/glob-matcher.js +51 -0
- package/build/core/glob-matcher.js.map +1 -0
- package/build/core/module-parser.d.ts +26 -0
- package/build/core/module-parser.d.ts.map +1 -0
- package/build/core/module-parser.js +98 -0
- package/build/core/module-parser.js.map +1 -0
- package/build/core/plan-builder.d.ts +12 -0
- package/build/core/plan-builder.d.ts.map +1 -0
- package/build/core/plan-builder.js +66 -0
- package/build/core/plan-builder.js.map +1 -0
- package/build/core/storage.d.ts +118 -0
- package/build/core/storage.d.ts.map +1 -0
- package/build/core/storage.js +590 -0
- package/build/core/storage.js.map +1 -0
- package/build/core/types.d.ts +268 -0
- package/build/core/types.d.ts.map +1 -0
- package/build/core/types.js +5 -0
- package/build/core/types.js.map +1 -0
- package/build/mcp/tools.d.ts +10 -0
- package/build/mcp/tools.d.ts.map +1 -0
- package/build/mcp/tools.js +354 -0
- package/build/mcp/tools.js.map +1 -0
- package/build/mcp-server.d.ts +3 -0
- package/build/mcp-server.d.ts.map +1 -0
- package/build/mcp-server.js +15 -0
- package/build/mcp-server.js.map +1 -0
- package/build/renderers/json.d.ts +4 -0
- package/build/renderers/json.d.ts.map +1 -0
- package/build/renderers/json.js +5 -0
- package/build/renderers/json.js.map +1 -0
- package/build/renderers/markdown.d.ts +4 -0
- package/build/renderers/markdown.d.ts.map +1 -0
- package/build/renderers/markdown.js +36 -0
- package/build/renderers/markdown.js.map +1 -0
- package/build/renderers/shared.d.ts +23 -0
- package/build/renderers/shared.d.ts.map +1 -0
- package/build/renderers/shared.js +30 -0
- package/build/renderers/shared.js.map +1 -0
- package/build/renderers/terminal.d.ts +4 -0
- package/build/renderers/terminal.d.ts.map +1 -0
- package/build/renderers/terminal.js +88 -0
- package/build/renderers/terminal.js.map +1 -0
- package/build/renderers/watch.d.ts +4 -0
- package/build/renderers/watch.d.ts.map +1 -0
- package/build/renderers/watch.js +119 -0
- package/build/renderers/watch.js.map +1 -0
- package/build/serve.d.ts +9 -0
- package/build/serve.d.ts.map +1 -0
- package/build/serve.js +249 -0
- package/build/serve.js.map +1 -0
- package/package.json +41 -0
- package/ui/dist/index.html +92 -0
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Helpers
|
|
5
|
+
// =============================================================================
|
|
6
|
+
/** Format a Date as YYYY-MM-DD_HHmmss for use as a plan ID / directory name. */
|
|
7
|
+
function formatTimestamp(date) {
|
|
8
|
+
const pad2 = (n) => String(n).padStart(2, "0");
|
|
9
|
+
return (`${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}` +
|
|
10
|
+
`_${pad2(date.getHours())}${pad2(date.getMinutes())}${pad2(date.getSeconds())}`);
|
|
11
|
+
}
|
|
12
|
+
/** Convert a review_id like "architecture/dto-enforcement" to "architecture--dto-enforcement". */
|
|
13
|
+
function flattenReviewId(reviewId) {
|
|
14
|
+
return reviewId.replace(/\//g, "--");
|
|
15
|
+
}
|
|
16
|
+
/** Zero-pad a number to 3 digits. */
|
|
17
|
+
function zeroPad3(n) {
|
|
18
|
+
return String(n).padStart(3, "0");
|
|
19
|
+
}
|
|
20
|
+
/** Stale threshold for in_progress tasks (5 minutes in milliseconds). */
|
|
21
|
+
const STALE_THRESHOLD_MS = 5 * 60 * 1000;
|
|
22
|
+
/** Maximum time to wait for a file lock (milliseconds). */
|
|
23
|
+
const LOCK_MAX_WAIT_MS = 10_000;
|
|
24
|
+
/** Spin delay between lock checks (milliseconds). */
|
|
25
|
+
const LOCK_SPIN_MS = 50;
|
|
26
|
+
// =============================================================================
|
|
27
|
+
// ReviewStorage
|
|
28
|
+
// =============================================================================
|
|
29
|
+
/**
|
|
30
|
+
* Manages the two-file storage format (plan.json + results.json) for deskcheck runs.
|
|
31
|
+
*
|
|
32
|
+
* Each deskcheck run lives in a timestamped directory under the configured storage
|
|
33
|
+
* directory. The plan file tracks tasks and coverage; the results file tracks
|
|
34
|
+
* findings and aggregations.
|
|
35
|
+
*/
|
|
36
|
+
export class ReviewStorage {
|
|
37
|
+
storageDir;
|
|
38
|
+
/** Tracks active lock file paths so they can be cleaned up on process exit. */
|
|
39
|
+
static activeLocks = new Set();
|
|
40
|
+
static {
|
|
41
|
+
const cleanup = () => {
|
|
42
|
+
for (const lockPath of ReviewStorage.activeLocks) {
|
|
43
|
+
try {
|
|
44
|
+
fs.unlinkSync(lockPath);
|
|
45
|
+
}
|
|
46
|
+
catch { /* ignore */ }
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
process.on("exit", cleanup);
|
|
50
|
+
process.on("SIGINT", () => { cleanup(); process.exit(130); });
|
|
51
|
+
process.on("SIGTERM", () => { cleanup(); process.exit(143); });
|
|
52
|
+
}
|
|
53
|
+
constructor(storageDir) {
|
|
54
|
+
this.storageDir = storageDir;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Execute a function while holding a file-based lock for the given plan.
|
|
58
|
+
*
|
|
59
|
+
* Uses `{ flag: "wx" }` for atomic exclusive create — either the file is
|
|
60
|
+
* created (lock acquired) or it already exists (another holder). This
|
|
61
|
+
* eliminates the TOCTOU race of existsSync + writeFileSync.
|
|
62
|
+
*
|
|
63
|
+
* Stale locks are detected via a timestamp in the lock file body.
|
|
64
|
+
*/
|
|
65
|
+
withLock(planId, fn) {
|
|
66
|
+
const lockPath = path.join(this.planDir(planId), ".lock");
|
|
67
|
+
const start = Date.now();
|
|
68
|
+
// Acquire lock using atomic exclusive create
|
|
69
|
+
while (true) {
|
|
70
|
+
try {
|
|
71
|
+
fs.writeFileSync(lockPath, JSON.stringify({ pid: process.pid, timestamp: Date.now() }), { flag: "wx" });
|
|
72
|
+
break; // Lock acquired
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
// File already exists — another process holds the lock
|
|
76
|
+
if (err.code === "EEXIST") {
|
|
77
|
+
// Check for stale lock (holder may have crashed)
|
|
78
|
+
try {
|
|
79
|
+
const lockData = JSON.parse(fs.readFileSync(lockPath, "utf-8"));
|
|
80
|
+
if (typeof lockData.timestamp === "number" && Date.now() - lockData.timestamp > LOCK_MAX_WAIT_MS) {
|
|
81
|
+
// Stale lock — force remove and retry
|
|
82
|
+
try {
|
|
83
|
+
fs.unlinkSync(lockPath);
|
|
84
|
+
}
|
|
85
|
+
catch { /* ignore */ }
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Can't read lock file — force remove and retry
|
|
91
|
+
try {
|
|
92
|
+
fs.unlinkSync(lockPath);
|
|
93
|
+
}
|
|
94
|
+
catch { /* ignore */ }
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (Date.now() - start > LOCK_MAX_WAIT_MS) {
|
|
98
|
+
throw new Error(`Storage lock timeout for plan ${planId}. Lock file: ${lockPath}`);
|
|
99
|
+
}
|
|
100
|
+
// Non-blocking wait using Atomics.wait on a shared buffer
|
|
101
|
+
const wait = new Int32Array(new SharedArrayBuffer(4));
|
|
102
|
+
Atomics.wait(wait, 0, 0, LOCK_SPIN_MS);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
throw err; // Unexpected error
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
ReviewStorage.activeLocks.add(lockPath);
|
|
109
|
+
try {
|
|
110
|
+
return fn();
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
ReviewStorage.activeLocks.delete(lockPath);
|
|
114
|
+
try {
|
|
115
|
+
fs.unlinkSync(lockPath);
|
|
116
|
+
}
|
|
117
|
+
catch { /* ignore */ }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** Get the directory path for a plan. */
|
|
121
|
+
planDir(planId) {
|
|
122
|
+
return path.join(this.storageDir, planId);
|
|
123
|
+
}
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// Plan Management
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
/**
|
|
128
|
+
* Create a new review plan with an empty task set.
|
|
129
|
+
*
|
|
130
|
+
* Creates the timestamped directory and writes an initial plan.json with
|
|
131
|
+
* status "planning" and empty collections.
|
|
132
|
+
*/
|
|
133
|
+
createPlan(name, source) {
|
|
134
|
+
const now = new Date();
|
|
135
|
+
const planId = formatTimestamp(now);
|
|
136
|
+
const planDir = path.join(this.storageDir, planId);
|
|
137
|
+
fs.mkdirSync(planDir, { recursive: true });
|
|
138
|
+
const plan = {
|
|
139
|
+
plan_id: planId,
|
|
140
|
+
name,
|
|
141
|
+
source,
|
|
142
|
+
status: "planning",
|
|
143
|
+
created_at: now.toISOString(),
|
|
144
|
+
finalized_at: null,
|
|
145
|
+
started_at: null,
|
|
146
|
+
completed_at: null,
|
|
147
|
+
matched_files: [],
|
|
148
|
+
unmatched_files: [],
|
|
149
|
+
tasks: {},
|
|
150
|
+
modules: {},
|
|
151
|
+
};
|
|
152
|
+
this.writePlan(planId, plan);
|
|
153
|
+
return plan;
|
|
154
|
+
}
|
|
155
|
+
/** Read the plan.json for a given plan ID. */
|
|
156
|
+
getPlan(planId) {
|
|
157
|
+
const planPath = this.planPath(planId);
|
|
158
|
+
const raw = fs.readFileSync(planPath, "utf-8");
|
|
159
|
+
return JSON.parse(raw);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Return the most recent plan ID (latest timestamped directory), or null if
|
|
163
|
+
* no plans exist.
|
|
164
|
+
*/
|
|
165
|
+
getLatestPlanId() {
|
|
166
|
+
if (!fs.existsSync(this.storageDir)) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
const entries = fs.readdirSync(this.storageDir, { withFileTypes: true });
|
|
170
|
+
const planDirs = entries
|
|
171
|
+
.filter((entry) => entry.isDirectory() &&
|
|
172
|
+
fs.existsSync(path.join(this.storageDir, entry.name, "plan.json")))
|
|
173
|
+
.map((entry) => entry.name)
|
|
174
|
+
.sort();
|
|
175
|
+
if (planDirs.length === 0) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
return planDirs[planDirs.length - 1];
|
|
179
|
+
}
|
|
180
|
+
/** List all plans with basic metadata. */
|
|
181
|
+
listPlans() {
|
|
182
|
+
if (!fs.existsSync(this.storageDir)) {
|
|
183
|
+
return [];
|
|
184
|
+
}
|
|
185
|
+
const entries = fs.readdirSync(this.storageDir, { withFileTypes: true });
|
|
186
|
+
const result = [];
|
|
187
|
+
for (const entry of entries) {
|
|
188
|
+
if (!entry.isDirectory())
|
|
189
|
+
continue;
|
|
190
|
+
const planJsonPath = path.join(this.storageDir, entry.name, "plan.json");
|
|
191
|
+
if (!fs.existsSync(planJsonPath))
|
|
192
|
+
continue;
|
|
193
|
+
const raw = fs.readFileSync(planJsonPath, "utf-8");
|
|
194
|
+
const plan = JSON.parse(raw);
|
|
195
|
+
result.push({
|
|
196
|
+
planId: plan.plan_id,
|
|
197
|
+
name: plan.name,
|
|
198
|
+
status: plan.status,
|
|
199
|
+
createdAt: plan.created_at,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return result.sort((a, b) => a.planId.localeCompare(b.planId));
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Finalize a plan by setting its status to "ready" and updating task counts
|
|
206
|
+
* in module summaries.
|
|
207
|
+
*/
|
|
208
|
+
finalizePlan(planId) {
|
|
209
|
+
return this.withLock(planId, () => {
|
|
210
|
+
const plan = this.getPlan(planId);
|
|
211
|
+
plan.status = "ready";
|
|
212
|
+
plan.finalized_at = new Date().toISOString();
|
|
213
|
+
// Recount tasks per module
|
|
214
|
+
for (const moduleSummary of Object.values(plan.modules)) {
|
|
215
|
+
moduleSummary.task_count = Object.values(plan.tasks).filter((task) => task.review_id === moduleSummary.review_id).length;
|
|
216
|
+
}
|
|
217
|
+
this.writePlan(planId, plan);
|
|
218
|
+
return plan;
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
// ---------------------------------------------------------------------------
|
|
222
|
+
// Task Management
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
/**
|
|
225
|
+
* Add a task to an existing plan.
|
|
226
|
+
*
|
|
227
|
+
* Auto-generates the task_id by flattening slashes in the review_id and
|
|
228
|
+
* appending a zero-padded incrementing suffix (e.g., "-001", "-002").
|
|
229
|
+
* The task is created with status "pending" and null context fields.
|
|
230
|
+
*/
|
|
231
|
+
addTask(planId, task) {
|
|
232
|
+
return this.withLock(planId, () => {
|
|
233
|
+
const plan = this.getPlan(planId);
|
|
234
|
+
// Auto-generate task_id: flatten review_id and auto-increment
|
|
235
|
+
const prefix = flattenReviewId(task.review_id);
|
|
236
|
+
const existingCount = Object.keys(plan.tasks).filter((id) => id.startsWith(prefix + "-")).length;
|
|
237
|
+
const taskId = `${prefix}-${zeroPad3(existingCount + 1)}`;
|
|
238
|
+
const newTask = {
|
|
239
|
+
task_id: taskId,
|
|
240
|
+
review_id: task.review_id,
|
|
241
|
+
review_file: task.review_file,
|
|
242
|
+
files: task.files,
|
|
243
|
+
hint: task.hint,
|
|
244
|
+
model: task.model,
|
|
245
|
+
status: "pending",
|
|
246
|
+
created_at: new Date().toISOString(),
|
|
247
|
+
started_at: null,
|
|
248
|
+
completed_at: null,
|
|
249
|
+
context_type: plan.source.type,
|
|
250
|
+
context: null,
|
|
251
|
+
symbol: null,
|
|
252
|
+
prompt: null,
|
|
253
|
+
};
|
|
254
|
+
plan.tasks[taskId] = newTask;
|
|
255
|
+
this.writePlan(planId, plan);
|
|
256
|
+
return newTask;
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Claim a pending task for execution.
|
|
261
|
+
*
|
|
262
|
+
* Sets the task status to "in_progress", fills in the context fields
|
|
263
|
+
* (context type, content, symbol, prompt), and records the start time.
|
|
264
|
+
*/
|
|
265
|
+
claimTask(planId, taskId, context) {
|
|
266
|
+
return this.withLock(planId, () => {
|
|
267
|
+
const plan = this.getPlan(planId);
|
|
268
|
+
const task = plan.tasks[taskId];
|
|
269
|
+
if (!task) {
|
|
270
|
+
throw new Error(`Task "${taskId}" not found in plan "${planId}"`);
|
|
271
|
+
}
|
|
272
|
+
task.status = "in_progress";
|
|
273
|
+
task.started_at = new Date().toISOString();
|
|
274
|
+
task.context_type = context.contextType;
|
|
275
|
+
task.context = context.content;
|
|
276
|
+
task.symbol = context.symbol ?? null;
|
|
277
|
+
task.prompt = context.prompt;
|
|
278
|
+
// Set plan to executing if it was ready
|
|
279
|
+
if (plan.status === "ready") {
|
|
280
|
+
plan.started_at = task.started_at;
|
|
281
|
+
plan.status = "executing";
|
|
282
|
+
}
|
|
283
|
+
this.writePlan(planId, plan);
|
|
284
|
+
return task;
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Return tasks eligible for execution: those with status "pending" or
|
|
289
|
+
* "in_progress" tasks that are stale (older than 5 minutes).
|
|
290
|
+
*/
|
|
291
|
+
getPendingTasks(planId) {
|
|
292
|
+
const plan = this.getPlan(planId);
|
|
293
|
+
const now = Date.now();
|
|
294
|
+
return Object.values(plan.tasks).filter((task) => {
|
|
295
|
+
if (task.status === "pending")
|
|
296
|
+
return true;
|
|
297
|
+
if (task.status === "in_progress" && task.started_at) {
|
|
298
|
+
const elapsed = now - new Date(task.started_at).getTime();
|
|
299
|
+
return elapsed > STALE_THRESHOLD_MS;
|
|
300
|
+
}
|
|
301
|
+
return false;
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
// ---------------------------------------------------------------------------
|
|
305
|
+
// Result Management
|
|
306
|
+
// ---------------------------------------------------------------------------
|
|
307
|
+
/**
|
|
308
|
+
* Mark a task as complete and record its findings.
|
|
309
|
+
*
|
|
310
|
+
* Updates the task status in plan.json, adds a TaskResult entry to
|
|
311
|
+
* results.json, and recomputes all aggregations (by_file, by_module,
|
|
312
|
+
* summary, completion).
|
|
313
|
+
*/
|
|
314
|
+
completeTask(planId, taskId, findings, usage) {
|
|
315
|
+
this.withLock(planId, () => {
|
|
316
|
+
const now = new Date().toISOString();
|
|
317
|
+
// Update plan.json task status
|
|
318
|
+
const plan = this.getPlan(planId);
|
|
319
|
+
const task = plan.tasks[taskId];
|
|
320
|
+
if (!task) {
|
|
321
|
+
throw new Error(`Task "${taskId}" not found in plan "${planId}"`);
|
|
322
|
+
}
|
|
323
|
+
task.status = "complete";
|
|
324
|
+
task.completed_at = now;
|
|
325
|
+
// Check if all tasks have reached a terminal status (complete or error)
|
|
326
|
+
const allDone = Object.values(plan.tasks).every((t) => t.status === "complete" || t.status === "error");
|
|
327
|
+
if (allDone) {
|
|
328
|
+
plan.status = "complete";
|
|
329
|
+
plan.completed_at = now;
|
|
330
|
+
}
|
|
331
|
+
this.writePlan(planId, plan);
|
|
332
|
+
// Add task result to results.json
|
|
333
|
+
const taskResult = {
|
|
334
|
+
task_id: taskId,
|
|
335
|
+
review_id: task.review_id,
|
|
336
|
+
files: task.files,
|
|
337
|
+
completed_at: now,
|
|
338
|
+
findings,
|
|
339
|
+
usage: usage ?? null,
|
|
340
|
+
};
|
|
341
|
+
const results = this.loadOrCreateResults(planId);
|
|
342
|
+
results.task_results[taskId] = taskResult;
|
|
343
|
+
// Recompute all aggregations from scratch
|
|
344
|
+
this.recomputeAggregations(results, plan);
|
|
345
|
+
this.writeResults(planId, results);
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Mark a task as errored.
|
|
350
|
+
*
|
|
351
|
+
* Sets the task status to "error" without recording any findings.
|
|
352
|
+
* Updates plan.json and recomputes result aggregations so the error
|
|
353
|
+
* is reflected in completion counts.
|
|
354
|
+
*/
|
|
355
|
+
errorTask(planId, taskId, errorMessage, usage) {
|
|
356
|
+
this.withLock(planId, () => {
|
|
357
|
+
const now = new Date().toISOString();
|
|
358
|
+
const plan = this.getPlan(planId);
|
|
359
|
+
const task = plan.tasks[taskId];
|
|
360
|
+
if (!task) {
|
|
361
|
+
throw new Error(`Task "${taskId}" not found in plan "${planId}"`);
|
|
362
|
+
}
|
|
363
|
+
task.status = "error";
|
|
364
|
+
task.completed_at = now;
|
|
365
|
+
// Check if all tasks have reached a terminal status
|
|
366
|
+
const allDone = Object.values(plan.tasks).every((t) => t.status === "complete" || t.status === "error");
|
|
367
|
+
if (allDone) {
|
|
368
|
+
plan.status = "complete";
|
|
369
|
+
plan.completed_at = now;
|
|
370
|
+
}
|
|
371
|
+
this.writePlan(planId, plan);
|
|
372
|
+
// Add task result to results.json (with empty findings but preserving usage data)
|
|
373
|
+
const results = this.loadOrCreateResults(planId);
|
|
374
|
+
if (usage) {
|
|
375
|
+
const taskResult = {
|
|
376
|
+
task_id: taskId,
|
|
377
|
+
review_id: task.review_id,
|
|
378
|
+
files: task.files,
|
|
379
|
+
completed_at: now,
|
|
380
|
+
findings: [],
|
|
381
|
+
usage: usage ?? null,
|
|
382
|
+
};
|
|
383
|
+
results.task_results[taskId] = taskResult;
|
|
384
|
+
}
|
|
385
|
+
// Recompute aggregations so completion counts reflect the error
|
|
386
|
+
this.recomputeAggregations(results, plan);
|
|
387
|
+
this.writeResults(planId, results);
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
/** Read the results.json for a given plan ID. */
|
|
391
|
+
getResults(planId) {
|
|
392
|
+
const resultsPath = this.resultsPath(planId);
|
|
393
|
+
if (!fs.existsSync(resultsPath)) {
|
|
394
|
+
// Return empty results if no results file exists yet
|
|
395
|
+
return this.createEmptyResults(planId);
|
|
396
|
+
}
|
|
397
|
+
const raw = fs.readFileSync(resultsPath, "utf-8");
|
|
398
|
+
return JSON.parse(raw);
|
|
399
|
+
}
|
|
400
|
+
// ---------------------------------------------------------------------------
|
|
401
|
+
// Coverage
|
|
402
|
+
// ---------------------------------------------------------------------------
|
|
403
|
+
/** Set the matched and unmatched file lists in the plan. */
|
|
404
|
+
setMatchedFiles(planId, matched, unmatched) {
|
|
405
|
+
this.withLock(planId, () => {
|
|
406
|
+
const plan = this.getPlan(planId);
|
|
407
|
+
plan.matched_files = matched;
|
|
408
|
+
plan.unmatched_files = unmatched;
|
|
409
|
+
this.writePlan(planId, plan);
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
/** Set the per-module summaries in the plan. */
|
|
413
|
+
setModules(planId, modules) {
|
|
414
|
+
this.withLock(planId, () => {
|
|
415
|
+
const plan = this.getPlan(planId);
|
|
416
|
+
plan.modules = modules;
|
|
417
|
+
this.writePlan(planId, plan);
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
// ---------------------------------------------------------------------------
|
|
421
|
+
// Private Helpers
|
|
422
|
+
// ---------------------------------------------------------------------------
|
|
423
|
+
planPath(planId) {
|
|
424
|
+
return path.join(this.storageDir, planId, "plan.json");
|
|
425
|
+
}
|
|
426
|
+
resultsPath(planId) {
|
|
427
|
+
return path.join(this.storageDir, planId, "results.json");
|
|
428
|
+
}
|
|
429
|
+
writePlan(planId, plan) {
|
|
430
|
+
const target = this.planPath(planId);
|
|
431
|
+
const tmp = target + ".tmp";
|
|
432
|
+
fs.writeFileSync(tmp, JSON.stringify(plan, null, 2) + "\n");
|
|
433
|
+
fs.renameSync(tmp, target);
|
|
434
|
+
}
|
|
435
|
+
writeResults(planId, results) {
|
|
436
|
+
const target = this.resultsPath(planId);
|
|
437
|
+
const tmp = target + ".tmp";
|
|
438
|
+
fs.writeFileSync(tmp, JSON.stringify(results, null, 2) + "\n");
|
|
439
|
+
fs.renameSync(tmp, target);
|
|
440
|
+
}
|
|
441
|
+
createEmptyResults(planId) {
|
|
442
|
+
return {
|
|
443
|
+
plan_id: planId,
|
|
444
|
+
status: "partial",
|
|
445
|
+
updated_at: new Date().toISOString(),
|
|
446
|
+
completion: {
|
|
447
|
+
total: 0,
|
|
448
|
+
completed: 0,
|
|
449
|
+
pending: 0,
|
|
450
|
+
in_progress: 0,
|
|
451
|
+
errored: 0,
|
|
452
|
+
},
|
|
453
|
+
summary: {
|
|
454
|
+
total: 0,
|
|
455
|
+
critical: 0,
|
|
456
|
+
warning: 0,
|
|
457
|
+
info: 0,
|
|
458
|
+
},
|
|
459
|
+
task_results: {},
|
|
460
|
+
by_file: {},
|
|
461
|
+
by_module: {},
|
|
462
|
+
total_usage: {
|
|
463
|
+
input_tokens: 0,
|
|
464
|
+
output_tokens: 0,
|
|
465
|
+
cache_read_tokens: 0,
|
|
466
|
+
cache_creation_tokens: 0,
|
|
467
|
+
cost_usd: 0,
|
|
468
|
+
duration_ms: 0,
|
|
469
|
+
duration_api_ms: 0,
|
|
470
|
+
num_turns: 0,
|
|
471
|
+
},
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Load existing results.json or create a new empty structure.
|
|
476
|
+
*/
|
|
477
|
+
loadOrCreateResults(planId) {
|
|
478
|
+
const resultsPath = this.resultsPath(planId);
|
|
479
|
+
if (fs.existsSync(resultsPath)) {
|
|
480
|
+
const raw = fs.readFileSync(resultsPath, "utf-8");
|
|
481
|
+
return JSON.parse(raw);
|
|
482
|
+
}
|
|
483
|
+
return this.createEmptyResults(planId);
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Recompute all derived aggregations in results from the task_results
|
|
487
|
+
* and the current plan state.
|
|
488
|
+
*
|
|
489
|
+
* This rebuilds by_file, by_module, summary, and completion from scratch
|
|
490
|
+
* on every completeTask call. Since there is a single orchestrator process,
|
|
491
|
+
* this is safe and keeps the logic simple.
|
|
492
|
+
*/
|
|
493
|
+
recomputeAggregations(results, plan) {
|
|
494
|
+
const now = new Date().toISOString();
|
|
495
|
+
results.updated_at = now;
|
|
496
|
+
// ---- Completion ----
|
|
497
|
+
const tasks = Object.values(plan.tasks);
|
|
498
|
+
results.completion = {
|
|
499
|
+
total: tasks.length,
|
|
500
|
+
completed: tasks.filter((t) => t.status === "complete").length,
|
|
501
|
+
pending: tasks.filter((t) => t.status === "pending").length,
|
|
502
|
+
in_progress: tasks.filter((t) => t.status === "in_progress").length,
|
|
503
|
+
errored: tasks.filter((t) => t.status === "error").length,
|
|
504
|
+
};
|
|
505
|
+
// ---- Summary (aggregate finding counts) ----
|
|
506
|
+
const summary = { total: 0, critical: 0, warning: 0, info: 0 };
|
|
507
|
+
for (const taskResult of Object.values(results.task_results)) {
|
|
508
|
+
for (const finding of taskResult.findings) {
|
|
509
|
+
summary.total++;
|
|
510
|
+
summary[finding.severity]++;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
results.summary = summary;
|
|
514
|
+
// ---- by_file (group all findings by file path) ----
|
|
515
|
+
const byFile = {};
|
|
516
|
+
for (const taskResult of Object.values(results.task_results)) {
|
|
517
|
+
for (const finding of taskResult.findings) {
|
|
518
|
+
const fileFinding = {
|
|
519
|
+
...finding,
|
|
520
|
+
review_id: taskResult.review_id,
|
|
521
|
+
task_id: taskResult.task_id,
|
|
522
|
+
};
|
|
523
|
+
if (!byFile[finding.file]) {
|
|
524
|
+
byFile[finding.file] = [];
|
|
525
|
+
}
|
|
526
|
+
byFile[finding.file].push(fileFinding);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
results.by_file = byFile;
|
|
530
|
+
// ---- by_module (group findings by criterion) ----
|
|
531
|
+
const byModule = {};
|
|
532
|
+
for (const taskResult of Object.values(results.task_results)) {
|
|
533
|
+
const reviewId = taskResult.review_id;
|
|
534
|
+
if (!byModule[reviewId]) {
|
|
535
|
+
// Look up module metadata from the plan
|
|
536
|
+
const moduleSummary = plan.modules[reviewId];
|
|
537
|
+
byModule[reviewId] = {
|
|
538
|
+
review_id: reviewId,
|
|
539
|
+
description: moduleSummary?.description ?? "",
|
|
540
|
+
severity: moduleSummary?.severity ?? "medium",
|
|
541
|
+
task_count: moduleSummary?.task_count ?? 0,
|
|
542
|
+
completed: 0,
|
|
543
|
+
counts: { critical: 0, warning: 0, info: 0, total: 0 },
|
|
544
|
+
findings: [],
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
const moduleFindings = byModule[reviewId];
|
|
548
|
+
moduleFindings.completed++;
|
|
549
|
+
for (const finding of taskResult.findings) {
|
|
550
|
+
moduleFindings.counts.total++;
|
|
551
|
+
moduleFindings.counts[finding.severity]++;
|
|
552
|
+
moduleFindings.findings.push(finding);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
results.by_module = byModule;
|
|
556
|
+
// ---- Status ----
|
|
557
|
+
// A result set is "complete" when all tasks have reached a terminal state
|
|
558
|
+
// (either completed successfully or errored out).
|
|
559
|
+
const terminalCount = results.completion.completed + results.completion.errored;
|
|
560
|
+
results.status =
|
|
561
|
+
terminalCount === results.completion.total
|
|
562
|
+
? "complete"
|
|
563
|
+
: "partial";
|
|
564
|
+
// ---- Total Usage ----
|
|
565
|
+
const totalUsage = {
|
|
566
|
+
input_tokens: 0,
|
|
567
|
+
output_tokens: 0,
|
|
568
|
+
cache_read_tokens: 0,
|
|
569
|
+
cache_creation_tokens: 0,
|
|
570
|
+
cost_usd: 0,
|
|
571
|
+
duration_ms: 0,
|
|
572
|
+
duration_api_ms: 0,
|
|
573
|
+
num_turns: 0,
|
|
574
|
+
};
|
|
575
|
+
for (const taskResult of Object.values(results.task_results)) {
|
|
576
|
+
if (taskResult.usage) {
|
|
577
|
+
totalUsage.input_tokens += taskResult.usage.input_tokens;
|
|
578
|
+
totalUsage.output_tokens += taskResult.usage.output_tokens;
|
|
579
|
+
totalUsage.cache_read_tokens += taskResult.usage.cache_read_tokens;
|
|
580
|
+
totalUsage.cache_creation_tokens += taskResult.usage.cache_creation_tokens;
|
|
581
|
+
totalUsage.cost_usd += taskResult.usage.cost_usd;
|
|
582
|
+
totalUsage.duration_ms += taskResult.usage.duration_ms;
|
|
583
|
+
totalUsage.duration_api_ms += taskResult.usage.duration_api_ms;
|
|
584
|
+
totalUsage.num_turns += taskResult.usage.num_turns;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
results.total_usage = totalUsage;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/core/storage.ts"],"names":[],"mappings":"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"}
|