@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/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 randomUUID35 } from "node:crypto";
1076
- import * as fsp38 from "node:fs/promises";
1077
- import * as path90 from "node:path";
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 path90.join(projectDir, FINDING_STORE_FILE);
1401
+ return path91.join(projectDir, FINDING_STORE_FILE);
1080
1402
  }
1081
- var FINDING_RESOLVED_RETENTION_MS, FINDING_IGNORED_RETENTION_MS, FINDING_DEFAULT_PAGE_SIZE, NL, LINE_SEPARATOR, FINDING_STORE_FILE, JsonlFindingStore;
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
- NL = "\n";
1092
- LINE_SEPARATOR = NL;
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 fsp38.appendFile(
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 fsp38.appendFile(
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 fsp38.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
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: randomUUID35(),
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 fsp38.appendFile(
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 fsp38.readFile(this.filePath, "utf8");
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: randomUUID35(),
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
- return matrixTarget ? { ...matrixTarget, source: "matrix", matrixSource: resolution.source } : void 0;
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 = chooseDiverseModelTarget(config, implementationTarget);
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 messages = batches.flat().filter((m) => {
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 = messages.filter((message) => isMailboxMessageVisibleTo(message, agentId, role));
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 { to, type: typeResult.type, subject: subject2, body, priority, audience, replyTo };
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 checkMailboxAwareness();
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 checkMailbox2;
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 randomUUID28 } from "node:crypto";
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 ?? randomUUID28();
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 randomUUID29 } from "node:crypto";
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: randomUUID29(),
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 randomUUID30 } from "node:crypto";
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 = randomUUID30();
49932
+ const logicalRequestId = randomUUID31();
49793
49933
  const promptManifest = createChroniclePromptManifest(request);
49794
49934
  let attempt = 0;
49795
49935
  for (; ; ) {
49796
- const attemptId = randomUUID30();
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 fsp28 from "node:fs/promises";
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 fsp28.readFile(filePath, "utf8");
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 path67 from "node:path";
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 = path67.join(dir, e.name, KIT_FILE);
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 = path67.join(path67.dirname(m.path), TOKENS_FILE);
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 = path67.dirname(fileURLToPath7(import.meta.url));
53977
+ const here = path68.dirname(fileURLToPath7(import.meta.url));
53838
53978
  const candidates = [
53839
- path67.join(here, "design-kits"),
53840
- path67.join(here, "..", "design-kits"),
53841
- path67.join(here, "..", "..", "design-kits"),
53842
- path67.join(here, "..", "..", "..", "design-kits")
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 path68 from "node:path";
54021
+ import * as path69 from "node:path";
53882
54022
  var DESIGN_DIR = ".design";
53883
54023
  function designProjectDir(projectRoot) {
53884
- return path68.join(projectRoot, DESIGN_DIR);
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(path68.join(designProjectDir(projectRoot), name), "utf8");
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(path68.join(designProjectDir(projectRoot), "active.json"), "utf8");
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 = path68.join(dir, ".gitignore");
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(path68.join(dir, "active.json"), `${JSON.stringify(record, null, 2)}
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(path68.join(dir, "decisions.md"), line);
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(path68.join(dir, "active.json"), `${JSON.stringify(record, null, 2)}
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
- path68.join(dir, "decisions.md"),
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(path68.join(designProjectDir(projectRoot), "active.json"), { force: true });
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 randomUUID31 } from "node:crypto";
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-${randomUUID31().slice(0, 8)}`,
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-${randomUUID31().slice(0, 8)}`,
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 = randomUUID31();
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 path69 from "node:path";
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(path69.join(dir, entry.name))).isDirectory();
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: path69.join(root, "." + tool.id, tool.subdir),
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 = path69.join(dir, e.name, "SKILL.md");
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 = path69.join(path69.dirname(m.path), "SKILL.save.md");
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 path71 from "node:path";
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 path70 from "node:path";
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(path70.join(this.dir, file), "utf8")
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 = path70.join(this.dir, `${id}.json`);
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 = path70.join(this.dir, `${entry.id}.json`);
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 = path70.join(this.dir, `${id}.json`);
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 ? path71.join(opts.bundledDir, "prompts") : void 0;
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 = path71.join(dir, e.name);
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 randomUUID33 } from "node:crypto";
58904
+ import { randomUUID as randomUUID34 } from "node:crypto";
58765
58905
  import * as fs34 from "node:fs/promises";
58766
- import * as path74 from "node:path";
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 path72 from "node:path";
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 = path72.isAbsolute(directoryInput) ? directoryInput : path72.resolve(ctx.workingDir, directoryInput);
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(path72.resolve(directory, target), ctx.projectRoot)
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(path72.join(cwd, input["name"]));
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 (path72.isAbsolute(candidate)) return candidate;
58969
- const absolute = path72.resolve(ctx.projectRoot, candidate);
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 = path72.join(await realpath3(probe2), ...missingSegments);
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 = path72.dirname(probe2);
59120
+ const parent = path73.dirname(probe2);
58981
59121
  if (parent === probe2) return absolute;
58982
- missingSegments.unshift(path72.basename(probe2));
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 = path72.isAbsolute(value) ? value : path72.resolve(ctx.workingDir, value);
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 = path72.relative(projectRoot, absolute).replace(/\\/g, "/");
59010
- return relative19.startsWith("../") || path72.isAbsolute(relative19) ? absolute : relative19 || ".";
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 randomUUID32 } from "node:crypto";
59182
+ import { createHash as createHash28, randomUUID as randomUUID33 } from "node:crypto";
59043
59183
  import * as fs33 from "node:fs/promises";
59044
- import * as path73 from "node:path";
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 = path73.join(wstackGlobalRoot(), "tool-output");
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 = path73.join(dir, `${stamp}-${safeTool}-${randomUUID32()}.log`);
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" ? path74.isAbsolute(inputPath) ? inputPath : path74.resolve(ctx.projectRoot, inputPath) : void 0;
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-${randomUUID33()}`,
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-${randomUUID33()}`;
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 path76 from "node:path";
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 path75 from "node:path";
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(path75.join(dir, `${id}.md`), "utf8").trimEnd();
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 = path75.dirname(fileURLToPath8(import.meta.url));
60748
+ const here = path76.dirname(fileURLToPath8(import.meta.url));
60609
60749
  const candidates = [
60610
- path75.resolve(here, "../../instructions/modes"),
60611
- path75.resolve(here, "../instructions/modes"),
60612
- path75.resolve(here, "instructions/modes")
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 = path76.join(this.configDir, "mode.json");
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 = path76.join(this.configDir, "mode.json");
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 = path76.join(modesDir, entry);
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 = path76.basename(entry, path76.extname(entry));
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 = path76.join(modesDir, "modes.json");
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 path77 from "node:path";
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 = 24 * 3600;
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 ? path77.join(path77.dirname(opts.cacheFile), "models-overlay-cache.json") : void 0);
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 path77.resolve(this.cacheFile);
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 path78 from "node:path";
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 = path78.resolve(projectRoot, rawPath);
62402
- const relative19 = path78.relative(projectRoot, resolved);
62403
- return !!relative19 && !relative19.startsWith("..") && !path78.isAbsolute(relative19);
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 fsp29 from "node:fs/promises";
63495
- import * as path79 from "node:path";
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 fsp29.mkdir(this.spoolDir, { recursive: true });
63516
- spooledPath = path79.join(this.spoolDir, `${id}.bin`);
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) => fsp29.unlink(p).catch(() => void 0)));
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 fsp29.readFile(att.path, { encoding: "base64" }) : "");
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 fsp29.readFile(att.path, "utf8") : "");
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 fsp30 from "node:fs/promises";
63764
- import { randomUUID as randomUUID34 } from "node:crypto";
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 fsp30.readFile(filePath, "utf8");
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()}_${randomUUID34().slice(0, 6)}`,
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()}_${randomUUID34().slice(0, 6)}`,
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 fsp31 from "node:fs/promises";
64080
- import * as path80 from "node:path";
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 = path80.join(opts.dir, "queue.json");
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 fsp31.stat(this.file);
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 fsp31.readFile(this.file, "utf8");
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 fsp31.unlink(this.file);
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 fsp32 from "node:fs/promises";
64469
+ import * as fsp33 from "node:fs/promises";
64330
64470
  import * as os10 from "node:os";
64331
- import * as path81 from "node:path";
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 = path81.join(opts.dir, LOCK_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(path81.dirname(this.file));
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 fsp32.writeFile(this.file, JSON.stringify(lock), { flag: "wx", mode: 384 });
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 fsp32.unlink(this.file);
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 fsp32.readFile(this.file, "utf8");
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 fsp33 from "node:fs/promises";
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 fsp33.readFile(filePath, "utf8");
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 fsp34 from "node:fs/promises";
70433
- import * as path82 from "node:path";
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) => path82.resolve(dir) !== path82.resolve(this.baseDir)
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 = path82.join(legacyDir, `${graphId}.json`);
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) => path82.join(dir, `${graphId}.json`))
70612
+ ...this.legacyBaseDirs.map((dir) => path83.join(dir, `${graphId}.json`))
70473
70613
  ];
70474
- await Promise.all(paths.map((filePath) => fsp34.unlink(filePath).catch(() => void 0)));
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 fsp34.readdir(this.baseDir, { withFileTypes: true });
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 fsp34.readFile(path82.join(this.baseDir, entry.name), "utf8");
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 path82.join(this.baseDir, `${graphId}.json`);
70643
+ return path83.join(this.baseDir, `${graphId}.json`);
70504
70644
  }
70505
70645
  async loadFromPath(filePath) {
70506
70646
  try {
70507
- const raw = await fsp34.readFile(filePath, "utf8");
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 fsp34.readdir(legacyDir, { withFileTypes: true }).catch(() => []);
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 = path82.join(legacyDir, entry.name);
70520
- const currentPath = this.getFilePath(path82.basename(entry.name, ".json"));
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 fsp34.access(filePath);
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 fsp34.unlink(legacyPath).catch(() => void 0);
70542
- await fsp34.rmdir(legacyDir).catch(() => void 0);
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 fsp35 from "node:fs/promises";
70669
- import * as path83 from "node:path";
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 ?? path83.join(opts.store.baseDir, ".checkpoints");
70820
+ this.baseDir = opts.baseDir ?? path84.join(opts.store.baseDir, ".checkpoints");
70681
70821
  }
70682
70822
  async initialize() {
70683
- await fsp35.mkdir(this.baseDir, { recursive: true });
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 = path83.join(this.baseDir, `${checkpoint.graphId}.json`);
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 fsp35.readFile(filePath, "utf8");
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 fsp35.readdir(this.baseDir);
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 = path83.join(this.baseDir, filename);
70913
+ const filePath = path84.join(this.baseDir, filename);
70774
70914
  try {
70775
70915
  await withFileLock(filePath, async () => {
70776
- const raw = await fsp35.readFile(filePath, "utf8");
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 fsp35.unlink(filePath);
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 fsp35.readdir(this.baseDir);
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 = path83.join(this.baseDir, filename);
70942
+ const filePath = path84.join(this.baseDir, filename);
70803
70943
  try {
70804
- const raw = await fsp35.readFile(filePath, "utf8");
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 fsp36 from "node:fs/promises";
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 fsp36.stat(sessionFile).catch(() => null);
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 fsp36.open(sessionFile, "r");
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 path84 from "node:path";
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 = path84.join(dataDir, "kanban");
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 path84.join(this.dirPath, `${safe}.json`);
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 path85 from "node:path";
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 = path85.join(opts.dataDir, "events.jsonl");
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 path86 from "node:path";
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 = path86.join(opts.dataDir, opts.filename);
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 path87 from "node:path";
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 = path87.join(opts.dataDir, "snapshot.json");
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 path88 from "node:path";
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 = path88.join(opts.dataDir, "timeseries.jsonl");
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 fsp37 from "node:fs/promises";
75577
- import * as path89 from "node:path";
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
- if (pool.length === 0) {
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 = pool.length;
76045
+ const len = filteredPool.length;
75898
76046
  const idx = (cursor % len + len) % len;
75899
- const primaryRef = pool[idx];
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 = [...pool.slice(idx + 1), ...pool.slice(0, idx)];
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 fsp37.stat(path89.join(cwd, file.path));
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 fsp37.readFile(path89.join(cwd, file.path), "utf8");
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 fsp37.access(path89.join(cwd, f.path));
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 = path89.join(cwd, f.path);
76412
- const content = await fsp37.readFile(absPath, "utf8");
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 randomUUID36 } from "node:crypto";
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 ?? randomUUID36();
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: randomUUID36(),
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 ?? randomUUID36(),
76786
+ reportId: context.reportId ?? randomUUID37(),
76639
76787
  sessionId: context.sessionId ?? "",
76640
76788
  agentId: context.agentId ?? "",
76641
76789
  reviewerModel: context.reviewerModel ?? ""