@hackersbaby/plugin 0.4.3 → 0.5.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/cli.js +192 -1
- package/dist/cli.js.map +1 -1
- package/dist/hooks/compact.js +428 -168
- package/dist/hooks/compact.js.map +1 -1
- package/dist/hooks/cursor/compact.js +428 -168
- package/dist/hooks/cursor/compact.js.map +1 -1
- package/dist/hooks/cursor/prompt-submit.js +428 -168
- package/dist/hooks/cursor/prompt-submit.js.map +1 -1
- package/dist/hooks/cursor/session-end.js +428 -168
- package/dist/hooks/cursor/session-end.js.map +1 -1
- package/dist/hooks/cursor/session-start.js +417 -165
- package/dist/hooks/cursor/session-start.js.map +1 -1
- package/dist/hooks/cursor/stop.js +428 -168
- package/dist/hooks/cursor/stop.js.map +1 -1
- package/dist/hooks/cursor/subagent.js +428 -168
- package/dist/hooks/cursor/subagent.js.map +1 -1
- package/dist/hooks/cursor/tool-call.js +337 -178
- package/dist/hooks/cursor/tool-call.js.map +1 -1
- package/dist/hooks/prompt-submit.js +428 -168
- package/dist/hooks/prompt-submit.js.map +1 -1
- package/dist/hooks/session-end.js +428 -168
- package/dist/hooks/session-end.js.map +1 -1
- package/dist/hooks/session-start.js +417 -165
- package/dist/hooks/session-start.js.map +1 -1
- package/dist/hooks/stop.js +428 -168
- package/dist/hooks/stop.js.map +1 -1
- package/dist/hooks/subagent.js +428 -168
- package/dist/hooks/subagent.js.map +1 -1
- package/dist/hooks/tool-call.js +337 -178
- package/dist/hooks/tool-call.js.map +1 -1
- package/dist/index.d.ts +39 -21
- package/dist/index.js +200 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -6,9 +6,16 @@ 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
|
};
|
|
15
|
+
var __export = (target, all) => {
|
|
16
|
+
for (var name in all)
|
|
17
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
18
|
+
};
|
|
12
19
|
var __copyProps = (to, from, except, desc) => {
|
|
13
20
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
21
|
for (let key of __getOwnPropNames(from))
|
|
@@ -25,6 +32,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
32
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
33
|
mod
|
|
27
34
|
));
|
|
35
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
36
|
|
|
29
37
|
// ../shared/dist/types.js
|
|
30
38
|
var require_types = __commonJS({
|
|
@@ -98,6 +106,45 @@ var require_scoring = __commonJS({
|
|
|
98
106
|
}
|
|
99
107
|
});
|
|
100
108
|
|
|
109
|
+
// ../shared/dist/anticheat.js
|
|
110
|
+
var require_anticheat = __commonJS({
|
|
111
|
+
"../shared/dist/anticheat.js"(exports2) {
|
|
112
|
+
"use strict";
|
|
113
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
114
|
+
exports2.hashEvent = hashEvent;
|
|
115
|
+
exports2.computeChainHash = computeChainHash2;
|
|
116
|
+
exports2.signBatch = signBatch2;
|
|
117
|
+
exports2.verifyBatchSignature = verifyBatchSignature;
|
|
118
|
+
var crypto_1 = require("crypto");
|
|
119
|
+
function hashEvent(event, prevHash) {
|
|
120
|
+
const payload = `${prevHash}|${event.action_type}|${event.value}|${event.timestamp}`;
|
|
121
|
+
return (0, crypto_1.createHash)("sha256").update(payload).digest("hex").slice(0, 16);
|
|
122
|
+
}
|
|
123
|
+
function computeChainHash2(events, initialHash = "0000000000000000") {
|
|
124
|
+
let hash = initialHash;
|
|
125
|
+
for (const event of events) {
|
|
126
|
+
hash = hashEvent(event, hash);
|
|
127
|
+
}
|
|
128
|
+
return hash;
|
|
129
|
+
}
|
|
130
|
+
function signBatch2(sessionId, events, chainHash, secret) {
|
|
131
|
+
const valueSum = events.reduce((s, e) => s + e.value, 0);
|
|
132
|
+
const message = `${sessionId}|${chainHash}|${events.length}|${valueSum}`;
|
|
133
|
+
return (0, crypto_1.createHmac)("sha256", secret).update(message).digest("hex");
|
|
134
|
+
}
|
|
135
|
+
function verifyBatchSignature(sessionId, events, chainHash, signature, secret) {
|
|
136
|
+
const expected = signBatch2(sessionId, events, chainHash, secret);
|
|
137
|
+
if (expected.length !== signature.length)
|
|
138
|
+
return false;
|
|
139
|
+
let mismatch = 0;
|
|
140
|
+
for (let i = 0; i < expected.length; i++) {
|
|
141
|
+
mismatch |= expected.charCodeAt(i) ^ signature.charCodeAt(i);
|
|
142
|
+
}
|
|
143
|
+
return mismatch === 0;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
101
148
|
// ../shared/dist/index.js
|
|
102
149
|
var require_dist = __commonJS({
|
|
103
150
|
"../shared/dist/index.js"(exports2) {
|
|
@@ -121,22 +168,11 @@ var require_dist = __commonJS({
|
|
|
121
168
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
122
169
|
__exportStar(require_types(), exports2);
|
|
123
170
|
__exportStar(require_scoring(), exports2);
|
|
171
|
+
__exportStar(require_anticheat(), exports2);
|
|
124
172
|
}
|
|
125
173
|
});
|
|
126
174
|
|
|
127
|
-
// src/hooks/shared/tool-call.ts
|
|
128
|
-
var import_shared = __toESM(require_dist());
|
|
129
|
-
|
|
130
|
-
// src/collector.ts
|
|
131
|
-
var import_uuid = require("uuid");
|
|
132
|
-
|
|
133
175
|
// src/config.ts
|
|
134
|
-
var import_fs = __toESM(require("fs"));
|
|
135
|
-
var import_path = __toESM(require("path"));
|
|
136
|
-
var import_os = __toESM(require("os"));
|
|
137
|
-
var CONFIG_DIR = import_path.default.join(import_os.default.homedir(), ".hackersbaby");
|
|
138
|
-
var CONFIG_FILE = import_path.default.join(CONFIG_DIR, "config.json");
|
|
139
|
-
var QUEUE_FILE = import_path.default.join(CONFIG_DIR, "queue.jsonl");
|
|
140
176
|
function sessionStateFile(source) {
|
|
141
177
|
return import_path.default.join(CONFIG_DIR, `active-session-${source}.json`);
|
|
142
178
|
}
|
|
@@ -158,122 +194,188 @@ function saveConfig(config) {
|
|
|
158
194
|
ensureConfigDir();
|
|
159
195
|
import_fs.default.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
|
|
160
196
|
}
|
|
197
|
+
var import_fs, import_path, import_os, CONFIG_DIR, CONFIG_FILE, QUEUE_FILE;
|
|
198
|
+
var init_config = __esm({
|
|
199
|
+
"src/config.ts"() {
|
|
200
|
+
"use strict";
|
|
201
|
+
import_fs = __toESM(require("fs"));
|
|
202
|
+
import_path = __toESM(require("path"));
|
|
203
|
+
import_os = __toESM(require("os"));
|
|
204
|
+
CONFIG_DIR = import_path.default.join(import_os.default.homedir(), ".hackersbaby");
|
|
205
|
+
CONFIG_FILE = import_path.default.join(CONFIG_DIR, "config.json");
|
|
206
|
+
QUEUE_FILE = import_path.default.join(CONFIG_DIR, "queue.jsonl");
|
|
207
|
+
}
|
|
208
|
+
});
|
|
161
209
|
|
|
162
210
|
// src/api-client.ts
|
|
163
|
-
var APIClient
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
211
|
+
var import_shared, APIClient;
|
|
212
|
+
var init_api_client = __esm({
|
|
213
|
+
"src/api-client.ts"() {
|
|
214
|
+
"use strict";
|
|
215
|
+
init_config();
|
|
216
|
+
import_shared = __toESM(require_dist());
|
|
217
|
+
APIClient = class {
|
|
218
|
+
config = loadConfig();
|
|
219
|
+
sessionSecret = null;
|
|
220
|
+
chainHash = "0000000000000000";
|
|
221
|
+
onChainUpdate = null;
|
|
222
|
+
/** Set callback to persist chain state between hook processes */
|
|
223
|
+
setChainUpdateCallback(cb) {
|
|
224
|
+
this.onChainUpdate = cb;
|
|
225
|
+
}
|
|
226
|
+
/** Restore crypto state from a previous session */
|
|
227
|
+
restoreCryptoState(secret, chainHash) {
|
|
228
|
+
this.sessionSecret = secret;
|
|
229
|
+
this.chainHash = chainHash;
|
|
230
|
+
}
|
|
231
|
+
get headers() {
|
|
232
|
+
return {
|
|
233
|
+
"Content-Type": "application/json",
|
|
234
|
+
Authorization: `Bearer ${this.config?.token || ""}`
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/** Get current crypto state for persistence */
|
|
238
|
+
getCryptoState() {
|
|
239
|
+
if (!this.sessionSecret) return null;
|
|
240
|
+
return { secret: this.sessionSecret, chainHash: this.chainHash };
|
|
241
|
+
}
|
|
242
|
+
/** Register session with server and get cryptographic secret */
|
|
243
|
+
async startSession(sessionId) {
|
|
244
|
+
try {
|
|
245
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
246
|
+
const res = await fetch(`${server}/api/sessions/start`, {
|
|
247
|
+
method: "POST",
|
|
248
|
+
headers: this.headers,
|
|
249
|
+
body: JSON.stringify({ session_id: sessionId })
|
|
250
|
+
});
|
|
251
|
+
if (res.ok) {
|
|
252
|
+
const data = await res.json();
|
|
253
|
+
this.sessionSecret = data.session_secret;
|
|
254
|
+
this.chainHash = data.initial_chain_hash;
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
return false;
|
|
258
|
+
} catch {
|
|
259
|
+
return false;
|
|
204
260
|
}
|
|
205
261
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
262
|
+
async sendBatch(batch) {
|
|
263
|
+
try {
|
|
264
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
265
|
+
if (this.sessionSecret) {
|
|
266
|
+
const prevChainHash = this.chainHash;
|
|
267
|
+
const newChainHash = (0, import_shared.computeChainHash)(batch.events, prevChainHash);
|
|
268
|
+
const signature = (0, import_shared.signBatch)(batch.session_id, batch.events, newChainHash, this.sessionSecret);
|
|
269
|
+
batch.signature = signature;
|
|
270
|
+
batch.chain_hash = newChainHash;
|
|
271
|
+
batch.prev_chain_hash = prevChainHash;
|
|
272
|
+
this.chainHash = newChainHash;
|
|
273
|
+
if (this.onChainUpdate) {
|
|
274
|
+
this.onChainUpdate(this.chainHash, this.sessionSecret);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const res = await fetch(`${server}/api/scores/batch`, {
|
|
278
|
+
method: "POST",
|
|
279
|
+
headers: this.headers,
|
|
280
|
+
body: JSON.stringify(batch)
|
|
281
|
+
});
|
|
282
|
+
return res.ok;
|
|
283
|
+
} catch {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
async refreshTokenIfNeeded() {
|
|
288
|
+
if (!this.config) return;
|
|
289
|
+
try {
|
|
290
|
+
const parts = this.config.token.split(".");
|
|
291
|
+
if (parts.length !== 3) return;
|
|
292
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64").toString("utf-8"));
|
|
293
|
+
const expMs = payload.exp * 1e3;
|
|
294
|
+
const oneDayMs = 24 * 60 * 60 * 1e3;
|
|
295
|
+
if (Date.now() + oneDayMs < expMs) return;
|
|
296
|
+
const res = await fetch(`${this.config.server}/api/auth/cli-token/refresh`, {
|
|
297
|
+
method: "POST",
|
|
298
|
+
headers: this.headers,
|
|
299
|
+
body: JSON.stringify({ refresh_token: this.config.refresh_token })
|
|
300
|
+
});
|
|
301
|
+
if (res.ok) {
|
|
302
|
+
const data = await res.json();
|
|
303
|
+
if (data.token) {
|
|
304
|
+
this.config.token = data.token;
|
|
305
|
+
if (data.refresh_token) this.config.refresh_token = data.refresh_token;
|
|
306
|
+
saveConfig(this.config);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
} catch {
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
async getStatus() {
|
|
313
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
314
|
+
const res = await fetch(`${server}/api/users/me`, { headers: this.headers });
|
|
315
|
+
if (!res.ok) throw new Error(`getStatus failed: ${res.status}`);
|
|
316
|
+
return res.json();
|
|
317
|
+
}
|
|
318
|
+
async getRank() {
|
|
319
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
320
|
+
const res = await fetch(`${server}/api/users/me/rank`, { headers: this.headers });
|
|
321
|
+
if (!res.ok) throw new Error(`getRank failed: ${res.status}`);
|
|
322
|
+
return res.json();
|
|
323
|
+
}
|
|
324
|
+
async getLeaderboard() {
|
|
325
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
326
|
+
const res = await fetch(`${server}/api/leaderboard/global?limit=10`, { headers: this.headers });
|
|
327
|
+
if (!res.ok) throw new Error(`getLeaderboard failed: ${res.status}`);
|
|
328
|
+
return res.json();
|
|
329
|
+
}
|
|
330
|
+
async getPublicStats() {
|
|
331
|
+
try {
|
|
332
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
333
|
+
const res = await fetch(`${server}/api/stats/public`);
|
|
334
|
+
if (!res.ok) return null;
|
|
335
|
+
return res.json();
|
|
336
|
+
} catch {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
async getNotifications() {
|
|
341
|
+
try {
|
|
342
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
343
|
+
const res = await fetch(`${server}/api/users/me/notifications`, { headers: this.headers });
|
|
344
|
+
if (!res.ok) return null;
|
|
345
|
+
return res.json();
|
|
346
|
+
} catch {
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
async claimReferral(code) {
|
|
351
|
+
try {
|
|
352
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
353
|
+
const res = await fetch(`${server}/api/referral/claim`, {
|
|
354
|
+
method: "POST",
|
|
355
|
+
headers: this.headers,
|
|
356
|
+
body: JSON.stringify({ referral_code: code })
|
|
357
|
+
});
|
|
358
|
+
if (!res.ok) return null;
|
|
359
|
+
return res.json();
|
|
360
|
+
} catch {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
async getReferralStats() {
|
|
365
|
+
try {
|
|
366
|
+
const server = this.config?.server || "https://hackers.baby";
|
|
367
|
+
const res = await fetch(`${server}/api/referral/stats`, { headers: this.headers });
|
|
368
|
+
if (!res.ok) return null;
|
|
369
|
+
return res.json();
|
|
370
|
+
} catch {
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
};
|
|
270
375
|
}
|
|
271
|
-
};
|
|
376
|
+
});
|
|
272
377
|
|
|
273
378
|
// src/queue.ts
|
|
274
|
-
var import_fs2 = __toESM(require("fs"));
|
|
275
|
-
var MAX_QUEUE_SIZE = 1e4;
|
|
276
|
-
var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
277
379
|
function enqueueEvents(events) {
|
|
278
380
|
ensureConfigDir();
|
|
279
381
|
const lines = events.map((e) => JSON.stringify(e)).join("\n");
|
|
@@ -311,75 +413,132 @@ function drainQueue() {
|
|
|
311
413
|
return [];
|
|
312
414
|
}
|
|
313
415
|
}
|
|
416
|
+
var import_fs2, MAX_QUEUE_SIZE, MAX_AGE_MS;
|
|
417
|
+
var init_queue = __esm({
|
|
418
|
+
"src/queue.ts"() {
|
|
419
|
+
"use strict";
|
|
420
|
+
import_fs2 = __toESM(require("fs"));
|
|
421
|
+
init_config();
|
|
422
|
+
MAX_QUEUE_SIZE = 1e4;
|
|
423
|
+
MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
424
|
+
}
|
|
425
|
+
});
|
|
314
426
|
|
|
315
427
|
// src/collector.ts
|
|
316
|
-
var
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
if (queued.length > 0) {
|
|
339
|
-
const batch = { session_id: this.sessionId, events: queued };
|
|
340
|
-
const ok = await this.client.sendBatch(batch);
|
|
341
|
-
if (!ok) {
|
|
342
|
-
enqueueEvents(queued);
|
|
428
|
+
var collector_exports = {};
|
|
429
|
+
__export(collector_exports, {
|
|
430
|
+
EventCollector: () => EventCollector
|
|
431
|
+
});
|
|
432
|
+
var import_uuid, EventCollector;
|
|
433
|
+
var init_collector = __esm({
|
|
434
|
+
"src/collector.ts"() {
|
|
435
|
+
"use strict";
|
|
436
|
+
import_uuid = require("uuid");
|
|
437
|
+
init_api_client();
|
|
438
|
+
init_queue();
|
|
439
|
+
init_config();
|
|
440
|
+
EventCollector = class {
|
|
441
|
+
sessionId;
|
|
442
|
+
buffer = [];
|
|
443
|
+
flushInterval = null;
|
|
444
|
+
client;
|
|
445
|
+
source;
|
|
446
|
+
constructor(sessionId, source) {
|
|
447
|
+
this.sessionId = sessionId ?? (0, import_uuid.v4)();
|
|
448
|
+
this.client = new APIClient();
|
|
449
|
+
this.source = source;
|
|
343
450
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
451
|
+
/** Restore crypto state from persisted session data */
|
|
452
|
+
restoreCrypto(secret, chainHash) {
|
|
453
|
+
this.client.restoreCryptoState(secret, chainHash);
|
|
454
|
+
}
|
|
455
|
+
/** Set callback to persist crypto state after each batch */
|
|
456
|
+
setCryptoUpdateCallback(cb) {
|
|
457
|
+
this.client.setChainUpdateCallback(cb);
|
|
458
|
+
}
|
|
459
|
+
addEvent(event) {
|
|
460
|
+
const metadata = this.source ? { ...event.metadata, source: this.source } : event.metadata;
|
|
461
|
+
this.buffer.push({
|
|
462
|
+
...event,
|
|
463
|
+
metadata,
|
|
464
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
async start() {
|
|
468
|
+
await this.client.refreshTokenIfNeeded();
|
|
469
|
+
await this.client.startSession(this.sessionId);
|
|
470
|
+
const queued = drainQueue();
|
|
471
|
+
if (queued.length > 0) {
|
|
472
|
+
const batch = { session_id: this.sessionId, events: queued };
|
|
473
|
+
const ok = await this.client.sendBatch(batch);
|
|
474
|
+
if (!ok) {
|
|
475
|
+
enqueueEvents(queued);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
const config = loadConfig();
|
|
479
|
+
const intervalMs = config?.preferences?.batch_interval_ms ?? 1e4;
|
|
480
|
+
this.flushInterval = setInterval(() => {
|
|
481
|
+
this.flush().catch(() => {
|
|
482
|
+
});
|
|
483
|
+
}, intervalMs);
|
|
484
|
+
}
|
|
485
|
+
async flush() {
|
|
486
|
+
if (this.buffer.length === 0) return;
|
|
487
|
+
const events = this.buffer.splice(0);
|
|
488
|
+
const batch = { session_id: this.sessionId, events };
|
|
489
|
+
const ok = await this.client.sendBatch(batch);
|
|
490
|
+
if (!ok) {
|
|
491
|
+
enqueueEvents(events);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
async stop() {
|
|
495
|
+
if (this.flushInterval !== null) {
|
|
496
|
+
clearInterval(this.flushInterval);
|
|
497
|
+
this.flushInterval = null;
|
|
498
|
+
}
|
|
499
|
+
this.addEvent({ action_type: "session_completed", value: 1, metadata: {} });
|
|
500
|
+
await this.flush();
|
|
501
|
+
}
|
|
502
|
+
};
|
|
368
503
|
}
|
|
369
|
-
};
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
// src/hooks/shared/tool-call.ts
|
|
507
|
+
var import_shared2 = __toESM(require_dist());
|
|
370
508
|
|
|
371
509
|
// src/hooks/shared/utils.ts
|
|
372
510
|
var import_fs3 = __toESM(require("fs"));
|
|
373
|
-
|
|
511
|
+
init_config();
|
|
512
|
+
function loadSessionState(source) {
|
|
374
513
|
try {
|
|
375
514
|
const file = sessionStateFile(source);
|
|
376
515
|
if (!import_fs3.default.existsSync(file)) return void 0;
|
|
377
|
-
|
|
378
|
-
return data.sessionId;
|
|
516
|
+
return JSON.parse(import_fs3.default.readFileSync(file, "utf-8"));
|
|
379
517
|
} catch {
|
|
380
518
|
return void 0;
|
|
381
519
|
}
|
|
382
520
|
}
|
|
521
|
+
function loadSessionId(source) {
|
|
522
|
+
return loadSessionState(source)?.sessionId;
|
|
523
|
+
}
|
|
524
|
+
function updateSessionState(source, updates) {
|
|
525
|
+
const state = loadSessionState(source);
|
|
526
|
+
if (!state) return;
|
|
527
|
+
const file = sessionStateFile(source);
|
|
528
|
+
import_fs3.default.writeFileSync(file, JSON.stringify({ ...state, ...updates }));
|
|
529
|
+
}
|
|
530
|
+
function createCollector(sessionId, source) {
|
|
531
|
+
const { EventCollector: EventCollector2 } = (init_collector(), __toCommonJS(collector_exports));
|
|
532
|
+
const collector = new EventCollector2(sessionId, source);
|
|
533
|
+
const state = loadSessionState(source);
|
|
534
|
+
if (state?.sessionSecret && state?.chainHash && state.sessionId === sessionId) {
|
|
535
|
+
collector.restoreCrypto(state.sessionSecret, state.chainHash);
|
|
536
|
+
collector.setCryptoUpdateCallback((chainHash, secret) => {
|
|
537
|
+
updateSessionState(source, { chainHash, sessionSecret: secret });
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
return collector;
|
|
541
|
+
}
|
|
383
542
|
function readStdin() {
|
|
384
543
|
return new Promise((resolve) => {
|
|
385
544
|
let input = "";
|
|
@@ -411,7 +570,7 @@ async function handleToolCall(source) {
|
|
|
411
570
|
const toolName = hookData.tool_name || "unknown";
|
|
412
571
|
const toolInput = hookData.tool_input || {};
|
|
413
572
|
const sessionId = hookData.session_id || loadSessionId(detected);
|
|
414
|
-
const collector =
|
|
573
|
+
const collector = createCollector(sessionId, detected);
|
|
415
574
|
collector.addEvent({ action_type: "tool_call", value: 1, metadata: { tool_name: toolName } });
|
|
416
575
|
if (hookData.input_tokens) {
|
|
417
576
|
collector.addEvent({ action_type: "token_input", value: hookData.input_tokens, metadata: {} });
|
|
@@ -419,7 +578,7 @@ async function handleToolCall(source) {
|
|
|
419
578
|
if (hookData.output_tokens) {
|
|
420
579
|
collector.addEvent({ action_type: "token_output", value: hookData.output_tokens, metadata: {} });
|
|
421
580
|
}
|
|
422
|
-
if (toolName === "Bash" && toolInput.command && (0,
|
|
581
|
+
if (toolName === "Bash" && toolInput.command && (0, import_shared2.isDeployCommand)(toolInput.command)) {
|
|
423
582
|
collector.addEvent({ action_type: "deployment", value: 1, metadata: {} });
|
|
424
583
|
}
|
|
425
584
|
if (toolName === "Write") {
|