@hackersbaby/plugin 0.5.0 → 0.5.2
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/cli.js +18 -0
- package/dist/cli.js.map +1 -1
- package/dist/hooks/compact.js +314 -228
- package/dist/hooks/compact.js.map +1 -1
- package/dist/hooks/cursor/compact.js +314 -228
- package/dist/hooks/cursor/compact.js.map +1 -1
- package/dist/hooks/cursor/prompt-submit.js +314 -228
- package/dist/hooks/cursor/prompt-submit.js.map +1 -1
- package/dist/hooks/cursor/session-end.js +338 -228
- package/dist/hooks/cursor/session-end.js.map +1 -1
- package/dist/hooks/cursor/session-start.js +330 -226
- package/dist/hooks/cursor/session-start.js.map +1 -1
- package/dist/hooks/cursor/stop.js +314 -228
- package/dist/hooks/cursor/stop.js.map +1 -1
- package/dist/hooks/cursor/subagent.js +314 -228
- package/dist/hooks/cursor/subagent.js.map +1 -1
- package/dist/hooks/cursor/tool-call.js +294 -208
- package/dist/hooks/cursor/tool-call.js.map +1 -1
- package/dist/hooks/prompt-submit.js +314 -228
- package/dist/hooks/prompt-submit.js.map +1 -1
- package/dist/hooks/session-end.js +338 -228
- package/dist/hooks/session-end.js.map +1 -1
- package/dist/hooks/session-start.js +330 -226
- package/dist/hooks/session-start.js.map +1 -1
- package/dist/hooks/stop.js +314 -228
- package/dist/hooks/stop.js.map +1 -1
- package/dist/hooks/subagent.js +314 -228
- package/dist/hooks/subagent.js.map +1 -1
- package/dist/hooks/tool-call.js +294 -208
- package/dist/hooks/tool-call.js.map +1 -1
- package/dist/index.d.ts +39 -25
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -6,6 +6,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
9
12
|
var __commonJS = (cb, mod) => function __require() {
|
|
10
13
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
11
14
|
};
|
|
@@ -26,6 +29,41 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
29
|
mod
|
|
27
30
|
));
|
|
28
31
|
|
|
32
|
+
// src/config.ts
|
|
33
|
+
function sessionStateFile(source) {
|
|
34
|
+
return import_path.default.join(CONFIG_DIR, `active-session-${source}.json`);
|
|
35
|
+
}
|
|
36
|
+
function ensureConfigDir() {
|
|
37
|
+
if (!import_fs.default.existsSync(CONFIG_DIR)) {
|
|
38
|
+
import_fs.default.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function loadConfig() {
|
|
42
|
+
try {
|
|
43
|
+
if (!import_fs.default.existsSync(CONFIG_FILE)) return null;
|
|
44
|
+
const raw = import_fs.default.readFileSync(CONFIG_FILE, "utf-8");
|
|
45
|
+
return JSON.parse(raw);
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function saveConfig(config) {
|
|
51
|
+
ensureConfigDir();
|
|
52
|
+
import_fs.default.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
|
|
53
|
+
}
|
|
54
|
+
var import_fs, import_path, import_os, CONFIG_DIR, CONFIG_FILE, QUEUE_FILE;
|
|
55
|
+
var init_config = __esm({
|
|
56
|
+
"src/config.ts"() {
|
|
57
|
+
"use strict";
|
|
58
|
+
import_fs = __toESM(require("fs"));
|
|
59
|
+
import_path = __toESM(require("path"));
|
|
60
|
+
import_os = __toESM(require("os"));
|
|
61
|
+
CONFIG_DIR = import_path.default.join(import_os.default.homedir(), ".hackersbaby");
|
|
62
|
+
CONFIG_FILE = import_path.default.join(CONFIG_DIR, "config.json");
|
|
63
|
+
QUEUE_FILE = import_path.default.join(CONFIG_DIR, "queue.jsonl");
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
29
67
|
// ../shared/dist/types.js
|
|
30
68
|
var require_types = __commonJS({
|
|
31
69
|
"../shared/dist/types.js"(exports2) {
|
|
@@ -164,185 +202,175 @@ var require_dist = __commonJS({
|
|
|
164
202
|
}
|
|
165
203
|
});
|
|
166
204
|
|
|
167
|
-
// src/collector.ts
|
|
168
|
-
var import_uuid = require("uuid");
|
|
169
|
-
|
|
170
|
-
// src/config.ts
|
|
171
|
-
var import_fs = __toESM(require("fs"));
|
|
172
|
-
var import_path = __toESM(require("path"));
|
|
173
|
-
var import_os = __toESM(require("os"));
|
|
174
|
-
var CONFIG_DIR = import_path.default.join(import_os.default.homedir(), ".hackersbaby");
|
|
175
|
-
var CONFIG_FILE = import_path.default.join(CONFIG_DIR, "config.json");
|
|
176
|
-
var QUEUE_FILE = import_path.default.join(CONFIG_DIR, "queue.jsonl");
|
|
177
|
-
function sessionStateFile(source) {
|
|
178
|
-
return import_path.default.join(CONFIG_DIR, `active-session-${source}.json`);
|
|
179
|
-
}
|
|
180
|
-
function ensureConfigDir() {
|
|
181
|
-
if (!import_fs.default.existsSync(CONFIG_DIR)) {
|
|
182
|
-
import_fs.default.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
function loadConfig() {
|
|
186
|
-
try {
|
|
187
|
-
if (!import_fs.default.existsSync(CONFIG_FILE)) return null;
|
|
188
|
-
const raw = import_fs.default.readFileSync(CONFIG_FILE, "utf-8");
|
|
189
|
-
return JSON.parse(raw);
|
|
190
|
-
} catch {
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
function saveConfig(config) {
|
|
195
|
-
ensureConfigDir();
|
|
196
|
-
import_fs.default.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
|
|
197
|
-
}
|
|
198
|
-
|
|
199
205
|
// src/api-client.ts
|
|
200
|
-
var import_shared
|
|
201
|
-
var
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const server = this.config?.server || "https://hackers.baby";
|
|
215
|
-
const res = await fetch(`${server}/api/sessions/start`, {
|
|
216
|
-
method: "POST",
|
|
217
|
-
headers: this.headers,
|
|
218
|
-
body: JSON.stringify({ session_id: sessionId })
|
|
219
|
-
});
|
|
220
|
-
if (res.ok) {
|
|
221
|
-
const data = await res.json();
|
|
222
|
-
this.sessionSecret = data.session_secret;
|
|
223
|
-
this.chainHash = data.initial_chain_hash;
|
|
224
|
-
return true;
|
|
206
|
+
var import_shared, APIClient;
|
|
207
|
+
var init_api_client = __esm({
|
|
208
|
+
"src/api-client.ts"() {
|
|
209
|
+
"use strict";
|
|
210
|
+
init_config();
|
|
211
|
+
import_shared = __toESM(require_dist());
|
|
212
|
+
APIClient = class {
|
|
213
|
+
config = loadConfig();
|
|
214
|
+
sessionSecret = null;
|
|
215
|
+
chainHash = "0000000000000000";
|
|
216
|
+
onChainUpdate = null;
|
|
217
|
+
/** Set callback to persist chain state between hook processes */
|
|
218
|
+
setChainUpdateCallback(cb) {
|
|
219
|
+
this.onChainUpdate = cb;
|
|
225
220
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
async sendBatch(batch) {
|
|
232
|
-
try {
|
|
233
|
-
const server = this.config?.server || "https://hackers.baby";
|
|
234
|
-
if (this.sessionSecret) {
|
|
235
|
-
const prevChainHash = this.chainHash;
|
|
236
|
-
const newChainHash = (0, import_shared.computeChainHash)(batch.events, prevChainHash);
|
|
237
|
-
const signature = (0, import_shared.signBatch)(batch.session_id, batch.events, newChainHash, this.sessionSecret);
|
|
238
|
-
batch.signature = signature;
|
|
239
|
-
batch.chain_hash = newChainHash;
|
|
240
|
-
batch.prev_chain_hash = prevChainHash;
|
|
241
|
-
this.chainHash = newChainHash;
|
|
221
|
+
/** Restore crypto state from a previous session */
|
|
222
|
+
restoreCryptoState(secret, chainHash) {
|
|
223
|
+
this.sessionSecret = secret;
|
|
224
|
+
this.chainHash = chainHash;
|
|
242
225
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
saveConfig(this.config);
|
|
226
|
+
get headers() {
|
|
227
|
+
return {
|
|
228
|
+
"Content-Type": "application/json",
|
|
229
|
+
Authorization: `Bearer ${this.config?.token || ""}`
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/** Get current crypto state for persistence */
|
|
233
|
+
getCryptoState() {
|
|
234
|
+
if (!this.sessionSecret) return null;
|
|
235
|
+
return { secret: this.sessionSecret, chainHash: this.chainHash };
|
|
236
|
+
}
|
|
237
|
+
/** Register session with server and get cryptographic secret */
|
|
238
|
+
async startSession(sessionId) {
|
|
239
|
+
try {
|
|
240
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
241
|
+
const res = await fetch(`${server}/api/sessions/start`, {
|
|
242
|
+
method: "POST",
|
|
243
|
+
headers: this.headers,
|
|
244
|
+
body: JSON.stringify({ session_id: sessionId })
|
|
245
|
+
});
|
|
246
|
+
if (res.ok) {
|
|
247
|
+
const data = await res.json();
|
|
248
|
+
this.sessionSecret = data.session_secret;
|
|
249
|
+
this.chainHash = data.initial_chain_hash;
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
return false;
|
|
253
|
+
} catch {
|
|
254
|
+
return false;
|
|
273
255
|
}
|
|
274
256
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
257
|
+
async sendBatch(batch) {
|
|
258
|
+
try {
|
|
259
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
260
|
+
if (this.sessionSecret) {
|
|
261
|
+
const prevChainHash = this.chainHash;
|
|
262
|
+
const newChainHash = (0, import_shared.computeChainHash)(batch.events, prevChainHash);
|
|
263
|
+
const signature = (0, import_shared.signBatch)(batch.session_id, batch.events, newChainHash, this.sessionSecret);
|
|
264
|
+
batch.signature = signature;
|
|
265
|
+
batch.chain_hash = newChainHash;
|
|
266
|
+
batch.prev_chain_hash = prevChainHash;
|
|
267
|
+
this.chainHash = newChainHash;
|
|
268
|
+
if (this.onChainUpdate) {
|
|
269
|
+
this.onChainUpdate(this.chainHash, this.sessionSecret);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const res = await fetch(`${server}/api/scores/batch`, {
|
|
273
|
+
method: "POST",
|
|
274
|
+
headers: this.headers,
|
|
275
|
+
body: JSON.stringify(batch)
|
|
276
|
+
});
|
|
277
|
+
return res.ok;
|
|
278
|
+
} catch {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
async refreshTokenIfNeeded() {
|
|
283
|
+
if (!this.config) return;
|
|
284
|
+
try {
|
|
285
|
+
const parts = this.config.token.split(".");
|
|
286
|
+
if (parts.length !== 3) return;
|
|
287
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64").toString("utf-8"));
|
|
288
|
+
const expMs = payload.exp * 1e3;
|
|
289
|
+
const oneDayMs = 24 * 60 * 60 * 1e3;
|
|
290
|
+
if (Date.now() + oneDayMs < expMs) return;
|
|
291
|
+
const res = await fetch(`${this.config.server}/api/auth/cli-token/refresh`, {
|
|
292
|
+
method: "POST",
|
|
293
|
+
headers: this.headers,
|
|
294
|
+
body: JSON.stringify({ refresh_token: this.config.refresh_token })
|
|
295
|
+
});
|
|
296
|
+
if (res.ok) {
|
|
297
|
+
const data = await res.json();
|
|
298
|
+
if (data.token) {
|
|
299
|
+
this.config.token = data.token;
|
|
300
|
+
if (data.refresh_token) this.config.refresh_token = data.refresh_token;
|
|
301
|
+
saveConfig(this.config);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
} catch {
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
async getStatus() {
|
|
308
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
309
|
+
const res = await fetch(`${server}/api/users/me`, { headers: this.headers });
|
|
310
|
+
if (!res.ok) throw new Error(`getStatus failed: ${res.status}`);
|
|
311
|
+
return res.json();
|
|
312
|
+
}
|
|
313
|
+
async getRank() {
|
|
314
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
315
|
+
const res = await fetch(`${server}/api/users/me/rank`, { headers: this.headers });
|
|
316
|
+
if (!res.ok) throw new Error(`getRank failed: ${res.status}`);
|
|
317
|
+
return res.json();
|
|
318
|
+
}
|
|
319
|
+
async getLeaderboard() {
|
|
320
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
321
|
+
const res = await fetch(`${server}/api/leaderboard/global?limit=10`, { headers: this.headers });
|
|
322
|
+
if (!res.ok) throw new Error(`getLeaderboard failed: ${res.status}`);
|
|
323
|
+
return res.json();
|
|
324
|
+
}
|
|
325
|
+
async getPublicStats() {
|
|
326
|
+
try {
|
|
327
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
328
|
+
const res = await fetch(`${server}/api/stats/public`);
|
|
329
|
+
if (!res.ok) return null;
|
|
330
|
+
return res.json();
|
|
331
|
+
} catch {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
async getNotifications() {
|
|
336
|
+
try {
|
|
337
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
338
|
+
const res = await fetch(`${server}/api/users/me/notifications`, { headers: this.headers });
|
|
339
|
+
if (!res.ok) return null;
|
|
340
|
+
return res.json();
|
|
341
|
+
} catch {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
async claimReferral(code) {
|
|
346
|
+
try {
|
|
347
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
348
|
+
const res = await fetch(`${server}/api/referral/claim`, {
|
|
349
|
+
method: "POST",
|
|
350
|
+
headers: this.headers,
|
|
351
|
+
body: JSON.stringify({ referral_code: code })
|
|
352
|
+
});
|
|
353
|
+
if (!res.ok) return null;
|
|
354
|
+
return res.json();
|
|
355
|
+
} catch {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
async getReferralStats() {
|
|
360
|
+
try {
|
|
361
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
362
|
+
const res = await fetch(`${server}/api/referral/stats`, { headers: this.headers });
|
|
363
|
+
if (!res.ok) return null;
|
|
364
|
+
return res.json();
|
|
365
|
+
} catch {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
};
|
|
339
370
|
}
|
|
340
|
-
};
|
|
371
|
+
});
|
|
341
372
|
|
|
342
373
|
// src/queue.ts
|
|
343
|
-
var import_fs2 = __toESM(require("fs"));
|
|
344
|
-
var MAX_QUEUE_SIZE = 1e4;
|
|
345
|
-
var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
346
374
|
function enqueueEvents(events) {
|
|
347
375
|
ensureConfigDir();
|
|
348
376
|
const lines = events.map((e) => JSON.stringify(e)).join("\n");
|
|
@@ -380,82 +408,158 @@ function drainQueue() {
|
|
|
380
408
|
return [];
|
|
381
409
|
}
|
|
382
410
|
}
|
|
411
|
+
var import_fs2, MAX_QUEUE_SIZE, MAX_AGE_MS;
|
|
412
|
+
var init_queue = __esm({
|
|
413
|
+
"src/queue.ts"() {
|
|
414
|
+
"use strict";
|
|
415
|
+
import_fs2 = __toESM(require("fs"));
|
|
416
|
+
init_config();
|
|
417
|
+
MAX_QUEUE_SIZE = 1e4;
|
|
418
|
+
MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
419
|
+
}
|
|
420
|
+
});
|
|
383
421
|
|
|
384
422
|
// src/collector.ts
|
|
385
|
-
var EventCollector
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
404
|
-
async start() {
|
|
405
|
-
await this.client.refreshTokenIfNeeded();
|
|
406
|
-
await this.client.startSession(this.sessionId);
|
|
407
|
-
const queued = drainQueue();
|
|
408
|
-
if (queued.length > 0) {
|
|
409
|
-
const batch = { session_id: this.sessionId, events: queued };
|
|
410
|
-
const ok = await this.client.sendBatch(batch);
|
|
411
|
-
if (!ok) {
|
|
412
|
-
enqueueEvents(queued);
|
|
423
|
+
var import_uuid, EventCollector;
|
|
424
|
+
var init_collector = __esm({
|
|
425
|
+
"src/collector.ts"() {
|
|
426
|
+
"use strict";
|
|
427
|
+
import_uuid = require("uuid");
|
|
428
|
+
init_api_client();
|
|
429
|
+
init_queue();
|
|
430
|
+
init_config();
|
|
431
|
+
EventCollector = class {
|
|
432
|
+
sessionId;
|
|
433
|
+
buffer = [];
|
|
434
|
+
flushInterval = null;
|
|
435
|
+
client;
|
|
436
|
+
source;
|
|
437
|
+
constructor(sessionId, source) {
|
|
438
|
+
this.sessionId = sessionId ?? (0, import_uuid.v4)();
|
|
439
|
+
this.client = new APIClient();
|
|
440
|
+
this.source = source;
|
|
413
441
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
442
|
+
/** Restore crypto state from persisted session data */
|
|
443
|
+
restoreCrypto(secret, chainHash) {
|
|
444
|
+
this.client.restoreCryptoState(secret, chainHash);
|
|
445
|
+
}
|
|
446
|
+
/** Set callback to persist crypto state after each batch */
|
|
447
|
+
setCryptoUpdateCallback(cb) {
|
|
448
|
+
this.client.setChainUpdateCallback(cb);
|
|
449
|
+
}
|
|
450
|
+
addEvent(event) {
|
|
451
|
+
const metadata = this.source ? { ...event.metadata, source: this.source } : event.metadata;
|
|
452
|
+
this.buffer.push({
|
|
453
|
+
...event,
|
|
454
|
+
metadata,
|
|
455
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
async start() {
|
|
459
|
+
await this.client.refreshTokenIfNeeded();
|
|
460
|
+
await this.client.startSession(this.sessionId);
|
|
461
|
+
const queued = drainQueue();
|
|
462
|
+
if (queued.length > 0) {
|
|
463
|
+
const batch = { session_id: this.sessionId, events: queued };
|
|
464
|
+
const ok = await this.client.sendBatch(batch);
|
|
465
|
+
if (!ok) {
|
|
466
|
+
enqueueEvents(queued);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
const config = loadConfig();
|
|
470
|
+
const intervalMs = config?.preferences?.batch_interval_ms ?? 1e4;
|
|
471
|
+
this.flushInterval = setInterval(() => {
|
|
472
|
+
this.flush().catch(() => {
|
|
473
|
+
});
|
|
474
|
+
}, intervalMs);
|
|
475
|
+
}
|
|
476
|
+
async flush() {
|
|
477
|
+
if (this.buffer.length === 0) return;
|
|
478
|
+
const events = this.buffer.splice(0);
|
|
479
|
+
const batch = { session_id: this.sessionId, events };
|
|
480
|
+
const ok = await this.client.sendBatch(batch);
|
|
481
|
+
if (!ok) {
|
|
482
|
+
enqueueEvents(events);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
async stop() {
|
|
486
|
+
if (this.flushInterval !== null) {
|
|
487
|
+
clearInterval(this.flushInterval);
|
|
488
|
+
this.flushInterval = null;
|
|
489
|
+
}
|
|
490
|
+
this.addEvent({ action_type: "session_completed", value: 1, metadata: {} });
|
|
491
|
+
await this.flush();
|
|
492
|
+
}
|
|
493
|
+
};
|
|
438
494
|
}
|
|
439
|
-
};
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
// src/hooks/shared/session-start.ts
|
|
498
|
+
init_collector();
|
|
499
|
+
init_api_client();
|
|
500
|
+
init_config();
|
|
440
501
|
|
|
441
502
|
// src/hooks/shared/utils.ts
|
|
442
503
|
var import_fs3 = __toESM(require("fs"));
|
|
504
|
+
init_config();
|
|
443
505
|
function saveSessionState(state) {
|
|
444
506
|
const file = sessionStateFile(state.source);
|
|
445
507
|
import_fs3.default.writeFileSync(file, JSON.stringify(state));
|
|
446
508
|
}
|
|
509
|
+
function readStdin() {
|
|
510
|
+
return new Promise((resolve) => {
|
|
511
|
+
let input = "";
|
|
512
|
+
process.stdin.on("data", (chunk) => {
|
|
513
|
+
input += chunk;
|
|
514
|
+
});
|
|
515
|
+
process.stdin.on("end", () => resolve(input));
|
|
516
|
+
});
|
|
517
|
+
}
|
|
447
518
|
function detectSource(payload) {
|
|
448
519
|
if (process.env.CURSOR_VERSION) return "cursor";
|
|
449
520
|
if (payload?.cursor_version) return "cursor";
|
|
450
521
|
return "claude";
|
|
451
522
|
}
|
|
523
|
+
function normalizePayload(source, raw) {
|
|
524
|
+
if (source === "cursor") {
|
|
525
|
+
return { ...raw };
|
|
526
|
+
}
|
|
527
|
+
return raw;
|
|
528
|
+
}
|
|
452
529
|
|
|
453
530
|
// src/hooks/shared/session-start.ts
|
|
454
531
|
async function handleSessionStart(source) {
|
|
532
|
+
let payloadSessionId;
|
|
533
|
+
try {
|
|
534
|
+
const input = await readStdin();
|
|
535
|
+
const raw = JSON.parse(input);
|
|
536
|
+
const detected2 = detectSource(raw);
|
|
537
|
+
const hookData = normalizePayload(detected2, raw);
|
|
538
|
+
if (typeof hookData.session_id === "string" && hookData.session_id.length > 0) {
|
|
539
|
+
payloadSessionId = hookData.session_id;
|
|
540
|
+
}
|
|
541
|
+
} catch {
|
|
542
|
+
}
|
|
455
543
|
const detected = detectSource();
|
|
456
|
-
const collector = new EventCollector(
|
|
544
|
+
const collector = new EventCollector(payloadSessionId, detected);
|
|
545
|
+
collector.setCryptoUpdateCallback((chainHash, secret) => {
|
|
546
|
+
saveSessionState({
|
|
547
|
+
sessionId: collector.sessionId,
|
|
548
|
+
pid: process.pid,
|
|
549
|
+
source: detected,
|
|
550
|
+
sessionSecret: secret,
|
|
551
|
+
chainHash
|
|
552
|
+
});
|
|
553
|
+
});
|
|
457
554
|
await collector.start();
|
|
458
|
-
|
|
555
|
+
const crypto = collector.client.getCryptoState();
|
|
556
|
+
saveSessionState({
|
|
557
|
+
sessionId: collector.sessionId,
|
|
558
|
+
pid: process.pid,
|
|
559
|
+
source: detected,
|
|
560
|
+
sessionSecret: crypto?.secret,
|
|
561
|
+
chainHash: crypto?.chainHash
|
|
562
|
+
});
|
|
459
563
|
try {
|
|
460
564
|
const config = loadConfig();
|
|
461
565
|
if (config?.token) {
|