@frostbridge/imdl 0.1.6 → 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.
Files changed (2) hide show
  1. package/dist/index.js +131 -2
  2. 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");
@@ -3196,7 +3213,9 @@ var CHAT_DATA_KEYS = [
3196
3213
  "workbench.panel.aichat.view.aichat.chatdata",
3197
3214
  "workbench.panel.aichat.view.aichat.chatdata.v2",
3198
3215
  "composer.composerData",
3199
- "composer.allComposers"
3216
+ "composer.allComposers",
3217
+ "aiService.prompts",
3218
+ "aiService.generations"
3200
3219
  ];
3201
3220
  var CursorAdapter = class _CursorAdapter {
3202
3221
  agentType = "cursor";
@@ -3233,6 +3252,11 @@ var CursorAdapter = class _CursorAdapter {
3233
3252
  */
3234
3253
  findVscdbFiles(baseDir) {
3235
3254
  const files = [];
3255
+ const directDb = join16(baseDir, "state.vscdb");
3256
+ if (existsSync17(directDb)) {
3257
+ files.push(directDb);
3258
+ return files;
3259
+ }
3236
3260
  try {
3237
3261
  const entries = readdirSync4(baseDir);
3238
3262
  for (const entry of entries) {
@@ -3263,9 +3287,23 @@ var CursorAdapter = class _CursorAdapter {
3263
3287
  try {
3264
3288
  db = new Database(dbPath, { readonly: true, fileMustExist: true });
3265
3289
  const rows = this.queryAIChatRows(db);
3290
+ let hasGenerations = false;
3266
3291
  for (const row of rows) {
3267
3292
  const parsed = this.parseJsonValue(row.value);
3268
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
+ }
3269
3307
  const conversations = this.extractConversations(parsed);
3270
3308
  for (const conv of conversations) {
3271
3309
  const convEvents = this.conversationToEvents(conv, dbPath, since);
@@ -3281,6 +3319,57 @@ var CursorAdapter = class _CursorAdapter {
3281
3319
  }
3282
3320
  return events;
3283
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
+ }
3284
3373
  /**
3285
3374
  * Query the ItemTable for rows with AI-related keys.
3286
3375
  */
@@ -3609,6 +3698,42 @@ async function collectPrompts() {
3609
3698
  }
3610
3699
  }
3611
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
+ }
3612
3737
  if (collected > 0) {
3613
3738
  try {
3614
3739
  await tryFlush();
@@ -5691,8 +5816,9 @@ async function handleHook(type) {
5691
5816
  behaviorRiskScore = computeRiskScore(signals);
5692
5817
  }
5693
5818
  }
5819
+ const sessionId = event.session_id || getLastSessionId();
5694
5820
  const buffered = {
5695
- sessionId: event.session_id,
5821
+ sessionId,
5696
5822
  type: hookType,
5697
5823
  toolName: event.tool_name,
5698
5824
  toolInput: redactObject(event.tool_input),
@@ -5704,6 +5830,9 @@ async function handleHook(type) {
5704
5830
  behaviorSignals,
5705
5831
  behaviorRiskScore
5706
5832
  };
5833
+ if (event.session_id) {
5834
+ saveLastSessionId(event.session_id);
5835
+ }
5707
5836
  appendEvent(buffered);
5708
5837
  try {
5709
5838
  await tryFlush();
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "restricted"
5
5
  },
6
- "version": "0.1.6",
6
+ "version": "0.1.7",
7
7
  "description": "IMDL — Intelligent Mediation & Detection Layer. AI agent security CLI.",
8
8
  "files": [
9
9
  "dist"