@frostbridge/imdl 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +133 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -726,6 +726,23 @@ function setPaused(paused) {
|
|
|
726
726
|
}
|
|
727
727
|
}
|
|
728
728
|
}
|
|
729
|
+
var SESSION_FILE = join3(IMDL_DIR, ".last-session");
|
|
730
|
+
function getLastSessionId() {
|
|
731
|
+
try {
|
|
732
|
+
if (existsSync4(SESSION_FILE)) {
|
|
733
|
+
return readFileSync(SESSION_FILE, "utf-8").trim() || "unknown";
|
|
734
|
+
}
|
|
735
|
+
} catch {
|
|
736
|
+
}
|
|
737
|
+
return "unknown";
|
|
738
|
+
}
|
|
739
|
+
function saveLastSessionId(sessionId) {
|
|
740
|
+
try {
|
|
741
|
+
ensureImdlDir();
|
|
742
|
+
writeFileSync(SESSION_FILE, sessionId, { mode: 384 });
|
|
743
|
+
} catch {
|
|
744
|
+
}
|
|
745
|
+
}
|
|
729
746
|
|
|
730
747
|
// src/mcp/reporter.ts
|
|
731
748
|
var THROTTLE_FILE = join4(getImdlDir(), "last-mcp-report");
|
|
@@ -2784,11 +2801,12 @@ async function sendBatch(apiUrl, sessionId, events, developerId) {
|
|
|
2784
2801
|
if (config.authToken) {
|
|
2785
2802
|
headers["X-IMDL-Key"] = config.authToken;
|
|
2786
2803
|
}
|
|
2804
|
+
const agentType = events.find((e) => e.agentType)?.agentType;
|
|
2787
2805
|
try {
|
|
2788
2806
|
const res = await fetch(`${apiUrl}/api/sessions/${sessionId}/events`, {
|
|
2789
2807
|
method: "POST",
|
|
2790
2808
|
headers,
|
|
2791
|
-
body: JSON.stringify({ events, developerId }),
|
|
2809
|
+
body: JSON.stringify({ events, developerId, ...agentType && { agentType } }),
|
|
2792
2810
|
signal: AbortSignal.timeout(FLUSH_TIMEOUT)
|
|
2793
2811
|
});
|
|
2794
2812
|
return res.ok;
|
|
@@ -3195,7 +3213,9 @@ var CHAT_DATA_KEYS = [
|
|
|
3195
3213
|
"workbench.panel.aichat.view.aichat.chatdata",
|
|
3196
3214
|
"workbench.panel.aichat.view.aichat.chatdata.v2",
|
|
3197
3215
|
"composer.composerData",
|
|
3198
|
-
"composer.allComposers"
|
|
3216
|
+
"composer.allComposers",
|
|
3217
|
+
"aiService.prompts",
|
|
3218
|
+
"aiService.generations"
|
|
3199
3219
|
];
|
|
3200
3220
|
var CursorAdapter = class _CursorAdapter {
|
|
3201
3221
|
agentType = "cursor";
|
|
@@ -3232,6 +3252,11 @@ var CursorAdapter = class _CursorAdapter {
|
|
|
3232
3252
|
*/
|
|
3233
3253
|
findVscdbFiles(baseDir) {
|
|
3234
3254
|
const files = [];
|
|
3255
|
+
const directDb = join16(baseDir, "state.vscdb");
|
|
3256
|
+
if (existsSync17(directDb)) {
|
|
3257
|
+
files.push(directDb);
|
|
3258
|
+
return files;
|
|
3259
|
+
}
|
|
3235
3260
|
try {
|
|
3236
3261
|
const entries = readdirSync4(baseDir);
|
|
3237
3262
|
for (const entry of entries) {
|
|
@@ -3262,9 +3287,23 @@ var CursorAdapter = class _CursorAdapter {
|
|
|
3262
3287
|
try {
|
|
3263
3288
|
db = new Database(dbPath, { readonly: true, fileMustExist: true });
|
|
3264
3289
|
const rows = this.queryAIChatRows(db);
|
|
3290
|
+
let hasGenerations = false;
|
|
3265
3291
|
for (const row of rows) {
|
|
3266
3292
|
const parsed = this.parseJsonValue(row.value);
|
|
3267
3293
|
if (!parsed) continue;
|
|
3294
|
+
if (row.key === "aiService.generations") {
|
|
3295
|
+
const genEvents = this.extractFromGenerations(parsed, dbPath, since);
|
|
3296
|
+
events.push(...genEvents);
|
|
3297
|
+
if (genEvents.length > 0) hasGenerations = true;
|
|
3298
|
+
continue;
|
|
3299
|
+
}
|
|
3300
|
+
if (row.key === "aiService.prompts") {
|
|
3301
|
+
if (!hasGenerations) {
|
|
3302
|
+
const promptEvents = this.extractFromPrompts(parsed, dbPath, since);
|
|
3303
|
+
events.push(...promptEvents);
|
|
3304
|
+
}
|
|
3305
|
+
continue;
|
|
3306
|
+
}
|
|
3268
3307
|
const conversations = this.extractConversations(parsed);
|
|
3269
3308
|
for (const conv of conversations) {
|
|
3270
3309
|
const convEvents = this.conversationToEvents(conv, dbPath, since);
|
|
@@ -3280,6 +3319,57 @@ var CursorAdapter = class _CursorAdapter {
|
|
|
3280
3319
|
}
|
|
3281
3320
|
return events;
|
|
3282
3321
|
}
|
|
3322
|
+
/**
|
|
3323
|
+
* Extract events from aiService.generations format:
|
|
3324
|
+
* [{unixMs, generationUUID, type, textDescription}, ...]
|
|
3325
|
+
*/
|
|
3326
|
+
extractFromGenerations(data, dbPath, since) {
|
|
3327
|
+
if (!Array.isArray(data)) return [];
|
|
3328
|
+
const events = [];
|
|
3329
|
+
const sessionId = this.sessionIdFromPath(dbPath);
|
|
3330
|
+
for (const gen of data) {
|
|
3331
|
+
if (!gen || typeof gen !== "object") continue;
|
|
3332
|
+
const { unixMs, textDescription, type } = gen;
|
|
3333
|
+
if (!textDescription || typeof textDescription !== "string") continue;
|
|
3334
|
+
if (!unixMs || typeof unixMs !== "number") continue;
|
|
3335
|
+
if (since && unixMs <= since.getTime()) continue;
|
|
3336
|
+
const genType = type;
|
|
3337
|
+
if (genType === "apply") continue;
|
|
3338
|
+
if (this.isNoisePrompt(textDescription)) continue;
|
|
3339
|
+
events.push({
|
|
3340
|
+
sessionId,
|
|
3341
|
+
type: "user_prompt",
|
|
3342
|
+
prompt: textDescription.slice(0, 1e4),
|
|
3343
|
+
timestamp: new Date(unixMs).toISOString(),
|
|
3344
|
+
agentType: "cursor"
|
|
3345
|
+
});
|
|
3346
|
+
}
|
|
3347
|
+
return events;
|
|
3348
|
+
}
|
|
3349
|
+
/**
|
|
3350
|
+
* Extract events from aiService.prompts format:
|
|
3351
|
+
* [{text, commandType}, ...]
|
|
3352
|
+
* No timestamps — only use if generations is empty.
|
|
3353
|
+
*/
|
|
3354
|
+
extractFromPrompts(data, dbPath, _since) {
|
|
3355
|
+
if (!Array.isArray(data) || data.length === 0) return [];
|
|
3356
|
+
const events = [];
|
|
3357
|
+
const sessionId = this.sessionIdFromPath(dbPath);
|
|
3358
|
+
for (const prompt of data) {
|
|
3359
|
+
if (!prompt || typeof prompt !== "object") continue;
|
|
3360
|
+
const { text } = prompt;
|
|
3361
|
+
if (!text || typeof text !== "string") continue;
|
|
3362
|
+
if (this.isNoisePrompt(text)) continue;
|
|
3363
|
+
events.push({
|
|
3364
|
+
sessionId,
|
|
3365
|
+
type: "user_prompt",
|
|
3366
|
+
prompt: text.slice(0, 1e4),
|
|
3367
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3368
|
+
agentType: "cursor"
|
|
3369
|
+
});
|
|
3370
|
+
}
|
|
3371
|
+
return events;
|
|
3372
|
+
}
|
|
3283
3373
|
/**
|
|
3284
3374
|
* Query the ItemTable for rows with AI-related keys.
|
|
3285
3375
|
*/
|
|
@@ -3608,6 +3698,42 @@ async function collectPrompts() {
|
|
|
3608
3698
|
}
|
|
3609
3699
|
}
|
|
3610
3700
|
}
|
|
3701
|
+
const cursorWorkspaces = CursorAdapter.getAllWorkspaces();
|
|
3702
|
+
if (cursorWorkspaces.length > 0) {
|
|
3703
|
+
const cursorAdapter = new CursorAdapter();
|
|
3704
|
+
for (const ws of cursorWorkspaces) {
|
|
3705
|
+
try {
|
|
3706
|
+
const events = await cursorAdapter.extractEvents({
|
|
3707
|
+
kind: "directory",
|
|
3708
|
+
path: ws,
|
|
3709
|
+
since: new Date(state.lastRun)
|
|
3710
|
+
});
|
|
3711
|
+
for (const event of events) {
|
|
3712
|
+
let violation;
|
|
3713
|
+
if (event.prompt) {
|
|
3714
|
+
const scan = scanPromptForSecrets(event.prompt);
|
|
3715
|
+
if (scan.hasSecrets) {
|
|
3716
|
+
violation = createPromptViolation(scan.findings);
|
|
3717
|
+
}
|
|
3718
|
+
}
|
|
3719
|
+
const buffered = {
|
|
3720
|
+
sessionId: event.sessionId,
|
|
3721
|
+
type: event.type,
|
|
3722
|
+
toolName: event.toolName,
|
|
3723
|
+
toolInput: event.toolInput ? redactObject(event.toolInput) : void 0,
|
|
3724
|
+
prompt: event.prompt ? redactObject(event.prompt) : void 0,
|
|
3725
|
+
timestamp: event.timestamp,
|
|
3726
|
+
cwd: event.cwd,
|
|
3727
|
+
agentType: "cursor",
|
|
3728
|
+
violation
|
|
3729
|
+
};
|
|
3730
|
+
appendEvent(buffered);
|
|
3731
|
+
collected++;
|
|
3732
|
+
}
|
|
3733
|
+
} catch {
|
|
3734
|
+
}
|
|
3735
|
+
}
|
|
3736
|
+
}
|
|
3611
3737
|
if (collected > 0) {
|
|
3612
3738
|
try {
|
|
3613
3739
|
await tryFlush();
|
|
@@ -5690,8 +5816,9 @@ async function handleHook(type) {
|
|
|
5690
5816
|
behaviorRiskScore = computeRiskScore(signals);
|
|
5691
5817
|
}
|
|
5692
5818
|
}
|
|
5819
|
+
const sessionId = event.session_id || getLastSessionId();
|
|
5693
5820
|
const buffered = {
|
|
5694
|
-
sessionId
|
|
5821
|
+
sessionId,
|
|
5695
5822
|
type: hookType,
|
|
5696
5823
|
toolName: event.tool_name,
|
|
5697
5824
|
toolInput: redactObject(event.tool_input),
|
|
@@ -5703,6 +5830,9 @@ async function handleHook(type) {
|
|
|
5703
5830
|
behaviorSignals,
|
|
5704
5831
|
behaviorRiskScore
|
|
5705
5832
|
};
|
|
5833
|
+
if (event.session_id) {
|
|
5834
|
+
saveLastSessionId(event.session_id);
|
|
5835
|
+
}
|
|
5706
5836
|
appendEvent(buffered);
|
|
5707
5837
|
try {
|
|
5708
5838
|
await tryFlush();
|