@wrongstack/core 0.310.1 → 0.313.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chronicle/index.js +84 -6391
- package/dist/chronicle/project-server.js +84 -4868
- package/dist/chunk-2BUUIMQB.js +225 -0
- package/dist/chunk-2FK4WTFF.js +207 -0
- package/dist/chunk-2FQL4PDC.js +292 -0
- package/dist/chunk-2KKODIQU.js +2256 -0
- package/dist/chunk-2YU4WVBW.js +134 -0
- package/dist/chunk-3E244UDA.js +356 -0
- package/dist/chunk-3XPVB7BA.js +135 -0
- package/dist/chunk-4LJJYBAU.js +388 -0
- package/dist/chunk-4VWO3ZXL.js +342 -0
- package/dist/chunk-4XV6IR37.js +187 -0
- package/dist/chunk-4ZHTKJHM.js +183 -0
- package/dist/chunk-52RTVH4M.js +361 -0
- package/dist/chunk-57GEWK5X.js +26 -0
- package/dist/chunk-5DSMEVA4.js +931 -0
- package/dist/chunk-5RP3QTRL.js +1223 -0
- package/dist/chunk-5S437PRC.js +50 -0
- package/dist/chunk-5XDUGTKN.js +511 -0
- package/dist/chunk-62V2AFVG.js +422 -0
- package/dist/chunk-65RDIOR2.js +2470 -0
- package/dist/chunk-6AKOTGLM.js +597 -0
- package/dist/chunk-7ZHZE5EO.js +28 -0
- package/dist/chunk-A455ATZB.js +140 -0
- package/dist/chunk-AD7ZFZCS.js +46 -0
- package/dist/chunk-AI4LLQ2U.js +856 -0
- package/dist/chunk-ASX6AW36.js +789 -0
- package/dist/chunk-AT4V4XGI.js +3522 -0
- package/dist/chunk-AWNQ6ED6.js +311 -0
- package/dist/chunk-B4AMLZPB.js +9 -0
- package/dist/chunk-BAKVJLEV.js +417 -0
- package/dist/chunk-BJHVULHO.js +55 -0
- package/dist/chunk-CB2HFKTP.js +9 -0
- package/dist/chunk-CE4ZOCOI.js +1640 -0
- package/dist/chunk-CQQL4ZOQ.js +151 -0
- package/dist/chunk-DEIQMBD2.js +65 -0
- package/dist/chunk-E6I5RXVK.js +58 -0
- package/dist/chunk-EFEHDQGY.js +1589 -0
- package/dist/chunk-EODDVJBM.js +82 -0
- package/dist/chunk-EPC3GZD4.js +308 -0
- package/dist/chunk-FAYRX2AD.js +13 -0
- package/dist/chunk-FFSX2QDQ.js +362 -0
- package/dist/chunk-FHAMQS7Q.js +5856 -0
- package/dist/chunk-FIV4IJL7.js +2263 -0
- package/dist/chunk-FNXVT7HF.js +52 -0
- package/dist/chunk-FSWCWSTS.js +395 -0
- package/dist/chunk-FW5LDDMJ.js +16464 -0
- package/dist/chunk-FXQLIX3K.js +211 -0
- package/dist/chunk-G5AAKEEZ.js +228 -0
- package/dist/chunk-G5S3S5ZN.js +38 -0
- package/dist/chunk-GAZEWQEZ.js +231 -0
- package/dist/chunk-GFJOMSHG.js +125 -0
- package/dist/chunk-GFXZTHNI.js +158 -0
- package/dist/chunk-GM54GJBU.js +960 -0
- package/dist/chunk-GPQ3NJPR.js +900 -0
- package/dist/chunk-GTCU6DZ3.js +1 -0
- package/dist/chunk-H5E77KUJ.js +15 -0
- package/dist/chunk-H72H4XDU.js +1023 -0
- package/dist/chunk-HA4ZYA6T.js +178 -0
- package/dist/chunk-I45KAW2N.js +5020 -0
- package/dist/chunk-IQ35HMQL.js +1396 -0
- package/dist/chunk-IYFBFX34.js +86 -0
- package/dist/chunk-JJPMWPB6.js +109 -0
- package/dist/chunk-JTHKOYWU.js +663 -0
- package/dist/chunk-JVGPR3TS.js +365 -0
- package/dist/chunk-JVKB2TBL.js +48 -0
- package/dist/chunk-JX7VBZDK.js +31 -0
- package/dist/chunk-K3G6JBUC.js +5232 -0
- package/dist/chunk-K4YUNKU7.js +589 -0
- package/dist/chunk-KBZGE6LN.js +710 -0
- package/dist/chunk-KDQJCT2J.js +45 -0
- package/dist/chunk-KI4L2DUL.js +560 -0
- package/dist/chunk-KJ2ZTQSL.js +47 -0
- package/dist/chunk-KSJ5UTP7.js +154 -0
- package/dist/chunk-LHOA5DWA.js +28 -0
- package/dist/chunk-LX5QWLBL.js +27 -0
- package/dist/chunk-LZDDLNCZ.js +279 -0
- package/dist/chunk-M2WF6AXG.js +115 -0
- package/dist/chunk-M7BS2K6U.js +1 -0
- package/dist/chunk-NDBIPFNY.js +102 -0
- package/dist/chunk-NEMIWEXC.js +1199 -0
- package/dist/chunk-NFAYHPRH.js +323 -0
- package/dist/chunk-O37BQ65S.js +21 -0
- package/dist/chunk-O74MJHXU.js +187 -0
- package/dist/chunk-OJZEX73F.js +112 -0
- package/dist/chunk-PAAWLLZX.js +74 -0
- package/dist/chunk-PFXFQQRT.js +339 -0
- package/dist/chunk-PFZO3C6H.js +14 -0
- package/dist/chunk-PHH7LD45.js +113 -0
- package/dist/chunk-QRTG4XTI.js +188 -0
- package/dist/chunk-QVOVMXJR.js +1351 -0
- package/dist/chunk-RCQYT2I4.js +757 -0
- package/dist/chunk-RD6DEE36.js +1178 -0
- package/dist/chunk-RJIZEJ42.js +30 -0
- package/dist/chunk-RPOA7IAE.js +150 -0
- package/dist/chunk-SN2DQRL6.js +1172 -0
- package/dist/chunk-SQJVFEBV.js +41 -0
- package/dist/chunk-SQP64RCS.js +5391 -0
- package/dist/chunk-SVT4RNTR.js +49 -0
- package/dist/chunk-SWUFN7XM.js +43 -0
- package/dist/chunk-SXMVYC5H.js +174 -0
- package/dist/chunk-SZ6AYUIZ.js +23 -0
- package/dist/chunk-T3KGZBU5.js +3171 -0
- package/dist/chunk-TBRL2RCC.js +9 -0
- package/dist/chunk-TRT2HRWZ.js +18 -0
- package/dist/chunk-TYW2GI5I.js +1077 -0
- package/dist/chunk-UIWONWVG.js +4959 -0
- package/dist/chunk-VB3H5WWB.js +151 -0
- package/dist/chunk-W4A6QA3D.js +258 -0
- package/dist/chunk-WBPVKEEE.js +227 -0
- package/dist/chunk-WEBMSQP2.js +123 -0
- package/dist/chunk-WOEZV3Q4.js +333 -0
- package/dist/chunk-WQQON3SV.js +473 -0
- package/dist/chunk-WQTOVMGV.js +119 -0
- package/dist/chunk-WZO23AWO.js +2779 -0
- package/dist/chunk-XBDP4QPW.js +7 -0
- package/dist/chunk-XEBHSJLT.js +103 -0
- package/dist/chunk-XQ2ECNK3.js +1 -0
- package/dist/chunk-XQ2XGIBF.js +2086 -0
- package/dist/chunk-Y2GE5TSI.js +355 -0
- package/dist/chunk-YBUJCZ57.js +351 -0
- package/dist/chunk-YNCVSFGF.js +149 -0
- package/dist/chunk-YUPMXOGP.js +282 -0
- package/dist/chunk-YY6APYUM.js +49 -0
- package/dist/chunk-Z2IJUO45.js +691 -0
- package/dist/chunk-ZEHUCJHY.js +129 -0
- package/dist/chunk-ZYU2YOJ6.js +1496 -0
- package/dist/chunk-ZZ4V3WIZ.js +163 -0
- package/dist/coordination/agents/index.js +145 -6260
- package/dist/coordination/index.js +365 -34323
- package/dist/coordination/mailbox-project-server.js +48 -3220
- package/dist/coordination/mailbox-types.d.ts +13 -1
- package/dist/coordination/provider-status-tracker.d.ts +4 -0
- package/dist/coordination/sqlite-mailbox.d.ts +2 -1
- package/dist/core/agent.d.ts +14 -1
- package/dist/core/index.js +267 -12479
- package/dist/core/model-ref.js +5 -23
- package/dist/core/provider-runner.d.ts +36 -1
- package/dist/design/index.js +50 -1087
- package/dist/execution/index.d.ts +1 -1
- package/dist/execution/index.js +1599 -21887
- package/dist/execution/prompt-enhancer.js +16 -535
- package/dist/execution/retry-policy.d.ts +31 -1
- package/dist/extension/index.js +7 -311
- package/dist/goal/index.js +33 -3435
- package/dist/hooks/index.js +14 -1138
- package/dist/hq/index.js +112 -5139
- package/dist/hq/protocol.js +21 -668
- package/dist/index.js +1410 -92655
- package/dist/infrastructure/index.js +64 -4811
- package/dist/kernel/events/provider-events.d.ts +15 -0
- package/dist/kernel/events/wrongtrace-events.d.ts +26 -0
- package/dist/kernel/events.d.ts +16 -7
- package/dist/kernel/index.js +14 -992
- package/dist/models/index.js +40 -1117
- package/dist/notifications/index.js +3 -108
- package/dist/observability/index.js +17 -279
- package/dist/plugin/index.js +584 -14835
- package/dist/prompts/index.js +14 -948
- package/dist/registry/index.js +9 -822
- package/dist/registry-R23UBE7H.js +14 -0
- package/dist/replay/index.js +6 -84
- package/dist/review-finding-store-DKAV3AS6.js +21 -0
- package/dist/review-report-store-OWY3EC3N.js +19 -0
- package/dist/security/index.js +114 -2202
- package/dist/session-catalog/index.js +36 -2103
- package/dist/session-catalog/project-server.js +42 -1435
- package/dist/skills/index.js +35 -1578
- package/dist/storage/index.js +182 -15600
- package/dist/tasking/index.js +10 -676
- package/dist/tools/index.js +52 -9589
- package/dist/types/config/autonomy.d.ts +5 -0
- package/dist/types/config/tools.d.ts +2 -2
- package/dist/types/config/ui.d.ts +1 -1
- package/dist/types/errors.d.ts +18 -0
- package/dist/types/index.js +121 -1341
- package/dist/types/provider-runner.d.ts +8 -0
- package/dist/types/session-markers.js +8 -144
- package/dist/utils/error.js +3 -4
- package/dist/utils/expect-defined.js +3 -9
- package/dist/utils/heap-watchdog.js +6 -706
- package/dist/utils/index.js +269 -5685
- package/dist/utils/sage-output-block.js +5 -42
- package/dist/wiring/proxy-rewrite.d.ts +92 -4
- package/dist/wiring/proxy-rewrite.js +20 -61
- package/dist/worktree/index.js +6 -887
- package/package.json +4 -4
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SECRET_FILE_MODE
|
|
3
|
+
} from "./chunk-H5E77KUJ.js";
|
|
4
|
+
import {
|
|
5
|
+
atomicWrite,
|
|
6
|
+
withFileLock
|
|
7
|
+
} from "./chunk-7ZHZE5EO.js";
|
|
8
|
+
|
|
9
|
+
// src/plugins/review-finding-store.ts
|
|
10
|
+
import { randomUUID } from "node:crypto";
|
|
11
|
+
import * as fsp from "node:fs/promises";
|
|
12
|
+
import * as path from "node:path";
|
|
13
|
+
|
|
14
|
+
// src/plugins/review-finding-types.ts
|
|
15
|
+
import { createHash } from "node:crypto";
|
|
16
|
+
var InvalidTransitionError = class extends Error {
|
|
17
|
+
from;
|
|
18
|
+
to;
|
|
19
|
+
constructor(from, to, reason) {
|
|
20
|
+
const msg = reason ?? `Invalid transition from "${from}" to "${to}"`;
|
|
21
|
+
super(msg);
|
|
22
|
+
this.name = "InvalidTransitionError";
|
|
23
|
+
this.from = from;
|
|
24
|
+
this.to = to;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
function normalizeFingerprintTitle(title) {
|
|
28
|
+
return title.trim().toLowerCase().replace(/[^\w\s]/g, "").replace(/\s+/g, " ").trim();
|
|
29
|
+
}
|
|
30
|
+
function computeFindingFingerprint(file, line, title) {
|
|
31
|
+
const normalizedTitle = normalizeFingerprintTitle(title);
|
|
32
|
+
const normalizedFile = file.replace(/\\/g, "/").trim().toLowerCase();
|
|
33
|
+
const lineStr = line != null && line >= 0 ? String(line) : "0";
|
|
34
|
+
const hash = createHash("sha256");
|
|
35
|
+
hash.update(`${normalizedFile}:${lineStr}:${normalizedTitle}`);
|
|
36
|
+
return hash.digest("hex");
|
|
37
|
+
}
|
|
38
|
+
var TRANSITION_MATRIX = {
|
|
39
|
+
active: /* @__PURE__ */ new Set(["triaged", "ignored", "resolved"]),
|
|
40
|
+
triaged: /* @__PURE__ */ new Set(["in_progress", "ignored", "resolved"]),
|
|
41
|
+
in_progress: /* @__PURE__ */ new Set(["resolved", "active"]),
|
|
42
|
+
ignored: /* @__PURE__ */ new Set(["active"]),
|
|
43
|
+
resolved: /* @__PURE__ */ new Set(["active"])
|
|
44
|
+
};
|
|
45
|
+
function validateTransition(from, to) {
|
|
46
|
+
if (from === to) return;
|
|
47
|
+
const allowed = TRANSITION_MATRIX[from];
|
|
48
|
+
if (!allowed?.has(to)) {
|
|
49
|
+
throw new InvalidTransitionError(from, to);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function validateResolution(status, outcome) {
|
|
53
|
+
if (status !== "resolved") return;
|
|
54
|
+
if (!outcome) {
|
|
55
|
+
throw new InvalidTransitionError(
|
|
56
|
+
"active",
|
|
57
|
+
"resolved",
|
|
58
|
+
'A resolution outcome is required when transitioning to "resolved"'
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/plugins/review-finding-store.ts
|
|
64
|
+
var FINDING_RESOLVED_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
65
|
+
var FINDING_IGNORED_RETENTION_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
66
|
+
var FINDING_DEFAULT_PAGE_SIZE = 50;
|
|
67
|
+
var NL = "\n";
|
|
68
|
+
var LINE_SEPARATOR = NL;
|
|
69
|
+
var FINDING_STORE_FILE = "review-findings.jsonl";
|
|
70
|
+
function resolveFindingStorePath(projectDir) {
|
|
71
|
+
return path.join(projectDir, FINDING_STORE_FILE);
|
|
72
|
+
}
|
|
73
|
+
var JsonlFindingStore = class {
|
|
74
|
+
filePath;
|
|
75
|
+
constructor(projectDir) {
|
|
76
|
+
this.filePath = resolveFindingStorePath(projectDir);
|
|
77
|
+
}
|
|
78
|
+
get storePath() {
|
|
79
|
+
return this.filePath;
|
|
80
|
+
}
|
|
81
|
+
// ── Path helpers ─────────────────────────────────────────────────
|
|
82
|
+
async upsert(newFindings, context) {
|
|
83
|
+
if (newFindings.length === 0) return { created: 0, relinked: 0, reopened: 0 };
|
|
84
|
+
const result = { created: 0, relinked: 0, reopened: 0 };
|
|
85
|
+
return withFileLock(this.filePath, async () => {
|
|
86
|
+
const existing = await this._readAll();
|
|
87
|
+
for (const finding of newFindings) {
|
|
88
|
+
const match = existing.find((e) => e.finding.fingerprint === finding.fingerprint);
|
|
89
|
+
if (match) {
|
|
90
|
+
const materialized = this._materialize(match);
|
|
91
|
+
if (materialized.status === "resolved" || materialized.status === "ignored") {
|
|
92
|
+
const reopenEvent = this._makeEvent(
|
|
93
|
+
match.finding.id,
|
|
94
|
+
"reopened",
|
|
95
|
+
materialized.status,
|
|
96
|
+
"active",
|
|
97
|
+
context
|
|
98
|
+
);
|
|
99
|
+
match.finding.status = "active";
|
|
100
|
+
match.finding.resolution = void 0;
|
|
101
|
+
const updatedRecord = { __finding: 1, data: match.finding };
|
|
102
|
+
await fsp.appendFile(
|
|
103
|
+
this.filePath,
|
|
104
|
+
JSON.stringify(updatedRecord) + LINE_SEPARATOR + JSON.stringify({ __findingEvent: 1, data: reopenEvent }) + LINE_SEPARATOR,
|
|
105
|
+
{ encoding: "utf8", mode: SECRET_FILE_MODE }
|
|
106
|
+
);
|
|
107
|
+
result.reopened++;
|
|
108
|
+
} else {
|
|
109
|
+
const relinkEvent = this._makeEvent(
|
|
110
|
+
match.finding.id,
|
|
111
|
+
"relinked",
|
|
112
|
+
match.finding.status,
|
|
113
|
+
match.finding.status,
|
|
114
|
+
context
|
|
115
|
+
);
|
|
116
|
+
await fsp.appendFile(
|
|
117
|
+
this.filePath,
|
|
118
|
+
JSON.stringify({ __findingEvent: 1, data: relinkEvent }) + LINE_SEPARATOR,
|
|
119
|
+
{ encoding: "utf8", mode: SECRET_FILE_MODE }
|
|
120
|
+
);
|
|
121
|
+
result.relinked++;
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
const record = { __finding: 1, data: finding };
|
|
125
|
+
const createdEvent = this._makeEvent(finding.id, "created", null, "active", context);
|
|
126
|
+
const lines = JSON.stringify(record) + LINE_SEPARATOR + JSON.stringify({ __findingEvent: 1, data: createdEvent }) + LINE_SEPARATOR;
|
|
127
|
+
await fsp.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
|
|
128
|
+
result.created++;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
async transition(findingId, to, actor, opts) {
|
|
135
|
+
return withFileLock(this.filePath, async () => {
|
|
136
|
+
const all = await this._readAll();
|
|
137
|
+
const entry = all.find((e) => e.finding.id === findingId);
|
|
138
|
+
if (!entry) throw new Error(`Finding not found: ${findingId}`);
|
|
139
|
+
const from = this._materialize(entry).status;
|
|
140
|
+
validateTransition(from, to);
|
|
141
|
+
validateResolution(to, opts?.outcome);
|
|
142
|
+
const event = {
|
|
143
|
+
id: randomUUID(),
|
|
144
|
+
findingId,
|
|
145
|
+
eventType: to === "resolved" ? "resolved" : to === "ignored" ? "ignored" : this._eventTypeFor(to),
|
|
146
|
+
fromStatus: from,
|
|
147
|
+
toStatus: to,
|
|
148
|
+
actorId: actor.id,
|
|
149
|
+
actorKind: actor.kind,
|
|
150
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
151
|
+
reason: opts?.reason
|
|
152
|
+
};
|
|
153
|
+
entry.finding.status = to;
|
|
154
|
+
if (to === "resolved" && opts?.outcome) {
|
|
155
|
+
entry.finding.resolution = {
|
|
156
|
+
outcome: opts.outcome,
|
|
157
|
+
resolvedAt: event.timestamp,
|
|
158
|
+
resolvedBy: actor.id,
|
|
159
|
+
notes: opts.reason
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
const updatedRecord = { __finding: 1, data: entry.finding };
|
|
163
|
+
await fsp.appendFile(
|
|
164
|
+
this.filePath,
|
|
165
|
+
JSON.stringify(updatedRecord) + LINE_SEPARATOR + JSON.stringify({ __findingEvent: 1, data: event }) + LINE_SEPARATOR,
|
|
166
|
+
{ encoding: "utf8", mode: SECRET_FILE_MODE }
|
|
167
|
+
);
|
|
168
|
+
return { ...entry.finding };
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
async list(opts) {
|
|
172
|
+
const all = await this._readAll();
|
|
173
|
+
let findings = all.map((e) => this._materialize(e));
|
|
174
|
+
if (opts?.severities && opts.severities.length > 0) {
|
|
175
|
+
const sevs = new Set(opts.severities);
|
|
176
|
+
findings = findings.filter((f) => sevs.has(f.severity));
|
|
177
|
+
}
|
|
178
|
+
if (opts?.statuses && opts.statuses.length > 0) {
|
|
179
|
+
const sts = new Set(opts.statuses);
|
|
180
|
+
findings = findings.filter((f) => sts.has(f.status));
|
|
181
|
+
}
|
|
182
|
+
if (opts?.file) {
|
|
183
|
+
const pattern = opts.file.toLowerCase();
|
|
184
|
+
findings = findings.filter((f) => f.location?.file.toLowerCase().includes(pattern));
|
|
185
|
+
}
|
|
186
|
+
if (opts?.reportId) {
|
|
187
|
+
findings = findings.filter((f) => f.originReport.reportId === opts.reportId);
|
|
188
|
+
}
|
|
189
|
+
const severityRank = {
|
|
190
|
+
critical: 0,
|
|
191
|
+
high: 1,
|
|
192
|
+
medium: 2,
|
|
193
|
+
low: 3
|
|
194
|
+
};
|
|
195
|
+
findings.sort((a, b) => {
|
|
196
|
+
const sa = severityRank[a.severity] - severityRank[b.severity];
|
|
197
|
+
if (sa !== 0) return sa;
|
|
198
|
+
return a.createdAt.localeCompare(b.createdAt);
|
|
199
|
+
});
|
|
200
|
+
const limit = opts?.limit ?? FINDING_DEFAULT_PAGE_SIZE;
|
|
201
|
+
return findings.slice(0, limit);
|
|
202
|
+
}
|
|
203
|
+
async get(idOrFingerprint) {
|
|
204
|
+
const all = await this._readAll();
|
|
205
|
+
const entry = all.find(
|
|
206
|
+
(e) => e.finding.id === idOrFingerprint || e.finding.fingerprint === idOrFingerprint
|
|
207
|
+
);
|
|
208
|
+
return entry ? this._materialize(entry) : null;
|
|
209
|
+
}
|
|
210
|
+
async getEvents(findingId) {
|
|
211
|
+
const all = await this._readAllLines();
|
|
212
|
+
const events = [];
|
|
213
|
+
for (const line of all) {
|
|
214
|
+
try {
|
|
215
|
+
const parsed = JSON.parse(line);
|
|
216
|
+
if (this._isLifecycleEvent(parsed) && parsed.data.findingId === findingId) {
|
|
217
|
+
events.push(parsed.data);
|
|
218
|
+
}
|
|
219
|
+
} catch {
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return events.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
223
|
+
}
|
|
224
|
+
async compact(opts) {
|
|
225
|
+
return withFileLock(this.filePath, async () => {
|
|
226
|
+
const resolvedMaxAge = opts?.resolvedMaxAgeMs ?? FINDING_RESOLVED_RETENTION_MS;
|
|
227
|
+
const ignoredMaxAge = opts?.ignoredMaxAgeMs ?? FINDING_IGNORED_RETENTION_MS;
|
|
228
|
+
const now = Date.now();
|
|
229
|
+
const all = await this._readAll();
|
|
230
|
+
const kept = [];
|
|
231
|
+
let removed = 0;
|
|
232
|
+
let eventsFolded = 0;
|
|
233
|
+
for (const entry of all) {
|
|
234
|
+
const age = now - new Date(entry.finding.createdAt).getTime();
|
|
235
|
+
const isResolved = entry.finding.status === "resolved";
|
|
236
|
+
const isIgnored = entry.finding.status === "ignored";
|
|
237
|
+
const maxAge = isResolved ? resolvedMaxAge : isIgnored ? ignoredMaxAge : Infinity;
|
|
238
|
+
if (age > maxAge && (isResolved || isIgnored)) {
|
|
239
|
+
removed++;
|
|
240
|
+
eventsFolded += entry.events.length;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
const oldEvents = entry.events.filter(
|
|
244
|
+
(ev) => now - new Date(ev.timestamp).getTime() > maxAge
|
|
245
|
+
);
|
|
246
|
+
if (oldEvents.length > 1) {
|
|
247
|
+
eventsFolded += oldEvents.length - 1;
|
|
248
|
+
const newestOld = oldEvents.sort((a, b) => b.timestamp.localeCompare(a.timestamp))[0];
|
|
249
|
+
entry.events = [
|
|
250
|
+
newestOld,
|
|
251
|
+
...entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() <= maxAge)
|
|
252
|
+
];
|
|
253
|
+
}
|
|
254
|
+
kept.push({ record: { __finding: 1, data: entry.finding }, events: entry.events });
|
|
255
|
+
}
|
|
256
|
+
const lines = [];
|
|
257
|
+
for (const { record, events } of kept) {
|
|
258
|
+
if (record) lines.push(JSON.stringify(record));
|
|
259
|
+
for (const ev of events) {
|
|
260
|
+
lines.push(JSON.stringify({ __findingEvent: 1, data: ev }));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
lines.push(
|
|
264
|
+
JSON.stringify({
|
|
265
|
+
__findingCompact: 1,
|
|
266
|
+
compactedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
267
|
+
removedFindings: removed,
|
|
268
|
+
foldedEvents: eventsFolded
|
|
269
|
+
})
|
|
270
|
+
);
|
|
271
|
+
await atomicWrite(this.filePath, lines.join(LINE_SEPARATOR) + LINE_SEPARATOR, {
|
|
272
|
+
mode: 384
|
|
273
|
+
});
|
|
274
|
+
return { removed, eventsFolded };
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
// ── Private helpers ──────────────────────────────────────────────
|
|
278
|
+
async _readAllLines() {
|
|
279
|
+
try {
|
|
280
|
+
const raw = await fsp.readFile(this.filePath, "utf8");
|
|
281
|
+
return raw.split(LINE_SEPARATOR).filter((l) => l.trim().length > 0);
|
|
282
|
+
} catch (err) {
|
|
283
|
+
if (err.code === "ENOENT") return [];
|
|
284
|
+
throw err;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
_isFindingRecord(v) {
|
|
288
|
+
return typeof v === "object" && v !== null && v["__finding"] === 1;
|
|
289
|
+
}
|
|
290
|
+
_isLifecycleEvent(v) {
|
|
291
|
+
return typeof v === "object" && v !== null && v["__findingEvent"] === 1;
|
|
292
|
+
}
|
|
293
|
+
async _readAll() {
|
|
294
|
+
const lines = await this._readAllLines();
|
|
295
|
+
const findings = /* @__PURE__ */ new Map();
|
|
296
|
+
const eventsMap = /* @__PURE__ */ new Map();
|
|
297
|
+
for (const line of lines) {
|
|
298
|
+
try {
|
|
299
|
+
const parsed = JSON.parse(line);
|
|
300
|
+
if (this._isFindingRecord(parsed)) {
|
|
301
|
+
findings.set(parsed.data.id, parsed.data);
|
|
302
|
+
if (!eventsMap.has(parsed.data.id)) eventsMap.set(parsed.data.id, []);
|
|
303
|
+
} else if (this._isLifecycleEvent(parsed)) {
|
|
304
|
+
const list = eventsMap.get(parsed.data.findingId);
|
|
305
|
+
if (list) list.push(parsed.data);
|
|
306
|
+
}
|
|
307
|
+
} catch {
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return Array.from(findings.entries()).map(([id, finding]) => ({
|
|
311
|
+
finding,
|
|
312
|
+
events: eventsMap.get(id) ?? []
|
|
313
|
+
}));
|
|
314
|
+
}
|
|
315
|
+
/** Materialize a finding's current status from its events. */
|
|
316
|
+
_materialize(entry) {
|
|
317
|
+
if (entry.events.length === 0) return { ...entry.finding };
|
|
318
|
+
const sorted = [...entry.events].sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
319
|
+
const latest = sorted[sorted.length - 1];
|
|
320
|
+
return {
|
|
321
|
+
...entry.finding,
|
|
322
|
+
status: latest.toStatus
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
_makeEvent(findingId, eventType, fromStatus, toStatus, context) {
|
|
326
|
+
return {
|
|
327
|
+
id: randomUUID(),
|
|
328
|
+
findingId,
|
|
329
|
+
eventType,
|
|
330
|
+
fromStatus,
|
|
331
|
+
toStatus,
|
|
332
|
+
actorId: context.agentId,
|
|
333
|
+
actorKind: "agent",
|
|
334
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
335
|
+
reason: `session:${context.sessionId} report:${context.reportId}`
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
_eventTypeFor(to) {
|
|
339
|
+
switch (to) {
|
|
340
|
+
case "triaged":
|
|
341
|
+
return "triaged";
|
|
342
|
+
case "in_progress":
|
|
343
|
+
return "started";
|
|
344
|
+
case "resolved":
|
|
345
|
+
return "resolved";
|
|
346
|
+
case "ignored":
|
|
347
|
+
return "ignored";
|
|
348
|
+
case "active":
|
|
349
|
+
return "reopened";
|
|
350
|
+
default:
|
|
351
|
+
return "created";
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
export {
|
|
357
|
+
computeFindingFingerprint,
|
|
358
|
+
FINDING_RESOLVED_RETENTION_MS,
|
|
359
|
+
FINDING_IGNORED_RETENTION_MS,
|
|
360
|
+
FINDING_DEFAULT_PAGE_SIZE,
|
|
361
|
+
FINDING_STORE_FILE,
|
|
362
|
+
resolveFindingStorePath,
|
|
363
|
+
JsonlFindingStore
|
|
364
|
+
};
|
|
365
|
+
//# sourceMappingURL=chunk-JVGPR3TS.js.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// src/skills/foreign-sources.ts
|
|
2
|
+
var FOREIGN_SKILL_TOOLS = [
|
|
3
|
+
{ id: "agents", subdir: "skills" },
|
|
4
|
+
// shared store (asm / agentskills.io ecosystem)
|
|
5
|
+
{ id: "codex", subdir: "skills" },
|
|
6
|
+
// OpenAI Codex CLI
|
|
7
|
+
{ id: "gemini", subdir: "skills" },
|
|
8
|
+
// Gemini CLI
|
|
9
|
+
{ id: "cursor", subdir: "skills" },
|
|
10
|
+
// Cursor (standard subdir, aligned with skills.sh ecosystem)
|
|
11
|
+
{ id: "qwen", subdir: "skills" },
|
|
12
|
+
// Qwen Code
|
|
13
|
+
{ id: "trae", subdir: "skills" },
|
|
14
|
+
// Trae
|
|
15
|
+
{ id: "windsurf", subdir: "skills" }
|
|
16
|
+
// Windsurf
|
|
17
|
+
];
|
|
18
|
+
var KNOWN_FOREIGN_IDS = new Set(FOREIGN_SKILL_TOOLS.map((t) => t.id));
|
|
19
|
+
function resolveForeignToolIds(opt) {
|
|
20
|
+
return resolveForeignToolIdsWithWarnings(opt).ids;
|
|
21
|
+
}
|
|
22
|
+
function resolveForeignToolIdsWithWarnings(opt) {
|
|
23
|
+
if (opt === false) return { ids: [], unknownIds: [] };
|
|
24
|
+
if (Array.isArray(opt)) {
|
|
25
|
+
const ids = [];
|
|
26
|
+
const unknownIds = [];
|
|
27
|
+
for (const id of opt) {
|
|
28
|
+
if (KNOWN_FOREIGN_IDS.has(id)) ids.push(id);
|
|
29
|
+
else unknownIds.push(id);
|
|
30
|
+
}
|
|
31
|
+
return { ids, unknownIds };
|
|
32
|
+
}
|
|
33
|
+
return { ids: FOREIGN_SKILL_TOOLS.map((t) => t.id), unknownIds: [] };
|
|
34
|
+
}
|
|
35
|
+
function securityScoreToTier(score) {
|
|
36
|
+
if (score == null || Number.isNaN(score)) return "low";
|
|
37
|
+
if (score < 30) return "low";
|
|
38
|
+
if (score < 70) return "medium";
|
|
39
|
+
return "high";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export {
|
|
43
|
+
FOREIGN_SKILL_TOOLS,
|
|
44
|
+
resolveForeignToolIds,
|
|
45
|
+
resolveForeignToolIdsWithWarnings,
|
|
46
|
+
securityScoreToTier
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=chunk-JVKB2TBL.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// src/coordination/mailbox-events.ts
|
|
2
|
+
var MailboxEventEmitter = class {
|
|
3
|
+
listeners = /* @__PURE__ */ new Set();
|
|
4
|
+
subscribe(fn) {
|
|
5
|
+
this.listeners.add(fn);
|
|
6
|
+
return () => {
|
|
7
|
+
this.listeners.delete(fn);
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
emit(event) {
|
|
11
|
+
const snapshot = [...this.listeners];
|
|
12
|
+
for (const fn of snapshot) {
|
|
13
|
+
try {
|
|
14
|
+
fn(event);
|
|
15
|
+
} catch {
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Number of active subscribers (for observability / metrics). */
|
|
20
|
+
get subscriberCount() {
|
|
21
|
+
return this.listeners.size;
|
|
22
|
+
}
|
|
23
|
+
clear() {
|
|
24
|
+
this.listeners.clear();
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
MailboxEventEmitter
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=chunk-JX7VBZDK.js.map
|