@wrongstack/core 0.298.1 → 0.298.3
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/dist/coordination/index.js +92 -7
- package/dist/coordination/mail-tools.d.ts +3 -3
- package/dist/coordination/mailbox-codecs.d.ts +1 -1
- package/dist/coordination/mailbox-project-server.js +32 -1
- package/dist/coordination/mailbox-types.d.ts +158 -3
- package/dist/coordination/model-matrix.d.ts +16 -0
- package/dist/core/index.js +447 -43
- package/dist/defaults/index.js +21 -2
- package/dist/index.js +667 -519
- package/dist/infrastructure/index.js +20 -1
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +108 -1
- package/dist/models/models-dev-schema.d.ts +308 -0
- package/dist/plugin/index.js +14 -6
- package/dist/plugins/auto-review-plugin.d.ts +17 -2
- package/dist/storage/index.js +20 -1
- package/dist/tools/index.js +30 -2
- package/dist/types/config/providers.d.ts +13 -1
- package/dist/types/models-registry.d.ts +9 -4
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -1007,6 +1007,328 @@ var init_session_registry = __esm({
|
|
|
1007
1007
|
}
|
|
1008
1008
|
});
|
|
1009
1009
|
|
|
1010
|
+
// src/plugins/review-report-types.ts
|
|
1011
|
+
function validateReportTransition(from, to) {
|
|
1012
|
+
if (from === to) return;
|
|
1013
|
+
const allowed = REPORT_TRANSITION_MATRIX[from];
|
|
1014
|
+
if (!allowed?.has(to)) {
|
|
1015
|
+
throw new InvalidReportTransitionError(from, to);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
function reportEventTypeFor(to) {
|
|
1019
|
+
switch (to) {
|
|
1020
|
+
case "actioned":
|
|
1021
|
+
return "actioned";
|
|
1022
|
+
case "completed":
|
|
1023
|
+
return "completed";
|
|
1024
|
+
case "skipped":
|
|
1025
|
+
return "skipped";
|
|
1026
|
+
default:
|
|
1027
|
+
return "reopened";
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
var InvalidReportTransitionError, REPORT_TRANSITION_MATRIX;
|
|
1031
|
+
var init_review_report_types = __esm({
|
|
1032
|
+
"src/plugins/review-report-types.ts"() {
|
|
1033
|
+
"use strict";
|
|
1034
|
+
InvalidReportTransitionError = class extends Error {
|
|
1035
|
+
from;
|
|
1036
|
+
to;
|
|
1037
|
+
constructor(from, to, reason) {
|
|
1038
|
+
const msg = reason ?? `Invalid report transition from "${from}" to "${to}"`;
|
|
1039
|
+
super(msg);
|
|
1040
|
+
this.name = "InvalidReportTransitionError";
|
|
1041
|
+
this.from = from;
|
|
1042
|
+
this.to = to;
|
|
1043
|
+
}
|
|
1044
|
+
};
|
|
1045
|
+
REPORT_TRANSITION_MATRIX = {
|
|
1046
|
+
open: /* @__PURE__ */ new Set(["actioned", "completed", "skipped"]),
|
|
1047
|
+
actioned: /* @__PURE__ */ new Set(["completed", "skipped"]),
|
|
1048
|
+
completed: /* @__PURE__ */ new Set(["open"]),
|
|
1049
|
+
skipped: /* @__PURE__ */ new Set(["open"])
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
// src/plugins/review-report-store.ts
|
|
1055
|
+
var review_report_store_exports = {};
|
|
1056
|
+
__export(review_report_store_exports, {
|
|
1057
|
+
JsonlReportStore: () => JsonlReportStore,
|
|
1058
|
+
REPORT_DEFAULT_PAGE_SIZE: () => REPORT_DEFAULT_PAGE_SIZE,
|
|
1059
|
+
REPORT_RETENTION_MS: () => REPORT_RETENTION_MS,
|
|
1060
|
+
REPORT_STORE_FILE: () => REPORT_STORE_FILE,
|
|
1061
|
+
resolveReportStorePath: () => resolveReportStorePath
|
|
1062
|
+
});
|
|
1063
|
+
import { randomUUID as randomUUID28 } from "node:crypto";
|
|
1064
|
+
import * as fsp28 from "node:fs/promises";
|
|
1065
|
+
import * as path67 from "node:path";
|
|
1066
|
+
function resolveReportStorePath(projectDir) {
|
|
1067
|
+
return path67.join(projectDir, REPORT_STORE_FILE);
|
|
1068
|
+
}
|
|
1069
|
+
var REPORT_RETENTION_MS, REPORT_DEFAULT_PAGE_SIZE, NL, REPORT_STORE_FILE, JsonlReportStore;
|
|
1070
|
+
var init_review_report_store = __esm({
|
|
1071
|
+
"src/plugins/review-report-store.ts"() {
|
|
1072
|
+
"use strict";
|
|
1073
|
+
init_file_permissions();
|
|
1074
|
+
init_atomic_write();
|
|
1075
|
+
init_review_report_types();
|
|
1076
|
+
REPORT_RETENTION_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
1077
|
+
REPORT_DEFAULT_PAGE_SIZE = 25;
|
|
1078
|
+
NL = "\n";
|
|
1079
|
+
REPORT_STORE_FILE = "review-reports.jsonl";
|
|
1080
|
+
JsonlReportStore = class {
|
|
1081
|
+
filePath;
|
|
1082
|
+
constructor(projectDir) {
|
|
1083
|
+
this.filePath = resolveReportStorePath(projectDir);
|
|
1084
|
+
}
|
|
1085
|
+
get storePath() {
|
|
1086
|
+
return this.filePath;
|
|
1087
|
+
}
|
|
1088
|
+
// ── Persist (create or reopen) ───────────────────────────────────
|
|
1089
|
+
async persist(input) {
|
|
1090
|
+
return withFileLock(this.filePath, async () => {
|
|
1091
|
+
const existing = await this._findRecord(input.id);
|
|
1092
|
+
if (existing) {
|
|
1093
|
+
const updated = {
|
|
1094
|
+
...existing,
|
|
1095
|
+
counts: input.counts,
|
|
1096
|
+
totalFindings: input.totalFindings,
|
|
1097
|
+
unparseableCount: input.unparseableCount,
|
|
1098
|
+
durationSeconds: input.durationSeconds ?? existing.durationSeconds,
|
|
1099
|
+
rawText: input.rawText || existing.rawText,
|
|
1100
|
+
files: input.files.length > 0 ? input.files : existing.files
|
|
1101
|
+
};
|
|
1102
|
+
await fsp28.appendFile(this.filePath, JSON.stringify({ __report: 1, data: updated }) + NL, {
|
|
1103
|
+
encoding: "utf8",
|
|
1104
|
+
mode: SECRET_FILE_MODE
|
|
1105
|
+
});
|
|
1106
|
+
return updated;
|
|
1107
|
+
}
|
|
1108
|
+
const report = {
|
|
1109
|
+
id: input.id,
|
|
1110
|
+
reviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1111
|
+
sessionId: input.sessionId,
|
|
1112
|
+
agentId: input.agentId,
|
|
1113
|
+
reviewerModel: input.reviewerModel,
|
|
1114
|
+
source: input.source,
|
|
1115
|
+
reviewStatus: input.reviewStatus,
|
|
1116
|
+
lifecycle: "open",
|
|
1117
|
+
files: input.files,
|
|
1118
|
+
counts: input.counts,
|
|
1119
|
+
totalFindings: input.totalFindings,
|
|
1120
|
+
unparseableCount: input.unparseableCount,
|
|
1121
|
+
durationSeconds: input.durationSeconds,
|
|
1122
|
+
rawText: input.rawText,
|
|
1123
|
+
...input.cascadeDepth !== void 0 ? { cascadeDepth: input.cascadeDepth } : {}
|
|
1124
|
+
};
|
|
1125
|
+
const createdEvent = {
|
|
1126
|
+
id: randomUUID28(),
|
|
1127
|
+
reportId: report.id,
|
|
1128
|
+
eventType: "created",
|
|
1129
|
+
fromLifecycle: null,
|
|
1130
|
+
toLifecycle: "open",
|
|
1131
|
+
actorId: "system",
|
|
1132
|
+
actorKind: "system",
|
|
1133
|
+
timestamp: report.reviewedAt
|
|
1134
|
+
};
|
|
1135
|
+
const lines = JSON.stringify({ __report: 1, data: report }) + NL + JSON.stringify({ __reportEvent: 1, data: createdEvent }) + NL;
|
|
1136
|
+
await fsp28.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
|
|
1137
|
+
return report;
|
|
1138
|
+
});
|
|
1139
|
+
}
|
|
1140
|
+
// ── Lifecycle transitions ────────────────────────────────────────
|
|
1141
|
+
async transition(reportId, to, actor, opts) {
|
|
1142
|
+
return withFileLock(this.filePath, async () => {
|
|
1143
|
+
const all = await this._readAll();
|
|
1144
|
+
const entry = all.find((e) => e.report.id === reportId);
|
|
1145
|
+
if (!entry) throw new Error(`Review report not found: ${reportId}`);
|
|
1146
|
+
const from = this._materialize(entry).lifecycle;
|
|
1147
|
+
validateReportTransition(from, to);
|
|
1148
|
+
const event = {
|
|
1149
|
+
id: randomUUID28(),
|
|
1150
|
+
reportId,
|
|
1151
|
+
eventType: reportEventTypeFor(to),
|
|
1152
|
+
fromLifecycle: from,
|
|
1153
|
+
toLifecycle: to,
|
|
1154
|
+
actorId: actor.id,
|
|
1155
|
+
actorKind: actor.kind,
|
|
1156
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1157
|
+
reason: opts?.reason
|
|
1158
|
+
};
|
|
1159
|
+
entry.report.lifecycle = to;
|
|
1160
|
+
await fsp28.appendFile(this.filePath, JSON.stringify({ __reportEvent: 1, data: event }) + NL, {
|
|
1161
|
+
encoding: "utf8",
|
|
1162
|
+
mode: SECRET_FILE_MODE
|
|
1163
|
+
});
|
|
1164
|
+
return { ...entry.report };
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
async addNote(reportId, actor, note) {
|
|
1168
|
+
return withFileLock(this.filePath, async () => {
|
|
1169
|
+
const all = await this._readAll();
|
|
1170
|
+
const entry = all.find((e) => e.report.id === reportId);
|
|
1171
|
+
if (!entry) throw new Error(`Review report not found: ${reportId}`);
|
|
1172
|
+
const materialized = this._materialize(entry);
|
|
1173
|
+
const event = {
|
|
1174
|
+
id: randomUUID28(),
|
|
1175
|
+
reportId,
|
|
1176
|
+
eventType: "note_added",
|
|
1177
|
+
fromLifecycle: materialized.lifecycle,
|
|
1178
|
+
toLifecycle: materialized.lifecycle,
|
|
1179
|
+
actorId: actor.id,
|
|
1180
|
+
actorKind: actor.kind,
|
|
1181
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1182
|
+
reason: note
|
|
1183
|
+
};
|
|
1184
|
+
await fsp28.appendFile(this.filePath, JSON.stringify({ __reportEvent: 1, data: event }) + NL, {
|
|
1185
|
+
encoding: "utf8",
|
|
1186
|
+
mode: SECRET_FILE_MODE
|
|
1187
|
+
});
|
|
1188
|
+
return materialized;
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1191
|
+
// ── Query ────────────────────────────────────────────────────────
|
|
1192
|
+
async list(opts) {
|
|
1193
|
+
const all = await this._readAll();
|
|
1194
|
+
let reports = all.map((e) => this._materialize(e));
|
|
1195
|
+
if (opts?.statuses && opts.statuses.length > 0) {
|
|
1196
|
+
const set = new Set(opts.statuses);
|
|
1197
|
+
reports = reports.filter((r) => set.has(r.lifecycle));
|
|
1198
|
+
}
|
|
1199
|
+
if (opts?.sources && opts.sources.length > 0) {
|
|
1200
|
+
const set = new Set(opts.sources);
|
|
1201
|
+
reports = reports.filter((r) => set.has(r.source));
|
|
1202
|
+
}
|
|
1203
|
+
reports.sort((a, b) => b.reviewedAt.localeCompare(a.reviewedAt));
|
|
1204
|
+
const limit = opts?.limit ?? REPORT_DEFAULT_PAGE_SIZE;
|
|
1205
|
+
return reports.slice(0, limit);
|
|
1206
|
+
}
|
|
1207
|
+
async get(id) {
|
|
1208
|
+
const all = await this._readAll();
|
|
1209
|
+
const entry = all.find((e) => e.report.id === id);
|
|
1210
|
+
return entry ? this._materialize(entry) : null;
|
|
1211
|
+
}
|
|
1212
|
+
async getEvents(reportId) {
|
|
1213
|
+
const all = await this._readAllLines();
|
|
1214
|
+
const events = [];
|
|
1215
|
+
for (const line of all) {
|
|
1216
|
+
try {
|
|
1217
|
+
const parsed = JSON.parse(line);
|
|
1218
|
+
if (this._isEventRecord(parsed) && parsed.data.reportId === reportId) {
|
|
1219
|
+
events.push(parsed.data);
|
|
1220
|
+
}
|
|
1221
|
+
} catch {
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
return events.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
1225
|
+
}
|
|
1226
|
+
// ── Compaction ───────────────────────────────────────────────────
|
|
1227
|
+
async compact(opts) {
|
|
1228
|
+
return withFileLock(this.filePath, async () => {
|
|
1229
|
+
const maxAge = opts?.maxAgeMs ?? REPORT_RETENTION_MS;
|
|
1230
|
+
const now = Date.now();
|
|
1231
|
+
const all = await this._readAll();
|
|
1232
|
+
const kept = [];
|
|
1233
|
+
let removed = 0;
|
|
1234
|
+
let eventsFolded = 0;
|
|
1235
|
+
for (const entry of all) {
|
|
1236
|
+
const age = now - new Date(entry.report.reviewedAt).getTime();
|
|
1237
|
+
const materialized = this._materialize(entry);
|
|
1238
|
+
const isTerminal = materialized.lifecycle === "completed" || materialized.lifecycle === "skipped";
|
|
1239
|
+
if (isTerminal && age > maxAge) {
|
|
1240
|
+
removed++;
|
|
1241
|
+
eventsFolded += entry.events.length;
|
|
1242
|
+
continue;
|
|
1243
|
+
}
|
|
1244
|
+
const oldEvents = entry.events.filter(
|
|
1245
|
+
(ev) => now - new Date(ev.timestamp).getTime() > maxAge
|
|
1246
|
+
);
|
|
1247
|
+
if (oldEvents.length > 1) {
|
|
1248
|
+
eventsFolded += oldEvents.length - 1;
|
|
1249
|
+
const newestOld = oldEvents.sort((a, b) => b.timestamp.localeCompare(a.timestamp))[0];
|
|
1250
|
+
entry.events = [
|
|
1251
|
+
newestOld,
|
|
1252
|
+
...entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() <= maxAge)
|
|
1253
|
+
];
|
|
1254
|
+
}
|
|
1255
|
+
kept.push({ record: { __report: 1, data: entry.report }, events: entry.events });
|
|
1256
|
+
}
|
|
1257
|
+
const lines = [];
|
|
1258
|
+
for (const { record, events } of kept) {
|
|
1259
|
+
if (record) lines.push(JSON.stringify(record));
|
|
1260
|
+
for (const ev of events) {
|
|
1261
|
+
lines.push(JSON.stringify({ __reportEvent: 1, data: ev }));
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
lines.push(
|
|
1265
|
+
JSON.stringify({
|
|
1266
|
+
__reportCompact: 1,
|
|
1267
|
+
compactedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1268
|
+
removedReports: removed,
|
|
1269
|
+
foldedEvents: eventsFolded
|
|
1270
|
+
})
|
|
1271
|
+
);
|
|
1272
|
+
await atomicWrite(this.filePath, lines.join(NL) + NL, { mode: 384 });
|
|
1273
|
+
return { removed, eventsFolded };
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1276
|
+
// ── Private helpers ──────────────────────────────────────────────
|
|
1277
|
+
async _readAllLines() {
|
|
1278
|
+
try {
|
|
1279
|
+
const raw = await fsp28.readFile(this.filePath, "utf8");
|
|
1280
|
+
return raw.split(NL).filter((l) => l.trim().length > 0);
|
|
1281
|
+
} catch (err) {
|
|
1282
|
+
if (err.code === "ENOENT") return [];
|
|
1283
|
+
throw err;
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
_isReportRecord(v) {
|
|
1287
|
+
return typeof v === "object" && v !== null && v["__report"] === 1;
|
|
1288
|
+
}
|
|
1289
|
+
_isEventRecord(v) {
|
|
1290
|
+
return typeof v === "object" && v !== null && v["__reportEvent"] === 1;
|
|
1291
|
+
}
|
|
1292
|
+
async _readAll() {
|
|
1293
|
+
const lines = await this._readAllLines();
|
|
1294
|
+
const reports = /* @__PURE__ */ new Map();
|
|
1295
|
+
const eventsMap = /* @__PURE__ */ new Map();
|
|
1296
|
+
for (const line of lines) {
|
|
1297
|
+
try {
|
|
1298
|
+
const parsed = JSON.parse(line);
|
|
1299
|
+
if (this._isReportRecord(parsed)) {
|
|
1300
|
+
reports.set(parsed.data.id, parsed.data);
|
|
1301
|
+
if (!eventsMap.has(parsed.data.id)) eventsMap.set(parsed.data.id, []);
|
|
1302
|
+
} else if (this._isEventRecord(parsed)) {
|
|
1303
|
+
const list = eventsMap.get(parsed.data.reportId);
|
|
1304
|
+
if (list) list.push(parsed.data);
|
|
1305
|
+
}
|
|
1306
|
+
} catch {
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
return Array.from(reports.entries()).map(([id, report]) => ({
|
|
1310
|
+
report,
|
|
1311
|
+
events: eventsMap.get(id) ?? []
|
|
1312
|
+
}));
|
|
1313
|
+
}
|
|
1314
|
+
async _findRecord(id) {
|
|
1315
|
+
const all = await this._readAll();
|
|
1316
|
+
const entry = all.find((e) => e.report.id === id);
|
|
1317
|
+
return entry ? this._materialize(entry) : null;
|
|
1318
|
+
}
|
|
1319
|
+
_materialize(entry) {
|
|
1320
|
+
if (entry.events.length === 0) return { ...entry.report };
|
|
1321
|
+
const sorted = [...entry.events].sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
1322
|
+
const latest = sorted[sorted.length - 1];
|
|
1323
|
+
if (latest.eventType !== "note_added") {
|
|
1324
|
+
return { ...entry.report, lifecycle: latest.toLifecycle };
|
|
1325
|
+
}
|
|
1326
|
+
return { ...entry.report };
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1330
|
+
});
|
|
1331
|
+
|
|
1010
1332
|
// src/plugins/review-finding-types.ts
|
|
1011
1333
|
import { createHash as createHash32 } from "node:crypto";
|
|
1012
1334
|
function normalizeFingerprintTitle(title) {
|
|
@@ -1072,13 +1394,13 @@ __export(review_finding_store_exports, {
|
|
|
1072
1394
|
JsonlFindingStore: () => JsonlFindingStore,
|
|
1073
1395
|
resolveFindingStorePath: () => resolveFindingStorePath
|
|
1074
1396
|
});
|
|
1075
|
-
import { randomUUID as
|
|
1076
|
-
import * as
|
|
1077
|
-
import * as
|
|
1397
|
+
import { randomUUID as randomUUID36 } from "node:crypto";
|
|
1398
|
+
import * as fsp39 from "node:fs/promises";
|
|
1399
|
+
import * as path91 from "node:path";
|
|
1078
1400
|
function resolveFindingStorePath(projectDir) {
|
|
1079
|
-
return
|
|
1401
|
+
return path91.join(projectDir, FINDING_STORE_FILE);
|
|
1080
1402
|
}
|
|
1081
|
-
var FINDING_RESOLVED_RETENTION_MS, FINDING_IGNORED_RETENTION_MS, FINDING_DEFAULT_PAGE_SIZE,
|
|
1403
|
+
var FINDING_RESOLVED_RETENTION_MS, FINDING_IGNORED_RETENTION_MS, FINDING_DEFAULT_PAGE_SIZE, NL2, LINE_SEPARATOR, FINDING_STORE_FILE, JsonlFindingStore;
|
|
1082
1404
|
var init_review_finding_store = __esm({
|
|
1083
1405
|
"src/plugins/review-finding-store.ts"() {
|
|
1084
1406
|
"use strict";
|
|
@@ -1088,8 +1410,8 @@ var init_review_finding_store = __esm({
|
|
|
1088
1410
|
FINDING_RESOLVED_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
1089
1411
|
FINDING_IGNORED_RETENTION_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
1090
1412
|
FINDING_DEFAULT_PAGE_SIZE = 50;
|
|
1091
|
-
|
|
1092
|
-
LINE_SEPARATOR =
|
|
1413
|
+
NL2 = "\n";
|
|
1414
|
+
LINE_SEPARATOR = NL2;
|
|
1093
1415
|
FINDING_STORE_FILE = "review-findings.jsonl";
|
|
1094
1416
|
JsonlFindingStore = class {
|
|
1095
1417
|
filePath;
|
|
@@ -1120,7 +1442,7 @@ var init_review_finding_store = __esm({
|
|
|
1120
1442
|
match.finding.status = "active";
|
|
1121
1443
|
match.finding.resolution = void 0;
|
|
1122
1444
|
const updatedRecord = { __finding: 1, data: match.finding };
|
|
1123
|
-
await
|
|
1445
|
+
await fsp39.appendFile(
|
|
1124
1446
|
this.filePath,
|
|
1125
1447
|
JSON.stringify(updatedRecord) + LINE_SEPARATOR + JSON.stringify({ __findingEvent: 1, data: reopenEvent }) + LINE_SEPARATOR,
|
|
1126
1448
|
{ encoding: "utf8", mode: SECRET_FILE_MODE }
|
|
@@ -1134,7 +1456,7 @@ var init_review_finding_store = __esm({
|
|
|
1134
1456
|
match.finding.status,
|
|
1135
1457
|
context
|
|
1136
1458
|
);
|
|
1137
|
-
await
|
|
1459
|
+
await fsp39.appendFile(
|
|
1138
1460
|
this.filePath,
|
|
1139
1461
|
JSON.stringify({ __findingEvent: 1, data: relinkEvent }) + LINE_SEPARATOR,
|
|
1140
1462
|
{ encoding: "utf8", mode: SECRET_FILE_MODE }
|
|
@@ -1145,7 +1467,7 @@ var init_review_finding_store = __esm({
|
|
|
1145
1467
|
const record = { __finding: 1, data: finding };
|
|
1146
1468
|
const createdEvent = this._makeEvent(finding.id, "created", null, "active", context);
|
|
1147
1469
|
const lines = JSON.stringify(record) + LINE_SEPARATOR + JSON.stringify({ __findingEvent: 1, data: createdEvent }) + LINE_SEPARATOR;
|
|
1148
|
-
await
|
|
1470
|
+
await fsp39.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
|
|
1149
1471
|
result.created++;
|
|
1150
1472
|
}
|
|
1151
1473
|
}
|
|
@@ -1161,7 +1483,7 @@ var init_review_finding_store = __esm({
|
|
|
1161
1483
|
validateTransition(from, to);
|
|
1162
1484
|
validateResolution(to, opts?.outcome);
|
|
1163
1485
|
const event = {
|
|
1164
|
-
id:
|
|
1486
|
+
id: randomUUID36(),
|
|
1165
1487
|
findingId,
|
|
1166
1488
|
eventType: to === "resolved" ? "resolved" : to === "ignored" ? "ignored" : this._eventTypeFor(to),
|
|
1167
1489
|
fromStatus: from,
|
|
@@ -1181,7 +1503,7 @@ var init_review_finding_store = __esm({
|
|
|
1181
1503
|
};
|
|
1182
1504
|
}
|
|
1183
1505
|
const updatedRecord = { __finding: 1, data: entry.finding };
|
|
1184
|
-
await
|
|
1506
|
+
await fsp39.appendFile(
|
|
1185
1507
|
this.filePath,
|
|
1186
1508
|
JSON.stringify(updatedRecord) + LINE_SEPARATOR + JSON.stringify({ __findingEvent: 1, data: event }) + LINE_SEPARATOR,
|
|
1187
1509
|
{ encoding: "utf8", mode: SECRET_FILE_MODE }
|
|
@@ -1298,7 +1620,7 @@ var init_review_finding_store = __esm({
|
|
|
1298
1620
|
// ── Private helpers ──────────────────────────────────────────────
|
|
1299
1621
|
async _readAllLines() {
|
|
1300
1622
|
try {
|
|
1301
|
-
const raw = await
|
|
1623
|
+
const raw = await fsp39.readFile(this.filePath, "utf8");
|
|
1302
1624
|
return raw.split(LINE_SEPARATOR).filter((l) => l.trim().length > 0);
|
|
1303
1625
|
} catch (err) {
|
|
1304
1626
|
if (err.code === "ENOENT") return [];
|
|
@@ -1345,7 +1667,7 @@ var init_review_finding_store = __esm({
|
|
|
1345
1667
|
}
|
|
1346
1668
|
_makeEvent(findingId, eventType, fromStatus, toStatus, context) {
|
|
1347
1669
|
return {
|
|
1348
|
-
id:
|
|
1670
|
+
id: randomUUID36(),
|
|
1349
1671
|
findingId,
|
|
1350
1672
|
eventType,
|
|
1351
1673
|
fromStatus,
|
|
@@ -1376,328 +1698,6 @@ var init_review_finding_store = __esm({
|
|
|
1376
1698
|
}
|
|
1377
1699
|
});
|
|
1378
1700
|
|
|
1379
|
-
// src/plugins/review-report-types.ts
|
|
1380
|
-
function validateReportTransition(from, to) {
|
|
1381
|
-
if (from === to) return;
|
|
1382
|
-
const allowed = REPORT_TRANSITION_MATRIX[from];
|
|
1383
|
-
if (!allowed?.has(to)) {
|
|
1384
|
-
throw new InvalidReportTransitionError(from, to);
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
function reportEventTypeFor(to) {
|
|
1388
|
-
switch (to) {
|
|
1389
|
-
case "actioned":
|
|
1390
|
-
return "actioned";
|
|
1391
|
-
case "completed":
|
|
1392
|
-
return "completed";
|
|
1393
|
-
case "skipped":
|
|
1394
|
-
return "skipped";
|
|
1395
|
-
default:
|
|
1396
|
-
return "reopened";
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
var InvalidReportTransitionError, REPORT_TRANSITION_MATRIX;
|
|
1400
|
-
var init_review_report_types = __esm({
|
|
1401
|
-
"src/plugins/review-report-types.ts"() {
|
|
1402
|
-
"use strict";
|
|
1403
|
-
InvalidReportTransitionError = class extends Error {
|
|
1404
|
-
from;
|
|
1405
|
-
to;
|
|
1406
|
-
constructor(from, to, reason) {
|
|
1407
|
-
const msg = reason ?? `Invalid report transition from "${from}" to "${to}"`;
|
|
1408
|
-
super(msg);
|
|
1409
|
-
this.name = "InvalidReportTransitionError";
|
|
1410
|
-
this.from = from;
|
|
1411
|
-
this.to = to;
|
|
1412
|
-
}
|
|
1413
|
-
};
|
|
1414
|
-
REPORT_TRANSITION_MATRIX = {
|
|
1415
|
-
open: /* @__PURE__ */ new Set(["actioned", "completed", "skipped"]),
|
|
1416
|
-
actioned: /* @__PURE__ */ new Set(["completed", "skipped"]),
|
|
1417
|
-
completed: /* @__PURE__ */ new Set(["open"]),
|
|
1418
|
-
skipped: /* @__PURE__ */ new Set(["open"])
|
|
1419
|
-
};
|
|
1420
|
-
}
|
|
1421
|
-
});
|
|
1422
|
-
|
|
1423
|
-
// src/plugins/review-report-store.ts
|
|
1424
|
-
var review_report_store_exports = {};
|
|
1425
|
-
__export(review_report_store_exports, {
|
|
1426
|
-
JsonlReportStore: () => JsonlReportStore,
|
|
1427
|
-
REPORT_DEFAULT_PAGE_SIZE: () => REPORT_DEFAULT_PAGE_SIZE,
|
|
1428
|
-
REPORT_RETENTION_MS: () => REPORT_RETENTION_MS,
|
|
1429
|
-
REPORT_STORE_FILE: () => REPORT_STORE_FILE,
|
|
1430
|
-
resolveReportStorePath: () => resolveReportStorePath
|
|
1431
|
-
});
|
|
1432
|
-
import { randomUUID as randomUUID37 } from "node:crypto";
|
|
1433
|
-
import * as fsp39 from "node:fs/promises";
|
|
1434
|
-
import * as path91 from "node:path";
|
|
1435
|
-
function resolveReportStorePath(projectDir) {
|
|
1436
|
-
return path91.join(projectDir, REPORT_STORE_FILE);
|
|
1437
|
-
}
|
|
1438
|
-
var REPORT_RETENTION_MS, REPORT_DEFAULT_PAGE_SIZE, NL2, REPORT_STORE_FILE, JsonlReportStore;
|
|
1439
|
-
var init_review_report_store = __esm({
|
|
1440
|
-
"src/plugins/review-report-store.ts"() {
|
|
1441
|
-
"use strict";
|
|
1442
|
-
init_file_permissions();
|
|
1443
|
-
init_atomic_write();
|
|
1444
|
-
init_review_report_types();
|
|
1445
|
-
REPORT_RETENTION_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
1446
|
-
REPORT_DEFAULT_PAGE_SIZE = 25;
|
|
1447
|
-
NL2 = "\n";
|
|
1448
|
-
REPORT_STORE_FILE = "review-reports.jsonl";
|
|
1449
|
-
JsonlReportStore = class {
|
|
1450
|
-
filePath;
|
|
1451
|
-
constructor(projectDir) {
|
|
1452
|
-
this.filePath = resolveReportStorePath(projectDir);
|
|
1453
|
-
}
|
|
1454
|
-
get storePath() {
|
|
1455
|
-
return this.filePath;
|
|
1456
|
-
}
|
|
1457
|
-
// ── Persist (create or reopen) ───────────────────────────────────
|
|
1458
|
-
async persist(input) {
|
|
1459
|
-
return withFileLock(this.filePath, async () => {
|
|
1460
|
-
const existing = await this._findRecord(input.id);
|
|
1461
|
-
if (existing) {
|
|
1462
|
-
const updated = {
|
|
1463
|
-
...existing,
|
|
1464
|
-
counts: input.counts,
|
|
1465
|
-
totalFindings: input.totalFindings,
|
|
1466
|
-
unparseableCount: input.unparseableCount,
|
|
1467
|
-
durationSeconds: input.durationSeconds ?? existing.durationSeconds,
|
|
1468
|
-
rawText: input.rawText || existing.rawText,
|
|
1469
|
-
files: input.files.length > 0 ? input.files : existing.files
|
|
1470
|
-
};
|
|
1471
|
-
await fsp39.appendFile(this.filePath, JSON.stringify({ __report: 1, data: updated }) + NL2, {
|
|
1472
|
-
encoding: "utf8",
|
|
1473
|
-
mode: SECRET_FILE_MODE
|
|
1474
|
-
});
|
|
1475
|
-
return updated;
|
|
1476
|
-
}
|
|
1477
|
-
const report = {
|
|
1478
|
-
id: input.id,
|
|
1479
|
-
reviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1480
|
-
sessionId: input.sessionId,
|
|
1481
|
-
agentId: input.agentId,
|
|
1482
|
-
reviewerModel: input.reviewerModel,
|
|
1483
|
-
source: input.source,
|
|
1484
|
-
reviewStatus: input.reviewStatus,
|
|
1485
|
-
lifecycle: "open",
|
|
1486
|
-
files: input.files,
|
|
1487
|
-
counts: input.counts,
|
|
1488
|
-
totalFindings: input.totalFindings,
|
|
1489
|
-
unparseableCount: input.unparseableCount,
|
|
1490
|
-
durationSeconds: input.durationSeconds,
|
|
1491
|
-
rawText: input.rawText,
|
|
1492
|
-
...input.cascadeDepth !== void 0 ? { cascadeDepth: input.cascadeDepth } : {}
|
|
1493
|
-
};
|
|
1494
|
-
const createdEvent = {
|
|
1495
|
-
id: randomUUID37(),
|
|
1496
|
-
reportId: report.id,
|
|
1497
|
-
eventType: "created",
|
|
1498
|
-
fromLifecycle: null,
|
|
1499
|
-
toLifecycle: "open",
|
|
1500
|
-
actorId: "system",
|
|
1501
|
-
actorKind: "system",
|
|
1502
|
-
timestamp: report.reviewedAt
|
|
1503
|
-
};
|
|
1504
|
-
const lines = JSON.stringify({ __report: 1, data: report }) + NL2 + JSON.stringify({ __reportEvent: 1, data: createdEvent }) + NL2;
|
|
1505
|
-
await fsp39.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
|
|
1506
|
-
return report;
|
|
1507
|
-
});
|
|
1508
|
-
}
|
|
1509
|
-
// ── Lifecycle transitions ────────────────────────────────────────
|
|
1510
|
-
async transition(reportId, to, actor, opts) {
|
|
1511
|
-
return withFileLock(this.filePath, async () => {
|
|
1512
|
-
const all = await this._readAll();
|
|
1513
|
-
const entry = all.find((e) => e.report.id === reportId);
|
|
1514
|
-
if (!entry) throw new Error(`Review report not found: ${reportId}`);
|
|
1515
|
-
const from = this._materialize(entry).lifecycle;
|
|
1516
|
-
validateReportTransition(from, to);
|
|
1517
|
-
const event = {
|
|
1518
|
-
id: randomUUID37(),
|
|
1519
|
-
reportId,
|
|
1520
|
-
eventType: reportEventTypeFor(to),
|
|
1521
|
-
fromLifecycle: from,
|
|
1522
|
-
toLifecycle: to,
|
|
1523
|
-
actorId: actor.id,
|
|
1524
|
-
actorKind: actor.kind,
|
|
1525
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1526
|
-
reason: opts?.reason
|
|
1527
|
-
};
|
|
1528
|
-
entry.report.lifecycle = to;
|
|
1529
|
-
await fsp39.appendFile(this.filePath, JSON.stringify({ __reportEvent: 1, data: event }) + NL2, {
|
|
1530
|
-
encoding: "utf8",
|
|
1531
|
-
mode: SECRET_FILE_MODE
|
|
1532
|
-
});
|
|
1533
|
-
return { ...entry.report };
|
|
1534
|
-
});
|
|
1535
|
-
}
|
|
1536
|
-
async addNote(reportId, actor, note) {
|
|
1537
|
-
return withFileLock(this.filePath, async () => {
|
|
1538
|
-
const all = await this._readAll();
|
|
1539
|
-
const entry = all.find((e) => e.report.id === reportId);
|
|
1540
|
-
if (!entry) throw new Error(`Review report not found: ${reportId}`);
|
|
1541
|
-
const materialized = this._materialize(entry);
|
|
1542
|
-
const event = {
|
|
1543
|
-
id: randomUUID37(),
|
|
1544
|
-
reportId,
|
|
1545
|
-
eventType: "note_added",
|
|
1546
|
-
fromLifecycle: materialized.lifecycle,
|
|
1547
|
-
toLifecycle: materialized.lifecycle,
|
|
1548
|
-
actorId: actor.id,
|
|
1549
|
-
actorKind: actor.kind,
|
|
1550
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1551
|
-
reason: note
|
|
1552
|
-
};
|
|
1553
|
-
await fsp39.appendFile(this.filePath, JSON.stringify({ __reportEvent: 1, data: event }) + NL2, {
|
|
1554
|
-
encoding: "utf8",
|
|
1555
|
-
mode: SECRET_FILE_MODE
|
|
1556
|
-
});
|
|
1557
|
-
return materialized;
|
|
1558
|
-
});
|
|
1559
|
-
}
|
|
1560
|
-
// ── Query ────────────────────────────────────────────────────────
|
|
1561
|
-
async list(opts) {
|
|
1562
|
-
const all = await this._readAll();
|
|
1563
|
-
let reports = all.map((e) => this._materialize(e));
|
|
1564
|
-
if (opts?.statuses && opts.statuses.length > 0) {
|
|
1565
|
-
const set = new Set(opts.statuses);
|
|
1566
|
-
reports = reports.filter((r) => set.has(r.lifecycle));
|
|
1567
|
-
}
|
|
1568
|
-
if (opts?.sources && opts.sources.length > 0) {
|
|
1569
|
-
const set = new Set(opts.sources);
|
|
1570
|
-
reports = reports.filter((r) => set.has(r.source));
|
|
1571
|
-
}
|
|
1572
|
-
reports.sort((a, b) => b.reviewedAt.localeCompare(a.reviewedAt));
|
|
1573
|
-
const limit = opts?.limit ?? REPORT_DEFAULT_PAGE_SIZE;
|
|
1574
|
-
return reports.slice(0, limit);
|
|
1575
|
-
}
|
|
1576
|
-
async get(id) {
|
|
1577
|
-
const all = await this._readAll();
|
|
1578
|
-
const entry = all.find((e) => e.report.id === id);
|
|
1579
|
-
return entry ? this._materialize(entry) : null;
|
|
1580
|
-
}
|
|
1581
|
-
async getEvents(reportId) {
|
|
1582
|
-
const all = await this._readAllLines();
|
|
1583
|
-
const events = [];
|
|
1584
|
-
for (const line of all) {
|
|
1585
|
-
try {
|
|
1586
|
-
const parsed = JSON.parse(line);
|
|
1587
|
-
if (this._isEventRecord(parsed) && parsed.data.reportId === reportId) {
|
|
1588
|
-
events.push(parsed.data);
|
|
1589
|
-
}
|
|
1590
|
-
} catch {
|
|
1591
|
-
}
|
|
1592
|
-
}
|
|
1593
|
-
return events.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
1594
|
-
}
|
|
1595
|
-
// ── Compaction ───────────────────────────────────────────────────
|
|
1596
|
-
async compact(opts) {
|
|
1597
|
-
return withFileLock(this.filePath, async () => {
|
|
1598
|
-
const maxAge = opts?.maxAgeMs ?? REPORT_RETENTION_MS;
|
|
1599
|
-
const now = Date.now();
|
|
1600
|
-
const all = await this._readAll();
|
|
1601
|
-
const kept = [];
|
|
1602
|
-
let removed = 0;
|
|
1603
|
-
let eventsFolded = 0;
|
|
1604
|
-
for (const entry of all) {
|
|
1605
|
-
const age = now - new Date(entry.report.reviewedAt).getTime();
|
|
1606
|
-
const materialized = this._materialize(entry);
|
|
1607
|
-
const isTerminal = materialized.lifecycle === "completed" || materialized.lifecycle === "skipped";
|
|
1608
|
-
if (isTerminal && age > maxAge) {
|
|
1609
|
-
removed++;
|
|
1610
|
-
eventsFolded += entry.events.length;
|
|
1611
|
-
continue;
|
|
1612
|
-
}
|
|
1613
|
-
const oldEvents = entry.events.filter(
|
|
1614
|
-
(ev) => now - new Date(ev.timestamp).getTime() > maxAge
|
|
1615
|
-
);
|
|
1616
|
-
if (oldEvents.length > 1) {
|
|
1617
|
-
eventsFolded += oldEvents.length - 1;
|
|
1618
|
-
const newestOld = oldEvents.sort((a, b) => b.timestamp.localeCompare(a.timestamp))[0];
|
|
1619
|
-
entry.events = [
|
|
1620
|
-
newestOld,
|
|
1621
|
-
...entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() <= maxAge)
|
|
1622
|
-
];
|
|
1623
|
-
}
|
|
1624
|
-
kept.push({ record: { __report: 1, data: entry.report }, events: entry.events });
|
|
1625
|
-
}
|
|
1626
|
-
const lines = [];
|
|
1627
|
-
for (const { record, events } of kept) {
|
|
1628
|
-
if (record) lines.push(JSON.stringify(record));
|
|
1629
|
-
for (const ev of events) {
|
|
1630
|
-
lines.push(JSON.stringify({ __reportEvent: 1, data: ev }));
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
lines.push(
|
|
1634
|
-
JSON.stringify({
|
|
1635
|
-
__reportCompact: 1,
|
|
1636
|
-
compactedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1637
|
-
removedReports: removed,
|
|
1638
|
-
foldedEvents: eventsFolded
|
|
1639
|
-
})
|
|
1640
|
-
);
|
|
1641
|
-
await atomicWrite(this.filePath, lines.join(NL2) + NL2, { mode: 384 });
|
|
1642
|
-
return { removed, eventsFolded };
|
|
1643
|
-
});
|
|
1644
|
-
}
|
|
1645
|
-
// ── Private helpers ──────────────────────────────────────────────
|
|
1646
|
-
async _readAllLines() {
|
|
1647
|
-
try {
|
|
1648
|
-
const raw = await fsp39.readFile(this.filePath, "utf8");
|
|
1649
|
-
return raw.split(NL2).filter((l) => l.trim().length > 0);
|
|
1650
|
-
} catch (err) {
|
|
1651
|
-
if (err.code === "ENOENT") return [];
|
|
1652
|
-
throw err;
|
|
1653
|
-
}
|
|
1654
|
-
}
|
|
1655
|
-
_isReportRecord(v) {
|
|
1656
|
-
return typeof v === "object" && v !== null && v["__report"] === 1;
|
|
1657
|
-
}
|
|
1658
|
-
_isEventRecord(v) {
|
|
1659
|
-
return typeof v === "object" && v !== null && v["__reportEvent"] === 1;
|
|
1660
|
-
}
|
|
1661
|
-
async _readAll() {
|
|
1662
|
-
const lines = await this._readAllLines();
|
|
1663
|
-
const reports = /* @__PURE__ */ new Map();
|
|
1664
|
-
const eventsMap = /* @__PURE__ */ new Map();
|
|
1665
|
-
for (const line of lines) {
|
|
1666
|
-
try {
|
|
1667
|
-
const parsed = JSON.parse(line);
|
|
1668
|
-
if (this._isReportRecord(parsed)) {
|
|
1669
|
-
reports.set(parsed.data.id, parsed.data);
|
|
1670
|
-
if (!eventsMap.has(parsed.data.id)) eventsMap.set(parsed.data.id, []);
|
|
1671
|
-
} else if (this._isEventRecord(parsed)) {
|
|
1672
|
-
const list = eventsMap.get(parsed.data.reportId);
|
|
1673
|
-
if (list) list.push(parsed.data);
|
|
1674
|
-
}
|
|
1675
|
-
} catch {
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1678
|
-
return Array.from(reports.entries()).map(([id, report]) => ({
|
|
1679
|
-
report,
|
|
1680
|
-
events: eventsMap.get(id) ?? []
|
|
1681
|
-
}));
|
|
1682
|
-
}
|
|
1683
|
-
async _findRecord(id) {
|
|
1684
|
-
const all = await this._readAll();
|
|
1685
|
-
const entry = all.find((e) => e.report.id === id);
|
|
1686
|
-
return entry ? this._materialize(entry) : null;
|
|
1687
|
-
}
|
|
1688
|
-
_materialize(entry) {
|
|
1689
|
-
if (entry.events.length === 0) return { ...entry.report };
|
|
1690
|
-
const sorted = [...entry.events].sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
1691
|
-
const latest = sorted[sorted.length - 1];
|
|
1692
|
-
if (latest.eventType !== "note_added") {
|
|
1693
|
-
return { ...entry.report, lifecycle: latest.toLifecycle };
|
|
1694
|
-
}
|
|
1695
|
-
return { ...entry.report };
|
|
1696
|
-
}
|
|
1697
|
-
};
|
|
1698
|
-
}
|
|
1699
|
-
});
|
|
1700
|
-
|
|
1701
1701
|
// src/boot.ts
|
|
1702
1702
|
import * as fs9 from "node:fs/promises";
|
|
1703
1703
|
import * as os3 from "node:os";
|
|
@@ -4014,13 +4014,32 @@ function inlineDefinition(model) {
|
|
|
4014
4014
|
if (maxOutput !== void 0) definition.maxOutput = maxOutput;
|
|
4015
4015
|
const capabilities = readCapabilities(model);
|
|
4016
4016
|
if (capabilities) definition.capabilities = capabilities;
|
|
4017
|
+
const { id: _id, ...rest } = model;
|
|
4018
|
+
if (Object.keys(rest).length > 0) {
|
|
4019
|
+
definition.modelsDev = rest;
|
|
4020
|
+
}
|
|
4017
4021
|
return definition;
|
|
4018
4022
|
}
|
|
4019
4023
|
function mergeDefinitions(base, patch) {
|
|
4024
|
+
const mergedModelsDev = (() => {
|
|
4025
|
+
if (!base?.modelsDev && !patch.modelsDev) return void 0;
|
|
4026
|
+
const baseMd = base?.modelsDev ?? {};
|
|
4027
|
+
const patchMd = patch.modelsDev ?? {};
|
|
4028
|
+
const result = { ...baseMd, ...patchMd };
|
|
4029
|
+
for (const nestedKey of ["limit", "cost", "modalities"]) {
|
|
4030
|
+
const bn = baseMd?.[nestedKey];
|
|
4031
|
+
const pn = patchMd?.[nestedKey];
|
|
4032
|
+
if (bn || pn) {
|
|
4033
|
+
result[nestedKey] = { ...bn ?? {}, ...pn ?? {} };
|
|
4034
|
+
}
|
|
4035
|
+
}
|
|
4036
|
+
return result;
|
|
4037
|
+
})();
|
|
4020
4038
|
return {
|
|
4021
4039
|
...base,
|
|
4022
4040
|
...patch,
|
|
4023
|
-
...base?.capabilities || patch.capabilities ? { capabilities: { ...base?.capabilities, ...patch.capabilities } } : {}
|
|
4041
|
+
...base?.capabilities || patch.capabilities ? { capabilities: { ...base?.capabilities, ...patch.capabilities } } : {},
|
|
4042
|
+
...mergedModelsDev ? { modelsDev: mergedModelsDev } : {}
|
|
4024
4043
|
};
|
|
4025
4044
|
}
|
|
4026
4045
|
function normalizeInlineProviderModels(config, warn) {
|
|
@@ -30697,8 +30716,16 @@ function resolveSubagentModelTarget(config, role, opts = {}) {
|
|
|
30697
30716
|
const resolution = resolveModelMatrixResolution(config.modelMatrix, role);
|
|
30698
30717
|
const matrixTarget = resolveModelTargetFromEntry(config, resolution?.entry);
|
|
30699
30718
|
const implementationTarget = opts.implementationTarget ?? resolveImplementationModelTarget(config);
|
|
30719
|
+
const isAvailable = (providerId, model) => {
|
|
30720
|
+
if (!opts.statusTracker) return true;
|
|
30721
|
+
if (!providerId || !model) return true;
|
|
30722
|
+
return opts.statusTracker.isAvailable(providerId, model);
|
|
30723
|
+
};
|
|
30724
|
+
const matrixEffective = materializeTarget(config, matrixTarget);
|
|
30725
|
+
const matrixIsAvailable = !matrixEffective || isAvailable(matrixEffective.provider, matrixEffective.model);
|
|
30700
30726
|
if (!roleNeedsIndependentReviewModel(role)) {
|
|
30701
30727
|
if (!matrixTarget) return void 0;
|
|
30728
|
+
if (!matrixIsAvailable) return void 0;
|
|
30702
30729
|
return {
|
|
30703
30730
|
...matrixTarget,
|
|
30704
30731
|
source: "matrix",
|
|
@@ -30707,16 +30734,27 @@ function resolveSubagentModelTarget(config, role, opts = {}) {
|
|
|
30707
30734
|
}
|
|
30708
30735
|
const matrixRef = materializeTarget(config, matrixTarget);
|
|
30709
30736
|
if (resolution?.source === "role" || resolution?.source === "phase") {
|
|
30710
|
-
|
|
30737
|
+
if (!matrixTarget) return void 0;
|
|
30738
|
+
if (!matrixIsAvailable) return void 0;
|
|
30739
|
+
return {
|
|
30740
|
+
...matrixTarget,
|
|
30741
|
+
source: "matrix",
|
|
30742
|
+
matrixSource: resolution.source
|
|
30743
|
+
};
|
|
30711
30744
|
}
|
|
30712
30745
|
if (matrixRef && !sameModelReference(matrixRef, implementationTarget)) {
|
|
30746
|
+
if (!matrixIsAvailable) return void 0;
|
|
30713
30747
|
return {
|
|
30714
30748
|
...matrixTarget ?? {},
|
|
30715
30749
|
source: "matrix",
|
|
30716
30750
|
matrixSource: resolution?.source
|
|
30717
30751
|
};
|
|
30718
30752
|
}
|
|
30719
|
-
const diverse =
|
|
30753
|
+
const diverse = chooseDiverseModelTargetWithTracker(
|
|
30754
|
+
config,
|
|
30755
|
+
implementationTarget,
|
|
30756
|
+
opts.statusTracker
|
|
30757
|
+
);
|
|
30720
30758
|
if (diverse) {
|
|
30721
30759
|
return {
|
|
30722
30760
|
provider: diverse.provider,
|
|
@@ -30730,6 +30768,7 @@ function resolveSubagentModelTarget(config, role, opts = {}) {
|
|
|
30730
30768
|
};
|
|
30731
30769
|
}
|
|
30732
30770
|
if (!matrixTarget) return void 0;
|
|
30771
|
+
if (!matrixIsAvailable) return void 0;
|
|
30733
30772
|
return {
|
|
30734
30773
|
...matrixTarget,
|
|
30735
30774
|
source: "matrix",
|
|
@@ -30766,6 +30805,14 @@ function chooseDiverseModelTarget(config, avoid) {
|
|
|
30766
30805
|
candidates.sort((a, b) => modelDiversityScore(b, avoid) - modelDiversityScore(a, avoid));
|
|
30767
30806
|
return candidates[0];
|
|
30768
30807
|
}
|
|
30808
|
+
function chooseDiverseModelTargetWithTracker(config, avoid, tracker) {
|
|
30809
|
+
if (!tracker) return chooseDiverseModelTarget(config, avoid);
|
|
30810
|
+
const ranked = collectConfiguredModelTargets(config).filter((candidate) => !sameModelReference(candidate, avoid)).sort((a, b) => modelDiversityScore(b, avoid) - modelDiversityScore(a, avoid));
|
|
30811
|
+
for (const candidate of ranked) {
|
|
30812
|
+
if (tracker.isAvailable(candidate.provider, candidate.model)) return candidate;
|
|
30813
|
+
}
|
|
30814
|
+
return void 0;
|
|
30815
|
+
}
|
|
30769
30816
|
function collectConfiguredModelTargets(config) {
|
|
30770
30817
|
const seen = /* @__PURE__ */ new Set();
|
|
30771
30818
|
const out = [];
|
|
@@ -37828,6 +37875,36 @@ function isMailboxLeader(agentId, role) {
|
|
|
37828
37875
|
function isMailboxMessageVisibleTo(message, agentId, role) {
|
|
37829
37876
|
return message.audience !== "leaders" || isMailboxLeader(agentId, role);
|
|
37830
37877
|
}
|
|
37878
|
+
function isAffectedBySessionAffinity(message) {
|
|
37879
|
+
return message.sessionAffinity !== void 0;
|
|
37880
|
+
}
|
|
37881
|
+
async function acceptMailboxMessageForSession(message, currentSessionId, ctx) {
|
|
37882
|
+
if (!isAffectedBySessionAffinity(message)) return true;
|
|
37883
|
+
const affinity = message.sessionAffinity;
|
|
37884
|
+
if (affinity === null || typeof affinity !== "object" || Array.isArray(affinity)) {
|
|
37885
|
+
return false;
|
|
37886
|
+
}
|
|
37887
|
+
if (affinity.sessionId !== void 0 && typeof affinity.sessionId !== "string" || affinity.reportId !== void 0 && typeof affinity.reportId !== "string") {
|
|
37888
|
+
return false;
|
|
37889
|
+
}
|
|
37890
|
+
if (!currentSessionId) {
|
|
37891
|
+
return ctx?.allowUnscoped === true;
|
|
37892
|
+
}
|
|
37893
|
+
if (typeof affinity.sessionId === "string" && affinity.sessionId.length > 0) {
|
|
37894
|
+
if (affinity.sessionId !== currentSessionId) return false;
|
|
37895
|
+
return true;
|
|
37896
|
+
}
|
|
37897
|
+
if (affinity.reportId && ctx?.resolveChimeraReportSessionId) {
|
|
37898
|
+
try {
|
|
37899
|
+
const resolved = await ctx.resolveChimeraReportSessionId(affinity.reportId);
|
|
37900
|
+
if (resolved === currentSessionId) return true;
|
|
37901
|
+
if (resolved !== void 0) return false;
|
|
37902
|
+
} catch {
|
|
37903
|
+
}
|
|
37904
|
+
}
|
|
37905
|
+
if (ctx?.allowUnscoped === true) return true;
|
|
37906
|
+
return false;
|
|
37907
|
+
}
|
|
37831
37908
|
function validateSendType(type, to) {
|
|
37832
37909
|
if (type === "control") {
|
|
37833
37910
|
throw new TypeError(
|
|
@@ -38452,7 +38529,7 @@ function makeMailboxTool(opts = {}) {
|
|
|
38452
38529
|
case "ack":
|
|
38453
38530
|
return executeAck(mb, callerId, i);
|
|
38454
38531
|
case "query":
|
|
38455
|
-
return executeQuery(mb, callerId, identity2.role, i);
|
|
38532
|
+
return executeQuery(mb, callerId, callerSessionId, identity2.role, i);
|
|
38456
38533
|
case "status":
|
|
38457
38534
|
return executeStatus(mb);
|
|
38458
38535
|
case "online":
|
|
@@ -38481,12 +38558,18 @@ async function executeCheck(mb, agentId, sessionId, aliases, role, i) {
|
|
|
38481
38558
|
)
|
|
38482
38559
|
);
|
|
38483
38560
|
const seen = /* @__PURE__ */ new Set();
|
|
38484
|
-
const
|
|
38561
|
+
const candidates = batches.flat().filter((m) => {
|
|
38485
38562
|
if (seen.has(m.id)) return false;
|
|
38486
38563
|
if (!isMailboxMessageVisibleTo(m, agentId, role)) return false;
|
|
38487
38564
|
seen.add(m.id);
|
|
38488
38565
|
return true;
|
|
38489
38566
|
});
|
|
38567
|
+
const messages = [];
|
|
38568
|
+
for (const m of candidates) {
|
|
38569
|
+
if (await acceptMailboxMessageForSession(m, sessionId)) {
|
|
38570
|
+
messages.push(m);
|
|
38571
|
+
}
|
|
38572
|
+
}
|
|
38490
38573
|
const acked = markRead || completed ? await mb.ackMany({
|
|
38491
38574
|
acks: messages.map((m) => ({
|
|
38492
38575
|
messageId: m.id,
|
|
@@ -38567,7 +38650,7 @@ async function executeAck(mb, agentId, i) {
|
|
|
38567
38650
|
summary: `Message ${messageId} acknowledged. Read by ${Object.keys(updated.readBy).length} agent(s), Completed: ${updated.completed}.`
|
|
38568
38651
|
};
|
|
38569
38652
|
}
|
|
38570
|
-
async function executeQuery(mb, agentId, role, i) {
|
|
38653
|
+
async function executeQuery(mb, agentId, sessionId, role, i) {
|
|
38571
38654
|
const limit = i.limit ?? 50;
|
|
38572
38655
|
const messages = await mb.query({
|
|
38573
38656
|
to: i.to,
|
|
@@ -38580,7 +38663,12 @@ async function executeQuery(mb, agentId, role, i) {
|
|
|
38580
38663
|
sessionId: i.sessionId,
|
|
38581
38664
|
limit
|
|
38582
38665
|
});
|
|
38583
|
-
const visible =
|
|
38666
|
+
const visible = [];
|
|
38667
|
+
for (const message of messages) {
|
|
38668
|
+
if (isMailboxMessageVisibleTo(message, agentId, role) && await acceptMailboxMessageForSession(message, sessionId)) {
|
|
38669
|
+
visible.push(message);
|
|
38670
|
+
}
|
|
38671
|
+
}
|
|
38584
38672
|
return { ok: true, count: visible.length, messages: visible, summary: `${visible.length} message(s).` };
|
|
38585
38673
|
}
|
|
38586
38674
|
async function executeStatus(mb) {
|
|
@@ -40011,6 +40099,14 @@ var SEND_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
|
|
|
40011
40099
|
"senderSessionId",
|
|
40012
40100
|
"ttlMs",
|
|
40013
40101
|
"taskContext"
|
|
40102
|
+
// 'sessionAffinity' is NOT in the allow-list. The trust-line contract:
|
|
40103
|
+
// session-affinity tokens are stamped ONLY by trusted internal callers
|
|
40104
|
+
// (chimera/auto-review pipelines) that call `mailbox.send()` directly
|
|
40105
|
+
// and never go through this boundary codec. Allowing the field at the
|
|
40106
|
+
// boundary would let any actor with `mail.send.informational` stamp
|
|
40107
|
+
// another session's id and bypass the receiver-side filter. The
|
|
40108
|
+
// receiver trusts the sender-asserted `sessionId`; the boundary must
|
|
40109
|
+
// refuse the field entirely.
|
|
40014
40110
|
]);
|
|
40015
40111
|
var ACK_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
|
|
40016
40112
|
"messageId",
|
|
@@ -40047,7 +40143,15 @@ function parseMailboxSendInput(payload, actor) {
|
|
|
40047
40143
|
const priority = validatePriority(rawPriority);
|
|
40048
40144
|
const audience = validateAudience(payload["audience"]);
|
|
40049
40145
|
const replyTo = optionalString2(payload, "replyTo", "send");
|
|
40050
|
-
return {
|
|
40146
|
+
return {
|
|
40147
|
+
to,
|
|
40148
|
+
type: typeResult.type,
|
|
40149
|
+
subject: subject2,
|
|
40150
|
+
body,
|
|
40151
|
+
priority,
|
|
40152
|
+
audience,
|
|
40153
|
+
replyTo
|
|
40154
|
+
};
|
|
40051
40155
|
}
|
|
40052
40156
|
function parseMailboxQueryInput(payload, actor) {
|
|
40053
40157
|
assertCapability(actor, "mail.read.self", "query");
|
|
@@ -48783,6 +48887,7 @@ function createHqPublisherFromEnv(options) {
|
|
|
48783
48887
|
|
|
48784
48888
|
// src/mailbox-attach.ts
|
|
48785
48889
|
init_error();
|
|
48890
|
+
init_review_report_store();
|
|
48786
48891
|
|
|
48787
48892
|
// src/core/mailbox-loop.ts
|
|
48788
48893
|
init_error();
|
|
@@ -49165,9 +49270,43 @@ function attachMailboxCheckerInner(a, source) {
|
|
|
49165
49270
|
agentId: () => ensureRegistered(),
|
|
49166
49271
|
role: () => resolveMailboxIdentity(a.ctx).role,
|
|
49167
49272
|
aliases: [baseIdOf()],
|
|
49168
|
-
sessionId: () => a.ctx.session.id
|
|
49273
|
+
sessionId: () => a.ctx.session.id,
|
|
49274
|
+
// ACK is deferred to the session-affinity wrapper so messages dropped
|
|
49275
|
+
// by the filter are NOT marked as read by this agent.
|
|
49276
|
+
ack: false
|
|
49169
49277
|
};
|
|
49170
49278
|
const checkMailbox2 = createMailboxChecker(mailboxCheckerOptions);
|
|
49279
|
+
const reportStore = new JsonlReportStore(
|
|
49280
|
+
resolveProjectDir(a.ctx.projectRoot, wstackGlobalRoot())
|
|
49281
|
+
);
|
|
49282
|
+
const sessionAffinityCtx = {
|
|
49283
|
+
resolveChimeraReportSessionId: async (reportId) => (await reportStore.get(reportId))?.sessionId
|
|
49284
|
+
};
|
|
49285
|
+
const applySessionAffinityFilter = (checker, ack) => {
|
|
49286
|
+
return async () => {
|
|
49287
|
+
const currentSessionId = a.ctx.session.id;
|
|
49288
|
+
const agentId = ack ? ensureRegistered() : null;
|
|
49289
|
+
const messages = await checker();
|
|
49290
|
+
const filtered = [];
|
|
49291
|
+
for (const m of messages) {
|
|
49292
|
+
if (await acceptMailboxMessageForSession(m, currentSessionId, sessionAffinityCtx)) {
|
|
49293
|
+
filtered.push(m);
|
|
49294
|
+
}
|
|
49295
|
+
}
|
|
49296
|
+
if (ack && filtered.length > 0 && agentId) {
|
|
49297
|
+
void getMailbox().ackMany({
|
|
49298
|
+
acks: filtered.map((m) => ({
|
|
49299
|
+
messageId: m.id,
|
|
49300
|
+
readerId: agentId,
|
|
49301
|
+
read: true
|
|
49302
|
+
}))
|
|
49303
|
+
}).catch(() => {
|
|
49304
|
+
});
|
|
49305
|
+
}
|
|
49306
|
+
return filtered;
|
|
49307
|
+
};
|
|
49308
|
+
};
|
|
49309
|
+
const sessionScopedCheckMailbox = applySessionAffinityFilter(checkMailbox2, true);
|
|
49171
49310
|
const checkMailboxAwareness = createMailboxChecker({
|
|
49172
49311
|
...mailboxCheckerOptions,
|
|
49173
49312
|
// Exclude out-of-band types (control) from awareness polling.
|
|
@@ -49177,6 +49316,7 @@ function attachMailboxCheckerInner(a, source) {
|
|
|
49177
49316
|
include: (m) => !MAILBOX_TYPE_PROPERTIES[m.type]?.outOfBand,
|
|
49178
49317
|
ack: false
|
|
49179
49318
|
});
|
|
49319
|
+
const sessionScopedCheckMailboxAwareness = applySessionAffinityFilter(checkMailboxAwareness, false);
|
|
49180
49320
|
const AWARENESS_FALLBACK_INTERVAL_MS = MAILBOX_AWARENESS_INTERVAL_MS;
|
|
49181
49321
|
const AWARENESS_PUSH_DEBOUNCE_MS = 500;
|
|
49182
49322
|
let pollInFlight = false;
|
|
@@ -49186,7 +49326,7 @@ function attachMailboxCheckerInner(a, source) {
|
|
|
49186
49326
|
if (awarenessDisposed || pollInFlight) return;
|
|
49187
49327
|
pollInFlight = true;
|
|
49188
49328
|
try {
|
|
49189
|
-
const messages = await
|
|
49329
|
+
const messages = await sessionScopedCheckMailboxAwareness();
|
|
49190
49330
|
if (!awarenessDisposed && messages.length > 0 && a.ctx.meta["coordinationContextMode"] !== "background") {
|
|
49191
49331
|
setBtwNote(a.ctx, buildMailboxBtwAwarenessBlock(messages).text);
|
|
49192
49332
|
}
|
|
@@ -49219,7 +49359,7 @@ function attachMailboxCheckerInner(a, source) {
|
|
|
49219
49359
|
if (pushDebounceTimer !== null) clearTimeout(pushDebounceTimer);
|
|
49220
49360
|
pushUnsub?.();
|
|
49221
49361
|
});
|
|
49222
|
-
return
|
|
49362
|
+
return sessionScopedCheckMailbox;
|
|
49223
49363
|
}
|
|
49224
49364
|
function attachFleetPulse(a, cfg) {
|
|
49225
49365
|
if (!a.ctx.projectRoot || cfg?.enabled === false) {
|
|
@@ -49310,7 +49450,7 @@ function requestLimitExtension(opts) {
|
|
|
49310
49450
|
init_errors();
|
|
49311
49451
|
|
|
49312
49452
|
// src/core/streaming-response-builder.ts
|
|
49313
|
-
import { randomUUID as
|
|
49453
|
+
import { randomUUID as randomUUID29 } from "node:crypto";
|
|
49314
49454
|
var STREAM_DRAIN_TIMEOUT_MS = 500;
|
|
49315
49455
|
function buildResponse(state) {
|
|
49316
49456
|
const content = [];
|
|
@@ -49370,7 +49510,7 @@ function handleContentBlockStart(state, ev) {
|
|
|
49370
49510
|
state.textBuffers.push("");
|
|
49371
49511
|
state.blockOrder.push({ kind: "text", idx: state.currentTextIndex });
|
|
49372
49512
|
} else if (kind === "tool_use") {
|
|
49373
|
-
const id = ev.id ??
|
|
49513
|
+
const id = ev.id ?? randomUUID29();
|
|
49374
49514
|
state.tools.set(id, { name: ev.name ?? "unknown", partial: "" });
|
|
49375
49515
|
state.blockOrder.push({ kind: "tool", id });
|
|
49376
49516
|
state.currentTextIndex = -1;
|
|
@@ -49605,7 +49745,7 @@ async function streamProviderToResponse(provider, req, signal, ctx, events, logg
|
|
|
49605
49745
|
|
|
49606
49746
|
// src/observability/network-telemetry.ts
|
|
49607
49747
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
49608
|
-
import { createHash as createHash23, randomUUID as
|
|
49748
|
+
import { createHash as createHash23, randomUUID as randomUUID30 } from "node:crypto";
|
|
49609
49749
|
import { channel } from "node:diagnostics_channel";
|
|
49610
49750
|
var storage = new AsyncLocalStorage();
|
|
49611
49751
|
var requests = /* @__PURE__ */ new WeakMap();
|
|
@@ -49642,7 +49782,7 @@ function subscribe() {
|
|
|
49642
49782
|
const requestBytes = numberField2(request, "contentLength");
|
|
49643
49783
|
const state = {
|
|
49644
49784
|
...context,
|
|
49645
|
-
requestId:
|
|
49785
|
+
requestId: randomUUID30(),
|
|
49646
49786
|
...target,
|
|
49647
49787
|
...requestBytes !== void 0 ? { requestBytes } : {},
|
|
49648
49788
|
startedAt,
|
|
@@ -49777,7 +49917,7 @@ function hash3(value) {
|
|
|
49777
49917
|
}
|
|
49778
49918
|
|
|
49779
49919
|
// src/core/provider-runner.ts
|
|
49780
|
-
import { randomUUID as
|
|
49920
|
+
import { randomUUID as randomUUID31 } from "node:crypto";
|
|
49781
49921
|
function providerLogCtx(p, r) {
|
|
49782
49922
|
return {
|
|
49783
49923
|
providerId: p.id,
|
|
@@ -49789,11 +49929,11 @@ function providerLogCtx(p, r) {
|
|
|
49789
49929
|
}
|
|
49790
49930
|
async function runProviderWithRetry(opts) {
|
|
49791
49931
|
const { provider, request, signal, ctx, events, retry, logger, tracer } = opts;
|
|
49792
|
-
const logicalRequestId =
|
|
49932
|
+
const logicalRequestId = randomUUID31();
|
|
49793
49933
|
const promptManifest = createChroniclePromptManifest(request);
|
|
49794
49934
|
let attempt = 0;
|
|
49795
49935
|
for (; ; ) {
|
|
49796
|
-
const attemptId =
|
|
49936
|
+
const attemptId = randomUUID31();
|
|
49797
49937
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
49798
49938
|
const startedNs = process.hrtime.bigint();
|
|
49799
49939
|
const correlation = {
|
|
@@ -53272,7 +53412,7 @@ var AutonomousRunner = class {
|
|
|
53272
53412
|
// src/storage/goal-store.ts
|
|
53273
53413
|
init_atomic_write();
|
|
53274
53414
|
init_error();
|
|
53275
|
-
import * as
|
|
53415
|
+
import * as fsp29 from "node:fs/promises";
|
|
53276
53416
|
init_errors();
|
|
53277
53417
|
var MAX_JOURNAL_ENTRIES = 500;
|
|
53278
53418
|
function goalFilePath(projectRoot) {
|
|
@@ -53282,7 +53422,7 @@ async function loadGoal(filePath, events, warn) {
|
|
|
53282
53422
|
const t0 = Date.now();
|
|
53283
53423
|
let raw;
|
|
53284
53424
|
try {
|
|
53285
|
-
raw = await
|
|
53425
|
+
raw = await fsp29.readFile(filePath, "utf8");
|
|
53286
53426
|
} catch (err) {
|
|
53287
53427
|
const code = err.code;
|
|
53288
53428
|
if (code === "ENOENT") {
|
|
@@ -53591,7 +53731,7 @@ var KNOWN_TOKEN_NAMES = Object.values(KNOWN_TOKEN_GROUPS).flat();
|
|
|
53591
53731
|
// src/execution/design-kit-loader.ts
|
|
53592
53732
|
import { existsSync as existsSync7 } from "node:fs";
|
|
53593
53733
|
import * as fs28 from "node:fs/promises";
|
|
53594
|
-
import * as
|
|
53734
|
+
import * as path68 from "node:path";
|
|
53595
53735
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
53596
53736
|
var KIT_FILE = "KIT.md";
|
|
53597
53737
|
var TOKENS_FILE = "tokens.json";
|
|
@@ -53697,7 +53837,7 @@ var DefaultDesignKitLoader = class {
|
|
|
53697
53837
|
}
|
|
53698
53838
|
for (const e of entries) {
|
|
53699
53839
|
if (!e.isDirectory()) continue;
|
|
53700
|
-
const kitFile =
|
|
53840
|
+
const kitFile = path68.join(dir, e.name, KIT_FILE);
|
|
53701
53841
|
try {
|
|
53702
53842
|
const raw = await fs28.readFile(kitFile, "utf8");
|
|
53703
53843
|
const fm = parseKitFrontmatter(raw);
|
|
@@ -53772,7 +53912,7 @@ var DefaultDesignKitLoader = class {
|
|
|
53772
53912
|
const m = await this.find(id);
|
|
53773
53913
|
let tokens;
|
|
53774
53914
|
if (m) {
|
|
53775
|
-
const tokensPath =
|
|
53915
|
+
const tokensPath = path68.join(path68.dirname(m.path), TOKENS_FILE);
|
|
53776
53916
|
try {
|
|
53777
53917
|
const raw = await fs28.readFile(tokensPath, "utf8");
|
|
53778
53918
|
tokens = JSON.parse(raw);
|
|
@@ -53834,12 +53974,12 @@ function mergeKitTokens(base, own) {
|
|
|
53834
53974
|
}
|
|
53835
53975
|
function resolveBundledDesignKitsDir() {
|
|
53836
53976
|
try {
|
|
53837
|
-
const here =
|
|
53977
|
+
const here = path68.dirname(fileURLToPath7(import.meta.url));
|
|
53838
53978
|
const candidates = [
|
|
53839
|
-
|
|
53840
|
-
|
|
53841
|
-
|
|
53842
|
-
|
|
53979
|
+
path68.join(here, "design-kits"),
|
|
53980
|
+
path68.join(here, "..", "design-kits"),
|
|
53981
|
+
path68.join(here, "..", "..", "design-kits"),
|
|
53982
|
+
path68.join(here, "..", "..", "..", "design-kits")
|
|
53843
53983
|
];
|
|
53844
53984
|
for (const c of candidates) {
|
|
53845
53985
|
if (existsSync7(c)) return c;
|
|
@@ -53878,10 +54018,10 @@ function _resetDesignKitLoaderMemo() {
|
|
|
53878
54018
|
// src/execution/design-project-store.ts
|
|
53879
54019
|
import { existsSync as existsSync8 } from "node:fs";
|
|
53880
54020
|
import * as fs29 from "node:fs/promises";
|
|
53881
|
-
import * as
|
|
54021
|
+
import * as path69 from "node:path";
|
|
53882
54022
|
var DESIGN_DIR = ".design";
|
|
53883
54023
|
function designProjectDir(projectRoot) {
|
|
53884
|
-
return
|
|
54024
|
+
return path69.join(projectRoot, DESIGN_DIR);
|
|
53885
54025
|
}
|
|
53886
54026
|
var RULE_FILES = ["rules.md", "RULES.md", "design.md"];
|
|
53887
54027
|
var rulesCache = /* @__PURE__ */ new Map();
|
|
@@ -53896,7 +54036,7 @@ async function loadProjectDesignRules(projectRoot) {
|
|
|
53896
54036
|
let rules;
|
|
53897
54037
|
for (const name of RULE_FILES) {
|
|
53898
54038
|
try {
|
|
53899
|
-
const txt = await fs29.readFile(
|
|
54039
|
+
const txt = await fs29.readFile(path69.join(designProjectDir(projectRoot), name), "utf8");
|
|
53900
54040
|
if (txt.trim()) {
|
|
53901
54041
|
rules = txt.trim();
|
|
53902
54042
|
break;
|
|
@@ -53922,7 +54062,7 @@ function parseOverrides(value) {
|
|
|
53922
54062
|
}
|
|
53923
54063
|
async function loadActiveKit(projectRoot) {
|
|
53924
54064
|
try {
|
|
53925
|
-
const raw = await fs29.readFile(
|
|
54065
|
+
const raw = await fs29.readFile(path69.join(designProjectDir(projectRoot), "active.json"), "utf8");
|
|
53926
54066
|
const parsed = JSON.parse(raw);
|
|
53927
54067
|
if (parsed && typeof parsed.kit === "string") {
|
|
53928
54068
|
return {
|
|
@@ -53956,7 +54096,7 @@ function applyTokenOverrides(tokens, overrides) {
|
|
|
53956
54096
|
async function ensureDesignDir(projectRoot) {
|
|
53957
54097
|
const dir = designProjectDir(projectRoot);
|
|
53958
54098
|
await fs29.mkdir(dir, { recursive: true });
|
|
53959
|
-
const gi =
|
|
54099
|
+
const gi = path69.join(dir, ".gitignore");
|
|
53960
54100
|
if (!existsSync8(gi)) {
|
|
53961
54101
|
try {
|
|
53962
54102
|
await fs29.writeFile(gi, "*\n");
|
|
@@ -53970,11 +54110,11 @@ async function recordKitChoice(projectRoot, kit, stack, source, isoTime, overrid
|
|
|
53970
54110
|
const dir = await ensureDesignDir(projectRoot);
|
|
53971
54111
|
const record = { kit, stack: stack ?? null };
|
|
53972
54112
|
if (overrides && Object.keys(overrides).length > 0) record.overrides = overrides;
|
|
53973
|
-
await fs29.writeFile(
|
|
54113
|
+
await fs29.writeFile(path69.join(dir, "active.json"), `${JSON.stringify(record, null, 2)}
|
|
53974
54114
|
`);
|
|
53975
54115
|
const line = `- ${isoTime} \xB7 kit=${kit}${stack ? ` stack=${stack}` : ""} \xB7 via=${source}
|
|
53976
54116
|
`;
|
|
53977
|
-
await fs29.appendFile(
|
|
54117
|
+
await fs29.appendFile(path69.join(dir, "decisions.md"), line);
|
|
53978
54118
|
} catch {
|
|
53979
54119
|
}
|
|
53980
54120
|
}
|
|
@@ -53990,11 +54130,11 @@ async function recordOverrides(projectRoot, patch, isoTime) {
|
|
|
53990
54130
|
const dir = await ensureDesignDir(projectRoot);
|
|
53991
54131
|
const record = { kit: active.kit, stack: active.stack ?? null };
|
|
53992
54132
|
if (Object.keys(merged).length > 0) record.overrides = merged;
|
|
53993
|
-
await fs29.writeFile(
|
|
54133
|
+
await fs29.writeFile(path69.join(dir, "active.json"), `${JSON.stringify(record, null, 2)}
|
|
53994
54134
|
`);
|
|
53995
54135
|
const keys = Object.keys(patch).join(",");
|
|
53996
54136
|
await fs29.appendFile(
|
|
53997
|
-
|
|
54137
|
+
path69.join(dir, "decisions.md"),
|
|
53998
54138
|
`- ${isoTime} \xB7 kit=${active.kit} \xB7 override=${keys} \xB7 via=set
|
|
53999
54139
|
`
|
|
54000
54140
|
);
|
|
@@ -54004,7 +54144,7 @@ async function recordOverrides(projectRoot, patch, isoTime) {
|
|
|
54004
54144
|
}
|
|
54005
54145
|
async function clearPersistedActiveKit(projectRoot) {
|
|
54006
54146
|
try {
|
|
54007
|
-
await fs29.rm(
|
|
54147
|
+
await fs29.rm(path69.join(designProjectDir(projectRoot), "active.json"), { force: true });
|
|
54008
54148
|
} catch {
|
|
54009
54149
|
}
|
|
54010
54150
|
}
|
|
@@ -56922,7 +57062,7 @@ ${summaryText}` : summaryText;
|
|
|
56922
57062
|
|
|
56923
57063
|
// src/execution/parallel-eternal-engine.ts
|
|
56924
57064
|
init_error();
|
|
56925
|
-
import { randomUUID as
|
|
57065
|
+
import { randomUUID as randomUUID32 } from "node:crypto";
|
|
56926
57066
|
var GOAL_COMPLETE_MARKER2 = /^\s*\[goal[_\s-]?complete\]\s*$/im;
|
|
56927
57067
|
var ParallelEternalEngine = class {
|
|
56928
57068
|
constructor(opts) {
|
|
@@ -56999,7 +57139,7 @@ var ParallelEternalEngine = class {
|
|
|
56999
57139
|
this.state = "running";
|
|
57000
57140
|
await this.persistState("running");
|
|
57001
57141
|
const config = {
|
|
57002
|
-
coordinatorId: `parallel-${
|
|
57142
|
+
coordinatorId: `parallel-${randomUUID32().slice(0, 8)}`,
|
|
57003
57143
|
maxConcurrent: this.slots,
|
|
57004
57144
|
doneCondition: { type: "all_tasks_done" }
|
|
57005
57145
|
};
|
|
@@ -57053,7 +57193,7 @@ var ParallelEternalEngine = class {
|
|
|
57053
57193
|
}
|
|
57054
57194
|
if (!this.coordinator) {
|
|
57055
57195
|
const config = {
|
|
57056
|
-
coordinatorId: `parallel-${
|
|
57196
|
+
coordinatorId: `parallel-${randomUUID32().slice(0, 8)}`,
|
|
57057
57197
|
maxConcurrent: this.slots,
|
|
57058
57198
|
doneCondition: { type: "all_tasks_done" }
|
|
57059
57199
|
};
|
|
@@ -57139,7 +57279,7 @@ ${recentJournal}` : "No prior iterations.",
|
|
|
57139
57279
|
const task = expectDefined(tasks[i]);
|
|
57140
57280
|
const route = routes[i] ?? null;
|
|
57141
57281
|
const subagentId = `parallel-${this.iterations}-${i}`;
|
|
57142
|
-
const taskId =
|
|
57282
|
+
const taskId = randomUUID32();
|
|
57143
57283
|
const personaLine = route ? `Acting agent: ${route.definition.config.name} \u2014 ${route.definition.capability.summary}
|
|
57144
57284
|
` : "";
|
|
57145
57285
|
const spec = {
|
|
@@ -57962,7 +58102,7 @@ Summarize the following message range:`;
|
|
|
57962
58102
|
|
|
57963
58103
|
// src/execution/skill-loader.ts
|
|
57964
58104
|
import * as fs30 from "node:fs/promises";
|
|
57965
|
-
import * as
|
|
58105
|
+
import * as path70 from "node:path";
|
|
57966
58106
|
|
|
57967
58107
|
// src/skills/foreign-sources.ts
|
|
57968
58108
|
var FOREIGN_SKILL_TOOLS = [
|
|
@@ -58032,7 +58172,7 @@ async function entryIsDirectory(dir, entry) {
|
|
|
58032
58172
|
if (entry.isDirectory()) return true;
|
|
58033
58173
|
if (entry.isSymbolicLink()) {
|
|
58034
58174
|
try {
|
|
58035
|
-
return (await fs30.stat(
|
|
58175
|
+
return (await fs30.stat(path70.join(dir, entry.name))).isDirectory();
|
|
58036
58176
|
} catch {
|
|
58037
58177
|
return false;
|
|
58038
58178
|
}
|
|
@@ -58056,7 +58196,7 @@ var DefaultSkillLoader = class {
|
|
|
58056
58196
|
for (const tool of FOREIGN_SKILL_TOOLS) {
|
|
58057
58197
|
if (!foreignIds.includes(tool.id)) continue;
|
|
58058
58198
|
dirs.push({
|
|
58059
|
-
dir:
|
|
58199
|
+
dir: path70.join(root, "." + tool.id, tool.subdir),
|
|
58060
58200
|
source: "foreign",
|
|
58061
58201
|
originTool: tool.id
|
|
58062
58202
|
});
|
|
@@ -58086,7 +58226,7 @@ var DefaultSkillLoader = class {
|
|
|
58086
58226
|
);
|
|
58087
58227
|
for (const e of entries) {
|
|
58088
58228
|
if (!await entryIsDirectory(dir, e)) continue;
|
|
58089
|
-
const skillFile =
|
|
58229
|
+
const skillFile = path70.join(dir, e.name, "SKILL.md");
|
|
58090
58230
|
let raw;
|
|
58091
58231
|
try {
|
|
58092
58232
|
raw = await fs30.readFile(skillFile, "utf8");
|
|
@@ -58215,7 +58355,7 @@ var DefaultSkillLoader = class {
|
|
|
58215
58355
|
if (cached2 !== void 0) return cached2;
|
|
58216
58356
|
const m = await this.find(name);
|
|
58217
58357
|
if (!m) throw new Error(`Skill "${name}" not found`);
|
|
58218
|
-
const savePath =
|
|
58358
|
+
const savePath = path70.join(path70.dirname(m.path), "SKILL.save.md");
|
|
58219
58359
|
let result;
|
|
58220
58360
|
try {
|
|
58221
58361
|
result = await fs30.readFile(savePath, "utf8");
|
|
@@ -58249,13 +58389,13 @@ function parseDescriptionFromText(desc) {
|
|
|
58249
58389
|
|
|
58250
58390
|
// src/execution/prompt-loader.ts
|
|
58251
58391
|
import * as fs32 from "node:fs/promises";
|
|
58252
|
-
import * as
|
|
58392
|
+
import * as path72 from "node:path";
|
|
58253
58393
|
|
|
58254
58394
|
// src/storage/prompt-store.ts
|
|
58255
58395
|
init_atomic_write();
|
|
58256
58396
|
import { createHash as createHash26 } from "node:crypto";
|
|
58257
58397
|
import * as fs31 from "node:fs/promises";
|
|
58258
|
-
import * as
|
|
58398
|
+
import * as path71 from "node:path";
|
|
58259
58399
|
var SCHEMA_VERSION3 = 2;
|
|
58260
58400
|
function promptChecksum(content) {
|
|
58261
58401
|
return createHash26("sha256").update(content, "utf8").digest("hex");
|
|
@@ -58324,7 +58464,7 @@ var DefaultPromptStore = class {
|
|
|
58324
58464
|
if (!file.endsWith(".json")) continue;
|
|
58325
58465
|
try {
|
|
58326
58466
|
const raw = JSON.parse(
|
|
58327
|
-
await fs31.readFile(
|
|
58467
|
+
await fs31.readFile(path71.join(this.dir, file), "utf8")
|
|
58328
58468
|
);
|
|
58329
58469
|
const migrated = migratePromptEntry(raw.entry);
|
|
58330
58470
|
if (migrated) entries.push(migrated);
|
|
@@ -58338,7 +58478,7 @@ var DefaultPromptStore = class {
|
|
|
58338
58478
|
);
|
|
58339
58479
|
}
|
|
58340
58480
|
async get(id) {
|
|
58341
|
-
const file =
|
|
58481
|
+
const file = path71.join(this.dir, `${id}.json`);
|
|
58342
58482
|
try {
|
|
58343
58483
|
const raw = JSON.parse(await fs31.readFile(file, "utf8"));
|
|
58344
58484
|
return migratePromptEntry(raw.entry);
|
|
@@ -58348,12 +58488,12 @@ var DefaultPromptStore = class {
|
|
|
58348
58488
|
}
|
|
58349
58489
|
async save(entry) {
|
|
58350
58490
|
await ensureDir(this.dir);
|
|
58351
|
-
const file =
|
|
58491
|
+
const file = path71.join(this.dir, `${entry.id}.json`);
|
|
58352
58492
|
const raw = { version: SCHEMA_VERSION3, entry };
|
|
58353
58493
|
await atomicWrite(file, JSON.stringify(raw, null, 2));
|
|
58354
58494
|
}
|
|
58355
58495
|
async delete(id) {
|
|
58356
|
-
const file =
|
|
58496
|
+
const file = path71.join(this.dir, `${id}.json`);
|
|
58357
58497
|
try {
|
|
58358
58498
|
await fs31.unlink(file);
|
|
58359
58499
|
return true;
|
|
@@ -58442,7 +58582,7 @@ var DefaultPromptLoader = class {
|
|
|
58442
58582
|
constructor(opts) {
|
|
58443
58583
|
this.projectStore = typeof opts.paths.inProjectPrompts === "string" ? new DefaultPromptStore(opts.paths.inProjectPrompts) : void 0;
|
|
58444
58584
|
this.userStore = typeof opts.paths.globalPrompts === "string" ? new DefaultPromptStore(opts.paths.globalPrompts) : void 0;
|
|
58445
|
-
this.builtinDir = opts.bundledDir ?
|
|
58585
|
+
this.builtinDir = opts.bundledDir ? path72.join(opts.bundledDir, "prompts") : void 0;
|
|
58446
58586
|
}
|
|
58447
58587
|
async list() {
|
|
58448
58588
|
if (this.cache) return this.cache;
|
|
@@ -58574,7 +58714,7 @@ async function walkJson(dir) {
|
|
|
58574
58714
|
return out;
|
|
58575
58715
|
}
|
|
58576
58716
|
for (const e of entries) {
|
|
58577
|
-
const full =
|
|
58717
|
+
const full = path72.join(dir, e.name);
|
|
58578
58718
|
if (e.isDirectory()) {
|
|
58579
58719
|
out.push(...await walkJson(full));
|
|
58580
58720
|
} else if (e.name.endsWith(".json") && e.name !== "index.json" && e.name !== "schema.json") {
|
|
@@ -58761,9 +58901,9 @@ function readPolicy(ctx) {
|
|
|
58761
58901
|
}
|
|
58762
58902
|
|
|
58763
58903
|
// src/execution/tool-executor.ts
|
|
58764
|
-
import { randomUUID as
|
|
58904
|
+
import { randomUUID as randomUUID34 } from "node:crypto";
|
|
58765
58905
|
import * as fs34 from "node:fs/promises";
|
|
58766
|
-
import * as
|
|
58906
|
+
import * as path75 from "node:path";
|
|
58767
58907
|
import { isDeepStrictEqual } from "node:util";
|
|
58768
58908
|
|
|
58769
58909
|
// src/observability/process-telemetry.ts
|
|
@@ -58855,7 +58995,7 @@ function emit(name, event) {
|
|
|
58855
58995
|
|
|
58856
58996
|
// src/security/kanban-boundary.ts
|
|
58857
58997
|
import { realpath as realpath3 } from "node:fs/promises";
|
|
58858
|
-
import * as
|
|
58998
|
+
import * as path73 from "node:path";
|
|
58859
58999
|
import {
|
|
58860
59000
|
evaluateKanbanBoundaryOpaque,
|
|
58861
59001
|
evaluateKanbanBoundaryPath,
|
|
@@ -58944,10 +59084,10 @@ function resolveKanbanIdentity(ctx) {
|
|
|
58944
59084
|
async function extractCandidatePaths(toolName, input, ctx) {
|
|
58945
59085
|
if (toolName === "patch" && typeof input["patch"] === "string") {
|
|
58946
59086
|
const directoryInput = stringValue(input["directory"]) ?? ctx.workingDir;
|
|
58947
|
-
const directory =
|
|
59087
|
+
const directory = path73.isAbsolute(directoryInput) ? directoryInput : path73.resolve(ctx.workingDir, directoryInput);
|
|
58948
59088
|
const strip = Math.max(1, numericValue(input["strip"]) ?? 1);
|
|
58949
59089
|
const targets = extractPatchTargets(input["patch"], strip).map(
|
|
58950
|
-
(target) => relativeToProject(
|
|
59090
|
+
(target) => relativeToProject(path73.resolve(directory, target), ctx.projectRoot)
|
|
58951
59091
|
);
|
|
58952
59092
|
return Promise.all(targets.map((target) => canonicalizeCandidatePath(target, ctx)));
|
|
58953
59093
|
}
|
|
@@ -58957,7 +59097,7 @@ async function extractCandidatePaths(toolName, input, ctx) {
|
|
|
58957
59097
|
collectPathValues(input, values, pathKeys);
|
|
58958
59098
|
if (toolName === "scaffold" && typeof input["name"] === "string") {
|
|
58959
59099
|
const cwd = stringValue(input["cwd"]) ?? ctx.workingDir;
|
|
58960
|
-
values.push(
|
|
59100
|
+
values.push(path73.join(cwd, input["name"]));
|
|
58961
59101
|
}
|
|
58962
59102
|
const candidates = [
|
|
58963
59103
|
...new Set(values.flatMap(splitPathList).map((value) => resolveInputPath(value, ctx)))
|
|
@@ -58965,21 +59105,21 @@ async function extractCandidatePaths(toolName, input, ctx) {
|
|
|
58965
59105
|
return Promise.all(candidates.map((candidate) => canonicalizeCandidatePath(candidate, ctx)));
|
|
58966
59106
|
}
|
|
58967
59107
|
async function canonicalizeCandidatePath(candidate, ctx) {
|
|
58968
|
-
if (
|
|
58969
|
-
const absolute =
|
|
59108
|
+
if (path73.isAbsolute(candidate)) return candidate;
|
|
59109
|
+
const absolute = path73.resolve(ctx.projectRoot, candidate);
|
|
58970
59110
|
const canonicalRoot = await realpath3(ctx.projectRoot).catch(() => ctx.projectRoot);
|
|
58971
59111
|
let probe2 = absolute;
|
|
58972
59112
|
const missingSegments = [];
|
|
58973
59113
|
while (true) {
|
|
58974
59114
|
try {
|
|
58975
|
-
const canonical =
|
|
59115
|
+
const canonical = path73.join(await realpath3(probe2), ...missingSegments);
|
|
58976
59116
|
return relativeToProject(canonical, canonicalRoot);
|
|
58977
59117
|
} catch (cause) {
|
|
58978
59118
|
const code = cause.code;
|
|
58979
59119
|
if (code !== "ENOENT" && code !== "ENOTDIR") return absolute;
|
|
58980
|
-
const parent =
|
|
59120
|
+
const parent = path73.dirname(probe2);
|
|
58981
59121
|
if (parent === probe2) return absolute;
|
|
58982
|
-
missingSegments.unshift(
|
|
59122
|
+
missingSegments.unshift(path73.basename(probe2));
|
|
58983
59123
|
probe2 = parent;
|
|
58984
59124
|
}
|
|
58985
59125
|
}
|
|
@@ -59002,12 +59142,12 @@ function splitPathList(value) {
|
|
|
59002
59142
|
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
59003
59143
|
}
|
|
59004
59144
|
function resolveInputPath(value, ctx) {
|
|
59005
|
-
const absolute =
|
|
59145
|
+
const absolute = path73.isAbsolute(value) ? value : path73.resolve(ctx.workingDir, value);
|
|
59006
59146
|
return relativeToProject(absolute, ctx.projectRoot);
|
|
59007
59147
|
}
|
|
59008
59148
|
function relativeToProject(absolute, projectRoot) {
|
|
59009
|
-
const relative19 =
|
|
59010
|
-
return relative19.startsWith("../") ||
|
|
59149
|
+
const relative19 = path73.relative(projectRoot, absolute).replace(/\\/g, "/");
|
|
59150
|
+
return relative19.startsWith("../") || path73.isAbsolute(relative19) ? absolute : relative19 || ".";
|
|
59011
59151
|
}
|
|
59012
59152
|
function extractPatchTargets(patchText, strip) {
|
|
59013
59153
|
const targets = [];
|
|
@@ -59039,9 +59179,9 @@ init_error();
|
|
|
59039
59179
|
init_errors();
|
|
59040
59180
|
|
|
59041
59181
|
// src/execution/tool-executor-support.ts
|
|
59042
|
-
import { createHash as createHash28, randomUUID as
|
|
59182
|
+
import { createHash as createHash28, randomUUID as randomUUID33 } from "node:crypto";
|
|
59043
59183
|
import * as fs33 from "node:fs/promises";
|
|
59044
|
-
import * as
|
|
59184
|
+
import * as path74 from "node:path";
|
|
59045
59185
|
|
|
59046
59186
|
// src/types/tool.ts
|
|
59047
59187
|
var ToolErrorCategory = /* @__PURE__ */ ((ToolErrorCategory2) => {
|
|
@@ -59179,11 +59319,11 @@ async function maybePersistLargeToolOutput(toolName, content, budget) {
|
|
|
59179
59319
|
return content;
|
|
59180
59320
|
}
|
|
59181
59321
|
try {
|
|
59182
|
-
const dir =
|
|
59322
|
+
const dir = path74.join(wstackGlobalRoot(), "tool-output");
|
|
59183
59323
|
await fs33.mkdir(dir, { recursive: true });
|
|
59184
59324
|
const safeTool = toolName.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40) || "tool";
|
|
59185
59325
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
59186
|
-
const filePath =
|
|
59326
|
+
const filePath = path74.join(dir, `${stamp}-${safeTool}-${randomUUID33()}.log`);
|
|
59187
59327
|
await fs33.writeFile(filePath, content, "utf8");
|
|
59188
59328
|
const marker = `[full tool output: ${bytes} bytes at ${filePath}; read/grep that file selectively instead of re-running or requesting more output]`;
|
|
59189
59329
|
const fixedBytes = Buffer.byteLength(marker + TOOL_OUTPUT_ARTIFACT_OMISSION, "utf8");
|
|
@@ -59769,7 +59909,7 @@ ${errorDetails}`,
|
|
|
59769
59909
|
const inputPath = use.input && typeof use.input === "object" ? use.input.path : void 0;
|
|
59770
59910
|
const caps = tool.capabilities ?? [];
|
|
59771
59911
|
const hasFileCapability = caps.includes("fs.read") || caps.includes("fs.write");
|
|
59772
|
-
const absPath = hasFileCapability && typeof inputPath === "string" ?
|
|
59912
|
+
const absPath = hasFileCapability && typeof inputPath === "string" ? path75.isAbsolute(inputPath) ? inputPath : path75.resolve(ctx.projectRoot, inputPath) : void 0;
|
|
59773
59913
|
let writeTargetExisted;
|
|
59774
59914
|
if (tool.name === "write" && caps.includes("fs.write") && absPath) {
|
|
59775
59915
|
writeTargetExisted = await fs34.stat(absPath).then(
|
|
@@ -59924,7 +60064,7 @@ ${post.additionalContext}`;
|
|
|
59924
60064
|
const bridge = async (toolName, input) => {
|
|
59925
60065
|
const nestedUse = {
|
|
59926
60066
|
type: "tool_use",
|
|
59927
|
-
id: `nested-${
|
|
60067
|
+
id: `nested-${randomUUID34()}`,
|
|
59928
60068
|
name: toolName,
|
|
59929
60069
|
input
|
|
59930
60070
|
};
|
|
@@ -60036,7 +60176,7 @@ ${post.additionalContext}`;
|
|
|
60036
60176
|
]);
|
|
60037
60177
|
let output;
|
|
60038
60178
|
const execute = () => typeof tool.executeStream === "function" ? this.runStreamedTool(tool, input, ctx, combined, toolUseId) : (async () => tool.execute(input, ctx, { signal: combined }))();
|
|
60039
|
-
const telemetryToolCallId = toolUseId ?? `nested-${
|
|
60179
|
+
const telemetryToolCallId = toolUseId ?? `nested-${randomUUID34()}`;
|
|
60040
60180
|
const toolPromise = this.opts.events ? runWithNetworkTelemetry(
|
|
60041
60181
|
{
|
|
60042
60182
|
events: this.opts.events,
|
|
@@ -60589,27 +60729,27 @@ function codexModelMeta(id) {
|
|
|
60589
60729
|
// src/models/mode-store.ts
|
|
60590
60730
|
init_atomic_write();
|
|
60591
60731
|
import * as fs35 from "node:fs/promises";
|
|
60592
|
-
import * as
|
|
60732
|
+
import * as path77 from "node:path";
|
|
60593
60733
|
|
|
60594
60734
|
// src/types/mode-prompts.ts
|
|
60595
60735
|
import { readFileSync as readFileSync17, statSync as statSync7 } from "node:fs";
|
|
60596
|
-
import * as
|
|
60736
|
+
import * as path76 from "node:path";
|
|
60597
60737
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
60598
60738
|
function modePrompt(id) {
|
|
60599
60739
|
for (const dir of modePromptDirCandidates()) {
|
|
60600
60740
|
try {
|
|
60601
|
-
return readFileSync17(
|
|
60741
|
+
return readFileSync17(path76.join(dir, `${id}.md`), "utf8").trimEnd();
|
|
60602
60742
|
} catch {
|
|
60603
60743
|
}
|
|
60604
60744
|
}
|
|
60605
60745
|
return "";
|
|
60606
60746
|
}
|
|
60607
60747
|
function modePromptDirCandidates() {
|
|
60608
|
-
const here =
|
|
60748
|
+
const here = path76.dirname(fileURLToPath8(import.meta.url));
|
|
60609
60749
|
const candidates = [
|
|
60610
|
-
|
|
60611
|
-
|
|
60612
|
-
|
|
60750
|
+
path76.resolve(here, "../../instructions/modes"),
|
|
60751
|
+
path76.resolve(here, "../instructions/modes"),
|
|
60752
|
+
path76.resolve(here, "instructions/modes")
|
|
60613
60753
|
];
|
|
60614
60754
|
return candidates.sort((a, b) => Number(!isDirectory4(a)) - Number(!isDirectory4(b)));
|
|
60615
60755
|
}
|
|
@@ -60841,7 +60981,7 @@ var DefaultModeStore = class {
|
|
|
60841
60981
|
}
|
|
60842
60982
|
async loadActiveMode() {
|
|
60843
60983
|
try {
|
|
60844
|
-
const configPath =
|
|
60984
|
+
const configPath = path77.join(this.configDir, "mode.json");
|
|
60845
60985
|
const content = await fs35.readFile(configPath, "utf8");
|
|
60846
60986
|
const data = JSON.parse(content);
|
|
60847
60987
|
this.activeModeId = data.activeMode ?? null;
|
|
@@ -60852,7 +60992,7 @@ var DefaultModeStore = class {
|
|
|
60852
60992
|
async saveActiveMode() {
|
|
60853
60993
|
try {
|
|
60854
60994
|
await fs35.mkdir(this.configDir, { recursive: true });
|
|
60855
|
-
const configPath =
|
|
60995
|
+
const configPath = path77.join(this.configDir, "mode.json");
|
|
60856
60996
|
await atomicWrite(
|
|
60857
60997
|
configPath,
|
|
60858
60998
|
JSON.stringify({ activeMode: this.activeModeId }, null, 2)
|
|
@@ -60867,11 +61007,11 @@ async function loadProjectModes(modesDir) {
|
|
|
60867
61007
|
const entries = await fs35.readdir(modesDir);
|
|
60868
61008
|
for (const entry of entries) {
|
|
60869
61009
|
if (!entry.endsWith(".md") && !entry.endsWith(".txt")) continue;
|
|
60870
|
-
const filePath =
|
|
61010
|
+
const filePath = path77.join(modesDir, entry);
|
|
60871
61011
|
const stat33 = await fs35.stat(filePath);
|
|
60872
61012
|
if (!stat33.isFile()) continue;
|
|
60873
61013
|
const content = await fs35.readFile(filePath, "utf8");
|
|
60874
|
-
const id =
|
|
61014
|
+
const id = path77.basename(entry, path77.extname(entry));
|
|
60875
61015
|
modes.push({
|
|
60876
61016
|
id,
|
|
60877
61017
|
name: id.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
|
|
@@ -60887,7 +61027,7 @@ async function loadProjectModes(modesDir) {
|
|
|
60887
61027
|
async function loadUserModes(modesDir) {
|
|
60888
61028
|
const modes = [];
|
|
60889
61029
|
try {
|
|
60890
|
-
const manifestPath =
|
|
61030
|
+
const manifestPath = path77.join(modesDir, "modes.json");
|
|
60891
61031
|
const content = await fs35.readFile(manifestPath, "utf8");
|
|
60892
61032
|
const manifest = JSON.parse(content);
|
|
60893
61033
|
for (const mode of manifest.modes) {
|
|
@@ -60900,13 +61040,13 @@ async function loadUserModes(modesDir) {
|
|
|
60900
61040
|
|
|
60901
61041
|
// src/models/models-registry.ts
|
|
60902
61042
|
import * as fs36 from "node:fs/promises";
|
|
60903
|
-
import * as
|
|
61043
|
+
import * as path78 from "node:path";
|
|
60904
61044
|
init_atomic_write();
|
|
60905
61045
|
init_error();
|
|
60906
61046
|
init_errors();
|
|
60907
61047
|
var DEFAULT_URL = "https://models.dev/api.json";
|
|
60908
61048
|
var ENV_URL_KEY = "WRONGSTACK_MODELS_DEV_URL";
|
|
60909
|
-
var DEFAULT_TTL_SECONDS =
|
|
61049
|
+
var DEFAULT_TTL_SECONDS = 3 * 3600;
|
|
60910
61050
|
var DEFAULT_REFRESH_TIMEOUT_MS = 15e3;
|
|
60911
61051
|
var FAMILY_BY_NPM = {
|
|
60912
61052
|
"@ai-sdk/anthropic": "anthropic",
|
|
@@ -60980,7 +61120,7 @@ var DefaultModelsRegistry = class {
|
|
|
60980
61120
|
this.overlay = opts.overlay;
|
|
60981
61121
|
this.overlayUrl = opts.overlayUrl;
|
|
60982
61122
|
this.overlayFile = opts.overlayFile;
|
|
60983
|
-
this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ?
|
|
61123
|
+
this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ? path78.join(path78.dirname(opts.cacheFile), "models-overlay-cache.json") : void 0);
|
|
60984
61124
|
this.logger = opts.logger ?? noOpLogger;
|
|
60985
61125
|
}
|
|
60986
61126
|
async load(opts = {}) {
|
|
@@ -61255,7 +61395,7 @@ var DefaultModelsRegistry = class {
|
|
|
61255
61395
|
}
|
|
61256
61396
|
/** Used by `wstack models refresh` to expose where the cache lives. */
|
|
61257
61397
|
cacheLocation() {
|
|
61258
|
-
return
|
|
61398
|
+
return path78.resolve(this.cacheFile);
|
|
61259
61399
|
}
|
|
61260
61400
|
};
|
|
61261
61401
|
var REASONING_EFFORTS = /* @__PURE__ */ new Set([
|
|
@@ -62338,7 +62478,7 @@ function validateTrustPolicy(value) {
|
|
|
62338
62478
|
}
|
|
62339
62479
|
|
|
62340
62480
|
// src/security/yolo-risk.ts
|
|
62341
|
-
import * as
|
|
62481
|
+
import * as path79 from "node:path";
|
|
62342
62482
|
var CATASTROPHIC_PATTERNS = [
|
|
62343
62483
|
/\b(?:mkfs(?:\.[a-z0-9]+)?|mke2fs|newfs)\b/i,
|
|
62344
62484
|
// make a filesystem — wipes a partition
|
|
@@ -62398,9 +62538,9 @@ function getInputString(input, key) {
|
|
|
62398
62538
|
function pathLooksInsideProject(rawPath, projectRoot) {
|
|
62399
62539
|
if (!projectRoot) return false;
|
|
62400
62540
|
if (rawPath === "~" || rawPath.startsWith("~/") || rawPath.startsWith("~\\")) return false;
|
|
62401
|
-
const resolved =
|
|
62402
|
-
const relative19 =
|
|
62403
|
-
return !!relative19 && !relative19.startsWith("..") && !
|
|
62541
|
+
const resolved = path79.resolve(projectRoot, rawPath);
|
|
62542
|
+
const relative19 = path79.relative(projectRoot, resolved);
|
|
62543
|
+
return !!relative19 && !relative19.startsWith("..") && !path79.isAbsolute(relative19);
|
|
62404
62544
|
}
|
|
62405
62545
|
function tokenizeShell(command) {
|
|
62406
62546
|
return command.match(/"[^"]*"|'[^']*'|\S+/g)?.map((token) => token.replace(/^['"]|['"]$/g, "")) ?? [];
|
|
@@ -63491,8 +63631,8 @@ var DefaultPermissionPolicy = class {
|
|
|
63491
63631
|
// src/storage/attachment-store.ts
|
|
63492
63632
|
init_atomic_write();
|
|
63493
63633
|
import { randomBytes as randomBytes6 } from "node:crypto";
|
|
63494
|
-
import * as
|
|
63495
|
-
import * as
|
|
63634
|
+
import * as fsp30 from "node:fs/promises";
|
|
63635
|
+
import * as path80 from "node:path";
|
|
63496
63636
|
var DEFAULT_SPOOL_THRESHOLD = 256 * 1024;
|
|
63497
63637
|
var PLACEHOLDER_RE = /\[(pasted|image|file) #(\d+)[^\]]*\]|\[file:([^\]]+)\]/g;
|
|
63498
63638
|
var DefaultAttachmentStore = class {
|
|
@@ -63512,8 +63652,8 @@ var DefaultAttachmentStore = class {
|
|
|
63512
63652
|
let spooledPath;
|
|
63513
63653
|
let data = input.data;
|
|
63514
63654
|
if (this.spoolDir && bytes >= this.spoolThreshold) {
|
|
63515
|
-
await
|
|
63516
|
-
spooledPath =
|
|
63655
|
+
await fsp30.mkdir(this.spoolDir, { recursive: true });
|
|
63656
|
+
spooledPath = path80.join(this.spoolDir, `${id}.bin`);
|
|
63517
63657
|
await atomicWrite(spooledPath, input.data, {
|
|
63518
63658
|
encoding: input.kind === "image" ? "base64" : "utf8"
|
|
63519
63659
|
});
|
|
@@ -63575,7 +63715,7 @@ var DefaultAttachmentStore = class {
|
|
|
63575
63715
|
for (const att of this.items.values()) {
|
|
63576
63716
|
if (att.path) toDelete.push(att.path);
|
|
63577
63717
|
}
|
|
63578
|
-
await Promise.all(toDelete.map((p) =>
|
|
63718
|
+
await Promise.all(toDelete.map((p) => fsp30.unlink(p).catch(() => void 0)));
|
|
63579
63719
|
}
|
|
63580
63720
|
this.items.clear();
|
|
63581
63721
|
this.refs.length = 0;
|
|
@@ -63583,7 +63723,7 @@ var DefaultAttachmentStore = class {
|
|
|
63583
63723
|
}
|
|
63584
63724
|
async toBlock(att) {
|
|
63585
63725
|
if (att.kind === "image") {
|
|
63586
|
-
const data = att.data ?? (att.path ? await
|
|
63726
|
+
const data = att.data ?? (att.path ? await fsp30.readFile(att.path, { encoding: "base64" }) : "");
|
|
63587
63727
|
return {
|
|
63588
63728
|
type: "image",
|
|
63589
63729
|
source: {
|
|
@@ -63593,7 +63733,7 @@ var DefaultAttachmentStore = class {
|
|
|
63593
63733
|
}
|
|
63594
63734
|
};
|
|
63595
63735
|
}
|
|
63596
|
-
const raw = att.data ?? (att.path ? await
|
|
63736
|
+
const raw = att.data ?? (att.path ? await fsp30.readFile(att.path, "utf8") : "");
|
|
63597
63737
|
const label = att.meta.filename ? `<file path="${att.meta.filename}">` : "<pasted>";
|
|
63598
63738
|
const close = att.meta.filename ? "</file>" : "</pasted>";
|
|
63599
63739
|
return { type: "text", text: `${label}
|
|
@@ -63760,13 +63900,13 @@ function deepFreeze(obj) {
|
|
|
63760
63900
|
init_atomic_write();
|
|
63761
63901
|
init_error();
|
|
63762
63902
|
init_errors();
|
|
63763
|
-
import * as
|
|
63764
|
-
import { randomUUID as
|
|
63903
|
+
import * as fsp31 from "node:fs/promises";
|
|
63904
|
+
import { randomUUID as randomUUID35 } from "node:crypto";
|
|
63765
63905
|
async function loadPlan(filePath, events) {
|
|
63766
63906
|
const t0 = Date.now();
|
|
63767
63907
|
let raw;
|
|
63768
63908
|
try {
|
|
63769
|
-
raw = await
|
|
63909
|
+
raw = await fsp31.readFile(filePath, "utf8");
|
|
63770
63910
|
} catch (err) {
|
|
63771
63911
|
events?.emit("storage.error", {
|
|
63772
63912
|
sessionId: "~boot~",
|
|
@@ -63859,7 +63999,7 @@ function emptyPlan(sessionId, title) {
|
|
|
63859
63999
|
function addPlanItem(plan, title, details) {
|
|
63860
64000
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
63861
64001
|
const item = {
|
|
63862
|
-
id: `plan_${Date.now()}_${
|
|
64002
|
+
id: `plan_${Date.now()}_${randomUUID35().slice(0, 6)}`,
|
|
63863
64003
|
title,
|
|
63864
64004
|
details,
|
|
63865
64005
|
status: "open",
|
|
@@ -63931,7 +64071,7 @@ function deriveTodosFromPlanItem(plan, idOrIndex, subtasks) {
|
|
|
63931
64071
|
if (subtasks && subtasks.length > 0) {
|
|
63932
64072
|
for (const st of subtasks) {
|
|
63933
64073
|
todos.push({
|
|
63934
|
-
id: `todo_${Date.now()}_${
|
|
64074
|
+
id: `todo_${Date.now()}_${randomUUID35().slice(0, 6)}`,
|
|
63935
64075
|
content: st,
|
|
63936
64076
|
status: "pending",
|
|
63937
64077
|
promotedFromPlan: item.id
|
|
@@ -64076,8 +64216,8 @@ ${cat}:`);
|
|
|
64076
64216
|
// src/storage/queue-store.ts
|
|
64077
64217
|
init_atomic_write();
|
|
64078
64218
|
init_error();
|
|
64079
|
-
import * as
|
|
64080
|
-
import * as
|
|
64219
|
+
import * as fsp32 from "node:fs/promises";
|
|
64220
|
+
import * as path81 from "node:path";
|
|
64081
64221
|
var QUEUE_MAX_ITEMS = 100;
|
|
64082
64222
|
var QUEUE_MAX_BYTES = 16 * 1024 * 1024;
|
|
64083
64223
|
var QUEUE_MAX_ITEM_BYTES = 8 * 1024 * 1024;
|
|
@@ -64110,7 +64250,7 @@ var QueueStore = class {
|
|
|
64110
64250
|
traceId;
|
|
64111
64251
|
logger;
|
|
64112
64252
|
constructor(opts) {
|
|
64113
|
-
this.file =
|
|
64253
|
+
this.file = path81.join(opts.dir, "queue.json");
|
|
64114
64254
|
this.events = opts.events;
|
|
64115
64255
|
this.traceId = opts.traceId;
|
|
64116
64256
|
this.logger = opts.logger;
|
|
@@ -64179,7 +64319,7 @@ var QueueStore = class {
|
|
|
64179
64319
|
const t0 = Date.now();
|
|
64180
64320
|
let raw;
|
|
64181
64321
|
try {
|
|
64182
|
-
const stat33 = await
|
|
64322
|
+
const stat33 = await fsp32.stat(this.file);
|
|
64183
64323
|
if (stat33.size > QUEUE_MAX_BYTES) {
|
|
64184
64324
|
this.logWarn("Queue file exceeds the safe read budget; ignoring it", {
|
|
64185
64325
|
event: "queue_store.read_budget_exceeded",
|
|
@@ -64199,7 +64339,7 @@ var QueueStore = class {
|
|
|
64199
64339
|
});
|
|
64200
64340
|
return [];
|
|
64201
64341
|
}
|
|
64202
|
-
raw = await
|
|
64342
|
+
raw = await fsp32.readFile(this.file, "utf8");
|
|
64203
64343
|
} catch (err) {
|
|
64204
64344
|
const code = err.code;
|
|
64205
64345
|
if (code === "ENOENT") {
|
|
@@ -64286,7 +64426,7 @@ var QueueStore = class {
|
|
|
64286
64426
|
async clear() {
|
|
64287
64427
|
const t0 = Date.now();
|
|
64288
64428
|
try {
|
|
64289
|
-
await
|
|
64429
|
+
await fsp32.unlink(this.file);
|
|
64290
64430
|
this.events?.emit("storage.write", {
|
|
64291
64431
|
sessionId: this.traceId ?? "~boot~",
|
|
64292
64432
|
store: "queue",
|
|
@@ -64326,9 +64466,9 @@ function isPersistedQueueItem(v) {
|
|
|
64326
64466
|
// src/storage/recovery-lock.ts
|
|
64327
64467
|
init_atomic_write();
|
|
64328
64468
|
init_pid();
|
|
64329
|
-
import * as
|
|
64469
|
+
import * as fsp33 from "node:fs/promises";
|
|
64330
64470
|
import * as os10 from "node:os";
|
|
64331
|
-
import * as
|
|
64471
|
+
import * as path82 from "node:path";
|
|
64332
64472
|
var LOCK_FILE = "active.json";
|
|
64333
64473
|
var DEFAULT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
64334
64474
|
var RecoveryLock = class {
|
|
@@ -64339,7 +64479,7 @@ var RecoveryLock = class {
|
|
|
64339
64479
|
sessionStore;
|
|
64340
64480
|
probe;
|
|
64341
64481
|
constructor(opts) {
|
|
64342
|
-
this.file =
|
|
64482
|
+
this.file = path82.join(opts.dir, LOCK_FILE);
|
|
64343
64483
|
this.pid = opts.pid ?? process.pid;
|
|
64344
64484
|
this.hostname = opts.hostname ?? os10.hostname();
|
|
64345
64485
|
this.maxAgeMs = opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
|
|
@@ -64413,7 +64553,7 @@ var RecoveryLock = class {
|
|
|
64413
64553
|
* null return before calling this.
|
|
64414
64554
|
*/
|
|
64415
64555
|
async write(sessionId) {
|
|
64416
|
-
await ensureDir(
|
|
64556
|
+
await ensureDir(path82.dirname(this.file));
|
|
64417
64557
|
const lock = {
|
|
64418
64558
|
v: 1,
|
|
64419
64559
|
sessionId,
|
|
@@ -64422,7 +64562,7 @@ var RecoveryLock = class {
|
|
|
64422
64562
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
64423
64563
|
};
|
|
64424
64564
|
try {
|
|
64425
|
-
await
|
|
64565
|
+
await fsp33.writeFile(this.file, JSON.stringify(lock), { flag: "wx", mode: 384 });
|
|
64426
64566
|
} catch (err) {
|
|
64427
64567
|
const code = err.code;
|
|
64428
64568
|
if (code === "EEXIST") {
|
|
@@ -64438,7 +64578,7 @@ var RecoveryLock = class {
|
|
|
64438
64578
|
*/
|
|
64439
64579
|
async clear() {
|
|
64440
64580
|
try {
|
|
64441
|
-
await
|
|
64581
|
+
await fsp33.unlink(this.file);
|
|
64442
64582
|
} catch (err) {
|
|
64443
64583
|
const code = err.code;
|
|
64444
64584
|
if (code === "ENOENT") return;
|
|
@@ -64448,7 +64588,7 @@ var RecoveryLock = class {
|
|
|
64448
64588
|
async readLock() {
|
|
64449
64589
|
let raw;
|
|
64450
64590
|
try {
|
|
64451
|
-
raw = await
|
|
64591
|
+
raw = await fsp33.readFile(this.file, "utf8");
|
|
64452
64592
|
} catch (err) {
|
|
64453
64593
|
const code = err.code;
|
|
64454
64594
|
if (code === "ENOENT") return null;
|
|
@@ -65060,12 +65200,12 @@ function renderPlainText(meta, events) {
|
|
|
65060
65200
|
// src/storage/todos-checkpoint.ts
|
|
65061
65201
|
init_atomic_write();
|
|
65062
65202
|
init_error();
|
|
65063
|
-
import * as
|
|
65203
|
+
import * as fsp34 from "node:fs/promises";
|
|
65064
65204
|
async function loadTodosCheckpoint(filePath, events, traceId, sessionId) {
|
|
65065
65205
|
const t0 = Date.now();
|
|
65066
65206
|
let raw;
|
|
65067
65207
|
try {
|
|
65068
|
-
raw = await
|
|
65208
|
+
raw = await fsp34.readFile(filePath, "utf8");
|
|
65069
65209
|
} catch (err) {
|
|
65070
65210
|
events?.emit("storage.error", {
|
|
65071
65211
|
sessionId: sessionId ?? "~boot~",
|
|
@@ -70429,8 +70569,8 @@ var PHASE_EVENT_NAMES = [
|
|
|
70429
70569
|
|
|
70430
70570
|
// src/goal/phase-store.ts
|
|
70431
70571
|
init_atomic_write();
|
|
70432
|
-
import * as
|
|
70433
|
-
import * as
|
|
70572
|
+
import * as fsp35 from "node:fs/promises";
|
|
70573
|
+
import * as path83 from "node:path";
|
|
70434
70574
|
var PHASE_STORE_VERSION = 1;
|
|
70435
70575
|
var PhaseStore = class {
|
|
70436
70576
|
baseDir;
|
|
@@ -70438,7 +70578,7 @@ var PhaseStore = class {
|
|
|
70438
70578
|
constructor(opts) {
|
|
70439
70579
|
this.baseDir = opts.baseDir;
|
|
70440
70580
|
this.legacyBaseDirs = (opts.legacyBaseDirs ?? []).filter(
|
|
70441
|
-
(dir) =>
|
|
70581
|
+
(dir) => path83.resolve(dir) !== path83.resolve(this.baseDir)
|
|
70442
70582
|
);
|
|
70443
70583
|
}
|
|
70444
70584
|
async save(graph) {
|
|
@@ -70453,7 +70593,7 @@ var PhaseStore = class {
|
|
|
70453
70593
|
const current = await this.loadFromPath(filePath);
|
|
70454
70594
|
if (current) return current;
|
|
70455
70595
|
for (const legacyDir of this.legacyBaseDirs) {
|
|
70456
|
-
const legacyPath =
|
|
70596
|
+
const legacyPath = path83.join(legacyDir, `${graphId}.json`);
|
|
70457
70597
|
const legacy = await this.loadFromPath(legacyPath);
|
|
70458
70598
|
if (!legacy) continue;
|
|
70459
70599
|
try {
|
|
@@ -70469,19 +70609,19 @@ var PhaseStore = class {
|
|
|
70469
70609
|
async delete(graphId) {
|
|
70470
70610
|
const paths = [
|
|
70471
70611
|
this.getFilePath(graphId),
|
|
70472
|
-
...this.legacyBaseDirs.map((dir) =>
|
|
70612
|
+
...this.legacyBaseDirs.map((dir) => path83.join(dir, `${graphId}.json`))
|
|
70473
70613
|
];
|
|
70474
|
-
await Promise.all(paths.map((filePath) =>
|
|
70614
|
+
await Promise.all(paths.map((filePath) => fsp35.unlink(filePath).catch(() => void 0)));
|
|
70475
70615
|
}
|
|
70476
70616
|
async list() {
|
|
70477
70617
|
try {
|
|
70478
70618
|
await this.migrateLegacyGraphs();
|
|
70479
|
-
const entries = await
|
|
70619
|
+
const entries = await fsp35.readdir(this.baseDir, { withFileTypes: true });
|
|
70480
70620
|
const graphs = [];
|
|
70481
70621
|
for (const entry of entries) {
|
|
70482
70622
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
70483
70623
|
try {
|
|
70484
|
-
const raw = await
|
|
70624
|
+
const raw = await fsp35.readFile(path83.join(this.baseDir, entry.name), "utf8");
|
|
70485
70625
|
const serialized = JSON.parse(raw);
|
|
70486
70626
|
const done = serialized.completedPhaseIds.length;
|
|
70487
70627
|
const total = serialized.phases.length;
|
|
@@ -70500,11 +70640,11 @@ var PhaseStore = class {
|
|
|
70500
70640
|
}
|
|
70501
70641
|
}
|
|
70502
70642
|
getFilePath(graphId) {
|
|
70503
|
-
return
|
|
70643
|
+
return path83.join(this.baseDir, `${graphId}.json`);
|
|
70504
70644
|
}
|
|
70505
70645
|
async loadFromPath(filePath) {
|
|
70506
70646
|
try {
|
|
70507
|
-
const raw = await
|
|
70647
|
+
const raw = await fsp35.readFile(filePath, "utf8");
|
|
70508
70648
|
const serialized = JSON.parse(raw);
|
|
70509
70649
|
return this.deserializeGraph(serialized);
|
|
70510
70650
|
} catch {
|
|
@@ -70513,11 +70653,11 @@ var PhaseStore = class {
|
|
|
70513
70653
|
}
|
|
70514
70654
|
async migrateLegacyGraphs() {
|
|
70515
70655
|
for (const legacyDir of this.legacyBaseDirs) {
|
|
70516
|
-
const entries = await
|
|
70656
|
+
const entries = await fsp35.readdir(legacyDir, { withFileTypes: true }).catch(() => []);
|
|
70517
70657
|
for (const entry of entries) {
|
|
70518
70658
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
70519
|
-
const legacyPath =
|
|
70520
|
-
const currentPath = this.getFilePath(
|
|
70659
|
+
const legacyPath = path83.join(legacyDir, entry.name);
|
|
70660
|
+
const currentPath = this.getFilePath(path83.basename(entry.name, ".json"));
|
|
70521
70661
|
if (await this.pathExists(currentPath)) {
|
|
70522
70662
|
await this.removeMigratedLegacyFile(legacyDir, legacyPath);
|
|
70523
70663
|
continue;
|
|
@@ -70531,15 +70671,15 @@ var PhaseStore = class {
|
|
|
70531
70671
|
}
|
|
70532
70672
|
async pathExists(filePath) {
|
|
70533
70673
|
try {
|
|
70534
|
-
await
|
|
70674
|
+
await fsp35.access(filePath);
|
|
70535
70675
|
return true;
|
|
70536
70676
|
} catch {
|
|
70537
70677
|
return false;
|
|
70538
70678
|
}
|
|
70539
70679
|
}
|
|
70540
70680
|
async removeMigratedLegacyFile(legacyDir, legacyPath) {
|
|
70541
|
-
await
|
|
70542
|
-
await
|
|
70681
|
+
await fsp35.unlink(legacyPath).catch(() => void 0);
|
|
70682
|
+
await fsp35.rmdir(legacyDir).catch(() => void 0);
|
|
70543
70683
|
}
|
|
70544
70684
|
serializeGraph(graph) {
|
|
70545
70685
|
return {
|
|
@@ -70665,8 +70805,8 @@ var PhaseStore = class {
|
|
|
70665
70805
|
|
|
70666
70806
|
// src/goal/checkpoint.ts
|
|
70667
70807
|
init_atomic_write();
|
|
70668
|
-
import * as
|
|
70669
|
-
import * as
|
|
70808
|
+
import * as fsp36 from "node:fs/promises";
|
|
70809
|
+
import * as path84 from "node:path";
|
|
70670
70810
|
var CheckpointManager = class {
|
|
70671
70811
|
store;
|
|
70672
70812
|
maxCheckpoints;
|
|
@@ -70677,10 +70817,10 @@ var CheckpointManager = class {
|
|
|
70677
70817
|
this.store = opts.store;
|
|
70678
70818
|
this.maxCheckpoints = opts.maxCheckpoints ?? 10;
|
|
70679
70819
|
this.maxCheckpointAgeMs = opts.maxCheckpointAgeMs ?? 7 * 24 * 60 * 60 * 1e3;
|
|
70680
|
-
this.baseDir = opts.baseDir ??
|
|
70820
|
+
this.baseDir = opts.baseDir ?? path84.join(opts.store.baseDir, ".checkpoints");
|
|
70681
70821
|
}
|
|
70682
70822
|
async initialize() {
|
|
70683
|
-
await
|
|
70823
|
+
await fsp36.mkdir(this.baseDir, { recursive: true });
|
|
70684
70824
|
await this.loadFromDisk();
|
|
70685
70825
|
}
|
|
70686
70826
|
async saveCheckpoint(graph, label) {
|
|
@@ -70743,14 +70883,14 @@ var CheckpointManager = class {
|
|
|
70743
70883
|
return true;
|
|
70744
70884
|
}
|
|
70745
70885
|
async saveToDisk(checkpoint) {
|
|
70746
|
-
const filePath =
|
|
70886
|
+
const filePath = path84.join(this.baseDir, `${checkpoint.graphId}.json`);
|
|
70747
70887
|
const serialized = {
|
|
70748
70888
|
...checkpoint
|
|
70749
70889
|
};
|
|
70750
70890
|
await withFileLock(filePath, async () => {
|
|
70751
70891
|
let existing = [];
|
|
70752
70892
|
try {
|
|
70753
|
-
const raw = await
|
|
70893
|
+
const raw = await fsp36.readFile(filePath, "utf8");
|
|
70754
70894
|
const parsed = JSON.parse(raw);
|
|
70755
70895
|
if (Array.isArray(parsed)) {
|
|
70756
70896
|
existing = parsed;
|
|
@@ -70764,23 +70904,23 @@ var CheckpointManager = class {
|
|
|
70764
70904
|
async deleteFromDisk(checkpointId) {
|
|
70765
70905
|
let entries;
|
|
70766
70906
|
try {
|
|
70767
|
-
entries = await
|
|
70907
|
+
entries = await fsp36.readdir(this.baseDir);
|
|
70768
70908
|
} catch {
|
|
70769
70909
|
return;
|
|
70770
70910
|
}
|
|
70771
70911
|
for (const filename of entries) {
|
|
70772
70912
|
if (!filename.endsWith(".json")) continue;
|
|
70773
|
-
const filePath =
|
|
70913
|
+
const filePath = path84.join(this.baseDir, filename);
|
|
70774
70914
|
try {
|
|
70775
70915
|
await withFileLock(filePath, async () => {
|
|
70776
|
-
const raw = await
|
|
70916
|
+
const raw = await fsp36.readFile(filePath, "utf8");
|
|
70777
70917
|
const parsed = JSON.parse(raw);
|
|
70778
70918
|
if (!Array.isArray(parsed)) return;
|
|
70779
70919
|
const existing = parsed;
|
|
70780
70920
|
const filtered = existing.filter((c) => c.id !== checkpointId);
|
|
70781
70921
|
if (filtered.length !== existing.length) {
|
|
70782
70922
|
if (filtered.length === 0) {
|
|
70783
|
-
await
|
|
70923
|
+
await fsp36.unlink(filePath);
|
|
70784
70924
|
} else {
|
|
70785
70925
|
await atomicWrite(filePath, JSON.stringify(filtered, null, 2), { mode: 384 });
|
|
70786
70926
|
}
|
|
@@ -70793,15 +70933,15 @@ var CheckpointManager = class {
|
|
|
70793
70933
|
async loadFromDisk() {
|
|
70794
70934
|
let entries;
|
|
70795
70935
|
try {
|
|
70796
|
-
entries = await
|
|
70936
|
+
entries = await fsp36.readdir(this.baseDir);
|
|
70797
70937
|
} catch {
|
|
70798
70938
|
return;
|
|
70799
70939
|
}
|
|
70800
70940
|
for (const filename of entries) {
|
|
70801
70941
|
if (!filename.endsWith(".json")) continue;
|
|
70802
|
-
const filePath =
|
|
70942
|
+
const filePath = path84.join(this.baseDir, filename);
|
|
70803
70943
|
try {
|
|
70804
|
-
const raw = await
|
|
70944
|
+
const raw = await fsp36.readFile(filePath, "utf8");
|
|
70805
70945
|
const parsed = JSON.parse(raw);
|
|
70806
70946
|
if (!Array.isArray(parsed)) continue;
|
|
70807
70947
|
const checkpoints = parsed;
|
|
@@ -71678,7 +71818,7 @@ function countShellHooks(hooks) {
|
|
|
71678
71818
|
|
|
71679
71819
|
// src/hq/session-bridge.ts
|
|
71680
71820
|
import * as fs38 from "node:fs";
|
|
71681
|
-
import * as
|
|
71821
|
+
import * as fsp37 from "node:fs/promises";
|
|
71682
71822
|
|
|
71683
71823
|
// src/types/session-markers.ts
|
|
71684
71824
|
var SESSION_MARKER_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -72136,12 +72276,12 @@ function startSessionTelemetryBridge(opts) {
|
|
|
72136
72276
|
if (disposed || tailing) return;
|
|
72137
72277
|
tailing = true;
|
|
72138
72278
|
try {
|
|
72139
|
-
const stat33 = await
|
|
72279
|
+
const stat33 = await fsp37.stat(sessionFile).catch(() => null);
|
|
72140
72280
|
if (disposed) return;
|
|
72141
72281
|
if (!stat33) return;
|
|
72142
72282
|
setupWatcher2();
|
|
72143
72283
|
if (stat33.size <= offset) return;
|
|
72144
|
-
const fd = await
|
|
72284
|
+
const fd = await fsp37.open(sessionFile, "r");
|
|
72145
72285
|
try {
|
|
72146
72286
|
if (disposed) return;
|
|
72147
72287
|
const len = stat33.size - offset;
|
|
@@ -72570,7 +72710,7 @@ function startCostTelemetryBridge(opts) {
|
|
|
72570
72710
|
init_atomic_write();
|
|
72571
72711
|
import { createHash as createHash29 } from "node:crypto";
|
|
72572
72712
|
import * as fs39 from "node:fs/promises";
|
|
72573
|
-
import * as
|
|
72713
|
+
import * as path85 from "node:path";
|
|
72574
72714
|
|
|
72575
72715
|
// src/hq/write-queues.ts
|
|
72576
72716
|
var BestEffortBatchQueue = class _BestEffortBatchQueue {
|
|
@@ -72665,7 +72805,7 @@ var HqKanbanStore = class {
|
|
|
72665
72805
|
writers = /* @__PURE__ */ new Map();
|
|
72666
72806
|
mergeChains = /* @__PURE__ */ new Map();
|
|
72667
72807
|
constructor(dataDir) {
|
|
72668
|
-
this.dirPath =
|
|
72808
|
+
this.dirPath = path85.join(dataDir, "kanban");
|
|
72669
72809
|
}
|
|
72670
72810
|
async load(projectId) {
|
|
72671
72811
|
const cached2 = this.cache.get(projectId);
|
|
@@ -72773,7 +72913,7 @@ var HqKanbanStore = class {
|
|
|
72773
72913
|
}
|
|
72774
72914
|
filePath(projectId) {
|
|
72775
72915
|
const safe = createHash29("sha256").update(projectId).digest("hex");
|
|
72776
|
-
return
|
|
72916
|
+
return path85.join(this.dirPath, `${safe}.json`);
|
|
72777
72917
|
}
|
|
72778
72918
|
};
|
|
72779
72919
|
function emptyKanbanSnapshot(projectId) {
|
|
@@ -72792,7 +72932,7 @@ function compareKanbanRecord(a, b) {
|
|
|
72792
72932
|
init_file_permissions();
|
|
72793
72933
|
init_atomic_write();
|
|
72794
72934
|
import * as fs41 from "node:fs/promises";
|
|
72795
|
-
import * as
|
|
72935
|
+
import * as path86 from "node:path";
|
|
72796
72936
|
|
|
72797
72937
|
// src/hq/persistence/jsonl-io.ts
|
|
72798
72938
|
import * as fs40 from "node:fs/promises";
|
|
@@ -73014,7 +73154,7 @@ var HqEventLog = class {
|
|
|
73014
73154
|
counted = false;
|
|
73015
73155
|
hydration;
|
|
73016
73156
|
constructor(opts) {
|
|
73017
|
-
this.filePath =
|
|
73157
|
+
this.filePath = path86.join(opts.dataDir, "events.jsonl");
|
|
73018
73158
|
this.maxLines = opts.maxLines ?? DEFAULT_EVENT_LOG_MAX_LINES;
|
|
73019
73159
|
this.rotateKeep = opts.rotateKeep ?? DEFAULT_EVENT_LOG_ROTATE_KEEP;
|
|
73020
73160
|
this.maxBytes = opts.maxBytes ?? DEFAULT_EVENT_LOG_MAX_BYTES;
|
|
@@ -73240,7 +73380,7 @@ async function readRecentEvents(filePath, limit, typeFilter) {
|
|
|
73240
73380
|
// src/hq/persistence/simple-log.ts
|
|
73241
73381
|
init_atomic_write();
|
|
73242
73382
|
import * as fs42 from "node:fs/promises";
|
|
73243
|
-
import * as
|
|
73383
|
+
import * as path87 from "node:path";
|
|
73244
73384
|
var HqSimpleLog = class {
|
|
73245
73385
|
filePath;
|
|
73246
73386
|
maxLines;
|
|
@@ -73251,7 +73391,7 @@ var HqSimpleLog = class {
|
|
|
73251
73391
|
counted = false;
|
|
73252
73392
|
hydration;
|
|
73253
73393
|
constructor(opts) {
|
|
73254
|
-
this.filePath =
|
|
73394
|
+
this.filePath = path87.join(opts.dataDir, opts.filename);
|
|
73255
73395
|
this.maxLines = opts.maxLines ?? Infinity;
|
|
73256
73396
|
this.rotateKeep = opts.rotateKeep ?? this.maxLines;
|
|
73257
73397
|
this.readLimit = opts.readLimit ?? Infinity;
|
|
@@ -73322,12 +73462,12 @@ var HqSimpleLog = class {
|
|
|
73322
73462
|
// src/hq/persistence/snapshot-store.ts
|
|
73323
73463
|
init_atomic_write();
|
|
73324
73464
|
import * as fs43 from "node:fs/promises";
|
|
73325
|
-
import * as
|
|
73465
|
+
import * as path88 from "node:path";
|
|
73326
73466
|
var HqSnapshotStore = class {
|
|
73327
73467
|
filePath;
|
|
73328
73468
|
writer;
|
|
73329
73469
|
constructor(opts) {
|
|
73330
|
-
this.filePath =
|
|
73470
|
+
this.filePath = path88.join(opts.dataDir, "snapshot.json");
|
|
73331
73471
|
this.writer = new BestEffortLatestQueue(
|
|
73332
73472
|
(snapshot) => atomicWrite(this.filePath, JSON.stringify(snapshot), { mode: 384 })
|
|
73333
73473
|
);
|
|
@@ -73355,7 +73495,7 @@ var HqSnapshotStore = class {
|
|
|
73355
73495
|
init_file_permissions();
|
|
73356
73496
|
init_atomic_write();
|
|
73357
73497
|
import * as fs44 from "node:fs/promises";
|
|
73358
|
-
import * as
|
|
73498
|
+
import * as path89 from "node:path";
|
|
73359
73499
|
var HqTimeseriesStore = class {
|
|
73360
73500
|
filePath;
|
|
73361
73501
|
bucketMs;
|
|
@@ -73368,7 +73508,7 @@ var HqTimeseriesStore = class {
|
|
|
73368
73508
|
loaded = false;
|
|
73369
73509
|
loadPromise;
|
|
73370
73510
|
constructor(opts) {
|
|
73371
|
-
this.filePath =
|
|
73511
|
+
this.filePath = path89.join(opts.dataDir, "timeseries.jsonl");
|
|
73372
73512
|
this.bucketMs = opts.bucketMs ?? 5 * 60 * 1e3;
|
|
73373
73513
|
this.maxBuckets = opts.maxBuckets ?? 2016;
|
|
73374
73514
|
this.writer = new BestEffortLatestQueue((snapshot) => this.flushInternal(snapshot));
|
|
@@ -75573,8 +75713,8 @@ function definePlugin(metadata, factory) {
|
|
|
75573
75713
|
// src/plugins/auto-review-plugin.ts
|
|
75574
75714
|
import { spawn as spawn9 } from "node:child_process";
|
|
75575
75715
|
import { createHash as createHash31 } from "node:crypto";
|
|
75576
|
-
import * as
|
|
75577
|
-
import * as
|
|
75716
|
+
import * as fsp38 from "node:fs/promises";
|
|
75717
|
+
import * as path90 from "node:path";
|
|
75578
75718
|
init_error();
|
|
75579
75719
|
|
|
75580
75720
|
// src/plugins/review-claim-registry.ts
|
|
@@ -75866,7 +76006,7 @@ function trimKnownFingerprints(map, max) {
|
|
|
75866
76006
|
map.delete(oldest);
|
|
75867
76007
|
}
|
|
75868
76008
|
}
|
|
75869
|
-
function buildReviewerModelPool(provider, model, fallbackModels = []) {
|
|
76009
|
+
function buildReviewerModelPool(provider, model, fallbackModels = [], statusTracker) {
|
|
75870
76010
|
const primaryProvider = provider.trim();
|
|
75871
76011
|
const primaryModel = model.trim();
|
|
75872
76012
|
const primaryRef = primaryProvider && primaryModel ? `${primaryProvider}/${primaryModel}` : "";
|
|
@@ -75881,12 +76021,20 @@ function buildReviewerModelPool(provider, model, fallbackModels = []) {
|
|
|
75881
76021
|
if (seen.has(normalized)) continue;
|
|
75882
76022
|
seen.add(ref);
|
|
75883
76023
|
seen.add(normalized);
|
|
76024
|
+
if (statusTracker && !statusTracker.isAvailable(parsed.provider.trim(), parsed.model.trim())) {
|
|
76025
|
+
continue;
|
|
76026
|
+
}
|
|
75884
76027
|
pool.push(normalized);
|
|
75885
76028
|
}
|
|
75886
76029
|
return pool;
|
|
75887
76030
|
}
|
|
75888
|
-
function selectRoundRobinReviewerAssignment(pool, cursor, fallbackProvider = "", fallbackModel = "") {
|
|
75889
|
-
|
|
76031
|
+
function selectRoundRobinReviewerAssignment(pool, cursor, fallbackProvider = "", fallbackModel = "", statusTracker) {
|
|
76032
|
+
const filteredPool = statusTracker ? pool.filter((ref) => {
|
|
76033
|
+
const parsed2 = parseModelRef(ref);
|
|
76034
|
+
if (!parsed2.provider?.trim() || !parsed2.model.trim()) return false;
|
|
76035
|
+
return statusTracker.isAvailable(parsed2.provider.trim(), parsed2.model.trim());
|
|
76036
|
+
}) : pool;
|
|
76037
|
+
if (filteredPool.length === 0) {
|
|
75890
76038
|
return {
|
|
75891
76039
|
provider: fallbackProvider,
|
|
75892
76040
|
model: fallbackModel,
|
|
@@ -75894,13 +76042,13 @@ function selectRoundRobinReviewerAssignment(pool, cursor, fallbackProvider = "",
|
|
|
75894
76042
|
nextCursor: cursor + 1
|
|
75895
76043
|
};
|
|
75896
76044
|
}
|
|
75897
|
-
const len =
|
|
76045
|
+
const len = filteredPool.length;
|
|
75898
76046
|
const idx = (cursor % len + len) % len;
|
|
75899
|
-
const primaryRef =
|
|
76047
|
+
const primaryRef = filteredPool[idx];
|
|
75900
76048
|
const parsed = parseModelRef(primaryRef);
|
|
75901
76049
|
const provider = parsed.provider?.trim() || fallbackProvider;
|
|
75902
76050
|
const model = parsed.model.trim() || fallbackModel;
|
|
75903
|
-
const fallbackModels = [...
|
|
76051
|
+
const fallbackModels = [...filteredPool.slice(idx + 1), ...filteredPool.slice(0, idx)];
|
|
75904
76052
|
return {
|
|
75905
76053
|
provider,
|
|
75906
76054
|
model,
|
|
@@ -76051,9 +76199,9 @@ async function snapshotChangedFiles(cwd) {
|
|
|
76051
76199
|
if (file.path.startsWith(".wrongstack/")) continue;
|
|
76052
76200
|
if (budget <= 0) break;
|
|
76053
76201
|
try {
|
|
76054
|
-
const stat33 = await
|
|
76202
|
+
const stat33 = await fsp38.stat(path90.join(cwd, file.path));
|
|
76055
76203
|
if (!stat33.isFile() || stat33.size > MAX_SNAPSHOT_FILE_BYTES) continue;
|
|
76056
|
-
const content = await
|
|
76204
|
+
const content = await fsp38.readFile(path90.join(cwd, file.path), "utf8");
|
|
76057
76205
|
budget -= content.length;
|
|
76058
76206
|
snapshots.push({
|
|
76059
76207
|
...file,
|
|
@@ -76398,7 +76546,7 @@ function createAutoReviewPlugin() {
|
|
|
76398
76546
|
for (const f of allChanged) {
|
|
76399
76547
|
if (f.path.startsWith(".wrongstack/")) continue;
|
|
76400
76548
|
try {
|
|
76401
|
-
await
|
|
76549
|
+
await fsp38.access(path90.join(cwd, f.path));
|
|
76402
76550
|
existing.push(f);
|
|
76403
76551
|
} catch {
|
|
76404
76552
|
}
|
|
@@ -76408,8 +76556,8 @@ function createAutoReviewPlugin() {
|
|
|
76408
76556
|
const filesWithContent = [];
|
|
76409
76557
|
for (const f of toReview) {
|
|
76410
76558
|
try {
|
|
76411
|
-
const absPath =
|
|
76412
|
-
const content = await
|
|
76559
|
+
const absPath = path90.join(cwd, f.path);
|
|
76560
|
+
const content = await fsp38.readFile(absPath, "utf8");
|
|
76413
76561
|
filesWithContent.push({ path: f.path, status: f.status, content });
|
|
76414
76562
|
} catch {
|
|
76415
76563
|
}
|
|
@@ -76515,7 +76663,7 @@ init_review_finding_store();
|
|
|
76515
76663
|
|
|
76516
76664
|
// src/plugins/review-finding-parser.ts
|
|
76517
76665
|
init_review_finding_types();
|
|
76518
|
-
import { randomUUID as
|
|
76666
|
+
import { randomUUID as randomUUID37 } from "node:crypto";
|
|
76519
76667
|
var SUGGEST_LINE = /^\s*(?:→|->|=>)\s*(.+)$/;
|
|
76520
76668
|
var DURATION_LINE = /^Duration:\s*(\d+)s\s*$/im;
|
|
76521
76669
|
function parseChimeraReviewReport(reportText, context = {}) {
|
|
@@ -76523,7 +76671,7 @@ function parseChimeraReviewReport(reportText, context = {}) {
|
|
|
76523
76671
|
return { findings: [], unparseableCount: 0 };
|
|
76524
76672
|
}
|
|
76525
76673
|
const findings = [];
|
|
76526
|
-
const reportId = context.reportId ??
|
|
76674
|
+
const reportId = context.reportId ?? randomUUID37();
|
|
76527
76675
|
let unparseableCount = 0;
|
|
76528
76676
|
let durationSeconds;
|
|
76529
76677
|
let currentSeverity = null;
|
|
@@ -76624,7 +76772,7 @@ function parseFindingSegment(segment, severity, context) {
|
|
|
76624
76772
|
const fullDesc = suggestions.length > 0 ? cleanDesc + "\n" + suggestions.map((s) => " \u2192 " + s).join("\n") : cleanDesc;
|
|
76625
76773
|
const suggestedFix = suggestions.length > 0 ? suggestions.join("\n") : void 0;
|
|
76626
76774
|
return {
|
|
76627
|
-
id:
|
|
76775
|
+
id: randomUUID37(),
|
|
76628
76776
|
fingerprint: computeFindingFingerprint(file ?? "", line ?? null, title),
|
|
76629
76777
|
severity,
|
|
76630
76778
|
source: normalizeFindingSource(context.reviewType),
|
|
@@ -76635,7 +76783,7 @@ function parseFindingSegment(segment, severity, context) {
|
|
|
76635
76783
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
76636
76784
|
status: "active",
|
|
76637
76785
|
originReport: {
|
|
76638
|
-
reportId: context.reportId ??
|
|
76786
|
+
reportId: context.reportId ?? randomUUID37(),
|
|
76639
76787
|
sessionId: context.sessionId ?? "",
|
|
76640
76788
|
agentId: context.agentId ?? "",
|
|
76641
76789
|
reviewerModel: context.reviewerModel ?? ""
|