@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,789 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CHRONICLE_MAX_APPEND_BATCH,
|
|
3
|
+
CHRONICLE_PROJECT_SERVER_MAX_FRAME_CHARS,
|
|
4
|
+
CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION,
|
|
5
|
+
ChronicleJournal,
|
|
6
|
+
ChronicleMetricsStore,
|
|
7
|
+
ChronicleQueryEngine,
|
|
8
|
+
ChronicleSqliteJournal,
|
|
9
|
+
chronicleProjectServerEndpoint,
|
|
10
|
+
chronicleProjectServerMetadataPath,
|
|
11
|
+
encodeChronicleProjectServerMessage,
|
|
12
|
+
importLegacyChronicleJournal,
|
|
13
|
+
resolveChronicleRuntimeLocation
|
|
14
|
+
} from "./chunk-AT4V4XGI.js";
|
|
15
|
+
import {
|
|
16
|
+
resolveWstackPaths
|
|
17
|
+
} from "./chunk-YNCVSFGF.js";
|
|
18
|
+
|
|
19
|
+
// src/chronicle/project-server-client.ts
|
|
20
|
+
import { spawn } from "node:child_process";
|
|
21
|
+
import * as fs from "node:fs";
|
|
22
|
+
import * as net from "node:net";
|
|
23
|
+
import * as path from "node:path";
|
|
24
|
+
import { fileURLToPath } from "node:url";
|
|
25
|
+
var CONNECT_ATTEMPT_TIMEOUT_MS = 750;
|
|
26
|
+
var SERVER_START_TIMEOUT_MS = 1e4;
|
|
27
|
+
var DEFAULT_CALL_TIMEOUT_MS = 3e4;
|
|
28
|
+
var APPEND_CALL_TIMEOUT_MS = 6e4;
|
|
29
|
+
var DEFAULT_BATCH_WINDOW_MS = 5;
|
|
30
|
+
var DEFAULT_MAX_PENDING = 1e5;
|
|
31
|
+
function resolveChronicleDaemonAvailability(moduleUrl = import.meta.url, exists = fs.existsSync) {
|
|
32
|
+
if (process.env["WRONGSTACK_CHRONICLE_INLINE"] || process.env["WRONGSTACK_CHRONICLE_SERVER"] === "0") {
|
|
33
|
+
return { kind: "inline-requested" };
|
|
34
|
+
}
|
|
35
|
+
const url = locateChronicleProjectServer(moduleUrl, exists);
|
|
36
|
+
return url ? { kind: "available", url } : { kind: "missing-build" };
|
|
37
|
+
}
|
|
38
|
+
function resolveChronicleProjectServerUrl(moduleUrl = import.meta.url, exists = fs.existsSync) {
|
|
39
|
+
const availability = resolveChronicleDaemonAvailability(moduleUrl, exists);
|
|
40
|
+
return availability.kind === "available" ? availability.url : null;
|
|
41
|
+
}
|
|
42
|
+
function locateChronicleProjectServer(moduleUrl, exists) {
|
|
43
|
+
const candidates = [
|
|
44
|
+
// Normal unbundled output: dist/chronicle/project-server-client.js.
|
|
45
|
+
"./project-server.js",
|
|
46
|
+
// Core plugin bundle: dist/plugin/index.js.
|
|
47
|
+
"../chronicle/project-server.js",
|
|
48
|
+
// Core root bundle: dist/index.js.
|
|
49
|
+
"./chronicle/project-server.js"
|
|
50
|
+
];
|
|
51
|
+
for (const relativePath of candidates) {
|
|
52
|
+
try {
|
|
53
|
+
const url = new URL(relativePath, moduleUrl);
|
|
54
|
+
if (url.protocol === "file:" && exists(fileURLToPath(url))) return url;
|
|
55
|
+
} catch {
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
function isChronicleProjectServerAvailable() {
|
|
61
|
+
return resolveChronicleProjectServerUrl() !== null;
|
|
62
|
+
}
|
|
63
|
+
function delay(ms) {
|
|
64
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
65
|
+
}
|
|
66
|
+
var ChronicleProjectServerClient = class {
|
|
67
|
+
constructor(options) {
|
|
68
|
+
this.options = options;
|
|
69
|
+
this.endpoint = chronicleProjectServerEndpoint(options.projectDir);
|
|
70
|
+
}
|
|
71
|
+
options;
|
|
72
|
+
endpoint;
|
|
73
|
+
socket = null;
|
|
74
|
+
info = null;
|
|
75
|
+
buffer = "";
|
|
76
|
+
connecting = null;
|
|
77
|
+
connectResolve = null;
|
|
78
|
+
connectReject = null;
|
|
79
|
+
nextId = 1;
|
|
80
|
+
/** WS-027: read from the owner-only metadata file — see currentAuthToken. */
|
|
81
|
+
authToken;
|
|
82
|
+
pending = /* @__PURE__ */ new Map();
|
|
83
|
+
async call(op, args, options = {}) {
|
|
84
|
+
await this.ensureConnected(true);
|
|
85
|
+
return this.request(
|
|
86
|
+
{ type: "request", op, args },
|
|
87
|
+
options.timeoutMs ?? DEFAULT_CALL_TIMEOUT_MS
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
ping() {
|
|
91
|
+
return this.call("ping", {}, { timeoutMs: 3e3 });
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Request the Chronicle project server to shut down cleanly.
|
|
95
|
+
*
|
|
96
|
+
* Returns the server PID and acknowledgment. Does not throw if the server
|
|
97
|
+
* is already offline or unreachable — the caller is assumed to want the
|
|
98
|
+
* server stopped regardless of current state.
|
|
99
|
+
*/
|
|
100
|
+
async shutdown(reason) {
|
|
101
|
+
try {
|
|
102
|
+
await this.ensureConnected(false);
|
|
103
|
+
} catch {
|
|
104
|
+
return { stopped: false, reason: "offline" };
|
|
105
|
+
}
|
|
106
|
+
const pid = this.info?.pid;
|
|
107
|
+
try {
|
|
108
|
+
const result = await this.request(
|
|
109
|
+
{ type: "shutdown", reason },
|
|
110
|
+
5e3
|
|
111
|
+
) ?? { stopped: true };
|
|
112
|
+
return { ...result, ...pid !== void 0 && result.pid === void 0 ? { pid } : {} };
|
|
113
|
+
} catch {
|
|
114
|
+
return { stopped: false, ...pid !== void 0 ? { pid } : {}, reason: "write-failed" };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async close() {
|
|
118
|
+
const socket = this.socket;
|
|
119
|
+
this.socket = null;
|
|
120
|
+
this.info = null;
|
|
121
|
+
if (socket && !socket.destroyed) {
|
|
122
|
+
await new Promise((resolve3) => {
|
|
123
|
+
socket.once("close", resolve3);
|
|
124
|
+
socket.end();
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async ensureConnected(spawnIfMissing) {
|
|
129
|
+
if (this.socket && !this.socket.destroyed && this.info) return;
|
|
130
|
+
if (this.connecting) return this.connecting;
|
|
131
|
+
if (!isChronicleProjectServerAvailable()) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
"Built Chronicle project server is unavailable. Build @wrongstack/core or use the inline journal."
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
this.connecting = this.connectWithElection(spawnIfMissing).finally(() => {
|
|
137
|
+
this.connecting = null;
|
|
138
|
+
});
|
|
139
|
+
return this.connecting;
|
|
140
|
+
}
|
|
141
|
+
async connectWithElection(spawnIfMissing) {
|
|
142
|
+
const deadline = Date.now() + (spawnIfMissing ? SERVER_START_TIMEOUT_MS : CONNECT_ATTEMPT_TIMEOUT_MS);
|
|
143
|
+
let spawned = false;
|
|
144
|
+
let lastError = new Error("Chronicle project server unavailable");
|
|
145
|
+
while (Date.now() < deadline) {
|
|
146
|
+
try {
|
|
147
|
+
await this.connectOnce();
|
|
148
|
+
return;
|
|
149
|
+
} catch (error) {
|
|
150
|
+
lastError = error;
|
|
151
|
+
}
|
|
152
|
+
if (!spawnIfMissing) break;
|
|
153
|
+
if (!spawned) {
|
|
154
|
+
this.spawnDetachedServer();
|
|
155
|
+
spawned = true;
|
|
156
|
+
}
|
|
157
|
+
await delay(75);
|
|
158
|
+
}
|
|
159
|
+
throw lastError;
|
|
160
|
+
}
|
|
161
|
+
connectOnce() {
|
|
162
|
+
this.socket?.destroy();
|
|
163
|
+
this.socket = null;
|
|
164
|
+
this.authToken = void 0;
|
|
165
|
+
this.info = null;
|
|
166
|
+
this.buffer = "";
|
|
167
|
+
return new Promise((resolve3, reject) => {
|
|
168
|
+
const socket = net.createConnection(this.endpoint);
|
|
169
|
+
this.socket = socket;
|
|
170
|
+
socket.setEncoding("utf8");
|
|
171
|
+
const timer = setTimeout(() => {
|
|
172
|
+
reject(new Error("Chronicle project server handshake timed out"));
|
|
173
|
+
socket.destroy();
|
|
174
|
+
}, CONNECT_ATTEMPT_TIMEOUT_MS);
|
|
175
|
+
timer.unref?.();
|
|
176
|
+
this.connectResolve = () => {
|
|
177
|
+
clearTimeout(timer);
|
|
178
|
+
this.connectResolve = null;
|
|
179
|
+
this.connectReject = null;
|
|
180
|
+
resolve3();
|
|
181
|
+
};
|
|
182
|
+
this.connectReject = (error) => {
|
|
183
|
+
clearTimeout(timer);
|
|
184
|
+
this.connectResolve = null;
|
|
185
|
+
this.connectReject = null;
|
|
186
|
+
reject(error);
|
|
187
|
+
};
|
|
188
|
+
socket.on("data", (chunk) => this.onData(socket, chunk));
|
|
189
|
+
socket.on("error", (error) => {
|
|
190
|
+
if (!this.info) this.connectReject?.(error);
|
|
191
|
+
});
|
|
192
|
+
socket.on("close", () => this.onClose(socket));
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* WS-027: the per-process token, read from the daemon's owner-only metadata
|
|
197
|
+
* file — never from the `hello` frame, which the daemon sends to every
|
|
198
|
+
* socket that connects (the mistake WS-028 found in the SAGE daemon).
|
|
199
|
+
*
|
|
200
|
+
* Read lazily and re-read while unknown: the daemon starts listening before
|
|
201
|
+
* it writes metadata (endpoint ownership has to be won first), and a
|
|
202
|
+
* respawned daemon mints a new token, so a cached wrong one would be sticky.
|
|
203
|
+
*/
|
|
204
|
+
currentAuthToken() {
|
|
205
|
+
if (this.authToken === void 0) {
|
|
206
|
+
try {
|
|
207
|
+
const raw = fs.readFileSync(
|
|
208
|
+
chronicleProjectServerMetadataPath(this.options.projectDir),
|
|
209
|
+
"utf8"
|
|
210
|
+
);
|
|
211
|
+
const parsed = JSON.parse(raw);
|
|
212
|
+
if (typeof parsed.authToken === "string" && parsed.authToken.length > 0) {
|
|
213
|
+
this.authToken = parsed.authToken;
|
|
214
|
+
}
|
|
215
|
+
} catch {
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return this.authToken;
|
|
219
|
+
}
|
|
220
|
+
request(message, timeoutMs) {
|
|
221
|
+
const socket = this.socket;
|
|
222
|
+
if (!socket || socket.destroyed) {
|
|
223
|
+
return Promise.reject(new Error("Chronicle project server connection is unavailable"));
|
|
224
|
+
}
|
|
225
|
+
const id = this.nextId++;
|
|
226
|
+
const encoded = encodeChronicleProjectServerMessage({
|
|
227
|
+
...message,
|
|
228
|
+
id,
|
|
229
|
+
authToken: this.currentAuthToken()
|
|
230
|
+
});
|
|
231
|
+
if (encoded.length > CHRONICLE_PROJECT_SERVER_MAX_FRAME_CHARS) {
|
|
232
|
+
return Promise.reject(new Error("Chronicle project server request exceeded frame limit"));
|
|
233
|
+
}
|
|
234
|
+
const label = message.type === "request" ? message.op : message.type;
|
|
235
|
+
return new Promise((resolve3, reject) => {
|
|
236
|
+
const timer = setTimeout(() => {
|
|
237
|
+
const pending = this.pending.get(id);
|
|
238
|
+
if (!pending) return;
|
|
239
|
+
this.pending.delete(id);
|
|
240
|
+
pending.reject(new Error(`Chronicle ${label} exceeded its ${timeoutMs}ms timeout`));
|
|
241
|
+
}, timeoutMs);
|
|
242
|
+
timer.unref?.();
|
|
243
|
+
this.pending.set(id, { resolve: resolve3, reject, timer });
|
|
244
|
+
socket.write(encoded);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
onData(socket, chunk) {
|
|
248
|
+
if (socket !== this.socket) return;
|
|
249
|
+
this.buffer += chunk;
|
|
250
|
+
if (this.buffer.length > CHRONICLE_PROJECT_SERVER_MAX_FRAME_CHARS) {
|
|
251
|
+
socket.destroy(new Error("Chronicle project server response exceeded frame limit"));
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
while (true) {
|
|
255
|
+
const newline = this.buffer.indexOf("\n");
|
|
256
|
+
if (newline < 0) return;
|
|
257
|
+
const line = this.buffer.slice(0, newline);
|
|
258
|
+
this.buffer = this.buffer.slice(newline + 1);
|
|
259
|
+
if (!line) continue;
|
|
260
|
+
let message;
|
|
261
|
+
try {
|
|
262
|
+
message = JSON.parse(line);
|
|
263
|
+
} catch {
|
|
264
|
+
socket.destroy(new Error("Invalid Chronicle project server response"));
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
this.onMessage(message);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
onMessage(message) {
|
|
271
|
+
if (message.type === "hello") {
|
|
272
|
+
if (message.protocolVersion !== CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION) {
|
|
273
|
+
this.connectReject?.(
|
|
274
|
+
new Error(
|
|
275
|
+
`Chronicle protocol mismatch: client=${CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION}, server=${message.protocolVersion}`
|
|
276
|
+
)
|
|
277
|
+
);
|
|
278
|
+
this.socket?.destroy();
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
if (normalizePath(message.projectRoot) !== normalizePath(this.options.projectRoot) || normalizePath(message.projectDir) !== normalizePath(this.options.projectDir)) {
|
|
282
|
+
this.connectReject?.(new Error("Chronicle project server identity mismatch"));
|
|
283
|
+
this.socket?.destroy();
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
this.info = message;
|
|
287
|
+
this.connectResolve?.();
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const pending = this.pending.get(message.id);
|
|
291
|
+
if (!pending) return;
|
|
292
|
+
this.pending.delete(message.id);
|
|
293
|
+
clearTimeout(pending.timer);
|
|
294
|
+
if (message.ok) pending.resolve(message.result);
|
|
295
|
+
else {
|
|
296
|
+
const error = new Error(message.error);
|
|
297
|
+
if (message.errorName) error.name = message.errorName;
|
|
298
|
+
pending.reject(error);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
onClose(socket) {
|
|
302
|
+
if (socket !== this.socket) return;
|
|
303
|
+
this.socket = null;
|
|
304
|
+
this.info = null;
|
|
305
|
+
const error = new Error("Chronicle project server connection closed");
|
|
306
|
+
this.connectReject?.(error);
|
|
307
|
+
this.connectResolve = null;
|
|
308
|
+
this.connectReject = null;
|
|
309
|
+
const pending = [...this.pending.values()];
|
|
310
|
+
this.pending.clear();
|
|
311
|
+
for (const request of pending) {
|
|
312
|
+
clearTimeout(request.timer);
|
|
313
|
+
request.reject(error);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
spawnDetachedServer() {
|
|
317
|
+
const url = resolveChronicleProjectServerUrl();
|
|
318
|
+
if (!url) throw new Error("Built Chronicle project server is unavailable");
|
|
319
|
+
const args = [
|
|
320
|
+
fileURLToPath(url),
|
|
321
|
+
"--project-root",
|
|
322
|
+
this.options.projectRoot,
|
|
323
|
+
"--global-root",
|
|
324
|
+
this.options.globalRoot,
|
|
325
|
+
"--project-id",
|
|
326
|
+
this.options.projectId,
|
|
327
|
+
"--project-dir",
|
|
328
|
+
this.options.projectDir,
|
|
329
|
+
"--workspace-id",
|
|
330
|
+
this.options.workspaceId
|
|
331
|
+
];
|
|
332
|
+
if (this.options.retentionDays !== void 0) {
|
|
333
|
+
args.push("--retention-days", String(this.options.retentionDays));
|
|
334
|
+
}
|
|
335
|
+
const child = spawn(process.execPath, args, {
|
|
336
|
+
detached: true,
|
|
337
|
+
stdio: "ignore",
|
|
338
|
+
windowsHide: true,
|
|
339
|
+
env: process.env
|
|
340
|
+
});
|
|
341
|
+
child.unref();
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
var ChronicleRemoteJournal = class {
|
|
345
|
+
client;
|
|
346
|
+
maxPending;
|
|
347
|
+
batchWindowMs;
|
|
348
|
+
pending = [];
|
|
349
|
+
timer;
|
|
350
|
+
inflight = /* @__PURE__ */ new Set();
|
|
351
|
+
counters = {
|
|
352
|
+
acceptedEvents: 0,
|
|
353
|
+
persistedEvents: 0,
|
|
354
|
+
rejectedEvents: 0,
|
|
355
|
+
failedEvents: 0,
|
|
356
|
+
batches: 0,
|
|
357
|
+
maxObservedPending: 0,
|
|
358
|
+
largestBatch: 0,
|
|
359
|
+
partitionRolls: 0
|
|
360
|
+
};
|
|
361
|
+
lastBatchDurationMs;
|
|
362
|
+
constructor(options, client = new ChronicleProjectServerClient(options)) {
|
|
363
|
+
this.client = client;
|
|
364
|
+
this.maxPending = Math.max(1, options.maxPending ?? DEFAULT_MAX_PENDING);
|
|
365
|
+
this.batchWindowMs = Math.max(0, options.batchWindowMs ?? DEFAULT_BATCH_WINDOW_MS);
|
|
366
|
+
}
|
|
367
|
+
append(input) {
|
|
368
|
+
if (this.pending.length >= this.maxPending) {
|
|
369
|
+
this.counters.rejectedEvents++;
|
|
370
|
+
return Promise.reject(
|
|
371
|
+
new Error(`Chronicle backpressure limit reached (${this.maxPending} pending events)`)
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
const promise = new Promise((resolve3, reject) => {
|
|
375
|
+
this.pending.push({ input, resolve: resolve3, reject });
|
|
376
|
+
});
|
|
377
|
+
this.counters.acceptedEvents++;
|
|
378
|
+
this.counters.maxObservedPending = Math.max(
|
|
379
|
+
this.counters.maxObservedPending,
|
|
380
|
+
this.pending.length
|
|
381
|
+
);
|
|
382
|
+
this.schedule();
|
|
383
|
+
return promise;
|
|
384
|
+
}
|
|
385
|
+
stats() {
|
|
386
|
+
return {
|
|
387
|
+
...this.counters,
|
|
388
|
+
pendingEvents: this.pending.length,
|
|
389
|
+
...this.lastBatchDurationMs !== void 0 ? { lastBatchDurationMs: this.lastBatchDurationMs } : {}
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
async flush() {
|
|
393
|
+
if (this.timer) {
|
|
394
|
+
clearTimeout(this.timer);
|
|
395
|
+
this.timer = void 0;
|
|
396
|
+
}
|
|
397
|
+
while (this.pending.length > 0 || this.inflight.size > 0) {
|
|
398
|
+
if (this.pending.length > 0) this.startBatch();
|
|
399
|
+
await Promise.all([...this.inflight]);
|
|
400
|
+
}
|
|
401
|
+
if (this.counters.acceptedEvents === 0) return;
|
|
402
|
+
await this.client.call("flush", {}, { timeoutMs: APPEND_CALL_TIMEOUT_MS });
|
|
403
|
+
}
|
|
404
|
+
async dispose() {
|
|
405
|
+
await this.flush();
|
|
406
|
+
await this.client.close();
|
|
407
|
+
}
|
|
408
|
+
schedule() {
|
|
409
|
+
if (this.timer) return;
|
|
410
|
+
if (this.batchWindowMs === 0) {
|
|
411
|
+
queueMicrotask(() => this.startBatch());
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
this.timer = setTimeout(() => {
|
|
415
|
+
this.timer = void 0;
|
|
416
|
+
this.startBatch();
|
|
417
|
+
}, this.batchWindowMs);
|
|
418
|
+
this.timer.unref?.();
|
|
419
|
+
}
|
|
420
|
+
startBatch() {
|
|
421
|
+
if (this.timer) {
|
|
422
|
+
clearTimeout(this.timer);
|
|
423
|
+
this.timer = void 0;
|
|
424
|
+
}
|
|
425
|
+
if (this.pending.length === 0) return;
|
|
426
|
+
const batch = this.pending.splice(0, CHRONICLE_MAX_APPEND_BATCH);
|
|
427
|
+
const started = performance.now();
|
|
428
|
+
this.counters.batches++;
|
|
429
|
+
this.counters.largestBatch = Math.max(this.counters.largestBatch, batch.length);
|
|
430
|
+
const run = this.client.call(
|
|
431
|
+
"append",
|
|
432
|
+
{ inputs: batch.map((entry) => entry.input) },
|
|
433
|
+
{ timeoutMs: APPEND_CALL_TIMEOUT_MS }
|
|
434
|
+
).then((events) => {
|
|
435
|
+
if (events.length !== batch.length) {
|
|
436
|
+
throw new Error(
|
|
437
|
+
`Chronicle server returned ${events.length} events for ${batch.length} inputs`
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
batch.forEach((entry, index) => {
|
|
441
|
+
entry.resolve(events[index]);
|
|
442
|
+
});
|
|
443
|
+
this.counters.persistedEvents += batch.length;
|
|
444
|
+
}).catch((error) => {
|
|
445
|
+
this.counters.failedEvents += batch.length;
|
|
446
|
+
for (const entry of batch) entry.reject(error);
|
|
447
|
+
}).finally(() => {
|
|
448
|
+
this.lastBatchDurationMs = performance.now() - started;
|
|
449
|
+
this.inflight.delete(run);
|
|
450
|
+
if (this.pending.length > 0) this.schedule();
|
|
451
|
+
});
|
|
452
|
+
this.inflight.add(run);
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
function normalizePath(value) {
|
|
456
|
+
const resolved = path.resolve(value);
|
|
457
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// src/chronicle/project-access.ts
|
|
461
|
+
import * as fsPromises from "node:fs/promises";
|
|
462
|
+
import * as os from "node:os";
|
|
463
|
+
import * as path2 from "node:path";
|
|
464
|
+
function resolveChronicleProjectServerOptions(options) {
|
|
465
|
+
if (options.projectPaths) {
|
|
466
|
+
return {
|
|
467
|
+
projectRoot: path2.resolve(options.projectRoot),
|
|
468
|
+
...options.projectPaths,
|
|
469
|
+
...options.retentionDays !== void 0 ? { retentionDays: options.retentionDays } : {}
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
const paths = resolveWstackPaths({
|
|
473
|
+
projectRoot: options.projectRoot,
|
|
474
|
+
userHome: options.userHome ?? os.homedir()
|
|
475
|
+
});
|
|
476
|
+
return {
|
|
477
|
+
projectRoot: path2.resolve(options.projectRoot),
|
|
478
|
+
globalRoot: paths.globalRoot,
|
|
479
|
+
projectId: paths.projectHash,
|
|
480
|
+
projectDir: paths.projectDir,
|
|
481
|
+
workspaceId: paths.projectSlug,
|
|
482
|
+
...options.retentionDays !== void 0 ? { retentionDays: options.retentionDays } : {}
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
function createChronicleProjectAccess(options) {
|
|
486
|
+
const resolved = resolveChronicleProjectServerOptions(options);
|
|
487
|
+
if (isChronicleProjectServerAvailable()) {
|
|
488
|
+
const client = new ChronicleProjectServerClient(resolved);
|
|
489
|
+
return {
|
|
490
|
+
mode: "server",
|
|
491
|
+
call: (op, args, callOptions) => client.call(op, args, callOptions),
|
|
492
|
+
close: () => client.close()
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
assertInlineWasRequested("createChronicleProjectAccess");
|
|
496
|
+
return new InlineChronicleProjectAccess(resolved);
|
|
497
|
+
}
|
|
498
|
+
function assertInlineWasRequested(caller) {
|
|
499
|
+
if (resolveChronicleDaemonAvailability().kind !== "missing-build") return;
|
|
500
|
+
throw new Error(
|
|
501
|
+
`${caller}: built Chronicle project server is unavailable. Build @wrongstack/core, or set WRONGSTACK_CHRONICLE_INLINE=1 to explicitly accept a process-local journal.`
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
function createChronicleEventJournal(options) {
|
|
505
|
+
const resolved = resolveChronicleProjectServerOptions(options);
|
|
506
|
+
const identity = resolveChronicleRuntimeLocation({
|
|
507
|
+
globalRoot: resolved.globalRoot,
|
|
508
|
+
projectId: resolved.projectId,
|
|
509
|
+
projectDir: resolved.projectDir
|
|
510
|
+
});
|
|
511
|
+
if (isChronicleProjectServerAvailable()) {
|
|
512
|
+
const journal2 = new ChronicleRemoteJournal(resolved);
|
|
513
|
+
return {
|
|
514
|
+
journal: journal2,
|
|
515
|
+
identity,
|
|
516
|
+
serverBacked: true,
|
|
517
|
+
dispose: () => journal2.dispose()
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
assertInlineWasRequested("createChronicleEventJournal");
|
|
521
|
+
if (useSqliteStore()) {
|
|
522
|
+
const journal2 = new ChronicleSqliteEventSink(path2.join(resolved.projectDir, "chronicle"));
|
|
523
|
+
return {
|
|
524
|
+
journal: journal2,
|
|
525
|
+
identity,
|
|
526
|
+
serverBacked: false,
|
|
527
|
+
dispose: () => journal2.close()
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
const journal = new ChronicleJournal({
|
|
531
|
+
filePath: legacyPartitionPath(identity),
|
|
532
|
+
retentionDays: options.retentionDays
|
|
533
|
+
});
|
|
534
|
+
return {
|
|
535
|
+
journal,
|
|
536
|
+
identity,
|
|
537
|
+
serverBacked: false,
|
|
538
|
+
dispose: () => journal.flush()
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
function legacyPartitionPath(location) {
|
|
542
|
+
return path2.join(location.chronicleDirectory, `${location.day}.events.jsonl`);
|
|
543
|
+
}
|
|
544
|
+
function useSqliteStore() {
|
|
545
|
+
return process.env["WRONGSTACK_CHRONICLE_STORE"] !== "jsonl";
|
|
546
|
+
}
|
|
547
|
+
var ChronicleSqliteEventSink = class {
|
|
548
|
+
ready;
|
|
549
|
+
last;
|
|
550
|
+
constructor(directory) {
|
|
551
|
+
this.ready = (async () => {
|
|
552
|
+
await fsPromises.mkdir(directory, { recursive: true });
|
|
553
|
+
const journal = new ChronicleSqliteJournal({ directory });
|
|
554
|
+
try {
|
|
555
|
+
await importLegacyChronicleJournal(journal, directory);
|
|
556
|
+
} catch (error) {
|
|
557
|
+
journal.close();
|
|
558
|
+
throw error;
|
|
559
|
+
}
|
|
560
|
+
return journal;
|
|
561
|
+
})();
|
|
562
|
+
}
|
|
563
|
+
async append(input) {
|
|
564
|
+
const journal = await this.ready;
|
|
565
|
+
const event = await journal.append(input);
|
|
566
|
+
this.last = journal.stats();
|
|
567
|
+
return event;
|
|
568
|
+
}
|
|
569
|
+
async flush() {
|
|
570
|
+
await this.ready;
|
|
571
|
+
}
|
|
572
|
+
stats() {
|
|
573
|
+
return this.last ?? EMPTY_JOURNAL_STATS;
|
|
574
|
+
}
|
|
575
|
+
async close() {
|
|
576
|
+
(await this.ready).close();
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
var EMPTY_JOURNAL_STATS = {
|
|
580
|
+
acceptedEvents: 0,
|
|
581
|
+
persistedEvents: 0,
|
|
582
|
+
rejectedEvents: 0,
|
|
583
|
+
failedEvents: 0,
|
|
584
|
+
batches: 0,
|
|
585
|
+
pendingEvents: 0,
|
|
586
|
+
maxObservedPending: 0,
|
|
587
|
+
largestBatch: 0,
|
|
588
|
+
partitionRolls: 0
|
|
589
|
+
};
|
|
590
|
+
var MAX_OPEN_JOURNAL_DAYS = 2;
|
|
591
|
+
var InlineChronicleProjectAccess = class {
|
|
592
|
+
constructor(options) {
|
|
593
|
+
this.options = options;
|
|
594
|
+
}
|
|
595
|
+
options;
|
|
596
|
+
mode = "inline";
|
|
597
|
+
journals = /* @__PURE__ */ new Map();
|
|
598
|
+
sqlite;
|
|
599
|
+
/**
|
|
600
|
+
* Open the SQLite journal, importing the legacy partitions the first time.
|
|
601
|
+
*
|
|
602
|
+
* The import is part of opening rather than a separate migration step so no
|
|
603
|
+
* caller can read a half-migrated store: until it finishes, this promise has
|
|
604
|
+
* not resolved and every operation is still queued behind it.
|
|
605
|
+
*/
|
|
606
|
+
store() {
|
|
607
|
+
this.sqlite ??= (async () => {
|
|
608
|
+
await fsPromises.mkdir(this.chronicleDirectory, { recursive: true });
|
|
609
|
+
const journal = new ChronicleSqliteJournal({ directory: this.chronicleDirectory });
|
|
610
|
+
try {
|
|
611
|
+
await importLegacyChronicleJournal(journal, this.chronicleDirectory);
|
|
612
|
+
} catch (error) {
|
|
613
|
+
this.sqlite = void 0;
|
|
614
|
+
journal.close();
|
|
615
|
+
throw error;
|
|
616
|
+
}
|
|
617
|
+
return journal;
|
|
618
|
+
})();
|
|
619
|
+
return this.sqlite;
|
|
620
|
+
}
|
|
621
|
+
async call(op, rawArgs, _callOptions) {
|
|
622
|
+
switch (op) {
|
|
623
|
+
case "ping":
|
|
624
|
+
return this.health();
|
|
625
|
+
case "append": {
|
|
626
|
+
const args = rawArgs;
|
|
627
|
+
if (useSqliteStore()) {
|
|
628
|
+
const store = await this.store();
|
|
629
|
+
return await store.appendBatch(args.inputs);
|
|
630
|
+
}
|
|
631
|
+
return await Promise.all(
|
|
632
|
+
args.inputs.map((input) => this.journalForToday().append(input))
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
case "flush":
|
|
636
|
+
await this.flush();
|
|
637
|
+
return void 0;
|
|
638
|
+
case "purge": {
|
|
639
|
+
const args = rawArgs;
|
|
640
|
+
if (useSqliteStore()) {
|
|
641
|
+
const store = await this.store();
|
|
642
|
+
return await store.purge(args);
|
|
643
|
+
}
|
|
644
|
+
return await this.journalForToday().purge(args);
|
|
645
|
+
}
|
|
646
|
+
case "query": {
|
|
647
|
+
const args = rawArgs;
|
|
648
|
+
return await (await this.queryEngine()).query(args.query);
|
|
649
|
+
}
|
|
650
|
+
case "facet": {
|
|
651
|
+
const args = rawArgs;
|
|
652
|
+
const engine = await this.queryEngine();
|
|
653
|
+
return {
|
|
654
|
+
values: await engine.facet(args.field, args.query, args.limit),
|
|
655
|
+
diagnostics: engine.diagnostics
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
case "facets": {
|
|
659
|
+
const args = rawArgs;
|
|
660
|
+
const engine = await this.queryEngine();
|
|
661
|
+
return {
|
|
662
|
+
values: await engine.facets(args.fields, args.query, args.limit),
|
|
663
|
+
diagnostics: engine.diagnostics
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
case "graph": {
|
|
667
|
+
const args = rawArgs;
|
|
668
|
+
return await (await this.queryEngine()).graph(args.seed, args.hops, args.maxNodes);
|
|
669
|
+
}
|
|
670
|
+
case "metrics": {
|
|
671
|
+
const args = rawArgs;
|
|
672
|
+
const store = ChronicleMetricsStore.open(this.chronicleDirectory);
|
|
673
|
+
try {
|
|
674
|
+
const refreshed = args.refresh === false ? { ingestedEvents: 0, ingestedBytes: 0, sourceFiles: 0, invalidLines: 0 } : await store.refresh();
|
|
675
|
+
const data = args.view === "providers" ? store.providerDaily(args.providers) : args.view === "tasks" ? store.taskOutcomes(args.tasks) : args.view === "files" ? store.fileLineage(args.files) : store.summary();
|
|
676
|
+
return { refreshed, data };
|
|
677
|
+
} finally {
|
|
678
|
+
store.close();
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
async close() {
|
|
684
|
+
await this.flush();
|
|
685
|
+
if (this.sqlite) {
|
|
686
|
+
const store = await this.sqlite;
|
|
687
|
+
this.sqlite = void 0;
|
|
688
|
+
store.close();
|
|
689
|
+
}
|
|
690
|
+
for (const journal of this.journals.values()) {
|
|
691
|
+
await journal.flush().catch(() => {
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
this.journals.clear();
|
|
695
|
+
}
|
|
696
|
+
get chronicleDirectory() {
|
|
697
|
+
return path2.join(this.options.projectDir, "chronicle");
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Drop journals for days we will not write to again.
|
|
701
|
+
*
|
|
702
|
+
* Mirrors the daemon's `pruneJournals` in `project-server.ts`: without a cap
|
|
703
|
+
* an inline access object that lives across midnight kept one open
|
|
704
|
+
* `ChronicleJournal` (with its write buffer and file handle) per day, forever.
|
|
705
|
+
*/
|
|
706
|
+
pruneJournals(currentDay) {
|
|
707
|
+
if (this.journals.size <= MAX_OPEN_JOURNAL_DAYS) return;
|
|
708
|
+
const keep = new Set(
|
|
709
|
+
[...this.journals.keys()].sort().reverse().slice(0, MAX_OPEN_JOURNAL_DAYS)
|
|
710
|
+
);
|
|
711
|
+
keep.add(currentDay);
|
|
712
|
+
for (const [day, journal] of this.journals) {
|
|
713
|
+
if (keep.has(day)) continue;
|
|
714
|
+
this.journals.delete(day);
|
|
715
|
+
void journal.flush().catch(() => {
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
journalForToday() {
|
|
720
|
+
const now = /* @__PURE__ */ new Date();
|
|
721
|
+
const day = now.toISOString().slice(0, 10);
|
|
722
|
+
let journal = this.journals.get(day);
|
|
723
|
+
if (!journal) {
|
|
724
|
+
const identity = resolveChronicleRuntimeLocation({
|
|
725
|
+
globalRoot: this.options.globalRoot,
|
|
726
|
+
projectId: this.options.projectId,
|
|
727
|
+
projectDir: this.options.projectDir,
|
|
728
|
+
now
|
|
729
|
+
});
|
|
730
|
+
journal = new ChronicleJournal({
|
|
731
|
+
filePath: legacyPartitionPath(identity),
|
|
732
|
+
retentionDays: this.options.retentionDays
|
|
733
|
+
});
|
|
734
|
+
this.journals.set(day, journal);
|
|
735
|
+
this.pruneJournals(day);
|
|
736
|
+
}
|
|
737
|
+
return journal;
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* Both engines expose the same read surface, so every `call()` branch is
|
|
741
|
+
* backend-agnostic. The SQLite one shares the journal's connection, which is
|
|
742
|
+
* also what makes the legacy import a precondition of reading.
|
|
743
|
+
*/
|
|
744
|
+
async queryEngine() {
|
|
745
|
+
if (useSqliteStore()) return (await this.store()).queryEngine();
|
|
746
|
+
return ChronicleQueryEngine.fromDirectory(this.chronicleDirectory);
|
|
747
|
+
}
|
|
748
|
+
async flush() {
|
|
749
|
+
if (useSqliteStore()) {
|
|
750
|
+
if (this.sqlite) await this.sqlite;
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
await Promise.all([...this.journals.values()].map((journal) => journal.flush()));
|
|
754
|
+
}
|
|
755
|
+
health() {
|
|
756
|
+
const memory = process.memoryUsage();
|
|
757
|
+
return {
|
|
758
|
+
protocolVersion: CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION,
|
|
759
|
+
pid: process.pid,
|
|
760
|
+
projectRoot: this.options.projectRoot,
|
|
761
|
+
projectDir: this.options.projectDir,
|
|
762
|
+
chronicleDirectory: this.chronicleDirectory,
|
|
763
|
+
endpoint: "inline",
|
|
764
|
+
startedAt: new Date(Date.now() - process.uptime() * 1e3).toISOString(),
|
|
765
|
+
checkedAt: Date.now(),
|
|
766
|
+
uptimeMs: Math.round(process.uptime() * 1e3),
|
|
767
|
+
clients: 1,
|
|
768
|
+
activeRequests: 0,
|
|
769
|
+
journal: this.journalForToday().stats(),
|
|
770
|
+
watcher: { active: false, watchedFiles: 0 },
|
|
771
|
+
memory: {
|
|
772
|
+
rss: memory.rss,
|
|
773
|
+
heapUsed: memory.heapUsed,
|
|
774
|
+
heapTotal: memory.heapTotal,
|
|
775
|
+
external: memory.external
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
export {
|
|
782
|
+
isChronicleProjectServerAvailable,
|
|
783
|
+
ChronicleProjectServerClient,
|
|
784
|
+
ChronicleRemoteJournal,
|
|
785
|
+
resolveChronicleProjectServerOptions,
|
|
786
|
+
createChronicleProjectAccess,
|
|
787
|
+
createChronicleEventJournal
|
|
788
|
+
};
|
|
789
|
+
//# sourceMappingURL=chunk-ASX6AW36.js.map
|