@posthog/agent 2.3.363 → 2.3.370

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.
@@ -805,15 +805,15 @@ var require_src2 = __commonJS({
805
805
  var fs_1 = require("fs");
806
806
  var debug_1 = __importDefault(require_src());
807
807
  var log = debug_1.default("@kwsites/file-exists");
808
- function check(path15, isFile, isDirectory) {
808
+ function check(path15, isFile2, isDirectory) {
809
809
  log(`checking %s`, path15);
810
810
  try {
811
- const stat = fs_1.statSync(path15);
812
- if (stat.isFile() && isFile) {
811
+ const stat2 = fs_1.statSync(path15);
812
+ if (stat2.isFile() && isFile2) {
813
813
  log(`[OK] path represents a file`);
814
814
  return true;
815
815
  }
816
- if (stat.isDirectory() && isDirectory) {
816
+ if (stat2.isDirectory() && isDirectory) {
817
817
  log(`[OK] path represents a directory`);
818
818
  return true;
819
819
  }
@@ -943,10 +943,10 @@ var require_tree_sitter = __commonJS({
943
943
  };
944
944
  readAsync = (filename, binary2 = true) => {
945
945
  filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename);
946
- return new Promise((resolve4, reject) => {
946
+ return new Promise((resolve6, reject) => {
947
947
  fs.readFile(filename, binary2 ? void 0 : "utf8", (err2, data) => {
948
948
  if (err2) reject(err2);
949
- else resolve4(binary2 ? data.buffer : data);
949
+ else resolve6(binary2 ? data.buffer : data);
950
950
  });
951
951
  });
952
952
  };
@@ -987,13 +987,13 @@ var require_tree_sitter = __commonJS({
987
987
  }
988
988
  readAsync = (url) => {
989
989
  if (isFileURI(url)) {
990
- return new Promise((reject, resolve4) => {
990
+ return new Promise((reject, resolve6) => {
991
991
  var xhr = new XMLHttpRequest();
992
992
  xhr.open("GET", url, true);
993
993
  xhr.responseType = "arraybuffer";
994
994
  xhr.onload = () => {
995
995
  if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
996
- resolve4(xhr.response);
996
+ resolve6(xhr.response);
997
997
  }
998
998
  reject(xhr.status);
999
999
  };
@@ -1953,8 +1953,8 @@ var require_tree_sitter = __commonJS({
1953
1953
  }
1954
1954
  var libFile = locateFile(libName2);
1955
1955
  if (flags2.loadAsync) {
1956
- return new Promise(function(resolve4, reject) {
1957
- asyncLoad(libFile, resolve4, reject);
1956
+ return new Promise(function(resolve6, reject) {
1957
+ asyncLoad(libFile, resolve6, reject);
1958
1958
  });
1959
1959
  }
1960
1960
  if (!readBinary) {
@@ -8498,10 +8498,10 @@ async function getIndexLockPath(repoPath) {
8498
8498
  async function getLockInfo(repoPath) {
8499
8499
  const lockPath = await getIndexLockPath(repoPath);
8500
8500
  try {
8501
- const stat = await import_promises.default.stat(lockPath);
8501
+ const stat2 = await import_promises.default.stat(lockPath);
8502
8502
  return {
8503
8503
  path: lockPath,
8504
- ageMs: Date.now() - stat.mtimeMs
8504
+ ageMs: Date.now() - stat2.mtimeMs
8505
8505
  };
8506
8506
  } catch {
8507
8507
  return null;
@@ -8536,10 +8536,10 @@ var AsyncReaderWriterLock = class {
8536
8536
  this.readers++;
8537
8537
  return;
8538
8538
  }
8539
- return new Promise((resolve4) => {
8539
+ return new Promise((resolve6) => {
8540
8540
  this.readQueue.push(() => {
8541
8541
  this.readers++;
8542
- resolve4();
8542
+ resolve6();
8543
8543
  });
8544
8544
  });
8545
8545
  }
@@ -8553,11 +8553,11 @@ var AsyncReaderWriterLock = class {
8553
8553
  return;
8554
8554
  }
8555
8555
  this.writerWaiting = true;
8556
- return new Promise((resolve4) => {
8556
+ return new Promise((resolve6) => {
8557
8557
  this.writeQueue.push(() => {
8558
8558
  this.writerWaiting = this.writeQueue.length > 0;
8559
8559
  this.writer = true;
8560
- resolve4();
8560
+ resolve6();
8561
8561
  });
8562
8562
  });
8563
8563
  }
@@ -8729,7 +8729,7 @@ var import_zod3 = require("zod");
8729
8729
  // package.json
8730
8730
  var package_default = {
8731
8731
  name: "@posthog/agent",
8732
- version: "2.3.363",
8732
+ version: "2.3.370",
8733
8733
  repository: "https://github.com/PostHog/code",
8734
8734
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
8735
8735
  exports: {
@@ -8984,17 +8984,17 @@ var Pushable = class {
8984
8984
  resolvers = [];
8985
8985
  done = false;
8986
8986
  push(item) {
8987
- const resolve4 = this.resolvers.shift();
8988
- if (resolve4) {
8989
- resolve4({ value: item, done: false });
8987
+ const resolve6 = this.resolvers.shift();
8988
+ if (resolve6) {
8989
+ resolve6({ value: item, done: false });
8990
8990
  } else {
8991
8991
  this.queue.push(item);
8992
8992
  }
8993
8993
  }
8994
8994
  end() {
8995
8995
  this.done = true;
8996
- for (const resolve4 of this.resolvers) {
8997
- resolve4({ value: void 0, done: true });
8996
+ for (const resolve6 of this.resolvers) {
8997
+ resolve6({ value: void 0, done: true });
8998
8998
  }
8999
8999
  this.resolvers = [];
9000
9000
  }
@@ -9011,8 +9011,8 @@ var Pushable = class {
9011
9011
  done: true
9012
9012
  });
9013
9013
  }
9014
- return new Promise((resolve4) => {
9015
- this.resolvers.push(resolve4);
9014
+ return new Promise((resolve6) => {
9015
+ this.resolvers.push(resolve6);
9016
9016
  });
9017
9017
  }
9018
9018
  };
@@ -9126,20 +9126,20 @@ function nodeReadableToWebReadable(nodeStream) {
9126
9126
  function nodeWritableToWebWritable(nodeStream) {
9127
9127
  return new import_web.WritableStream({
9128
9128
  write(chunk) {
9129
- return new Promise((resolve4, reject) => {
9129
+ return new Promise((resolve6, reject) => {
9130
9130
  const ok = nodeStream.write(Buffer.from(chunk), (err2) => {
9131
9131
  if (err2) reject(err2);
9132
9132
  });
9133
9133
  if (ok) {
9134
- resolve4();
9134
+ resolve6();
9135
9135
  } else {
9136
- nodeStream.once("drain", resolve4);
9136
+ nodeStream.once("drain", resolve6);
9137
9137
  }
9138
9138
  });
9139
9139
  },
9140
9140
  close() {
9141
- return new Promise((resolve4) => {
9142
- nodeStream.end(resolve4);
9141
+ return new Promise((resolve6) => {
9142
+ nodeStream.end(resolve6);
9143
9143
  });
9144
9144
  },
9145
9145
  abort(reason) {
@@ -9165,10 +9165,12 @@ var path4 = __toESM(require("path"), 1);
9165
9165
  // ../enricher/dist/index.js
9166
9166
  var import_fs = require("fs");
9167
9167
  var path3 = __toESM(require("path"), 1);
9168
+ var import_fs2 = require("fs");
9169
+ var path22 = __toESM(require("path"), 1);
9168
9170
  var import_url = require("url");
9169
9171
  var import_web_tree_sitter = __toESM(require_tree_sitter(), 1);
9170
9172
  var fs4 = __toESM(require("fs/promises"), 1);
9171
- var path22 = __toESM(require("path"), 1);
9173
+ var path32 = __toESM(require("path"), 1);
9172
9174
  var import_meta = {};
9173
9175
  function getCapture(captures, name2) {
9174
9176
  const found = captures.find((c) => c.name === name2);
@@ -9284,6 +9286,22 @@ function walkNodes(root, type, callback) {
9284
9286
  };
9285
9287
  visit(root);
9286
9288
  }
9289
+ var JSX_NODE_TYPES = /* @__PURE__ */ new Set([
9290
+ "jsx_element",
9291
+ "jsx_fragment",
9292
+ "jsx_self_closing_element",
9293
+ "jsx_opening_element",
9294
+ "jsx_closing_element",
9295
+ "jsx_attribute"
9296
+ ]);
9297
+ function isInsideJsx(node) {
9298
+ let cur = node.parent;
9299
+ while (cur) {
9300
+ if (JSX_NODE_TYPES.has(cur.type)) return true;
9301
+ cur = cur.parent;
9302
+ }
9303
+ return false;
9304
+ }
9287
9305
  var JS_CAPTURE_METHODS = /* @__PURE__ */ new Set(["capture"]);
9288
9306
  var JS_FLAG_METHODS = /* @__PURE__ */ new Set([
9289
9307
  "getFeatureFlag",
@@ -9469,6 +9487,33 @@ var JS_QUERIES = {
9469
9487
  object: (_) @client
9470
9488
  property: (property_identifier) @method)
9471
9489
  arguments: (arguments . (_) @first_arg)) @call
9490
+ `,
9491
+ imports: `
9492
+ (import_statement
9493
+ (import_clause
9494
+ (identifier) @default_name)
9495
+ source: (string (string_fragment) @source)) @stmt
9496
+
9497
+ (import_statement
9498
+ (import_clause
9499
+ (named_imports
9500
+ (import_specifier
9501
+ name: (identifier) @imported_name) @spec))
9502
+ source: (string (string_fragment) @source)) @stmt
9503
+
9504
+ (import_statement
9505
+ (import_clause
9506
+ (named_imports
9507
+ (import_specifier
9508
+ name: (identifier) @imported_name
9509
+ alias: (identifier) @local_name) @spec))
9510
+ source: (string (string_fragment) @source)) @stmt
9511
+
9512
+ (import_statement
9513
+ (import_clause
9514
+ (namespace_import
9515
+ (identifier) @namespace_name))
9516
+ source: (string (string_fragment) @source)) @stmt
9472
9517
  `
9473
9518
  };
9474
9519
  var PY_QUERIES = {
@@ -9545,6 +9590,31 @@ var PY_QUERIES = {
9545
9590
  object: (_) @client
9546
9591
  attribute: (identifier) @method)
9547
9592
  arguments: (argument_list . (_) @first_arg)) @call
9593
+ `,
9594
+ imports: `
9595
+ (import_from_statement
9596
+ module_name: (dotted_name) @source
9597
+ name: (dotted_name) @imported_name) @stmt
9598
+
9599
+ (import_from_statement
9600
+ module_name: (dotted_name) @source
9601
+ name: (aliased_import
9602
+ name: (dotted_name) @imported_name
9603
+ alias: (identifier) @local_name)) @stmt
9604
+
9605
+ (import_from_statement
9606
+ module_name: (relative_import
9607
+ (import_prefix) @relative_prefix
9608
+ (dotted_name)? @relative_name)
9609
+ name: (dotted_name) @imported_name) @stmt
9610
+
9611
+ (import_from_statement
9612
+ module_name: (relative_import
9613
+ (import_prefix) @relative_prefix
9614
+ (dotted_name)? @relative_name)
9615
+ name: (aliased_import
9616
+ name: (dotted_name) @imported_name
9617
+ alias: (identifier) @local_name)) @stmt
9548
9618
  `
9549
9619
  };
9550
9620
  var GO_QUERIES = {
@@ -9936,7 +10006,7 @@ function buildConstantMap(pm, lang, tree) {
9936
10006
  }
9937
10007
  var POSTHOG_CLASS_NAMES2 = /* @__PURE__ */ new Set(["PostHog", "Posthog"]);
9938
10008
  var GO_CONSTRUCTOR_NAMES2 = /* @__PURE__ */ new Set(["New", "NewWithConfig"]);
9939
- async function findPostHogCalls(pm, source, languageId) {
10009
+ async function findPostHogCalls(pm, source, languageId, context) {
9940
10010
  const ready = await pm.ensureReady(languageId);
9941
10011
  if (!ready) {
9942
10012
  return [];
@@ -9965,6 +10035,7 @@ async function findPostHogCalls(pm, source, languageId) {
9965
10035
  const clientNode = getCapture(match.captures, "client");
9966
10036
  const methodNode = getCapture(match.captures, "method");
9967
10037
  const keyNode = getCapture(match.captures, "key");
10038
+ const callNode = getCapture(match.captures, "call");
9968
10039
  if (!clientNode || !methodNode || !keyNode) {
9969
10040
  continue;
9970
10041
  }
@@ -9990,7 +10061,8 @@ async function findPostHogCalls(pm, source, languageId) {
9990
10061
  key: cleanStringValue(keyNode.text),
9991
10062
  line: keyNode.startPosition.row,
9992
10063
  keyStartCol: keyNode.startPosition.column,
9993
- keyEndCol: keyNode.endPosition.column
10064
+ keyEndCol: keyNode.endPosition.column,
10065
+ inJsx: callNode ? isInsideJsx(callNode) : void 0
9994
10066
  });
9995
10067
  }
9996
10068
  }
@@ -10045,6 +10117,7 @@ async function findPostHogCalls(pm, source, languageId) {
10045
10117
  const methodNode = getCapture(match.captures, "method");
10046
10118
  const propNameNode = getCapture(match.captures, "prop_name");
10047
10119
  const keyNode = getCapture(match.captures, "key");
10120
+ const callNode = getCapture(match.captures, "call");
10048
10121
  if (!clientNode || !methodNode || !propNameNode || !keyNode) {
10049
10122
  continue;
10050
10123
  }
@@ -10067,7 +10140,8 @@ async function findPostHogCalls(pm, source, languageId) {
10067
10140
  key: cleanStringValue(keyNode.text),
10068
10141
  line: keyNode.startPosition.row,
10069
10142
  keyStartCol: keyNode.startPosition.column,
10070
- keyEndCol: keyNode.endPosition.column
10143
+ keyEndCol: keyNode.endPosition.column,
10144
+ inJsx: callNode ? isInsideJsx(callNode) : void 0
10071
10145
  });
10072
10146
  }
10073
10147
  }
@@ -10164,6 +10238,7 @@ async function findPostHogCalls(pm, source, languageId) {
10164
10238
  for (const match of matches) {
10165
10239
  const funcNode = getCapture(match.captures, "func_name");
10166
10240
  const keyNode = getCapture(match.captures, "key");
10241
+ const callNode = getCapture(match.captures, "call");
10167
10242
  if (!funcNode || !keyNode) {
10168
10243
  continue;
10169
10244
  }
@@ -10174,7 +10249,8 @@ async function findPostHogCalls(pm, source, languageId) {
10174
10249
  key: cleanStringValue(keyNode.text),
10175
10250
  line: keyNode.startPosition.row,
10176
10251
  keyStartCol: keyNode.startPosition.column,
10177
- keyEndCol: keyNode.endPosition.column
10252
+ keyEndCol: keyNode.endPosition.column,
10253
+ inJsx: callNode ? isInsideJsx(callNode) : void 0
10178
10254
  });
10179
10255
  }
10180
10256
  }
@@ -10188,6 +10264,7 @@ async function findPostHogCalls(pm, source, languageId) {
10188
10264
  for (const match of matches) {
10189
10265
  const funcNode = getCapture(match.captures, "func_name");
10190
10266
  const keyNode = getCapture(match.captures, "key");
10267
+ const callNode = getCapture(match.captures, "call");
10191
10268
  if (!funcNode || !keyNode) {
10192
10269
  continue;
10193
10270
  }
@@ -10197,7 +10274,8 @@ async function findPostHogCalls(pm, source, languageId) {
10197
10274
  key: cleanStringValue(keyNode.text),
10198
10275
  line: keyNode.startPosition.row,
10199
10276
  keyStartCol: keyNode.startPosition.column,
10200
- keyEndCol: keyNode.endPosition.column
10277
+ keyEndCol: keyNode.endPosition.column,
10278
+ inJsx: callNode ? isInsideJsx(callNode) : void 0
10201
10279
  });
10202
10280
  }
10203
10281
  }
@@ -10212,6 +10290,7 @@ async function findPostHogCalls(pm, source, languageId) {
10212
10290
  const clientNode = getCapture(match.captures, "client");
10213
10291
  const methodNode = getCapture(match.captures, "method");
10214
10292
  const argNode = getCapture(match.captures, "arg_id");
10293
+ const callNode = getCapture(match.captures, "call");
10215
10294
  if (!clientNode || !methodNode || !argNode) {
10216
10295
  continue;
10217
10296
  }
@@ -10241,7 +10320,8 @@ async function findPostHogCalls(pm, source, languageId) {
10241
10320
  key: resolved,
10242
10321
  line,
10243
10322
  keyStartCol: argNode.startPosition.column,
10244
- keyEndCol: argNode.endPosition.column
10323
+ keyEndCol: argNode.endPosition.column,
10324
+ inJsx: callNode ? isInsideJsx(callNode) : void 0
10245
10325
  });
10246
10326
  }
10247
10327
  }
@@ -10254,6 +10334,7 @@ async function findPostHogCalls(pm, source, languageId) {
10254
10334
  const clientNode = getCapture(match.captures, "client");
10255
10335
  const methodNode = getCapture(match.captures, "method");
10256
10336
  const firstArgNode = getCapture(match.captures, "first_arg");
10337
+ const callNode = getCapture(match.captures, "call");
10257
10338
  if (!clientNode || !methodNode || !firstArgNode) {
10258
10339
  continue;
10259
10340
  }
@@ -10278,13 +10359,167 @@ async function findPostHogCalls(pm, source, languageId) {
10278
10359
  line,
10279
10360
  keyStartCol: firstArgNode.startPosition.column,
10280
10361
  keyEndCol: firstArgNode.endPosition.column,
10281
- dynamic: true
10362
+ dynamic: true,
10363
+ inJsx: callNode ? isInsideJsx(callNode) : void 0
10282
10364
  });
10283
10365
  matchedLines.add(line);
10284
10366
  }
10285
10367
  }
10368
+ if (context?.wrappersByLocalName?.size) {
10369
+ synthesizeBareWrapperCalls(
10370
+ pm,
10371
+ lang,
10372
+ tree,
10373
+ languageId,
10374
+ context.wrappersByLocalName,
10375
+ constantMap,
10376
+ calls,
10377
+ matchedLines
10378
+ );
10379
+ }
10380
+ if (context?.namespaceWrappers?.size) {
10381
+ synthesizeNamespaceWrapperCalls(
10382
+ pm,
10383
+ lang,
10384
+ tree,
10385
+ languageId,
10386
+ context.namespaceWrappers,
10387
+ constantMap,
10388
+ calls,
10389
+ matchedLines
10390
+ );
10391
+ }
10286
10392
  return calls;
10287
10393
  }
10394
+ var WRAPPER_BARE_CALL_QUERIES = {
10395
+ javascript: `(call_expression function: (identifier) @func_name arguments: (arguments) @args) @call`,
10396
+ javascriptreact: `(call_expression function: (identifier) @func_name arguments: (arguments) @args) @call`,
10397
+ typescript: `(call_expression function: (identifier) @func_name arguments: (arguments) @args) @call`,
10398
+ typescriptreact: `(call_expression function: (identifier) @func_name arguments: (arguments) @args) @call`,
10399
+ python: `(call function: (identifier) @func_name arguments: (argument_list) @args) @call`
10400
+ };
10401
+ var WRAPPER_NAMESPACE_CALL_QUERIES = {
10402
+ javascript: `(call_expression function: (member_expression object: (identifier) @ns property: (property_identifier) @method) arguments: (arguments) @args) @call`,
10403
+ javascriptreact: `(call_expression function: (member_expression object: (identifier) @ns property: (property_identifier) @method) arguments: (arguments) @args) @call`,
10404
+ typescript: `(call_expression function: (member_expression object: (identifier) @ns property: (property_identifier) @method) arguments: (arguments) @args) @call`,
10405
+ typescriptreact: `(call_expression function: (member_expression object: (identifier) @ns property: (property_identifier) @method) arguments: (arguments) @args) @call`,
10406
+ python: `(call function: (attribute object: (identifier) @ns attribute: (identifier) @method) arguments: (argument_list) @args) @call`
10407
+ };
10408
+ function synthesizeBareWrapperCalls(pm, lang, tree, languageId, wrappers, constantMap, calls, matchedLines) {
10409
+ const queryStr = WRAPPER_BARE_CALL_QUERIES[languageId];
10410
+ if (!queryStr) return;
10411
+ const query2 = pm.getQuery(lang, queryStr);
10412
+ if (!query2) return;
10413
+ for (const match of query2.matches(tree.rootNode)) {
10414
+ const funcNode = getCapture(match.captures, "func_name");
10415
+ const argsNode = getCapture(match.captures, "args");
10416
+ const callNode = getCapture(match.captures, "call");
10417
+ if (!funcNode || !argsNode) continue;
10418
+ const wrapper = wrappers.get(funcNode.text);
10419
+ if (!wrapper) continue;
10420
+ pushWrapperCall(
10421
+ wrapper,
10422
+ funcNode,
10423
+ argsNode,
10424
+ callNode,
10425
+ constantMap,
10426
+ calls,
10427
+ matchedLines
10428
+ );
10429
+ }
10430
+ }
10431
+ function synthesizeNamespaceWrapperCalls(pm, lang, tree, languageId, namespaceWrappers, constantMap, calls, matchedLines) {
10432
+ const queryStr = WRAPPER_NAMESPACE_CALL_QUERIES[languageId];
10433
+ if (!queryStr) return;
10434
+ const query2 = pm.getQuery(lang, queryStr);
10435
+ if (!query2) return;
10436
+ for (const match of query2.matches(tree.rootNode)) {
10437
+ const nsNode = getCapture(match.captures, "ns");
10438
+ const methodNode = getCapture(match.captures, "method");
10439
+ const argsNode = getCapture(match.captures, "args");
10440
+ const callNode = getCapture(match.captures, "call");
10441
+ if (!nsNode || !methodNode || !argsNode) continue;
10442
+ const nsWrappers = namespaceWrappers.get(nsNode.text);
10443
+ if (!nsWrappers) continue;
10444
+ const wrapper = nsWrappers.get(methodNode.text);
10445
+ if (!wrapper) continue;
10446
+ pushWrapperCall(
10447
+ wrapper,
10448
+ methodNode,
10449
+ argsNode,
10450
+ callNode,
10451
+ constantMap,
10452
+ calls,
10453
+ matchedLines
10454
+ );
10455
+ }
10456
+ }
10457
+ function pushWrapperCall(wrapper, callerNode, argsNode, callNode, constantMap, calls, matchedLines) {
10458
+ let line = callerNode.startPosition.row;
10459
+ let keyStartCol = callerNode.startPosition.column;
10460
+ let keyEndCol = callerNode.endPosition.column;
10461
+ let key = "";
10462
+ let dynamic = false;
10463
+ if (wrapper.classification.kind === "fixed-key") {
10464
+ key = wrapper.classification.key;
10465
+ } else {
10466
+ const positional = argsNode.namedChildren.filter(
10467
+ (c) => c.type !== "comment" && c.type !== "keyword_argument"
10468
+ );
10469
+ const arg = positional[wrapper.classification.paramIndex];
10470
+ if (!arg) return;
10471
+ line = arg.startPosition.row;
10472
+ keyStartCol = arg.startPosition.column;
10473
+ keyEndCol = arg.endPosition.column;
10474
+ if (arg.type === "string") {
10475
+ const fragment = arg.namedChildren.find(
10476
+ (c) => c.type === "string_fragment" || c.type === "string_content"
10477
+ );
10478
+ if (fragment) {
10479
+ key = fragment.text;
10480
+ } else {
10481
+ dynamic = true;
10482
+ }
10483
+ } else if (arg.type === "template_string") {
10484
+ const fragments = arg.namedChildren.filter(
10485
+ (c) => c.type === "string_fragment"
10486
+ );
10487
+ const hasInterp = arg.namedChildren.some(
10488
+ (c) => c.type === "template_substitution"
10489
+ );
10490
+ if (!hasInterp && fragments.length === 1) {
10491
+ key = fragments[0].text;
10492
+ } else {
10493
+ dynamic = true;
10494
+ }
10495
+ } else if (arg.type === "interpreted_string_literal") {
10496
+ key = arg.text.slice(1, -1);
10497
+ } else if (arg.type === "identifier") {
10498
+ const resolved = constantMap.get(arg.text);
10499
+ if (resolved) {
10500
+ key = resolved;
10501
+ } else {
10502
+ dynamic = true;
10503
+ }
10504
+ } else {
10505
+ dynamic = true;
10506
+ }
10507
+ }
10508
+ if (matchedLines.has(line) && dynamic) {
10509
+ return;
10510
+ }
10511
+ calls.push({
10512
+ method: wrapper.posthogMethod,
10513
+ key,
10514
+ line,
10515
+ keyStartCol,
10516
+ keyEndCol,
10517
+ dynamic: dynamic ? true : void 0,
10518
+ viaWrapper: wrapper.name,
10519
+ inJsx: callNode ? isInsideJsx(callNode) : void 0
10520
+ });
10521
+ matchedLines.add(line);
10522
+ }
10288
10523
  async function findInitCalls(pm, source, languageId) {
10289
10524
  const ready = await pm.ensureReady(languageId);
10290
10525
  if (!ready) {
@@ -10697,6 +10932,7 @@ async function findFunctions(pm, source, languageId) {
10697
10932
  }
10698
10933
  const params = singleParamNode ? [singleParamNode.text] : paramsNode ? extractParams(paramsNode.text) : [];
10699
10934
  const bodyLine = bodyNode.startPosition.row;
10935
+ const bodyEndLine = bodyNode.endPosition.row;
10700
10936
  const nextLineIdx = bodyLine + 1;
10701
10937
  const lines = text2.split("\n");
10702
10938
  const nextLine = nextLineIdx < lines.length ? lines[nextLineIdx] : "";
@@ -10706,6 +10942,7 @@ async function findFunctions(pm, source, languageId) {
10706
10942
  params,
10707
10943
  isComponent: /^[A-Z]/.test(name2),
10708
10944
  bodyLine,
10945
+ bodyEndLine,
10709
10946
  bodyIndent
10710
10947
  });
10711
10948
  }
@@ -10763,6 +11000,157 @@ async function findFlagAssignments(pm, source, languageId) {
10763
11000
  }
10764
11001
  return assignments;
10765
11002
  }
11003
+ var JS_EXTENSION_PROBES = [
11004
+ ".ts",
11005
+ ".tsx",
11006
+ ".mts",
11007
+ ".cts",
11008
+ ".js",
11009
+ ".jsx",
11010
+ ".mjs",
11011
+ ".cjs"
11012
+ ];
11013
+ var PY_EXTENSION_PROBES = [".py"];
11014
+ function isRelativeSpecifier(spec) {
11015
+ return spec.startsWith("./") || spec.startsWith("../") || spec === ".";
11016
+ }
11017
+ function resolveJsPath(callerAbsPath, specifier) {
11018
+ if (!isRelativeSpecifier(specifier)) return null;
11019
+ const dir = path3.dirname(callerAbsPath);
11020
+ const base = path3.resolve(dir, specifier);
11021
+ if (JS_EXTENSION_PROBES.includes(path3.extname(specifier))) {
11022
+ return isFile(base) ? base : null;
11023
+ }
11024
+ if (isFile(base)) return base;
11025
+ for (const ext of JS_EXTENSION_PROBES) {
11026
+ const candidate = base + ext;
11027
+ if (isFile(candidate)) return candidate;
11028
+ }
11029
+ for (const ext of JS_EXTENSION_PROBES) {
11030
+ const candidate = path3.join(base, `index${ext}`);
11031
+ if (isFile(candidate)) return candidate;
11032
+ }
11033
+ return null;
11034
+ }
11035
+ function isFile(p) {
11036
+ try {
11037
+ return (0, import_fs.statSync)(p).isFile();
11038
+ } catch {
11039
+ return false;
11040
+ }
11041
+ }
11042
+ function resolvePythonModule(callerAbsPath, relativePrefix, moduleName) {
11043
+ if (!relativePrefix) return null;
11044
+ const dots = relativePrefix.length;
11045
+ const levelsUp = dots - 1;
11046
+ let baseDir = path3.dirname(callerAbsPath);
11047
+ for (let i2 = 0; i2 < levelsUp; i2++) {
11048
+ baseDir = path3.dirname(baseDir);
11049
+ }
11050
+ if (!moduleName) {
11051
+ const init2 = path3.join(baseDir, "__init__.py");
11052
+ return isFile(init2) ? init2 : null;
11053
+ }
11054
+ const parts2 = moduleName.split(".");
11055
+ const joined = path3.join(baseDir, ...parts2);
11056
+ for (const ext of PY_EXTENSION_PROBES) {
11057
+ const candidate = joined + ext;
11058
+ if (isFile(candidate)) return candidate;
11059
+ }
11060
+ const pkgInit = path3.join(joined, "__init__.py");
11061
+ if (isFile(pkgInit)) return pkgInit;
11062
+ return null;
11063
+ }
11064
+ async function findImports(pm, source, languageId, callerAbsPath) {
11065
+ const ready = await pm.ensureReady(languageId);
11066
+ if (!ready) return [];
11067
+ const { lang, family } = ready;
11068
+ if (!family.queries.imports) return [];
11069
+ const tree = pm.parse(source, lang);
11070
+ if (!tree) return [];
11071
+ const query2 = pm.getQuery(lang, family.queries.imports);
11072
+ if (!query2) return [];
11073
+ const edges = [];
11074
+ const isPython = languageId === "python";
11075
+ for (const match of query2.matches(tree.rootNode)) {
11076
+ if (isPython) {
11077
+ pushPythonEdge(match.captures, callerAbsPath, edges);
11078
+ } else {
11079
+ pushJsEdge(match.captures, callerAbsPath, edges);
11080
+ }
11081
+ }
11082
+ return dedupe(edges);
11083
+ }
11084
+ function pushJsEdge(captures, callerAbsPath, out2) {
11085
+ const sourceNode = getCapture(captures, "source");
11086
+ if (!sourceNode) return;
11087
+ const specifier = sourceNode.text;
11088
+ if (!isRelativeSpecifier(specifier)) return;
11089
+ const resolvedAbsPath = resolveJsPath(callerAbsPath, specifier);
11090
+ const defaultNode = getCapture(captures, "default_name");
11091
+ if (defaultNode) {
11092
+ out2.push({
11093
+ localName: defaultNode.text,
11094
+ importedName: "default",
11095
+ isDefault: true,
11096
+ resolvedAbsPath
11097
+ });
11098
+ return;
11099
+ }
11100
+ const namespaceNode = getCapture(captures, "namespace_name");
11101
+ if (namespaceNode) {
11102
+ out2.push({
11103
+ localName: namespaceNode.text,
11104
+ importedName: "*",
11105
+ isNamespace: true,
11106
+ resolvedAbsPath
11107
+ });
11108
+ return;
11109
+ }
11110
+ const importedNode = getCapture(captures, "imported_name");
11111
+ if (importedNode) {
11112
+ const localNode = getCapture(captures, "local_name");
11113
+ out2.push({
11114
+ localName: (localNode ?? importedNode).text,
11115
+ importedName: importedNode.text,
11116
+ resolvedAbsPath
11117
+ });
11118
+ }
11119
+ }
11120
+ function pushPythonEdge(captures, callerAbsPath, out2) {
11121
+ const importedNode = getCapture(captures, "imported_name");
11122
+ if (!importedNode) return;
11123
+ const relativePrefix = getCapture(captures, "relative_prefix");
11124
+ const relativeName = getCapture(captures, "relative_name");
11125
+ const sourceNode = getCapture(captures, "source");
11126
+ let resolvedAbsPath = null;
11127
+ if (relativePrefix) {
11128
+ resolvedAbsPath = resolvePythonModule(
11129
+ callerAbsPath,
11130
+ relativePrefix.text,
11131
+ relativeName ? relativeName.text : null
11132
+ );
11133
+ } else if (sourceNode) {
11134
+ resolvedAbsPath = resolvePythonModule(callerAbsPath, ".", sourceNode.text);
11135
+ }
11136
+ const localNode = getCapture(captures, "local_name");
11137
+ out2.push({
11138
+ localName: (localNode ?? importedNode).text,
11139
+ importedName: importedNode.text,
11140
+ resolvedAbsPath
11141
+ });
11142
+ }
11143
+ function dedupe(edges) {
11144
+ const seen = /* @__PURE__ */ new Set();
11145
+ const out2 = [];
11146
+ for (const e of edges) {
11147
+ const key = `${e.localName}|${e.importedName}|${e.resolvedAbsPath ?? ""}|${e.isDefault ? "d" : ""}|${e.isNamespace ? "n" : ""}`;
11148
+ if (seen.has(key)) continue;
11149
+ seen.add(key);
11150
+ out2.push(e);
11151
+ }
11152
+ return out2;
11153
+ }
10766
11154
  var noop = {
10767
11155
  warn() {
10768
11156
  }
@@ -10778,17 +11166,18 @@ var DEFAULT_CONFIG = {
10778
11166
  };
10779
11167
  function resolveGrammarsDir() {
10780
11168
  const thisFile = (0, import_url.fileURLToPath)(import_meta.url);
10781
- const dir = path3.dirname(thisFile);
11169
+ const dir = path22.dirname(thisFile);
10782
11170
  const candidates = [
10783
- path3.join(dir, "..", "grammars"),
10784
- path3.join(dir, "grammars"),
10785
- path3.join(dir, "..", "..", "grammars")
11171
+ path22.join(dir, "..", "grammars"),
11172
+ path22.join(dir, "grammars"),
11173
+ path22.join(dir, "..", "..", "grammars")
10786
11174
  ];
10787
- return candidates.find((p) => (0, import_fs.existsSync)(p)) ?? candidates[0];
11175
+ return candidates.find((p) => (0, import_fs2.existsSync)(p)) ?? candidates[0];
10788
11176
  }
10789
11177
  var ParserManager = class {
10790
11178
  parser = null;
10791
11179
  languages = /* @__PURE__ */ new Map();
11180
+ languageKeys = /* @__PURE__ */ new WeakMap();
10792
11181
  queryCache = /* @__PURE__ */ new Map();
10793
11182
  maxCacheSize = 256;
10794
11183
  initPromise = null;
@@ -10807,7 +11196,7 @@ var ParserManager = class {
10807
11196
  async doInit() {
10808
11197
  try {
10809
11198
  await import_web_tree_sitter.default.init({
10810
- locateFile: (scriptName) => path3.join(this.wasmDir, scriptName)
11199
+ locateFile: (scriptName) => path22.join(this.wasmDir, scriptName)
10811
11200
  });
10812
11201
  this.parser = new import_web_tree_sitter.default();
10813
11202
  } catch (err2) {
@@ -10834,9 +11223,10 @@ var ParserManager = class {
10834
11223
  let lang = this.languages.get(family.wasm);
10835
11224
  if (!lang) {
10836
11225
  try {
10837
- const wasmPath = path3.join(this.wasmDir, family.wasm);
11226
+ const wasmPath = path22.join(this.wasmDir, family.wasm);
10838
11227
  lang = await import_web_tree_sitter.default.Language.load(wasmPath);
10839
11228
  this.languages.set(family.wasm, lang);
11229
+ this.languageKeys.set(lang, family.wasm);
10840
11230
  } catch (err2) {
10841
11231
  warn(`Failed to load grammar ${family.wasm}`, err2);
10842
11232
  return null;
@@ -10855,7 +11245,8 @@ var ParserManager = class {
10855
11245
  if (!queryStr.trim()) {
10856
11246
  return null;
10857
11247
  }
10858
- const cacheKey = `${lang.toString()}:${queryStr}`;
11248
+ const langKey = this.languageKeys.get(lang) ?? lang.toString();
11249
+ const cacheKey = `${langKey}:${queryStr}`;
10859
11250
  let query2 = this.queryCache.get(cacheKey);
10860
11251
  if (query2) {
10861
11252
  this.queryCache.delete(cacheKey);
@@ -10882,6 +11273,7 @@ var ParserManager = class {
10882
11273
  this.parser = null;
10883
11274
  this.initPromise = null;
10884
11275
  this.languages.clear();
11276
+ this.languageKeys = /* @__PURE__ */ new WeakMap();
10885
11277
  this.queryCache.clear();
10886
11278
  }
10887
11279
  };
@@ -11696,6 +12088,260 @@ function isTruthinessCheckForVar(conditionNode, varName) {
11696
12088
  }
11697
12089
  return false;
11698
12090
  }
12091
+ var CONTROL_FLOW_KEYWORDS = /* @__PURE__ */ new Set([
12092
+ "if",
12093
+ "for",
12094
+ "while",
12095
+ "switch",
12096
+ "catch",
12097
+ "else"
12098
+ ]);
12099
+ function getKeyArgLocator(method, family, languageId) {
12100
+ if (languageId === "python") {
12101
+ if (family.captureMethods.has(method)) {
12102
+ return { positionalIndex: 1, kwargName: "event" };
12103
+ }
12104
+ if (family.flagMethods.has(method)) {
12105
+ return { positionalIndex: 0, kwargName: "key" };
12106
+ }
12107
+ return null;
12108
+ }
12109
+ if (family.allMethods.has(method)) {
12110
+ return { positionalIndex: 0 };
12111
+ }
12112
+ return null;
12113
+ }
12114
+ function extractRawParams(paramsNode, singleParamNode, languageId) {
12115
+ if (singleParamNode) {
12116
+ return [singleParamNode.text];
12117
+ }
12118
+ if (!paramsNode) {
12119
+ return [];
12120
+ }
12121
+ const names = [];
12122
+ for (const child of paramsNode.namedChildren) {
12123
+ const n = extractParamName(child, languageId);
12124
+ if (n) {
12125
+ names.push(n);
12126
+ } else {
12127
+ names.push("");
12128
+ }
12129
+ }
12130
+ return names;
12131
+ }
12132
+ function extractParamName(node, languageId) {
12133
+ switch (node.type) {
12134
+ case "identifier":
12135
+ return node.text;
12136
+ case "required_parameter":
12137
+ case "optional_parameter": {
12138
+ const pat = node.childForFieldName("pattern");
12139
+ if (pat) return extractParamName(pat, languageId);
12140
+ const name2 = node.childForFieldName("name");
12141
+ if (name2) return extractParamName(name2, languageId);
12142
+ const id = node.namedChildren.find((c) => c.type === "identifier");
12143
+ return id?.text ?? null;
12144
+ }
12145
+ case "assignment_pattern": {
12146
+ const left = node.childForFieldName("left");
12147
+ return left ? extractParamName(left, languageId) : null;
12148
+ }
12149
+ case "typed_parameter":
12150
+ case "default_parameter":
12151
+ case "typed_default_parameter": {
12152
+ const name2 = node.childForFieldName("name");
12153
+ if (name2) return extractParamName(name2, languageId);
12154
+ const id = node.namedChildren.find((c) => c.type === "identifier");
12155
+ return id?.text ?? null;
12156
+ }
12157
+ case "parameter": {
12158
+ const id = node.namedChildren.find(
12159
+ (c) => c.type === "identifier" || c.type === "field_identifier"
12160
+ );
12161
+ return id?.text ?? null;
12162
+ }
12163
+ default: {
12164
+ const id = node.namedChildren.find((c) => c.type === "identifier");
12165
+ return id?.text ?? null;
12166
+ }
12167
+ }
12168
+ }
12169
+ function findPostHogCallInBody(body2, allClients, family, languageId, detectNested) {
12170
+ let found = null;
12171
+ const visit = (node) => {
12172
+ if (found) return;
12173
+ const call = matchPostHogCall(
12174
+ node,
12175
+ allClients,
12176
+ family,
12177
+ languageId,
12178
+ detectNested
12179
+ );
12180
+ if (call) {
12181
+ found = call;
12182
+ return;
12183
+ }
12184
+ for (const child of node.namedChildren) {
12185
+ if (found) return;
12186
+ visit(child);
12187
+ }
12188
+ };
12189
+ visit(body2);
12190
+ return found;
12191
+ }
12192
+ function matchPostHogCall(node, allClients, family, languageId, detectNested) {
12193
+ if (node.type !== "call_expression" && node.type !== "call") return null;
12194
+ const funcNode = node.childForFieldName("function");
12195
+ if (!funcNode) return null;
12196
+ let method = null;
12197
+ if (funcNode.type === "member_expression" || funcNode.type === "attribute") {
12198
+ const objNode = funcNode.childForFieldName("object") || funcNode.childForFieldName("operand");
12199
+ const propNode = funcNode.childForFieldName("property") || funcNode.childForFieldName("attribute");
12200
+ if (!objNode || !propNode) return null;
12201
+ const clientName = extractClientName(objNode, detectNested);
12202
+ if (!clientName || !allClients.has(clientName)) return null;
12203
+ method = propNode.text;
12204
+ } else if (funcNode.type === "selector_expression") {
12205
+ const opNode = funcNode.childForFieldName("operand");
12206
+ const fieldNode = funcNode.childForFieldName("field");
12207
+ if (!opNode || !fieldNode) return null;
12208
+ const clientName = extractClientName(opNode, detectNested);
12209
+ if (!clientName || !allClients.has(clientName)) return null;
12210
+ method = fieldNode.text;
12211
+ } else {
12212
+ return null;
12213
+ }
12214
+ if (!method || !family.allMethods.has(method)) return null;
12215
+ const locator = getKeyArgLocator(method, family, languageId);
12216
+ if (!locator) return null;
12217
+ const argsNode = node.childForFieldName("arguments") || node.namedChildren.find(
12218
+ (c) => c.type === "arguments" || c.type === "argument_list"
12219
+ ) || null;
12220
+ if (!argsNode) return null;
12221
+ const { keyNode, kwargName } = pickKeyArg(argsNode, locator);
12222
+ return {
12223
+ method,
12224
+ keyArgNode: keyNode,
12225
+ kwargName
12226
+ };
12227
+ }
12228
+ function pickKeyArg(argsNode, locator) {
12229
+ const positional = [];
12230
+ let kwargHit = null;
12231
+ let kwargName = null;
12232
+ for (const child of argsNode.namedChildren) {
12233
+ if (child.type === "keyword_argument") {
12234
+ const nameNode = child.childForFieldName("name");
12235
+ const valueNode = child.childForFieldName("value");
12236
+ if (nameNode && valueNode && locator.kwargName && nameNode.text === locator.kwargName) {
12237
+ kwargHit = valueNode;
12238
+ kwargName = nameNode.text;
12239
+ }
12240
+ continue;
12241
+ }
12242
+ positional.push(child);
12243
+ }
12244
+ if (kwargHit) {
12245
+ return { keyNode: kwargHit, kwargName };
12246
+ }
12247
+ const positionalHit = positional[locator.positionalIndex] ?? null;
12248
+ return { keyNode: positionalHit, kwargName: null };
12249
+ }
12250
+ function classifyKeyArg(keyArgNode, params) {
12251
+ if (!keyArgNode) return null;
12252
+ if (keyArgNode.type === "string" || keyArgNode.type === "interpreted_string_literal") {
12253
+ const key = extractStringFromNode(keyArgNode);
12254
+ return key !== null ? { kind: "fixed-key", key } : null;
12255
+ }
12256
+ if (keyArgNode.type === "template_string") {
12257
+ const hasInterpolation = keyArgNode.namedChildren.some(
12258
+ (c) => c.type === "template_substitution"
12259
+ );
12260
+ if (hasInterpolation) return null;
12261
+ const key = extractStringFromNode(keyArgNode);
12262
+ return key !== null ? { kind: "fixed-key", key } : null;
12263
+ }
12264
+ if (keyArgNode.type === "identifier") {
12265
+ const idx = params.indexOf(keyArgNode.text);
12266
+ if (idx >= 0) return { kind: "pass-through", paramIndex: idx };
12267
+ return null;
12268
+ }
12269
+ return null;
12270
+ }
12271
+ function getExportStatus(nameNode, languageId) {
12272
+ const defNode = nameNode.parent;
12273
+ if (!defNode) return { isDefaultExport: false, isNamedExport: false };
12274
+ if (languageId === "python") {
12275
+ let cur2 = defNode.parent;
12276
+ while (cur2) {
12277
+ if (cur2.type === "module") {
12278
+ return { isDefaultExport: false, isNamedExport: true };
12279
+ }
12280
+ if (cur2.type === "function_definition" || cur2.type === "class_definition") {
12281
+ return { isDefaultExport: false, isNamedExport: false };
12282
+ }
12283
+ cur2 = cur2.parent;
12284
+ }
12285
+ return { isDefaultExport: false, isNamedExport: false };
12286
+ }
12287
+ let cur = defNode.parent;
12288
+ while (cur) {
12289
+ if (cur.type === "export_statement") {
12290
+ const hasDefault = cur.children.some((c) => c.type === "default");
12291
+ return { isDefaultExport: hasDefault, isNamedExport: !hasDefault };
12292
+ }
12293
+ if (cur.type === "program" || cur.type === "module") break;
12294
+ cur = cur.parent;
12295
+ }
12296
+ return { isDefaultExport: false, isNamedExport: false };
12297
+ }
12298
+ async function findWrappers(pm, source, languageId) {
12299
+ const ready = await pm.ensureReady(languageId);
12300
+ if (!ready) return [];
12301
+ const { lang, family } = ready;
12302
+ const tree = pm.parse(source, lang);
12303
+ if (!tree) return [];
12304
+ const functionQuery = pm.getQuery(lang, family.queries.functions);
12305
+ if (!functionQuery) return [];
12306
+ const allClients = getEffectiveClients(pm.config);
12307
+ const { clientAliases } = findAliases(pm, lang, tree, family);
12308
+ for (const a of clientAliases) allClients.add(a);
12309
+ const wrappers = [];
12310
+ const seen = /* @__PURE__ */ new Set();
12311
+ for (const match of functionQuery.matches(tree.rootNode)) {
12312
+ const nameNode = getCapture(match.captures, "func_name");
12313
+ const paramsNode = getCapture(match.captures, "func_params");
12314
+ const singleParamNode = getCapture(match.captures, "func_single_param");
12315
+ const bodyNode = getCapture(match.captures, "func_body");
12316
+ if (!nameNode || !bodyNode) continue;
12317
+ const name2 = nameNode.text;
12318
+ if (CONTROL_FLOW_KEYWORDS.has(name2)) continue;
12319
+ if (seen.has(name2)) continue;
12320
+ const params = extractRawParams(paramsNode, singleParamNode, languageId);
12321
+ const call = findPostHogCallInBody(
12322
+ bodyNode,
12323
+ allClients,
12324
+ family,
12325
+ languageId,
12326
+ pm.config.detectNestedClients
12327
+ );
12328
+ if (!call) continue;
12329
+ const classification = classifyKeyArg(call.keyArgNode, params);
12330
+ if (!classification) continue;
12331
+ const methodKind = family.captureMethods.has(call.method) ? "capture" : "flag";
12332
+ const posthogMethod = call.method === "Enqueue" ? "capture" : call.method;
12333
+ const exportStatus = getExportStatus(nameNode, languageId);
12334
+ seen.add(name2);
12335
+ wrappers.push({
12336
+ name: name2,
12337
+ methodKind,
12338
+ posthogMethod,
12339
+ classification,
12340
+ ...exportStatus
12341
+ });
12342
+ }
12343
+ return wrappers;
12344
+ }
11699
12345
  var PostHogDetector = class {
11700
12346
  pm = new ParserManager();
11701
12347
  updateConfig(config) {
@@ -11707,8 +12353,8 @@ var PostHogDetector = class {
11707
12353
  get supportedLanguages() {
11708
12354
  return this.pm.supportedLanguages;
11709
12355
  }
11710
- async findPostHogCalls(source, languageId) {
11711
- return findPostHogCalls(this.pm, source, languageId);
12356
+ async findPostHogCalls(source, languageId, context) {
12357
+ return findPostHogCalls(this.pm, source, languageId, context);
11712
12358
  }
11713
12359
  async findInitCalls(source, languageId) {
11714
12360
  return findInitCalls(this.pm, source, languageId);
@@ -11722,6 +12368,12 @@ var PostHogDetector = class {
11722
12368
  async findFlagAssignments(source, languageId) {
11723
12369
  return findFlagAssignments(this.pm, source, languageId);
11724
12370
  }
12371
+ async findWrappers(source, languageId) {
12372
+ return findWrappers(this.pm, source, languageId);
12373
+ }
12374
+ async findImports(source, languageId, callerAbsPath) {
12375
+ return findImports(this.pm, source, languageId, callerAbsPath);
12376
+ }
11725
12377
  dispose() {
11726
12378
  this.pm.dispose();
11727
12379
  }
@@ -11826,18 +12478,32 @@ function commentPrefix(languageId) {
11826
12478
  }
11827
12479
  function formatFlagComment(flag) {
11828
12480
  const parts2 = [`Flag: "${flag.flagKey}"`];
11829
- if (flag.flag) {
11830
- parts2.push(flag.flagType);
11831
- if (flag.rollout !== null) {
11832
- parts2.push(`${flag.rollout}% rolled out`);
11833
- }
11834
- if (flag.experiment) {
11835
- const status = flag.experiment.end_date ? "complete" : "running";
11836
- parts2.push(`Experiment: "${flag.experiment.name}" (${status})`);
11837
- }
11838
- if (flag.staleness) {
11839
- parts2.push(`STALE (${flag.staleness})`);
11840
- }
12481
+ if (!flag.flag) {
12482
+ parts2.push("not in PostHog");
12483
+ return parts2.join(" \u2014 ");
12484
+ }
12485
+ parts2.push(flag.flagType);
12486
+ parts2.push(flag.flag.active ? "active" : "inactive");
12487
+ if (flag.rollout !== null) {
12488
+ parts2.push(`${flag.rollout}% rolled out`);
12489
+ }
12490
+ if (flag.evaluationStats) {
12491
+ const evals = flag.evaluationStats.evaluations.toLocaleString();
12492
+ const users = flag.evaluationStats.uniqueUsers.toLocaleString();
12493
+ const days = flag.evaluationStats.windowDays;
12494
+ parts2.push(`${evals} evals / ${users} users (${days}d)`);
12495
+ } else if (flag.evaluationStatsError) {
12496
+ parts2.push("eval stats unavailable");
12497
+ }
12498
+ if (flag.experiment) {
12499
+ const status = flag.experiment.end_date ? "complete" : "running";
12500
+ parts2.push(`Experiment: "${flag.experiment.name}" (${status})`);
12501
+ }
12502
+ if (flag.staleness) {
12503
+ parts2.push(`STALE (${flag.staleness})`);
12504
+ }
12505
+ if (flag.url) {
12506
+ parts2.push(flag.url);
11841
12507
  }
11842
12508
  return parts2.join(" \u2014 ");
11843
12509
  }
@@ -11858,21 +12524,25 @@ function formatEventComment(event) {
11858
12524
  return parts2.join(" \u2014 ");
11859
12525
  }
11860
12526
  function buildCommentBody(item, enrichedFlags, enrichedEvents) {
12527
+ let body2 = null;
11861
12528
  if (item.type === "flag") {
11862
12529
  const flag = enrichedFlags.get(item.name);
11863
- if (flag) return formatFlagComment(flag);
11864
- return null;
11865
- }
11866
- if (item.type === "event") {
12530
+ body2 = flag ? formatFlagComment(flag) : null;
12531
+ } else if (item.type === "event") {
11867
12532
  const event = enrichedEvents.get(item.name);
11868
- if (event) return formatEventComment(event);
11869
- if (item.detail) return `Event: ${item.detail}`;
11870
- return null;
12533
+ if (event) {
12534
+ body2 = formatEventComment(event);
12535
+ } else if (item.detail) {
12536
+ body2 = `Event: ${item.detail}`;
12537
+ }
12538
+ } else if (item.type === "init") {
12539
+ body2 = `Init: token "${item.name}"`;
11871
12540
  }
11872
- if (item.type === "init") {
11873
- return `Init: token "${item.name}"`;
12541
+ if (!body2) return null;
12542
+ if (item.viaWrapper) {
12543
+ body2 = `${body2} (via ${item.viaWrapper})`;
11874
12544
  }
11875
- return null;
12545
+ return body2;
11876
12546
  }
11877
12547
  function formatComments(source, languageId, items, enrichedFlags, enrichedEvents) {
11878
12548
  const prefix = commentPrefix(languageId);
@@ -11883,7 +12553,7 @@ function formatComments(source, languageId, items, enrichedFlags, enrichedEvents
11883
12553
  const targetLine = item.line + offset;
11884
12554
  const body2 = buildCommentBody(item, enrichedFlags, enrichedEvents);
11885
12555
  if (!body2) continue;
11886
- const comment = `${prefix} [PostHog] ${body2}`;
12556
+ const comment = item.inJsx ? `{/* [PostHog] ${body2} */}` : `${prefix} [PostHog] ${body2}`;
11887
12557
  const indent = lines[targetLine]?.match(/^(\s*)/)?.[1] ?? "";
11888
12558
  lines.splice(targetLine, 0, `${indent}${comment}`);
11889
12559
  offset++;
@@ -11897,15 +12567,32 @@ function formatInlineComments(source, languageId, items, enrichedFlags, enriched
11897
12567
  for (const item of items) {
11898
12568
  const body2 = buildCommentBody(item, enrichedFlags, enrichedEvents);
11899
12569
  if (!body2) continue;
11900
- const arr = byLine.get(item.line) ?? [];
11901
- arr.push(body2);
11902
- byLine.set(item.line, arr);
12570
+ const entry = byLine.get(item.line) ?? { jsxBodies: [], nonJsxBodies: [] };
12571
+ (item.inJsx ? entry.jsxBodies : entry.nonJsxBodies).push(body2);
12572
+ byLine.set(item.line, entry);
11903
12573
  }
11904
- for (const [lineIdx, bodies] of byLine) {
12574
+ const leadingInserts = [];
12575
+ for (const [lineIdx, { jsxBodies, nonJsxBodies }] of byLine) {
11905
12576
  if (lineIdx < 0 || lineIdx >= lines.length) continue;
11906
- const suffix = ` ${prefix} [PostHog] ${bodies.join(" | ")}`;
12577
+ if (jsxBodies.length > 0 && nonJsxBodies.length > 0) {
12578
+ const joined2 = [...nonJsxBodies, ...jsxBodies].join(" | ");
12579
+ const indent = lines[lineIdx]?.match(/^(\s*)/)?.[1] ?? "";
12580
+ leadingInserts.push({
12581
+ atLine: lineIdx,
12582
+ text: `${indent}{/* [PostHog] ${joined2} */}`
12583
+ });
12584
+ continue;
12585
+ }
12586
+ const isJsx = jsxBodies.length > 0;
12587
+ const bodies = isJsx ? jsxBodies : nonJsxBodies;
12588
+ const joined = bodies.join(" | ");
12589
+ const suffix = isJsx ? ` {/* [PostHog] ${joined} */}` : ` ${prefix} [PostHog] ${joined}`;
11907
12590
  lines[lineIdx] = `${lines[lineIdx]}${suffix}`;
11908
12591
  }
12592
+ leadingInserts.sort((a, b) => b.atLine - a.atLine);
12593
+ for (const { atLine, text: text2 } of leadingInserts) {
12594
+ lines.splice(atLine, 0, text2);
12595
+ }
11909
12596
  return lines.join("\n");
11910
12597
  }
11911
12598
  var EnrichedResult = class {
@@ -11928,6 +12615,7 @@ var EnrichedResult = class {
11928
12615
  let entry = flagMap.get(check.flagKey);
11929
12616
  if (!entry) {
11930
12617
  const flag = this.context.flags?.get(check.flagKey);
12618
+ const url = this.context.flagUrls?.get(check.flagKey) ?? null;
11931
12619
  entry = {
11932
12620
  flagKey: check.flagKey,
11933
12621
  occurrences: [],
@@ -11943,7 +12631,10 @@ var EnrichedResult = class {
11943
12631
  variants: flag ? extractVariants(flag) : [],
11944
12632
  experiment: experiments.find(
11945
12633
  (e) => e.feature_flag_key === check.flagKey
11946
- )
12634
+ ),
12635
+ url,
12636
+ evaluationStats: this.context.flagEvaluationStats?.get(check.flagKey),
12637
+ evaluationStatsError: this.context.flagEvaluationStatsError ?? false
11947
12638
  };
11948
12639
  flagMap.set(check.flagKey, entry);
11949
12640
  }
@@ -12001,6 +12692,10 @@ var EnrichedResult = class {
12001
12692
  enriched.flagType = flag.flagType;
12002
12693
  enriched.staleness = flag.staleness;
12003
12694
  enriched.rollout = flag.rollout;
12695
+ enriched.active = flag.flag?.active;
12696
+ enriched.url = flag.url;
12697
+ enriched.evaluations = flag.evaluationStats?.evaluations;
12698
+ enriched.evaluationUsers = flag.evaluationStats?.uniqueUsers;
12004
12699
  if (flag.experiment) {
12005
12700
  enriched.experimentName = flag.experiment.name;
12006
12701
  enriched.experimentStatus = flag.experiment.end_date ? "complete" : "running";
@@ -12067,8 +12762,8 @@ var PostHogApi = class {
12067
12762
  get signal() {
12068
12763
  return AbortSignal.timeout(this.config.timeoutMs ?? 1e4);
12069
12764
  }
12070
- async get(path32) {
12071
- const res = await fetch(`${this.baseUrl}${path32}`, {
12765
+ async get(path42) {
12766
+ const res = await fetch(`${this.baseUrl}${path42}`, {
12072
12767
  headers: {
12073
12768
  Authorization: `Bearer ${this.config.apiKey}`,
12074
12769
  "Content-Type": "application/json"
@@ -12077,13 +12772,13 @@ var PostHogApi = class {
12077
12772
  });
12078
12773
  if (!res.ok) {
12079
12774
  throw new Error(
12080
- `PostHog API error: ${res.status} ${res.statusText} on GET ${path32}`
12775
+ `PostHog API error: ${res.status} ${res.statusText} on GET ${path42}`
12081
12776
  );
12082
12777
  }
12083
12778
  return res.json();
12084
12779
  }
12085
- async post(path32, body2) {
12086
- const res = await fetch(`${this.baseUrl}${path32}`, {
12780
+ async post(path42, body2) {
12781
+ const res = await fetch(`${this.baseUrl}${path42}`, {
12087
12782
  method: "POST",
12088
12783
  headers: {
12089
12784
  Authorization: `Bearer ${this.config.apiKey}`,
@@ -12094,7 +12789,7 @@ var PostHogApi = class {
12094
12789
  });
12095
12790
  if (!res.ok) {
12096
12791
  throw new Error(
12097
- `PostHog API error: ${res.status} ${res.statusText} on POST ${path32}`
12792
+ `PostHog API error: ${res.status} ${res.statusText} on POST ${path42}`
12098
12793
  );
12099
12794
  }
12100
12795
  return res.json();
@@ -12112,11 +12807,11 @@ var PostHogApi = class {
12112
12807
  return data.results;
12113
12808
  }
12114
12809
  async getEventDefinitions(names) {
12115
- let path32 = "/event_definitions/?limit=500";
12810
+ let path42 = "/event_definitions/?limit=500";
12116
12811
  if (names && names.length > 0) {
12117
- path32 += `&search=${encodeURIComponent(names.join(","))}`;
12812
+ path42 += `&search=${encodeURIComponent(names.join(","))}`;
12118
12813
  }
12119
- const data = await this.get(path32);
12814
+ const data = await this.get(path42);
12120
12815
  return data.results;
12121
12816
  }
12122
12817
  async getEventStats(eventNames, daysBack = 30) {
@@ -12152,6 +12847,35 @@ var PostHogApi = class {
12152
12847
  }
12153
12848
  return stats;
12154
12849
  }
12850
+ async getFlagEvaluationStats(flagKeys, daysBack = 7) {
12851
+ if (flagKeys.length === 0) {
12852
+ return /* @__PURE__ */ new Map();
12853
+ }
12854
+ const days = Math.max(1, Math.min(365, Math.floor(daysBack)));
12855
+ const query2 = `
12856
+ SELECT
12857
+ properties.$feature_flag AS flag_key,
12858
+ count() AS evaluations,
12859
+ count(DISTINCT person_id) AS unique_users
12860
+ FROM events
12861
+ WHERE event = '$feature_flag_called'
12862
+ AND properties.$feature_flag IN {flagKeys}
12863
+ AND timestamp >= now() - INTERVAL ${days} DAY
12864
+ GROUP BY flag_key
12865
+ `;
12866
+ const data = await this.post("/query/", {
12867
+ query: {
12868
+ kind: "HogQLQuery",
12869
+ query: query2,
12870
+ values: { flagKeys }
12871
+ }
12872
+ });
12873
+ const stats = /* @__PURE__ */ new Map();
12874
+ for (const [flagKey, evaluations, uniqueUsers] of data.results) {
12875
+ stats.set(flagKey, { evaluations, uniqueUsers, windowDays: days });
12876
+ }
12877
+ return stats;
12878
+ }
12155
12879
  };
12156
12880
  var CAPTURE_METHODS = /* @__PURE__ */ new Set(["capture", "Enqueue"]);
12157
12881
  var ParseResult = class {
@@ -12175,14 +12899,18 @@ var ParseResult = class {
12175
12899
  return this.calls.filter((c) => CAPTURE_METHODS.has(c.method)).map((c) => ({
12176
12900
  name: c.key,
12177
12901
  line: c.line,
12178
- dynamic: c.dynamic ?? false
12902
+ dynamic: c.dynamic ?? false,
12903
+ viaWrapper: c.viaWrapper,
12904
+ inJsx: c.inJsx
12179
12905
  }));
12180
12906
  }
12181
12907
  get flagChecks() {
12182
12908
  return this.calls.filter((c) => !CAPTURE_METHODS.has(c.method)).map((c) => ({
12183
12909
  method: c.method,
12184
12910
  flagKey: c.key,
12185
- line: c.line
12911
+ line: c.line,
12912
+ viaWrapper: c.viaWrapper,
12913
+ inJsx: c.inJsx
12186
12914
  }));
12187
12915
  }
12188
12916
  get flagKeys() {
@@ -12210,7 +12938,9 @@ var ParseResult = class {
12210
12938
  line: call.line,
12211
12939
  name: call.key,
12212
12940
  method: call.method,
12213
- detail: call.dynamic ? "dynamic event name" : void 0
12941
+ detail: call.dynamic ? "dynamic event name" : void 0,
12942
+ viaWrapper: call.viaWrapper,
12943
+ inJsx: call.inJsx
12214
12944
  });
12215
12945
  }
12216
12946
  return items.sort((a, b) => a.line - b.line);
@@ -12223,14 +12953,22 @@ var ParseResult = class {
12223
12953
  flagKeys.length > 0 ? api.getFeatureFlags() : Promise.resolve([]),
12224
12954
  flagKeys.length > 0 ? api.getExperiments() : Promise.resolve([]),
12225
12955
  eventNames.length > 0 ? api.getEventDefinitions(eventNames) : Promise.resolve([]),
12226
- eventNames.length > 0 ? api.getEventStats(eventNames) : Promise.resolve(/* @__PURE__ */ new Map())
12956
+ eventNames.length > 0 ? api.getEventStats(eventNames) : Promise.resolve(/* @__PURE__ */ new Map()),
12957
+ flagKeys.length > 0 ? api.getFlagEvaluationStats(flagKeys, 7) : Promise.resolve(/* @__PURE__ */ new Map())
12227
12958
  ]);
12228
- const [flagsResult, experimentsResult, eventDefsResult, eventStatsResult] = settled;
12959
+ const [
12960
+ flagsResult,
12961
+ experimentsResult,
12962
+ eventDefsResult,
12963
+ eventStatsResult,
12964
+ flagEvalStatsResult
12965
+ ] = settled;
12229
12966
  const labels = [
12230
12967
  "getFeatureFlags",
12231
12968
  "getExperiments",
12232
12969
  "getEventDefinitions",
12233
- "getEventStats"
12970
+ "getEventStats",
12971
+ "getFlagEvaluationStats"
12234
12972
  ];
12235
12973
  settled.forEach((r, i2) => {
12236
12974
  if (r.status === "rejected") {
@@ -12241,6 +12979,8 @@ var ParseResult = class {
12241
12979
  const allExperiments = experimentsResult.status === "fulfilled" ? experimentsResult.value : [];
12242
12980
  const allEventDefs = eventDefsResult.status === "fulfilled" ? eventDefsResult.value : [];
12243
12981
  const eventStats = eventStatsResult.status === "fulfilled" ? eventStatsResult.value : /* @__PURE__ */ new Map();
12982
+ const flagEvaluationStats = flagEvalStatsResult.status === "fulfilled" ? flagEvalStatsResult.value : /* @__PURE__ */ new Map();
12983
+ const flagEvaluationStatsError = flagEvalStatsResult.status === "rejected";
12244
12984
  const flagKeySet = new Set(flagKeys);
12245
12985
  const flags2 = new Map(
12246
12986
  allFlags.filter((f) => flagKeySet.has(f.key)).map((f) => [f.key, f])
@@ -12251,18 +12991,34 @@ var ParseResult = class {
12251
12991
  const eventDefinitions = new Map(
12252
12992
  allEventDefs.filter((d) => eventNames.includes(d.name)).map((d) => [d.name, d])
12253
12993
  );
12994
+ const host = config.host.replace(/\/$/, "");
12995
+ const flagUrls = /* @__PURE__ */ new Map();
12996
+ for (const [key, flag] of flags2) {
12997
+ flagUrls.set(
12998
+ key,
12999
+ `${host}/project/${config.projectId}/feature_flags/${flag.id}`
13000
+ );
13001
+ }
12254
13002
  return new EnrichedResult(this, {
12255
13003
  flags: flags2,
12256
13004
  experiments,
12257
13005
  eventDefinitions,
12258
- eventStats
13006
+ eventStats,
13007
+ flagEvaluationStats,
13008
+ flagEvaluationStatsError,
13009
+ flagUrls
12259
13010
  });
12260
13011
  }
12261
13012
  };
13013
+ var MAX_WRAPPER_SOURCE_BYTES = 1e6;
13014
+ var WRAPPER_CACHE_MAX = 1024;
13015
+ var POSTHOG_LITERAL_REGEX = /posthog/i;
12262
13016
  var PostHogEnricher = class {
12263
13017
  detector = new PostHogDetector();
13018
+ wrapperCache = /* @__PURE__ */ new Map();
12264
13019
  updateConfig(config) {
12265
13020
  this.detector.updateConfig(config);
13021
+ this.wrapperCache.clear();
12266
13022
  }
12267
13023
  isSupported(langId) {
12268
13024
  return this.detector.isSupported(langId);
@@ -12270,9 +13026,9 @@ var PostHogEnricher = class {
12270
13026
  get supportedLanguages() {
12271
13027
  return this.detector.supportedLanguages;
12272
13028
  }
12273
- async parse(source, languageId) {
13029
+ async parse(source, languageId, context) {
12274
13030
  const results = await Promise.allSettled([
12275
- this.detector.findPostHogCalls(source, languageId),
13031
+ this.detector.findPostHogCalls(source, languageId, context),
12276
13032
  this.detector.findInitCalls(source, languageId),
12277
13033
  this.detector.findFlagAssignments(source, languageId),
12278
13034
  this.detector.findVariantBranches(source, languageId),
@@ -12303,7 +13059,7 @@ var PostHogEnricher = class {
12303
13059
  );
12304
13060
  }
12305
13061
  async parseFile(filePath) {
12306
- const ext = path22.extname(filePath).toLowerCase();
13062
+ const ext = path32.extname(filePath).toLowerCase();
12307
13063
  const languageId = EXT_TO_LANG_ID[ext];
12308
13064
  if (!languageId) {
12309
13065
  throw new Error(`Unsupported file extension: ${ext}`);
@@ -12311,8 +13067,70 @@ var PostHogEnricher = class {
12311
13067
  const source = await fs4.readFile(filePath, "utf-8");
12312
13068
  return this.parse(source, languageId);
12313
13069
  }
13070
+ /**
13071
+ * Parse a file for wrapper definitions (functions that directly call PostHog SDK methods).
13072
+ * Results are cached per absolute path + mtime so subsequent calls within the same session
13073
+ * are cheap. Returns [] for unsupported extensions, unreadable files, or files larger than
13074
+ * `MAX_WRAPPER_SOURCE_BYTES`.
13075
+ */
13076
+ async getWrappersForFile(absPath) {
13077
+ const ext = path32.extname(absPath).toLowerCase();
13078
+ const languageId = EXT_TO_LANG_ID[ext];
13079
+ if (!languageId || !this.isSupported(languageId)) {
13080
+ return this.setWrapperCache(absPath, 0, []);
13081
+ }
13082
+ let mtimeMs = 0;
13083
+ try {
13084
+ const stat2 = await fs4.stat(absPath);
13085
+ mtimeMs = stat2.mtimeMs;
13086
+ if (stat2.size > MAX_WRAPPER_SOURCE_BYTES) {
13087
+ return this.setWrapperCache(absPath, mtimeMs, []);
13088
+ }
13089
+ } catch {
13090
+ return this.setWrapperCache(absPath, 0, []);
13091
+ }
13092
+ const cached = this.wrapperCache.get(absPath);
13093
+ if (cached && cached.mtimeMs === mtimeMs) {
13094
+ this.touchCache(absPath);
13095
+ return cached.wrappers;
13096
+ }
13097
+ let source;
13098
+ try {
13099
+ source = await fs4.readFile(absPath, "utf-8");
13100
+ } catch {
13101
+ return this.setWrapperCache(absPath, mtimeMs, []);
13102
+ }
13103
+ if (!POSTHOG_LITERAL_REGEX.test(source)) {
13104
+ return this.setWrapperCache(absPath, mtimeMs, []);
13105
+ }
13106
+ const wrappers = await this.detector.findWrappers(source, languageId);
13107
+ return this.setWrapperCache(absPath, mtimeMs, wrappers);
13108
+ }
13109
+ async findImportsInSource(source, languageId, callerAbsPath) {
13110
+ return this.detector.findImports(source, languageId, callerAbsPath);
13111
+ }
13112
+ clearWrapperCache() {
13113
+ this.wrapperCache.clear();
13114
+ }
12314
13115
  dispose() {
12315
13116
  this.detector.dispose();
13117
+ this.wrapperCache.clear();
13118
+ }
13119
+ setWrapperCache(absPath, mtimeMs, wrappers) {
13120
+ if (this.wrapperCache.size >= WRAPPER_CACHE_MAX) {
13121
+ const oldest = this.wrapperCache.keys().next().value;
13122
+ if (oldest !== void 0) {
13123
+ this.wrapperCache.delete(oldest);
13124
+ }
13125
+ }
13126
+ this.wrapperCache.set(absPath, { mtimeMs, wrappers });
13127
+ return wrappers;
13128
+ }
13129
+ touchCache(absPath) {
13130
+ const entry = this.wrapperCache.get(absPath);
13131
+ if (!entry) return;
13132
+ this.wrapperCache.delete(absPath);
13133
+ this.wrapperCache.set(absPath, entry);
12316
13134
  }
12317
13135
  };
12318
13136
 
@@ -12326,14 +13144,25 @@ function createEnrichment(apiConfig, logger) {
12326
13144
  };
12327
13145
  }
12328
13146
  var MAX_ENRICHMENT_BYTES = 1e6;
13147
+ var MAX_RELATIVE_IMPORTS = 64;
13148
+ var RELATIVE_IMPORT_REGEX = /(?:^|\n)\s*(?:import\b[^\n]*['"]\.{1,2}\/|from\s+\.)/;
13149
+ var POSTHOG_LITERAL_REGEX2 = /posthog/i;
12329
13150
  async function enrichFileForAgent(deps, filePath, content) {
12330
13151
  if (!content || content.length > MAX_ENRICHMENT_BYTES) return null;
12331
- if (!/posthog/i.test(content)) return null;
12332
13152
  const ext = path4.extname(filePath).toLowerCase();
12333
13153
  const langId = EXT_TO_LANG_ID[ext];
12334
13154
  if (!langId || !deps.enricher.isSupported(langId)) return null;
13155
+ const hasPostHogLiteral = POSTHOG_LITERAL_REGEX2.test(content);
13156
+ const hasRelativeImport = RELATIVE_IMPORT_REGEX.test(content);
13157
+ let parseContext;
13158
+ if (hasRelativeImport) {
13159
+ const absPath = path4.resolve(filePath);
13160
+ const ctx = await buildWrapperContext(deps, content, langId, absPath);
13161
+ if (ctx) parseContext = ctx;
13162
+ }
13163
+ if (!hasPostHogLiteral && !parseContext) return null;
12335
13164
  try {
12336
- const parsed = await deps.enricher.parse(content, langId);
13165
+ const parsed = await deps.enricher.parse(content, langId, parseContext);
12337
13166
  if (parsed.calls.length === 0 && parsed.initCalls.length === 0) {
12338
13167
  return null;
12339
13168
  }
@@ -12355,7 +13184,8 @@ async function enrichFileForAgent(deps, filePath, content) {
12355
13184
  }
12356
13185
  deps.logger?.debug("File enriched", {
12357
13186
  filePath,
12358
- calls: parsed.calls.length
13187
+ calls: parsed.calls.length,
13188
+ viaWrappers: parsed.calls.filter((c) => c.viaWrapper).length
12359
13189
  });
12360
13190
  return annotated;
12361
13191
  } catch (err2) {
@@ -12364,11 +13194,62 @@ async function enrichFileForAgent(deps, filePath, content) {
12364
13194
  return null;
12365
13195
  }
12366
13196
  }
13197
+ async function buildWrapperContext(deps, content, langId, absPath) {
13198
+ let edges;
13199
+ try {
13200
+ edges = await deps.enricher.findImportsInSource(content, langId, absPath);
13201
+ } catch (err2) {
13202
+ deps.logger?.debug("Import resolution failed", {
13203
+ absPath,
13204
+ err: err2 instanceof Error ? err2.message : String(err2)
13205
+ });
13206
+ return null;
13207
+ }
13208
+ if (!edges.length) return null;
13209
+ const bounded = edges.slice(0, MAX_RELATIVE_IMPORTS);
13210
+ const wrappersByLocalName = /* @__PURE__ */ new Map();
13211
+ const namespaceWrappers = /* @__PURE__ */ new Map();
13212
+ const resolutions = await Promise.all(
13213
+ bounded.map(async (edge) => {
13214
+ if (!edge.resolvedAbsPath) return null;
13215
+ const wrappers = await deps.enricher.getWrappersForFile(
13216
+ edge.resolvedAbsPath
13217
+ );
13218
+ if (!wrappers.length) return null;
13219
+ return { edge, wrappers };
13220
+ })
13221
+ );
13222
+ for (const entry of resolutions) {
13223
+ if (!entry) continue;
13224
+ const { edge, wrappers } = entry;
13225
+ if (edge.isNamespace) {
13226
+ const nsMap = /* @__PURE__ */ new Map();
13227
+ for (const w of wrappers) {
13228
+ if (w.isNamedExport || w.isDefaultExport) {
13229
+ nsMap.set(w.name, w);
13230
+ }
13231
+ }
13232
+ if (nsMap.size) namespaceWrappers.set(edge.localName, nsMap);
13233
+ continue;
13234
+ }
13235
+ if (edge.isDefault) {
13236
+ const target2 = wrappers.find((w) => w.isDefaultExport);
13237
+ if (target2) wrappersByLocalName.set(edge.localName, target2);
13238
+ continue;
13239
+ }
13240
+ const target = wrappers.find(
13241
+ (w) => w.name === edge.importedName && w.isNamedExport
13242
+ );
13243
+ if (target) wrappersByLocalName.set(edge.localName, target);
13244
+ }
13245
+ if (!wrappersByLocalName.size && !namespaceWrappers.size) return null;
13246
+ return { wrappersByLocalName, namespaceWrappers };
13247
+ }
12367
13248
 
12368
13249
  // src/utils/common.ts
12369
13250
  async function withTimeout(operation, timeoutMs) {
12370
13251
  const timeoutPromise = new Promise(
12371
- (resolve4) => setTimeout(() => resolve4({ result: "timeout" }), timeoutMs)
13252
+ (resolve6) => setTimeout(() => resolve6({ result: "timeout" }), timeoutMs)
12372
13253
  );
12373
13254
  const operationPromise = operation.then((value) => ({
12374
13255
  result: "success",
@@ -12854,7 +13735,7 @@ function buildToolKey(serverName, toolName) {
12854
13735
  return `mcp__${serverName}__${toolName}`;
12855
13736
  }
12856
13737
  function delay2(ms) {
12857
- return new Promise((resolve4) => setTimeout(resolve4, ms));
13738
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
12858
13739
  }
12859
13740
  async function fetchMcpToolMetadata(q, logger = new Logger({ debug: false, prefix: "[McpToolMetadata]" })) {
12860
13741
  let retries = 0;
@@ -15068,8 +15949,8 @@ var AsyncMutex = class {
15068
15949
  this.locked = true;
15069
15950
  return;
15070
15951
  }
15071
- return new Promise((resolve4) => {
15072
- this.queue.push(resolve4);
15952
+ return new Promise((resolve6) => {
15953
+ this.queue.push(resolve6);
15073
15954
  });
15074
15955
  }
15075
15956
  release() {
@@ -15604,8 +16485,8 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
15604
16485
  if (this.session.promptRunning) {
15605
16486
  this.session.input.push(userMessage);
15606
16487
  const order = this.session.nextPendingOrder++;
15607
- const cancelled = await new Promise((resolve4) => {
15608
- this.session.pendingMessages.set(promptUuid, { resolve: resolve4, order });
16488
+ const cancelled = await new Promise((resolve6) => {
16489
+ this.session.pendingMessages.set(promptUuid, { resolve: resolve6, order });
15609
16490
  });
15610
16491
  if (cancelled) {
15611
16492
  return { stopReason: "cancelled" };
@@ -16476,7 +17357,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
16476
17357
  */
16477
17358
  deferBackgroundFetches(q) {
16478
17359
  Promise.all([
16479
- new Promise((resolve4) => setTimeout(resolve4, 10)).then(
17360
+ new Promise((resolve6) => setTimeout(resolve6, 10)).then(
16480
17361
  () => this.sendAvailableCommandsUpdate()
16481
17362
  ),
16482
17363
  fetchMcpToolMetadata(q, this.logger).then(() => {
@@ -19433,7 +20314,7 @@ var AgentServer = class _AgentServer {
19433
20314
  return app;
19434
20315
  }
19435
20316
  async start() {
19436
- await new Promise((resolve4) => {
20317
+ await new Promise((resolve6) => {
19437
20318
  this.server = (0, import_node_server.serve)(
19438
20319
  {
19439
20320
  fetch: this.app.fetch,
@@ -19443,7 +20324,7 @@ var AgentServer = class _AgentServer {
19443
20324
  this.logger.debug(
19444
20325
  `HTTP server listening on port ${this.config.port}`
19445
20326
  );
19446
- resolve4();
20327
+ resolve6();
19447
20328
  }
19448
20329
  );
19449
20330
  });
@@ -20802,8 +21683,8 @@ ${attributionInstructions}
20802
21683
  options: params.options,
20803
21684
  toolCall: params.toolCall
20804
21685
  });
20805
- return new Promise((resolve4) => {
20806
- this.pendingPermissions.set(requestId, { resolve: resolve4 });
21686
+ return new Promise((resolve6) => {
21687
+ this.pendingPermissions.set(requestId, { resolve: resolve6 });
20807
21688
  });
20808
21689
  }
20809
21690
  resolvePermission(requestId, optionId, customInput, answers) {