@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.
@@ -809,15 +809,15 @@ var require_src2 = __commonJS({
809
809
  var fs_1 = __require("fs");
810
810
  var debug_1 = __importDefault(require_src());
811
811
  var log = debug_1.default("@kwsites/file-exists");
812
- function check(path15, isFile, isDirectory) {
812
+ function check(path15, isFile2, isDirectory) {
813
813
  log(`checking %s`, path15);
814
814
  try {
815
- const stat = fs_1.statSync(path15);
816
- if (stat.isFile() && isFile) {
815
+ const stat2 = fs_1.statSync(path15);
816
+ if (stat2.isFile() && isFile2) {
817
817
  log(`[OK] path represents a file`);
818
818
  return true;
819
819
  }
820
- if (stat.isDirectory() && isDirectory) {
820
+ if (stat2.isDirectory() && isDirectory) {
821
821
  log(`[OK] path represents a directory`);
822
822
  return true;
823
823
  }
@@ -947,10 +947,10 @@ var require_tree_sitter = __commonJS({
947
947
  };
948
948
  readAsync = (filename, binary2 = true) => {
949
949
  filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename);
950
- return new Promise((resolve4, reject) => {
950
+ return new Promise((resolve6, reject) => {
951
951
  fs.readFile(filename, binary2 ? void 0 : "utf8", (err2, data) => {
952
952
  if (err2) reject(err2);
953
- else resolve4(binary2 ? data.buffer : data);
953
+ else resolve6(binary2 ? data.buffer : data);
954
954
  });
955
955
  });
956
956
  };
@@ -991,13 +991,13 @@ var require_tree_sitter = __commonJS({
991
991
  }
992
992
  readAsync = (url) => {
993
993
  if (isFileURI(url)) {
994
- return new Promise((reject, resolve4) => {
994
+ return new Promise((reject, resolve6) => {
995
995
  var xhr = new XMLHttpRequest();
996
996
  xhr.open("GET", url, true);
997
997
  xhr.responseType = "arraybuffer";
998
998
  xhr.onload = () => {
999
999
  if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
1000
- resolve4(xhr.response);
1000
+ resolve6(xhr.response);
1001
1001
  }
1002
1002
  reject(xhr.status);
1003
1003
  };
@@ -1957,8 +1957,8 @@ var require_tree_sitter = __commonJS({
1957
1957
  }
1958
1958
  var libFile = locateFile(libName2);
1959
1959
  if (flags2.loadAsync) {
1960
- return new Promise(function(resolve4, reject) {
1961
- asyncLoad(libFile, resolve4, reject);
1960
+ return new Promise(function(resolve6, reject) {
1961
+ asyncLoad(libFile, resolve6, reject);
1962
1962
  });
1963
1963
  }
1964
1964
  if (!readBinary) {
@@ -3785,7 +3785,7 @@ ${JSON.stringify(symbolNames, null, 2)}`);
3785
3785
 
3786
3786
  // src/server/agent-server.ts
3787
3787
  import { mkdir as mkdir5, writeFile as writeFile5 } from "fs/promises";
3788
- import { basename as basename2, join as join11 } from "path";
3788
+ import { basename as basename2, join as join12 } from "path";
3789
3789
  import { pathToFileURL } from "url";
3790
3790
  import {
3791
3791
  ClientSideConnection as ClientSideConnection2,
@@ -8374,10 +8374,10 @@ async function getIndexLockPath(repoPath) {
8374
8374
  async function getLockInfo(repoPath) {
8375
8375
  const lockPath = await getIndexLockPath(repoPath);
8376
8376
  try {
8377
- const stat = await fs2.stat(lockPath);
8377
+ const stat2 = await fs2.stat(lockPath);
8378
8378
  return {
8379
8379
  path: lockPath,
8380
- ageMs: Date.now() - stat.mtimeMs
8380
+ ageMs: Date.now() - stat2.mtimeMs
8381
8381
  };
8382
8382
  } catch {
8383
8383
  return null;
@@ -8412,10 +8412,10 @@ var AsyncReaderWriterLock = class {
8412
8412
  this.readers++;
8413
8413
  return;
8414
8414
  }
8415
- return new Promise((resolve4) => {
8415
+ return new Promise((resolve6) => {
8416
8416
  this.readQueue.push(() => {
8417
8417
  this.readers++;
8418
- resolve4();
8418
+ resolve6();
8419
8419
  });
8420
8420
  });
8421
8421
  }
@@ -8429,11 +8429,11 @@ var AsyncReaderWriterLock = class {
8429
8429
  return;
8430
8430
  }
8431
8431
  this.writerWaiting = true;
8432
- return new Promise((resolve4) => {
8432
+ return new Promise((resolve6) => {
8433
8433
  this.writeQueue.push(() => {
8434
8434
  this.writerWaiting = this.writeQueue.length > 0;
8435
8435
  this.writer = true;
8436
- resolve4();
8436
+ resolve6();
8437
8437
  });
8438
8438
  });
8439
8439
  }
@@ -8605,7 +8605,7 @@ import { z as z4 } from "zod";
8605
8605
  // package.json
8606
8606
  var package_default = {
8607
8607
  name: "@posthog/agent",
8608
- version: "2.3.363",
8608
+ version: "2.3.370",
8609
8609
  repository: "https://github.com/PostHog/code",
8610
8610
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
8611
8611
  exports: {
@@ -8860,17 +8860,17 @@ var Pushable = class {
8860
8860
  resolvers = [];
8861
8861
  done = false;
8862
8862
  push(item) {
8863
- const resolve4 = this.resolvers.shift();
8864
- if (resolve4) {
8865
- resolve4({ value: item, done: false });
8863
+ const resolve6 = this.resolvers.shift();
8864
+ if (resolve6) {
8865
+ resolve6({ value: item, done: false });
8866
8866
  } else {
8867
8867
  this.queue.push(item);
8868
8868
  }
8869
8869
  }
8870
8870
  end() {
8871
8871
  this.done = true;
8872
- for (const resolve4 of this.resolvers) {
8873
- resolve4({ value: void 0, done: true });
8872
+ for (const resolve6 of this.resolvers) {
8873
+ resolve6({ value: void 0, done: true });
8874
8874
  }
8875
8875
  this.resolvers = [];
8876
8876
  }
@@ -8887,8 +8887,8 @@ var Pushable = class {
8887
8887
  done: true
8888
8888
  });
8889
8889
  }
8890
- return new Promise((resolve4) => {
8891
- this.resolvers.push(resolve4);
8890
+ return new Promise((resolve6) => {
8891
+ this.resolvers.push(resolve6);
8892
8892
  });
8893
8893
  }
8894
8894
  };
@@ -9002,20 +9002,20 @@ function nodeReadableToWebReadable(nodeStream) {
9002
9002
  function nodeWritableToWebWritable(nodeStream) {
9003
9003
  return new WritableStream2({
9004
9004
  write(chunk) {
9005
- return new Promise((resolve4, reject) => {
9005
+ return new Promise((resolve6, reject) => {
9006
9006
  const ok = nodeStream.write(Buffer.from(chunk), (err2) => {
9007
9007
  if (err2) reject(err2);
9008
9008
  });
9009
9009
  if (ok) {
9010
- resolve4();
9010
+ resolve6();
9011
9011
  } else {
9012
- nodeStream.once("drain", resolve4);
9012
+ nodeStream.once("drain", resolve6);
9013
9013
  }
9014
9014
  });
9015
9015
  },
9016
9016
  close() {
9017
- return new Promise((resolve4) => {
9018
- nodeStream.end(resolve4);
9017
+ return new Promise((resolve6) => {
9018
+ nodeStream.end(resolve6);
9019
9019
  });
9020
9020
  },
9021
9021
  abort(reason) {
@@ -9046,11 +9046,13 @@ import * as path4 from "path";
9046
9046
 
9047
9047
  // ../enricher/dist/index.js
9048
9048
  var import_web_tree_sitter = __toESM(require_tree_sitter(), 1);
9049
- import { existsSync } from "fs";
9049
+ import { statSync } from "fs";
9050
9050
  import * as path3 from "path";
9051
+ import { existsSync } from "fs";
9052
+ import * as path22 from "path";
9051
9053
  import { fileURLToPath } from "url";
9052
9054
  import * as fs4 from "fs/promises";
9053
- import * as path22 from "path";
9055
+ import * as path32 from "path";
9054
9056
  function getCapture(captures, name2) {
9055
9057
  const found = captures.find((c) => c.name === name2);
9056
9058
  return found ? found.node : null;
@@ -9165,6 +9167,22 @@ function walkNodes(root, type, callback) {
9165
9167
  };
9166
9168
  visit(root);
9167
9169
  }
9170
+ var JSX_NODE_TYPES = /* @__PURE__ */ new Set([
9171
+ "jsx_element",
9172
+ "jsx_fragment",
9173
+ "jsx_self_closing_element",
9174
+ "jsx_opening_element",
9175
+ "jsx_closing_element",
9176
+ "jsx_attribute"
9177
+ ]);
9178
+ function isInsideJsx(node) {
9179
+ let cur = node.parent;
9180
+ while (cur) {
9181
+ if (JSX_NODE_TYPES.has(cur.type)) return true;
9182
+ cur = cur.parent;
9183
+ }
9184
+ return false;
9185
+ }
9168
9186
  var JS_CAPTURE_METHODS = /* @__PURE__ */ new Set(["capture"]);
9169
9187
  var JS_FLAG_METHODS = /* @__PURE__ */ new Set([
9170
9188
  "getFeatureFlag",
@@ -9350,6 +9368,33 @@ var JS_QUERIES = {
9350
9368
  object: (_) @client
9351
9369
  property: (property_identifier) @method)
9352
9370
  arguments: (arguments . (_) @first_arg)) @call
9371
+ `,
9372
+ imports: `
9373
+ (import_statement
9374
+ (import_clause
9375
+ (identifier) @default_name)
9376
+ source: (string (string_fragment) @source)) @stmt
9377
+
9378
+ (import_statement
9379
+ (import_clause
9380
+ (named_imports
9381
+ (import_specifier
9382
+ name: (identifier) @imported_name) @spec))
9383
+ source: (string (string_fragment) @source)) @stmt
9384
+
9385
+ (import_statement
9386
+ (import_clause
9387
+ (named_imports
9388
+ (import_specifier
9389
+ name: (identifier) @imported_name
9390
+ alias: (identifier) @local_name) @spec))
9391
+ source: (string (string_fragment) @source)) @stmt
9392
+
9393
+ (import_statement
9394
+ (import_clause
9395
+ (namespace_import
9396
+ (identifier) @namespace_name))
9397
+ source: (string (string_fragment) @source)) @stmt
9353
9398
  `
9354
9399
  };
9355
9400
  var PY_QUERIES = {
@@ -9426,6 +9471,31 @@ var PY_QUERIES = {
9426
9471
  object: (_) @client
9427
9472
  attribute: (identifier) @method)
9428
9473
  arguments: (argument_list . (_) @first_arg)) @call
9474
+ `,
9475
+ imports: `
9476
+ (import_from_statement
9477
+ module_name: (dotted_name) @source
9478
+ name: (dotted_name) @imported_name) @stmt
9479
+
9480
+ (import_from_statement
9481
+ module_name: (dotted_name) @source
9482
+ name: (aliased_import
9483
+ name: (dotted_name) @imported_name
9484
+ alias: (identifier) @local_name)) @stmt
9485
+
9486
+ (import_from_statement
9487
+ module_name: (relative_import
9488
+ (import_prefix) @relative_prefix
9489
+ (dotted_name)? @relative_name)
9490
+ name: (dotted_name) @imported_name) @stmt
9491
+
9492
+ (import_from_statement
9493
+ module_name: (relative_import
9494
+ (import_prefix) @relative_prefix
9495
+ (dotted_name)? @relative_name)
9496
+ name: (aliased_import
9497
+ name: (dotted_name) @imported_name
9498
+ alias: (identifier) @local_name)) @stmt
9429
9499
  `
9430
9500
  };
9431
9501
  var GO_QUERIES = {
@@ -9817,7 +9887,7 @@ function buildConstantMap(pm, lang, tree) {
9817
9887
  }
9818
9888
  var POSTHOG_CLASS_NAMES2 = /* @__PURE__ */ new Set(["PostHog", "Posthog"]);
9819
9889
  var GO_CONSTRUCTOR_NAMES2 = /* @__PURE__ */ new Set(["New", "NewWithConfig"]);
9820
- async function findPostHogCalls(pm, source, languageId) {
9890
+ async function findPostHogCalls(pm, source, languageId, context) {
9821
9891
  const ready = await pm.ensureReady(languageId);
9822
9892
  if (!ready) {
9823
9893
  return [];
@@ -9846,6 +9916,7 @@ async function findPostHogCalls(pm, source, languageId) {
9846
9916
  const clientNode = getCapture(match.captures, "client");
9847
9917
  const methodNode = getCapture(match.captures, "method");
9848
9918
  const keyNode = getCapture(match.captures, "key");
9919
+ const callNode = getCapture(match.captures, "call");
9849
9920
  if (!clientNode || !methodNode || !keyNode) {
9850
9921
  continue;
9851
9922
  }
@@ -9871,7 +9942,8 @@ async function findPostHogCalls(pm, source, languageId) {
9871
9942
  key: cleanStringValue(keyNode.text),
9872
9943
  line: keyNode.startPosition.row,
9873
9944
  keyStartCol: keyNode.startPosition.column,
9874
- keyEndCol: keyNode.endPosition.column
9945
+ keyEndCol: keyNode.endPosition.column,
9946
+ inJsx: callNode ? isInsideJsx(callNode) : void 0
9875
9947
  });
9876
9948
  }
9877
9949
  }
@@ -9926,6 +9998,7 @@ async function findPostHogCalls(pm, source, languageId) {
9926
9998
  const methodNode = getCapture(match.captures, "method");
9927
9999
  const propNameNode = getCapture(match.captures, "prop_name");
9928
10000
  const keyNode = getCapture(match.captures, "key");
10001
+ const callNode = getCapture(match.captures, "call");
9929
10002
  if (!clientNode || !methodNode || !propNameNode || !keyNode) {
9930
10003
  continue;
9931
10004
  }
@@ -9948,7 +10021,8 @@ async function findPostHogCalls(pm, source, languageId) {
9948
10021
  key: cleanStringValue(keyNode.text),
9949
10022
  line: keyNode.startPosition.row,
9950
10023
  keyStartCol: keyNode.startPosition.column,
9951
- keyEndCol: keyNode.endPosition.column
10024
+ keyEndCol: keyNode.endPosition.column,
10025
+ inJsx: callNode ? isInsideJsx(callNode) : void 0
9952
10026
  });
9953
10027
  }
9954
10028
  }
@@ -10045,6 +10119,7 @@ async function findPostHogCalls(pm, source, languageId) {
10045
10119
  for (const match of matches) {
10046
10120
  const funcNode = getCapture(match.captures, "func_name");
10047
10121
  const keyNode = getCapture(match.captures, "key");
10122
+ const callNode = getCapture(match.captures, "call");
10048
10123
  if (!funcNode || !keyNode) {
10049
10124
  continue;
10050
10125
  }
@@ -10055,7 +10130,8 @@ async function findPostHogCalls(pm, source, languageId) {
10055
10130
  key: cleanStringValue(keyNode.text),
10056
10131
  line: keyNode.startPosition.row,
10057
10132
  keyStartCol: keyNode.startPosition.column,
10058
- keyEndCol: keyNode.endPosition.column
10133
+ keyEndCol: keyNode.endPosition.column,
10134
+ inJsx: callNode ? isInsideJsx(callNode) : void 0
10059
10135
  });
10060
10136
  }
10061
10137
  }
@@ -10069,6 +10145,7 @@ async function findPostHogCalls(pm, source, languageId) {
10069
10145
  for (const match of matches) {
10070
10146
  const funcNode = getCapture(match.captures, "func_name");
10071
10147
  const keyNode = getCapture(match.captures, "key");
10148
+ const callNode = getCapture(match.captures, "call");
10072
10149
  if (!funcNode || !keyNode) {
10073
10150
  continue;
10074
10151
  }
@@ -10078,7 +10155,8 @@ async function findPostHogCalls(pm, source, languageId) {
10078
10155
  key: cleanStringValue(keyNode.text),
10079
10156
  line: keyNode.startPosition.row,
10080
10157
  keyStartCol: keyNode.startPosition.column,
10081
- keyEndCol: keyNode.endPosition.column
10158
+ keyEndCol: keyNode.endPosition.column,
10159
+ inJsx: callNode ? isInsideJsx(callNode) : void 0
10082
10160
  });
10083
10161
  }
10084
10162
  }
@@ -10093,6 +10171,7 @@ async function findPostHogCalls(pm, source, languageId) {
10093
10171
  const clientNode = getCapture(match.captures, "client");
10094
10172
  const methodNode = getCapture(match.captures, "method");
10095
10173
  const argNode = getCapture(match.captures, "arg_id");
10174
+ const callNode = getCapture(match.captures, "call");
10096
10175
  if (!clientNode || !methodNode || !argNode) {
10097
10176
  continue;
10098
10177
  }
@@ -10122,7 +10201,8 @@ async function findPostHogCalls(pm, source, languageId) {
10122
10201
  key: resolved,
10123
10202
  line,
10124
10203
  keyStartCol: argNode.startPosition.column,
10125
- keyEndCol: argNode.endPosition.column
10204
+ keyEndCol: argNode.endPosition.column,
10205
+ inJsx: callNode ? isInsideJsx(callNode) : void 0
10126
10206
  });
10127
10207
  }
10128
10208
  }
@@ -10135,6 +10215,7 @@ async function findPostHogCalls(pm, source, languageId) {
10135
10215
  const clientNode = getCapture(match.captures, "client");
10136
10216
  const methodNode = getCapture(match.captures, "method");
10137
10217
  const firstArgNode = getCapture(match.captures, "first_arg");
10218
+ const callNode = getCapture(match.captures, "call");
10138
10219
  if (!clientNode || !methodNode || !firstArgNode) {
10139
10220
  continue;
10140
10221
  }
@@ -10159,13 +10240,167 @@ async function findPostHogCalls(pm, source, languageId) {
10159
10240
  line,
10160
10241
  keyStartCol: firstArgNode.startPosition.column,
10161
10242
  keyEndCol: firstArgNode.endPosition.column,
10162
- dynamic: true
10243
+ dynamic: true,
10244
+ inJsx: callNode ? isInsideJsx(callNode) : void 0
10163
10245
  });
10164
10246
  matchedLines.add(line);
10165
10247
  }
10166
10248
  }
10249
+ if (context?.wrappersByLocalName?.size) {
10250
+ synthesizeBareWrapperCalls(
10251
+ pm,
10252
+ lang,
10253
+ tree,
10254
+ languageId,
10255
+ context.wrappersByLocalName,
10256
+ constantMap,
10257
+ calls,
10258
+ matchedLines
10259
+ );
10260
+ }
10261
+ if (context?.namespaceWrappers?.size) {
10262
+ synthesizeNamespaceWrapperCalls(
10263
+ pm,
10264
+ lang,
10265
+ tree,
10266
+ languageId,
10267
+ context.namespaceWrappers,
10268
+ constantMap,
10269
+ calls,
10270
+ matchedLines
10271
+ );
10272
+ }
10167
10273
  return calls;
10168
10274
  }
10275
+ var WRAPPER_BARE_CALL_QUERIES = {
10276
+ javascript: `(call_expression function: (identifier) @func_name arguments: (arguments) @args) @call`,
10277
+ javascriptreact: `(call_expression function: (identifier) @func_name arguments: (arguments) @args) @call`,
10278
+ typescript: `(call_expression function: (identifier) @func_name arguments: (arguments) @args) @call`,
10279
+ typescriptreact: `(call_expression function: (identifier) @func_name arguments: (arguments) @args) @call`,
10280
+ python: `(call function: (identifier) @func_name arguments: (argument_list) @args) @call`
10281
+ };
10282
+ var WRAPPER_NAMESPACE_CALL_QUERIES = {
10283
+ javascript: `(call_expression function: (member_expression object: (identifier) @ns property: (property_identifier) @method) arguments: (arguments) @args) @call`,
10284
+ javascriptreact: `(call_expression function: (member_expression object: (identifier) @ns property: (property_identifier) @method) arguments: (arguments) @args) @call`,
10285
+ typescript: `(call_expression function: (member_expression object: (identifier) @ns property: (property_identifier) @method) arguments: (arguments) @args) @call`,
10286
+ typescriptreact: `(call_expression function: (member_expression object: (identifier) @ns property: (property_identifier) @method) arguments: (arguments) @args) @call`,
10287
+ python: `(call function: (attribute object: (identifier) @ns attribute: (identifier) @method) arguments: (argument_list) @args) @call`
10288
+ };
10289
+ function synthesizeBareWrapperCalls(pm, lang, tree, languageId, wrappers, constantMap, calls, matchedLines) {
10290
+ const queryStr = WRAPPER_BARE_CALL_QUERIES[languageId];
10291
+ if (!queryStr) return;
10292
+ const query2 = pm.getQuery(lang, queryStr);
10293
+ if (!query2) return;
10294
+ for (const match of query2.matches(tree.rootNode)) {
10295
+ const funcNode = getCapture(match.captures, "func_name");
10296
+ const argsNode = getCapture(match.captures, "args");
10297
+ const callNode = getCapture(match.captures, "call");
10298
+ if (!funcNode || !argsNode) continue;
10299
+ const wrapper = wrappers.get(funcNode.text);
10300
+ if (!wrapper) continue;
10301
+ pushWrapperCall(
10302
+ wrapper,
10303
+ funcNode,
10304
+ argsNode,
10305
+ callNode,
10306
+ constantMap,
10307
+ calls,
10308
+ matchedLines
10309
+ );
10310
+ }
10311
+ }
10312
+ function synthesizeNamespaceWrapperCalls(pm, lang, tree, languageId, namespaceWrappers, constantMap, calls, matchedLines) {
10313
+ const queryStr = WRAPPER_NAMESPACE_CALL_QUERIES[languageId];
10314
+ if (!queryStr) return;
10315
+ const query2 = pm.getQuery(lang, queryStr);
10316
+ if (!query2) return;
10317
+ for (const match of query2.matches(tree.rootNode)) {
10318
+ const nsNode = getCapture(match.captures, "ns");
10319
+ const methodNode = getCapture(match.captures, "method");
10320
+ const argsNode = getCapture(match.captures, "args");
10321
+ const callNode = getCapture(match.captures, "call");
10322
+ if (!nsNode || !methodNode || !argsNode) continue;
10323
+ const nsWrappers = namespaceWrappers.get(nsNode.text);
10324
+ if (!nsWrappers) continue;
10325
+ const wrapper = nsWrappers.get(methodNode.text);
10326
+ if (!wrapper) continue;
10327
+ pushWrapperCall(
10328
+ wrapper,
10329
+ methodNode,
10330
+ argsNode,
10331
+ callNode,
10332
+ constantMap,
10333
+ calls,
10334
+ matchedLines
10335
+ );
10336
+ }
10337
+ }
10338
+ function pushWrapperCall(wrapper, callerNode, argsNode, callNode, constantMap, calls, matchedLines) {
10339
+ let line = callerNode.startPosition.row;
10340
+ let keyStartCol = callerNode.startPosition.column;
10341
+ let keyEndCol = callerNode.endPosition.column;
10342
+ let key = "";
10343
+ let dynamic = false;
10344
+ if (wrapper.classification.kind === "fixed-key") {
10345
+ key = wrapper.classification.key;
10346
+ } else {
10347
+ const positional = argsNode.namedChildren.filter(
10348
+ (c) => c.type !== "comment" && c.type !== "keyword_argument"
10349
+ );
10350
+ const arg = positional[wrapper.classification.paramIndex];
10351
+ if (!arg) return;
10352
+ line = arg.startPosition.row;
10353
+ keyStartCol = arg.startPosition.column;
10354
+ keyEndCol = arg.endPosition.column;
10355
+ if (arg.type === "string") {
10356
+ const fragment = arg.namedChildren.find(
10357
+ (c) => c.type === "string_fragment" || c.type === "string_content"
10358
+ );
10359
+ if (fragment) {
10360
+ key = fragment.text;
10361
+ } else {
10362
+ dynamic = true;
10363
+ }
10364
+ } else if (arg.type === "template_string") {
10365
+ const fragments = arg.namedChildren.filter(
10366
+ (c) => c.type === "string_fragment"
10367
+ );
10368
+ const hasInterp = arg.namedChildren.some(
10369
+ (c) => c.type === "template_substitution"
10370
+ );
10371
+ if (!hasInterp && fragments.length === 1) {
10372
+ key = fragments[0].text;
10373
+ } else {
10374
+ dynamic = true;
10375
+ }
10376
+ } else if (arg.type === "interpreted_string_literal") {
10377
+ key = arg.text.slice(1, -1);
10378
+ } else if (arg.type === "identifier") {
10379
+ const resolved = constantMap.get(arg.text);
10380
+ if (resolved) {
10381
+ key = resolved;
10382
+ } else {
10383
+ dynamic = true;
10384
+ }
10385
+ } else {
10386
+ dynamic = true;
10387
+ }
10388
+ }
10389
+ if (matchedLines.has(line) && dynamic) {
10390
+ return;
10391
+ }
10392
+ calls.push({
10393
+ method: wrapper.posthogMethod,
10394
+ key,
10395
+ line,
10396
+ keyStartCol,
10397
+ keyEndCol,
10398
+ dynamic: dynamic ? true : void 0,
10399
+ viaWrapper: wrapper.name,
10400
+ inJsx: callNode ? isInsideJsx(callNode) : void 0
10401
+ });
10402
+ matchedLines.add(line);
10403
+ }
10169
10404
  async function findInitCalls(pm, source, languageId) {
10170
10405
  const ready = await pm.ensureReady(languageId);
10171
10406
  if (!ready) {
@@ -10578,6 +10813,7 @@ async function findFunctions(pm, source, languageId) {
10578
10813
  }
10579
10814
  const params = singleParamNode ? [singleParamNode.text] : paramsNode ? extractParams(paramsNode.text) : [];
10580
10815
  const bodyLine = bodyNode.startPosition.row;
10816
+ const bodyEndLine = bodyNode.endPosition.row;
10581
10817
  const nextLineIdx = bodyLine + 1;
10582
10818
  const lines = text2.split("\n");
10583
10819
  const nextLine = nextLineIdx < lines.length ? lines[nextLineIdx] : "";
@@ -10587,6 +10823,7 @@ async function findFunctions(pm, source, languageId) {
10587
10823
  params,
10588
10824
  isComponent: /^[A-Z]/.test(name2),
10589
10825
  bodyLine,
10826
+ bodyEndLine,
10590
10827
  bodyIndent
10591
10828
  });
10592
10829
  }
@@ -10644,6 +10881,157 @@ async function findFlagAssignments(pm, source, languageId) {
10644
10881
  }
10645
10882
  return assignments;
10646
10883
  }
10884
+ var JS_EXTENSION_PROBES = [
10885
+ ".ts",
10886
+ ".tsx",
10887
+ ".mts",
10888
+ ".cts",
10889
+ ".js",
10890
+ ".jsx",
10891
+ ".mjs",
10892
+ ".cjs"
10893
+ ];
10894
+ var PY_EXTENSION_PROBES = [".py"];
10895
+ function isRelativeSpecifier(spec) {
10896
+ return spec.startsWith("./") || spec.startsWith("../") || spec === ".";
10897
+ }
10898
+ function resolveJsPath(callerAbsPath, specifier) {
10899
+ if (!isRelativeSpecifier(specifier)) return null;
10900
+ const dir = path3.dirname(callerAbsPath);
10901
+ const base = path3.resolve(dir, specifier);
10902
+ if (JS_EXTENSION_PROBES.includes(path3.extname(specifier))) {
10903
+ return isFile(base) ? base : null;
10904
+ }
10905
+ if (isFile(base)) return base;
10906
+ for (const ext of JS_EXTENSION_PROBES) {
10907
+ const candidate = base + ext;
10908
+ if (isFile(candidate)) return candidate;
10909
+ }
10910
+ for (const ext of JS_EXTENSION_PROBES) {
10911
+ const candidate = path3.join(base, `index${ext}`);
10912
+ if (isFile(candidate)) return candidate;
10913
+ }
10914
+ return null;
10915
+ }
10916
+ function isFile(p) {
10917
+ try {
10918
+ return statSync(p).isFile();
10919
+ } catch {
10920
+ return false;
10921
+ }
10922
+ }
10923
+ function resolvePythonModule(callerAbsPath, relativePrefix, moduleName) {
10924
+ if (!relativePrefix) return null;
10925
+ const dots = relativePrefix.length;
10926
+ const levelsUp = dots - 1;
10927
+ let baseDir = path3.dirname(callerAbsPath);
10928
+ for (let i2 = 0; i2 < levelsUp; i2++) {
10929
+ baseDir = path3.dirname(baseDir);
10930
+ }
10931
+ if (!moduleName) {
10932
+ const init2 = path3.join(baseDir, "__init__.py");
10933
+ return isFile(init2) ? init2 : null;
10934
+ }
10935
+ const parts2 = moduleName.split(".");
10936
+ const joined = path3.join(baseDir, ...parts2);
10937
+ for (const ext of PY_EXTENSION_PROBES) {
10938
+ const candidate = joined + ext;
10939
+ if (isFile(candidate)) return candidate;
10940
+ }
10941
+ const pkgInit = path3.join(joined, "__init__.py");
10942
+ if (isFile(pkgInit)) return pkgInit;
10943
+ return null;
10944
+ }
10945
+ async function findImports(pm, source, languageId, callerAbsPath) {
10946
+ const ready = await pm.ensureReady(languageId);
10947
+ if (!ready) return [];
10948
+ const { lang, family } = ready;
10949
+ if (!family.queries.imports) return [];
10950
+ const tree = pm.parse(source, lang);
10951
+ if (!tree) return [];
10952
+ const query2 = pm.getQuery(lang, family.queries.imports);
10953
+ if (!query2) return [];
10954
+ const edges = [];
10955
+ const isPython = languageId === "python";
10956
+ for (const match of query2.matches(tree.rootNode)) {
10957
+ if (isPython) {
10958
+ pushPythonEdge(match.captures, callerAbsPath, edges);
10959
+ } else {
10960
+ pushJsEdge(match.captures, callerAbsPath, edges);
10961
+ }
10962
+ }
10963
+ return dedupe(edges);
10964
+ }
10965
+ function pushJsEdge(captures, callerAbsPath, out2) {
10966
+ const sourceNode = getCapture(captures, "source");
10967
+ if (!sourceNode) return;
10968
+ const specifier = sourceNode.text;
10969
+ if (!isRelativeSpecifier(specifier)) return;
10970
+ const resolvedAbsPath = resolveJsPath(callerAbsPath, specifier);
10971
+ const defaultNode = getCapture(captures, "default_name");
10972
+ if (defaultNode) {
10973
+ out2.push({
10974
+ localName: defaultNode.text,
10975
+ importedName: "default",
10976
+ isDefault: true,
10977
+ resolvedAbsPath
10978
+ });
10979
+ return;
10980
+ }
10981
+ const namespaceNode = getCapture(captures, "namespace_name");
10982
+ if (namespaceNode) {
10983
+ out2.push({
10984
+ localName: namespaceNode.text,
10985
+ importedName: "*",
10986
+ isNamespace: true,
10987
+ resolvedAbsPath
10988
+ });
10989
+ return;
10990
+ }
10991
+ const importedNode = getCapture(captures, "imported_name");
10992
+ if (importedNode) {
10993
+ const localNode = getCapture(captures, "local_name");
10994
+ out2.push({
10995
+ localName: (localNode ?? importedNode).text,
10996
+ importedName: importedNode.text,
10997
+ resolvedAbsPath
10998
+ });
10999
+ }
11000
+ }
11001
+ function pushPythonEdge(captures, callerAbsPath, out2) {
11002
+ const importedNode = getCapture(captures, "imported_name");
11003
+ if (!importedNode) return;
11004
+ const relativePrefix = getCapture(captures, "relative_prefix");
11005
+ const relativeName = getCapture(captures, "relative_name");
11006
+ const sourceNode = getCapture(captures, "source");
11007
+ let resolvedAbsPath = null;
11008
+ if (relativePrefix) {
11009
+ resolvedAbsPath = resolvePythonModule(
11010
+ callerAbsPath,
11011
+ relativePrefix.text,
11012
+ relativeName ? relativeName.text : null
11013
+ );
11014
+ } else if (sourceNode) {
11015
+ resolvedAbsPath = resolvePythonModule(callerAbsPath, ".", sourceNode.text);
11016
+ }
11017
+ const localNode = getCapture(captures, "local_name");
11018
+ out2.push({
11019
+ localName: (localNode ?? importedNode).text,
11020
+ importedName: importedNode.text,
11021
+ resolvedAbsPath
11022
+ });
11023
+ }
11024
+ function dedupe(edges) {
11025
+ const seen = /* @__PURE__ */ new Set();
11026
+ const out2 = [];
11027
+ for (const e of edges) {
11028
+ const key = `${e.localName}|${e.importedName}|${e.resolvedAbsPath ?? ""}|${e.isDefault ? "d" : ""}|${e.isNamespace ? "n" : ""}`;
11029
+ if (seen.has(key)) continue;
11030
+ seen.add(key);
11031
+ out2.push(e);
11032
+ }
11033
+ return out2;
11034
+ }
10647
11035
  var noop = {
10648
11036
  warn() {
10649
11037
  }
@@ -10659,17 +11047,18 @@ var DEFAULT_CONFIG = {
10659
11047
  };
10660
11048
  function resolveGrammarsDir() {
10661
11049
  const thisFile = fileURLToPath(import.meta.url);
10662
- const dir = path3.dirname(thisFile);
11050
+ const dir = path22.dirname(thisFile);
10663
11051
  const candidates = [
10664
- path3.join(dir, "..", "grammars"),
10665
- path3.join(dir, "grammars"),
10666
- path3.join(dir, "..", "..", "grammars")
11052
+ path22.join(dir, "..", "grammars"),
11053
+ path22.join(dir, "grammars"),
11054
+ path22.join(dir, "..", "..", "grammars")
10667
11055
  ];
10668
11056
  return candidates.find((p) => existsSync(p)) ?? candidates[0];
10669
11057
  }
10670
11058
  var ParserManager = class {
10671
11059
  parser = null;
10672
11060
  languages = /* @__PURE__ */ new Map();
11061
+ languageKeys = /* @__PURE__ */ new WeakMap();
10673
11062
  queryCache = /* @__PURE__ */ new Map();
10674
11063
  maxCacheSize = 256;
10675
11064
  initPromise = null;
@@ -10688,7 +11077,7 @@ var ParserManager = class {
10688
11077
  async doInit() {
10689
11078
  try {
10690
11079
  await import_web_tree_sitter.default.init({
10691
- locateFile: (scriptName) => path3.join(this.wasmDir, scriptName)
11080
+ locateFile: (scriptName) => path22.join(this.wasmDir, scriptName)
10692
11081
  });
10693
11082
  this.parser = new import_web_tree_sitter.default();
10694
11083
  } catch (err2) {
@@ -10715,9 +11104,10 @@ var ParserManager = class {
10715
11104
  let lang = this.languages.get(family.wasm);
10716
11105
  if (!lang) {
10717
11106
  try {
10718
- const wasmPath = path3.join(this.wasmDir, family.wasm);
11107
+ const wasmPath = path22.join(this.wasmDir, family.wasm);
10719
11108
  lang = await import_web_tree_sitter.default.Language.load(wasmPath);
10720
11109
  this.languages.set(family.wasm, lang);
11110
+ this.languageKeys.set(lang, family.wasm);
10721
11111
  } catch (err2) {
10722
11112
  warn(`Failed to load grammar ${family.wasm}`, err2);
10723
11113
  return null;
@@ -10736,7 +11126,8 @@ var ParserManager = class {
10736
11126
  if (!queryStr.trim()) {
10737
11127
  return null;
10738
11128
  }
10739
- const cacheKey = `${lang.toString()}:${queryStr}`;
11129
+ const langKey = this.languageKeys.get(lang) ?? lang.toString();
11130
+ const cacheKey = `${langKey}:${queryStr}`;
10740
11131
  let query2 = this.queryCache.get(cacheKey);
10741
11132
  if (query2) {
10742
11133
  this.queryCache.delete(cacheKey);
@@ -10763,6 +11154,7 @@ var ParserManager = class {
10763
11154
  this.parser = null;
10764
11155
  this.initPromise = null;
10765
11156
  this.languages.clear();
11157
+ this.languageKeys = /* @__PURE__ */ new WeakMap();
10766
11158
  this.queryCache.clear();
10767
11159
  }
10768
11160
  };
@@ -11577,6 +11969,260 @@ function isTruthinessCheckForVar(conditionNode, varName) {
11577
11969
  }
11578
11970
  return false;
11579
11971
  }
11972
+ var CONTROL_FLOW_KEYWORDS = /* @__PURE__ */ new Set([
11973
+ "if",
11974
+ "for",
11975
+ "while",
11976
+ "switch",
11977
+ "catch",
11978
+ "else"
11979
+ ]);
11980
+ function getKeyArgLocator(method, family, languageId) {
11981
+ if (languageId === "python") {
11982
+ if (family.captureMethods.has(method)) {
11983
+ return { positionalIndex: 1, kwargName: "event" };
11984
+ }
11985
+ if (family.flagMethods.has(method)) {
11986
+ return { positionalIndex: 0, kwargName: "key" };
11987
+ }
11988
+ return null;
11989
+ }
11990
+ if (family.allMethods.has(method)) {
11991
+ return { positionalIndex: 0 };
11992
+ }
11993
+ return null;
11994
+ }
11995
+ function extractRawParams(paramsNode, singleParamNode, languageId) {
11996
+ if (singleParamNode) {
11997
+ return [singleParamNode.text];
11998
+ }
11999
+ if (!paramsNode) {
12000
+ return [];
12001
+ }
12002
+ const names = [];
12003
+ for (const child of paramsNode.namedChildren) {
12004
+ const n = extractParamName(child, languageId);
12005
+ if (n) {
12006
+ names.push(n);
12007
+ } else {
12008
+ names.push("");
12009
+ }
12010
+ }
12011
+ return names;
12012
+ }
12013
+ function extractParamName(node, languageId) {
12014
+ switch (node.type) {
12015
+ case "identifier":
12016
+ return node.text;
12017
+ case "required_parameter":
12018
+ case "optional_parameter": {
12019
+ const pat = node.childForFieldName("pattern");
12020
+ if (pat) return extractParamName(pat, languageId);
12021
+ const name2 = node.childForFieldName("name");
12022
+ if (name2) return extractParamName(name2, languageId);
12023
+ const id = node.namedChildren.find((c) => c.type === "identifier");
12024
+ return id?.text ?? null;
12025
+ }
12026
+ case "assignment_pattern": {
12027
+ const left = node.childForFieldName("left");
12028
+ return left ? extractParamName(left, languageId) : null;
12029
+ }
12030
+ case "typed_parameter":
12031
+ case "default_parameter":
12032
+ case "typed_default_parameter": {
12033
+ const name2 = node.childForFieldName("name");
12034
+ if (name2) return extractParamName(name2, languageId);
12035
+ const id = node.namedChildren.find((c) => c.type === "identifier");
12036
+ return id?.text ?? null;
12037
+ }
12038
+ case "parameter": {
12039
+ const id = node.namedChildren.find(
12040
+ (c) => c.type === "identifier" || c.type === "field_identifier"
12041
+ );
12042
+ return id?.text ?? null;
12043
+ }
12044
+ default: {
12045
+ const id = node.namedChildren.find((c) => c.type === "identifier");
12046
+ return id?.text ?? null;
12047
+ }
12048
+ }
12049
+ }
12050
+ function findPostHogCallInBody(body2, allClients, family, languageId, detectNested) {
12051
+ let found = null;
12052
+ const visit = (node) => {
12053
+ if (found) return;
12054
+ const call = matchPostHogCall(
12055
+ node,
12056
+ allClients,
12057
+ family,
12058
+ languageId,
12059
+ detectNested
12060
+ );
12061
+ if (call) {
12062
+ found = call;
12063
+ return;
12064
+ }
12065
+ for (const child of node.namedChildren) {
12066
+ if (found) return;
12067
+ visit(child);
12068
+ }
12069
+ };
12070
+ visit(body2);
12071
+ return found;
12072
+ }
12073
+ function matchPostHogCall(node, allClients, family, languageId, detectNested) {
12074
+ if (node.type !== "call_expression" && node.type !== "call") return null;
12075
+ const funcNode = node.childForFieldName("function");
12076
+ if (!funcNode) return null;
12077
+ let method = null;
12078
+ if (funcNode.type === "member_expression" || funcNode.type === "attribute") {
12079
+ const objNode = funcNode.childForFieldName("object") || funcNode.childForFieldName("operand");
12080
+ const propNode = funcNode.childForFieldName("property") || funcNode.childForFieldName("attribute");
12081
+ if (!objNode || !propNode) return null;
12082
+ const clientName = extractClientName(objNode, detectNested);
12083
+ if (!clientName || !allClients.has(clientName)) return null;
12084
+ method = propNode.text;
12085
+ } else if (funcNode.type === "selector_expression") {
12086
+ const opNode = funcNode.childForFieldName("operand");
12087
+ const fieldNode = funcNode.childForFieldName("field");
12088
+ if (!opNode || !fieldNode) return null;
12089
+ const clientName = extractClientName(opNode, detectNested);
12090
+ if (!clientName || !allClients.has(clientName)) return null;
12091
+ method = fieldNode.text;
12092
+ } else {
12093
+ return null;
12094
+ }
12095
+ if (!method || !family.allMethods.has(method)) return null;
12096
+ const locator = getKeyArgLocator(method, family, languageId);
12097
+ if (!locator) return null;
12098
+ const argsNode = node.childForFieldName("arguments") || node.namedChildren.find(
12099
+ (c) => c.type === "arguments" || c.type === "argument_list"
12100
+ ) || null;
12101
+ if (!argsNode) return null;
12102
+ const { keyNode, kwargName } = pickKeyArg(argsNode, locator);
12103
+ return {
12104
+ method,
12105
+ keyArgNode: keyNode,
12106
+ kwargName
12107
+ };
12108
+ }
12109
+ function pickKeyArg(argsNode, locator) {
12110
+ const positional = [];
12111
+ let kwargHit = null;
12112
+ let kwargName = null;
12113
+ for (const child of argsNode.namedChildren) {
12114
+ if (child.type === "keyword_argument") {
12115
+ const nameNode = child.childForFieldName("name");
12116
+ const valueNode = child.childForFieldName("value");
12117
+ if (nameNode && valueNode && locator.kwargName && nameNode.text === locator.kwargName) {
12118
+ kwargHit = valueNode;
12119
+ kwargName = nameNode.text;
12120
+ }
12121
+ continue;
12122
+ }
12123
+ positional.push(child);
12124
+ }
12125
+ if (kwargHit) {
12126
+ return { keyNode: kwargHit, kwargName };
12127
+ }
12128
+ const positionalHit = positional[locator.positionalIndex] ?? null;
12129
+ return { keyNode: positionalHit, kwargName: null };
12130
+ }
12131
+ function classifyKeyArg(keyArgNode, params) {
12132
+ if (!keyArgNode) return null;
12133
+ if (keyArgNode.type === "string" || keyArgNode.type === "interpreted_string_literal") {
12134
+ const key = extractStringFromNode(keyArgNode);
12135
+ return key !== null ? { kind: "fixed-key", key } : null;
12136
+ }
12137
+ if (keyArgNode.type === "template_string") {
12138
+ const hasInterpolation = keyArgNode.namedChildren.some(
12139
+ (c) => c.type === "template_substitution"
12140
+ );
12141
+ if (hasInterpolation) return null;
12142
+ const key = extractStringFromNode(keyArgNode);
12143
+ return key !== null ? { kind: "fixed-key", key } : null;
12144
+ }
12145
+ if (keyArgNode.type === "identifier") {
12146
+ const idx = params.indexOf(keyArgNode.text);
12147
+ if (idx >= 0) return { kind: "pass-through", paramIndex: idx };
12148
+ return null;
12149
+ }
12150
+ return null;
12151
+ }
12152
+ function getExportStatus(nameNode, languageId) {
12153
+ const defNode = nameNode.parent;
12154
+ if (!defNode) return { isDefaultExport: false, isNamedExport: false };
12155
+ if (languageId === "python") {
12156
+ let cur2 = defNode.parent;
12157
+ while (cur2) {
12158
+ if (cur2.type === "module") {
12159
+ return { isDefaultExport: false, isNamedExport: true };
12160
+ }
12161
+ if (cur2.type === "function_definition" || cur2.type === "class_definition") {
12162
+ return { isDefaultExport: false, isNamedExport: false };
12163
+ }
12164
+ cur2 = cur2.parent;
12165
+ }
12166
+ return { isDefaultExport: false, isNamedExport: false };
12167
+ }
12168
+ let cur = defNode.parent;
12169
+ while (cur) {
12170
+ if (cur.type === "export_statement") {
12171
+ const hasDefault = cur.children.some((c) => c.type === "default");
12172
+ return { isDefaultExport: hasDefault, isNamedExport: !hasDefault };
12173
+ }
12174
+ if (cur.type === "program" || cur.type === "module") break;
12175
+ cur = cur.parent;
12176
+ }
12177
+ return { isDefaultExport: false, isNamedExport: false };
12178
+ }
12179
+ async function findWrappers(pm, source, languageId) {
12180
+ const ready = await pm.ensureReady(languageId);
12181
+ if (!ready) return [];
12182
+ const { lang, family } = ready;
12183
+ const tree = pm.parse(source, lang);
12184
+ if (!tree) return [];
12185
+ const functionQuery = pm.getQuery(lang, family.queries.functions);
12186
+ if (!functionQuery) return [];
12187
+ const allClients = getEffectiveClients(pm.config);
12188
+ const { clientAliases } = findAliases(pm, lang, tree, family);
12189
+ for (const a of clientAliases) allClients.add(a);
12190
+ const wrappers = [];
12191
+ const seen = /* @__PURE__ */ new Set();
12192
+ for (const match of functionQuery.matches(tree.rootNode)) {
12193
+ const nameNode = getCapture(match.captures, "func_name");
12194
+ const paramsNode = getCapture(match.captures, "func_params");
12195
+ const singleParamNode = getCapture(match.captures, "func_single_param");
12196
+ const bodyNode = getCapture(match.captures, "func_body");
12197
+ if (!nameNode || !bodyNode) continue;
12198
+ const name2 = nameNode.text;
12199
+ if (CONTROL_FLOW_KEYWORDS.has(name2)) continue;
12200
+ if (seen.has(name2)) continue;
12201
+ const params = extractRawParams(paramsNode, singleParamNode, languageId);
12202
+ const call = findPostHogCallInBody(
12203
+ bodyNode,
12204
+ allClients,
12205
+ family,
12206
+ languageId,
12207
+ pm.config.detectNestedClients
12208
+ );
12209
+ if (!call) continue;
12210
+ const classification = classifyKeyArg(call.keyArgNode, params);
12211
+ if (!classification) continue;
12212
+ const methodKind = family.captureMethods.has(call.method) ? "capture" : "flag";
12213
+ const posthogMethod = call.method === "Enqueue" ? "capture" : call.method;
12214
+ const exportStatus = getExportStatus(nameNode, languageId);
12215
+ seen.add(name2);
12216
+ wrappers.push({
12217
+ name: name2,
12218
+ methodKind,
12219
+ posthogMethod,
12220
+ classification,
12221
+ ...exportStatus
12222
+ });
12223
+ }
12224
+ return wrappers;
12225
+ }
11580
12226
  var PostHogDetector = class {
11581
12227
  pm = new ParserManager();
11582
12228
  updateConfig(config) {
@@ -11588,8 +12234,8 @@ var PostHogDetector = class {
11588
12234
  get supportedLanguages() {
11589
12235
  return this.pm.supportedLanguages;
11590
12236
  }
11591
- async findPostHogCalls(source, languageId) {
11592
- return findPostHogCalls(this.pm, source, languageId);
12237
+ async findPostHogCalls(source, languageId, context) {
12238
+ return findPostHogCalls(this.pm, source, languageId, context);
11593
12239
  }
11594
12240
  async findInitCalls(source, languageId) {
11595
12241
  return findInitCalls(this.pm, source, languageId);
@@ -11603,6 +12249,12 @@ var PostHogDetector = class {
11603
12249
  async findFlagAssignments(source, languageId) {
11604
12250
  return findFlagAssignments(this.pm, source, languageId);
11605
12251
  }
12252
+ async findWrappers(source, languageId) {
12253
+ return findWrappers(this.pm, source, languageId);
12254
+ }
12255
+ async findImports(source, languageId, callerAbsPath) {
12256
+ return findImports(this.pm, source, languageId, callerAbsPath);
12257
+ }
11606
12258
  dispose() {
11607
12259
  this.pm.dispose();
11608
12260
  }
@@ -11707,18 +12359,32 @@ function commentPrefix(languageId) {
11707
12359
  }
11708
12360
  function formatFlagComment(flag) {
11709
12361
  const parts2 = [`Flag: "${flag.flagKey}"`];
11710
- if (flag.flag) {
11711
- parts2.push(flag.flagType);
11712
- if (flag.rollout !== null) {
11713
- parts2.push(`${flag.rollout}% rolled out`);
11714
- }
11715
- if (flag.experiment) {
11716
- const status = flag.experiment.end_date ? "complete" : "running";
11717
- parts2.push(`Experiment: "${flag.experiment.name}" (${status})`);
11718
- }
11719
- if (flag.staleness) {
11720
- parts2.push(`STALE (${flag.staleness})`);
11721
- }
12362
+ if (!flag.flag) {
12363
+ parts2.push("not in PostHog");
12364
+ return parts2.join(" \u2014 ");
12365
+ }
12366
+ parts2.push(flag.flagType);
12367
+ parts2.push(flag.flag.active ? "active" : "inactive");
12368
+ if (flag.rollout !== null) {
12369
+ parts2.push(`${flag.rollout}% rolled out`);
12370
+ }
12371
+ if (flag.evaluationStats) {
12372
+ const evals = flag.evaluationStats.evaluations.toLocaleString();
12373
+ const users = flag.evaluationStats.uniqueUsers.toLocaleString();
12374
+ const days = flag.evaluationStats.windowDays;
12375
+ parts2.push(`${evals} evals / ${users} users (${days}d)`);
12376
+ } else if (flag.evaluationStatsError) {
12377
+ parts2.push("eval stats unavailable");
12378
+ }
12379
+ if (flag.experiment) {
12380
+ const status = flag.experiment.end_date ? "complete" : "running";
12381
+ parts2.push(`Experiment: "${flag.experiment.name}" (${status})`);
12382
+ }
12383
+ if (flag.staleness) {
12384
+ parts2.push(`STALE (${flag.staleness})`);
12385
+ }
12386
+ if (flag.url) {
12387
+ parts2.push(flag.url);
11722
12388
  }
11723
12389
  return parts2.join(" \u2014 ");
11724
12390
  }
@@ -11739,21 +12405,25 @@ function formatEventComment(event) {
11739
12405
  return parts2.join(" \u2014 ");
11740
12406
  }
11741
12407
  function buildCommentBody(item, enrichedFlags, enrichedEvents) {
12408
+ let body2 = null;
11742
12409
  if (item.type === "flag") {
11743
12410
  const flag = enrichedFlags.get(item.name);
11744
- if (flag) return formatFlagComment(flag);
11745
- return null;
11746
- }
11747
- if (item.type === "event") {
12411
+ body2 = flag ? formatFlagComment(flag) : null;
12412
+ } else if (item.type === "event") {
11748
12413
  const event = enrichedEvents.get(item.name);
11749
- if (event) return formatEventComment(event);
11750
- if (item.detail) return `Event: ${item.detail}`;
11751
- return null;
12414
+ if (event) {
12415
+ body2 = formatEventComment(event);
12416
+ } else if (item.detail) {
12417
+ body2 = `Event: ${item.detail}`;
12418
+ }
12419
+ } else if (item.type === "init") {
12420
+ body2 = `Init: token "${item.name}"`;
11752
12421
  }
11753
- if (item.type === "init") {
11754
- return `Init: token "${item.name}"`;
12422
+ if (!body2) return null;
12423
+ if (item.viaWrapper) {
12424
+ body2 = `${body2} (via ${item.viaWrapper})`;
11755
12425
  }
11756
- return null;
12426
+ return body2;
11757
12427
  }
11758
12428
  function formatComments(source, languageId, items, enrichedFlags, enrichedEvents) {
11759
12429
  const prefix = commentPrefix(languageId);
@@ -11764,7 +12434,7 @@ function formatComments(source, languageId, items, enrichedFlags, enrichedEvents
11764
12434
  const targetLine = item.line + offset;
11765
12435
  const body2 = buildCommentBody(item, enrichedFlags, enrichedEvents);
11766
12436
  if (!body2) continue;
11767
- const comment = `${prefix} [PostHog] ${body2}`;
12437
+ const comment = item.inJsx ? `{/* [PostHog] ${body2} */}` : `${prefix} [PostHog] ${body2}`;
11768
12438
  const indent = lines[targetLine]?.match(/^(\s*)/)?.[1] ?? "";
11769
12439
  lines.splice(targetLine, 0, `${indent}${comment}`);
11770
12440
  offset++;
@@ -11778,15 +12448,32 @@ function formatInlineComments(source, languageId, items, enrichedFlags, enriched
11778
12448
  for (const item of items) {
11779
12449
  const body2 = buildCommentBody(item, enrichedFlags, enrichedEvents);
11780
12450
  if (!body2) continue;
11781
- const arr = byLine.get(item.line) ?? [];
11782
- arr.push(body2);
11783
- byLine.set(item.line, arr);
12451
+ const entry = byLine.get(item.line) ?? { jsxBodies: [], nonJsxBodies: [] };
12452
+ (item.inJsx ? entry.jsxBodies : entry.nonJsxBodies).push(body2);
12453
+ byLine.set(item.line, entry);
11784
12454
  }
11785
- for (const [lineIdx, bodies] of byLine) {
12455
+ const leadingInserts = [];
12456
+ for (const [lineIdx, { jsxBodies, nonJsxBodies }] of byLine) {
11786
12457
  if (lineIdx < 0 || lineIdx >= lines.length) continue;
11787
- const suffix = ` ${prefix} [PostHog] ${bodies.join(" | ")}`;
12458
+ if (jsxBodies.length > 0 && nonJsxBodies.length > 0) {
12459
+ const joined2 = [...nonJsxBodies, ...jsxBodies].join(" | ");
12460
+ const indent = lines[lineIdx]?.match(/^(\s*)/)?.[1] ?? "";
12461
+ leadingInserts.push({
12462
+ atLine: lineIdx,
12463
+ text: `${indent}{/* [PostHog] ${joined2} */}`
12464
+ });
12465
+ continue;
12466
+ }
12467
+ const isJsx = jsxBodies.length > 0;
12468
+ const bodies = isJsx ? jsxBodies : nonJsxBodies;
12469
+ const joined = bodies.join(" | ");
12470
+ const suffix = isJsx ? ` {/* [PostHog] ${joined} */}` : ` ${prefix} [PostHog] ${joined}`;
11788
12471
  lines[lineIdx] = `${lines[lineIdx]}${suffix}`;
11789
12472
  }
12473
+ leadingInserts.sort((a, b) => b.atLine - a.atLine);
12474
+ for (const { atLine, text: text2 } of leadingInserts) {
12475
+ lines.splice(atLine, 0, text2);
12476
+ }
11790
12477
  return lines.join("\n");
11791
12478
  }
11792
12479
  var EnrichedResult = class {
@@ -11809,6 +12496,7 @@ var EnrichedResult = class {
11809
12496
  let entry = flagMap.get(check.flagKey);
11810
12497
  if (!entry) {
11811
12498
  const flag = this.context.flags?.get(check.flagKey);
12499
+ const url = this.context.flagUrls?.get(check.flagKey) ?? null;
11812
12500
  entry = {
11813
12501
  flagKey: check.flagKey,
11814
12502
  occurrences: [],
@@ -11824,7 +12512,10 @@ var EnrichedResult = class {
11824
12512
  variants: flag ? extractVariants(flag) : [],
11825
12513
  experiment: experiments.find(
11826
12514
  (e) => e.feature_flag_key === check.flagKey
11827
- )
12515
+ ),
12516
+ url,
12517
+ evaluationStats: this.context.flagEvaluationStats?.get(check.flagKey),
12518
+ evaluationStatsError: this.context.flagEvaluationStatsError ?? false
11828
12519
  };
11829
12520
  flagMap.set(check.flagKey, entry);
11830
12521
  }
@@ -11882,6 +12573,10 @@ var EnrichedResult = class {
11882
12573
  enriched.flagType = flag.flagType;
11883
12574
  enriched.staleness = flag.staleness;
11884
12575
  enriched.rollout = flag.rollout;
12576
+ enriched.active = flag.flag?.active;
12577
+ enriched.url = flag.url;
12578
+ enriched.evaluations = flag.evaluationStats?.evaluations;
12579
+ enriched.evaluationUsers = flag.evaluationStats?.uniqueUsers;
11885
12580
  if (flag.experiment) {
11886
12581
  enriched.experimentName = flag.experiment.name;
11887
12582
  enriched.experimentStatus = flag.experiment.end_date ? "complete" : "running";
@@ -11948,8 +12643,8 @@ var PostHogApi = class {
11948
12643
  get signal() {
11949
12644
  return AbortSignal.timeout(this.config.timeoutMs ?? 1e4);
11950
12645
  }
11951
- async get(path32) {
11952
- const res = await fetch(`${this.baseUrl}${path32}`, {
12646
+ async get(path42) {
12647
+ const res = await fetch(`${this.baseUrl}${path42}`, {
11953
12648
  headers: {
11954
12649
  Authorization: `Bearer ${this.config.apiKey}`,
11955
12650
  "Content-Type": "application/json"
@@ -11958,13 +12653,13 @@ var PostHogApi = class {
11958
12653
  });
11959
12654
  if (!res.ok) {
11960
12655
  throw new Error(
11961
- `PostHog API error: ${res.status} ${res.statusText} on GET ${path32}`
12656
+ `PostHog API error: ${res.status} ${res.statusText} on GET ${path42}`
11962
12657
  );
11963
12658
  }
11964
12659
  return res.json();
11965
12660
  }
11966
- async post(path32, body2) {
11967
- const res = await fetch(`${this.baseUrl}${path32}`, {
12661
+ async post(path42, body2) {
12662
+ const res = await fetch(`${this.baseUrl}${path42}`, {
11968
12663
  method: "POST",
11969
12664
  headers: {
11970
12665
  Authorization: `Bearer ${this.config.apiKey}`,
@@ -11975,7 +12670,7 @@ var PostHogApi = class {
11975
12670
  });
11976
12671
  if (!res.ok) {
11977
12672
  throw new Error(
11978
- `PostHog API error: ${res.status} ${res.statusText} on POST ${path32}`
12673
+ `PostHog API error: ${res.status} ${res.statusText} on POST ${path42}`
11979
12674
  );
11980
12675
  }
11981
12676
  return res.json();
@@ -11993,11 +12688,11 @@ var PostHogApi = class {
11993
12688
  return data.results;
11994
12689
  }
11995
12690
  async getEventDefinitions(names) {
11996
- let path32 = "/event_definitions/?limit=500";
12691
+ let path42 = "/event_definitions/?limit=500";
11997
12692
  if (names && names.length > 0) {
11998
- path32 += `&search=${encodeURIComponent(names.join(","))}`;
12693
+ path42 += `&search=${encodeURIComponent(names.join(","))}`;
11999
12694
  }
12000
- const data = await this.get(path32);
12695
+ const data = await this.get(path42);
12001
12696
  return data.results;
12002
12697
  }
12003
12698
  async getEventStats(eventNames, daysBack = 30) {
@@ -12033,6 +12728,35 @@ var PostHogApi = class {
12033
12728
  }
12034
12729
  return stats;
12035
12730
  }
12731
+ async getFlagEvaluationStats(flagKeys, daysBack = 7) {
12732
+ if (flagKeys.length === 0) {
12733
+ return /* @__PURE__ */ new Map();
12734
+ }
12735
+ const days = Math.max(1, Math.min(365, Math.floor(daysBack)));
12736
+ const query2 = `
12737
+ SELECT
12738
+ properties.$feature_flag AS flag_key,
12739
+ count() AS evaluations,
12740
+ count(DISTINCT person_id) AS unique_users
12741
+ FROM events
12742
+ WHERE event = '$feature_flag_called'
12743
+ AND properties.$feature_flag IN {flagKeys}
12744
+ AND timestamp >= now() - INTERVAL ${days} DAY
12745
+ GROUP BY flag_key
12746
+ `;
12747
+ const data = await this.post("/query/", {
12748
+ query: {
12749
+ kind: "HogQLQuery",
12750
+ query: query2,
12751
+ values: { flagKeys }
12752
+ }
12753
+ });
12754
+ const stats = /* @__PURE__ */ new Map();
12755
+ for (const [flagKey, evaluations, uniqueUsers] of data.results) {
12756
+ stats.set(flagKey, { evaluations, uniqueUsers, windowDays: days });
12757
+ }
12758
+ return stats;
12759
+ }
12036
12760
  };
12037
12761
  var CAPTURE_METHODS = /* @__PURE__ */ new Set(["capture", "Enqueue"]);
12038
12762
  var ParseResult = class {
@@ -12056,14 +12780,18 @@ var ParseResult = class {
12056
12780
  return this.calls.filter((c) => CAPTURE_METHODS.has(c.method)).map((c) => ({
12057
12781
  name: c.key,
12058
12782
  line: c.line,
12059
- dynamic: c.dynamic ?? false
12783
+ dynamic: c.dynamic ?? false,
12784
+ viaWrapper: c.viaWrapper,
12785
+ inJsx: c.inJsx
12060
12786
  }));
12061
12787
  }
12062
12788
  get flagChecks() {
12063
12789
  return this.calls.filter((c) => !CAPTURE_METHODS.has(c.method)).map((c) => ({
12064
12790
  method: c.method,
12065
12791
  flagKey: c.key,
12066
- line: c.line
12792
+ line: c.line,
12793
+ viaWrapper: c.viaWrapper,
12794
+ inJsx: c.inJsx
12067
12795
  }));
12068
12796
  }
12069
12797
  get flagKeys() {
@@ -12091,7 +12819,9 @@ var ParseResult = class {
12091
12819
  line: call.line,
12092
12820
  name: call.key,
12093
12821
  method: call.method,
12094
- detail: call.dynamic ? "dynamic event name" : void 0
12822
+ detail: call.dynamic ? "dynamic event name" : void 0,
12823
+ viaWrapper: call.viaWrapper,
12824
+ inJsx: call.inJsx
12095
12825
  });
12096
12826
  }
12097
12827
  return items.sort((a, b) => a.line - b.line);
@@ -12104,14 +12834,22 @@ var ParseResult = class {
12104
12834
  flagKeys.length > 0 ? api.getFeatureFlags() : Promise.resolve([]),
12105
12835
  flagKeys.length > 0 ? api.getExperiments() : Promise.resolve([]),
12106
12836
  eventNames.length > 0 ? api.getEventDefinitions(eventNames) : Promise.resolve([]),
12107
- eventNames.length > 0 ? api.getEventStats(eventNames) : Promise.resolve(/* @__PURE__ */ new Map())
12837
+ eventNames.length > 0 ? api.getEventStats(eventNames) : Promise.resolve(/* @__PURE__ */ new Map()),
12838
+ flagKeys.length > 0 ? api.getFlagEvaluationStats(flagKeys, 7) : Promise.resolve(/* @__PURE__ */ new Map())
12108
12839
  ]);
12109
- const [flagsResult, experimentsResult, eventDefsResult, eventStatsResult] = settled;
12840
+ const [
12841
+ flagsResult,
12842
+ experimentsResult,
12843
+ eventDefsResult,
12844
+ eventStatsResult,
12845
+ flagEvalStatsResult
12846
+ ] = settled;
12110
12847
  const labels = [
12111
12848
  "getFeatureFlags",
12112
12849
  "getExperiments",
12113
12850
  "getEventDefinitions",
12114
- "getEventStats"
12851
+ "getEventStats",
12852
+ "getFlagEvaluationStats"
12115
12853
  ];
12116
12854
  settled.forEach((r, i2) => {
12117
12855
  if (r.status === "rejected") {
@@ -12122,6 +12860,8 @@ var ParseResult = class {
12122
12860
  const allExperiments = experimentsResult.status === "fulfilled" ? experimentsResult.value : [];
12123
12861
  const allEventDefs = eventDefsResult.status === "fulfilled" ? eventDefsResult.value : [];
12124
12862
  const eventStats = eventStatsResult.status === "fulfilled" ? eventStatsResult.value : /* @__PURE__ */ new Map();
12863
+ const flagEvaluationStats = flagEvalStatsResult.status === "fulfilled" ? flagEvalStatsResult.value : /* @__PURE__ */ new Map();
12864
+ const flagEvaluationStatsError = flagEvalStatsResult.status === "rejected";
12125
12865
  const flagKeySet = new Set(flagKeys);
12126
12866
  const flags2 = new Map(
12127
12867
  allFlags.filter((f) => flagKeySet.has(f.key)).map((f) => [f.key, f])
@@ -12132,18 +12872,34 @@ var ParseResult = class {
12132
12872
  const eventDefinitions = new Map(
12133
12873
  allEventDefs.filter((d) => eventNames.includes(d.name)).map((d) => [d.name, d])
12134
12874
  );
12875
+ const host = config.host.replace(/\/$/, "");
12876
+ const flagUrls = /* @__PURE__ */ new Map();
12877
+ for (const [key, flag] of flags2) {
12878
+ flagUrls.set(
12879
+ key,
12880
+ `${host}/project/${config.projectId}/feature_flags/${flag.id}`
12881
+ );
12882
+ }
12135
12883
  return new EnrichedResult(this, {
12136
12884
  flags: flags2,
12137
12885
  experiments,
12138
12886
  eventDefinitions,
12139
- eventStats
12887
+ eventStats,
12888
+ flagEvaluationStats,
12889
+ flagEvaluationStatsError,
12890
+ flagUrls
12140
12891
  });
12141
12892
  }
12142
12893
  };
12894
+ var MAX_WRAPPER_SOURCE_BYTES = 1e6;
12895
+ var WRAPPER_CACHE_MAX = 1024;
12896
+ var POSTHOG_LITERAL_REGEX = /posthog/i;
12143
12897
  var PostHogEnricher = class {
12144
12898
  detector = new PostHogDetector();
12899
+ wrapperCache = /* @__PURE__ */ new Map();
12145
12900
  updateConfig(config) {
12146
12901
  this.detector.updateConfig(config);
12902
+ this.wrapperCache.clear();
12147
12903
  }
12148
12904
  isSupported(langId) {
12149
12905
  return this.detector.isSupported(langId);
@@ -12151,9 +12907,9 @@ var PostHogEnricher = class {
12151
12907
  get supportedLanguages() {
12152
12908
  return this.detector.supportedLanguages;
12153
12909
  }
12154
- async parse(source, languageId) {
12910
+ async parse(source, languageId, context) {
12155
12911
  const results = await Promise.allSettled([
12156
- this.detector.findPostHogCalls(source, languageId),
12912
+ this.detector.findPostHogCalls(source, languageId, context),
12157
12913
  this.detector.findInitCalls(source, languageId),
12158
12914
  this.detector.findFlagAssignments(source, languageId),
12159
12915
  this.detector.findVariantBranches(source, languageId),
@@ -12184,7 +12940,7 @@ var PostHogEnricher = class {
12184
12940
  );
12185
12941
  }
12186
12942
  async parseFile(filePath) {
12187
- const ext = path22.extname(filePath).toLowerCase();
12943
+ const ext = path32.extname(filePath).toLowerCase();
12188
12944
  const languageId = EXT_TO_LANG_ID[ext];
12189
12945
  if (!languageId) {
12190
12946
  throw new Error(`Unsupported file extension: ${ext}`);
@@ -12192,8 +12948,70 @@ var PostHogEnricher = class {
12192
12948
  const source = await fs4.readFile(filePath, "utf-8");
12193
12949
  return this.parse(source, languageId);
12194
12950
  }
12951
+ /**
12952
+ * Parse a file for wrapper definitions (functions that directly call PostHog SDK methods).
12953
+ * Results are cached per absolute path + mtime so subsequent calls within the same session
12954
+ * are cheap. Returns [] for unsupported extensions, unreadable files, or files larger than
12955
+ * `MAX_WRAPPER_SOURCE_BYTES`.
12956
+ */
12957
+ async getWrappersForFile(absPath) {
12958
+ const ext = path32.extname(absPath).toLowerCase();
12959
+ const languageId = EXT_TO_LANG_ID[ext];
12960
+ if (!languageId || !this.isSupported(languageId)) {
12961
+ return this.setWrapperCache(absPath, 0, []);
12962
+ }
12963
+ let mtimeMs = 0;
12964
+ try {
12965
+ const stat2 = await fs4.stat(absPath);
12966
+ mtimeMs = stat2.mtimeMs;
12967
+ if (stat2.size > MAX_WRAPPER_SOURCE_BYTES) {
12968
+ return this.setWrapperCache(absPath, mtimeMs, []);
12969
+ }
12970
+ } catch {
12971
+ return this.setWrapperCache(absPath, 0, []);
12972
+ }
12973
+ const cached = this.wrapperCache.get(absPath);
12974
+ if (cached && cached.mtimeMs === mtimeMs) {
12975
+ this.touchCache(absPath);
12976
+ return cached.wrappers;
12977
+ }
12978
+ let source;
12979
+ try {
12980
+ source = await fs4.readFile(absPath, "utf-8");
12981
+ } catch {
12982
+ return this.setWrapperCache(absPath, mtimeMs, []);
12983
+ }
12984
+ if (!POSTHOG_LITERAL_REGEX.test(source)) {
12985
+ return this.setWrapperCache(absPath, mtimeMs, []);
12986
+ }
12987
+ const wrappers = await this.detector.findWrappers(source, languageId);
12988
+ return this.setWrapperCache(absPath, mtimeMs, wrappers);
12989
+ }
12990
+ async findImportsInSource(source, languageId, callerAbsPath) {
12991
+ return this.detector.findImports(source, languageId, callerAbsPath);
12992
+ }
12993
+ clearWrapperCache() {
12994
+ this.wrapperCache.clear();
12995
+ }
12195
12996
  dispose() {
12196
12997
  this.detector.dispose();
12998
+ this.wrapperCache.clear();
12999
+ }
13000
+ setWrapperCache(absPath, mtimeMs, wrappers) {
13001
+ if (this.wrapperCache.size >= WRAPPER_CACHE_MAX) {
13002
+ const oldest = this.wrapperCache.keys().next().value;
13003
+ if (oldest !== void 0) {
13004
+ this.wrapperCache.delete(oldest);
13005
+ }
13006
+ }
13007
+ this.wrapperCache.set(absPath, { mtimeMs, wrappers });
13008
+ return wrappers;
13009
+ }
13010
+ touchCache(absPath) {
13011
+ const entry = this.wrapperCache.get(absPath);
13012
+ if (!entry) return;
13013
+ this.wrapperCache.delete(absPath);
13014
+ this.wrapperCache.set(absPath, entry);
12197
13015
  }
12198
13016
  };
12199
13017
 
@@ -12207,14 +13025,25 @@ function createEnrichment(apiConfig, logger) {
12207
13025
  };
12208
13026
  }
12209
13027
  var MAX_ENRICHMENT_BYTES = 1e6;
13028
+ var MAX_RELATIVE_IMPORTS = 64;
13029
+ var RELATIVE_IMPORT_REGEX = /(?:^|\n)\s*(?:import\b[^\n]*['"]\.{1,2}\/|from\s+\.)/;
13030
+ var POSTHOG_LITERAL_REGEX2 = /posthog/i;
12210
13031
  async function enrichFileForAgent(deps, filePath, content) {
12211
13032
  if (!content || content.length > MAX_ENRICHMENT_BYTES) return null;
12212
- if (!/posthog/i.test(content)) return null;
12213
13033
  const ext = path4.extname(filePath).toLowerCase();
12214
13034
  const langId = EXT_TO_LANG_ID[ext];
12215
13035
  if (!langId || !deps.enricher.isSupported(langId)) return null;
13036
+ const hasPostHogLiteral = POSTHOG_LITERAL_REGEX2.test(content);
13037
+ const hasRelativeImport = RELATIVE_IMPORT_REGEX.test(content);
13038
+ let parseContext;
13039
+ if (hasRelativeImport) {
13040
+ const absPath = path4.resolve(filePath);
13041
+ const ctx = await buildWrapperContext(deps, content, langId, absPath);
13042
+ if (ctx) parseContext = ctx;
13043
+ }
13044
+ if (!hasPostHogLiteral && !parseContext) return null;
12216
13045
  try {
12217
- const parsed = await deps.enricher.parse(content, langId);
13046
+ const parsed = await deps.enricher.parse(content, langId, parseContext);
12218
13047
  if (parsed.calls.length === 0 && parsed.initCalls.length === 0) {
12219
13048
  return null;
12220
13049
  }
@@ -12236,7 +13065,8 @@ async function enrichFileForAgent(deps, filePath, content) {
12236
13065
  }
12237
13066
  deps.logger?.debug("File enriched", {
12238
13067
  filePath,
12239
- calls: parsed.calls.length
13068
+ calls: parsed.calls.length,
13069
+ viaWrappers: parsed.calls.filter((c) => c.viaWrapper).length
12240
13070
  });
12241
13071
  return annotated;
12242
13072
  } catch (err2) {
@@ -12245,11 +13075,62 @@ async function enrichFileForAgent(deps, filePath, content) {
12245
13075
  return null;
12246
13076
  }
12247
13077
  }
13078
+ async function buildWrapperContext(deps, content, langId, absPath) {
13079
+ let edges;
13080
+ try {
13081
+ edges = await deps.enricher.findImportsInSource(content, langId, absPath);
13082
+ } catch (err2) {
13083
+ deps.logger?.debug("Import resolution failed", {
13084
+ absPath,
13085
+ err: err2 instanceof Error ? err2.message : String(err2)
13086
+ });
13087
+ return null;
13088
+ }
13089
+ if (!edges.length) return null;
13090
+ const bounded = edges.slice(0, MAX_RELATIVE_IMPORTS);
13091
+ const wrappersByLocalName = /* @__PURE__ */ new Map();
13092
+ const namespaceWrappers = /* @__PURE__ */ new Map();
13093
+ const resolutions = await Promise.all(
13094
+ bounded.map(async (edge) => {
13095
+ if (!edge.resolvedAbsPath) return null;
13096
+ const wrappers = await deps.enricher.getWrappersForFile(
13097
+ edge.resolvedAbsPath
13098
+ );
13099
+ if (!wrappers.length) return null;
13100
+ return { edge, wrappers };
13101
+ })
13102
+ );
13103
+ for (const entry of resolutions) {
13104
+ if (!entry) continue;
13105
+ const { edge, wrappers } = entry;
13106
+ if (edge.isNamespace) {
13107
+ const nsMap = /* @__PURE__ */ new Map();
13108
+ for (const w of wrappers) {
13109
+ if (w.isNamedExport || w.isDefaultExport) {
13110
+ nsMap.set(w.name, w);
13111
+ }
13112
+ }
13113
+ if (nsMap.size) namespaceWrappers.set(edge.localName, nsMap);
13114
+ continue;
13115
+ }
13116
+ if (edge.isDefault) {
13117
+ const target2 = wrappers.find((w) => w.isDefaultExport);
13118
+ if (target2) wrappersByLocalName.set(edge.localName, target2);
13119
+ continue;
13120
+ }
13121
+ const target = wrappers.find(
13122
+ (w) => w.name === edge.importedName && w.isNamedExport
13123
+ );
13124
+ if (target) wrappersByLocalName.set(edge.localName, target);
13125
+ }
13126
+ if (!wrappersByLocalName.size && !namespaceWrappers.size) return null;
13127
+ return { wrappersByLocalName, namespaceWrappers };
13128
+ }
12248
13129
 
12249
13130
  // src/utils/common.ts
12250
13131
  async function withTimeout(operation, timeoutMs) {
12251
13132
  const timeoutPromise = new Promise(
12252
- (resolve4) => setTimeout(() => resolve4({ result: "timeout" }), timeoutMs)
13133
+ (resolve6) => setTimeout(() => resolve6({ result: "timeout" }), timeoutMs)
12253
13134
  );
12254
13135
  const operationPromise = operation.then((value) => ({
12255
13136
  result: "success",
@@ -12735,7 +13616,7 @@ function buildToolKey(serverName, toolName) {
12735
13616
  return `mcp__${serverName}__${toolName}`;
12736
13617
  }
12737
13618
  function delay2(ms) {
12738
- return new Promise((resolve4) => setTimeout(resolve4, ms));
13619
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
12739
13620
  }
12740
13621
  async function fetchMcpToolMetadata(q, logger = new Logger({ debug: false, prefix: "[McpToolMetadata]" })) {
12741
13622
  let retries = 0;
@@ -15056,8 +15937,8 @@ var AsyncMutex = class {
15056
15937
  this.locked = true;
15057
15938
  return;
15058
15939
  }
15059
- return new Promise((resolve4) => {
15060
- this.queue.push(resolve4);
15940
+ return new Promise((resolve6) => {
15941
+ this.queue.push(resolve6);
15061
15942
  });
15062
15943
  }
15063
15944
  release() {
@@ -15592,8 +16473,8 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
15592
16473
  if (this.session.promptRunning) {
15593
16474
  this.session.input.push(userMessage);
15594
16475
  const order = this.session.nextPendingOrder++;
15595
- const cancelled = await new Promise((resolve4) => {
15596
- this.session.pendingMessages.set(promptUuid, { resolve: resolve4, order });
16476
+ const cancelled = await new Promise((resolve6) => {
16477
+ this.session.pendingMessages.set(promptUuid, { resolve: resolve6, order });
15597
16478
  });
15598
16479
  if (cancelled) {
15599
16480
  return { stopReason: "cancelled" };
@@ -16464,7 +17345,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
16464
17345
  */
16465
17346
  deferBackgroundFetches(q) {
16466
17347
  Promise.all([
16467
- new Promise((resolve4) => setTimeout(resolve4, 10)).then(
17348
+ new Promise((resolve6) => setTimeout(resolve6, 10)).then(
16468
17349
  () => this.sendAvailableCommandsUpdate()
16469
17350
  ),
16470
17351
  fetchMcpToolMetadata(q, this.logger).then(() => {
@@ -16746,7 +17627,7 @@ function parseCodexToml(content, cwd) {
16746
17627
  // src/adapters/codex/spawn.ts
16747
17628
  import { spawn as spawn3 } from "child_process";
16748
17629
  import { existsSync as existsSync4 } from "fs";
16749
- import { delimiter, dirname as dirname4 } from "path";
17630
+ import { delimiter, dirname as dirname5 } from "path";
16750
17631
  function buildConfigArgs(options) {
16751
17632
  const args2 = [];
16752
17633
  args2.push("-c", `features.remote_models=false`);
@@ -16797,7 +17678,7 @@ function spawnCodexProcess(options) {
16797
17678
  }
16798
17679
  const { command, args: args2 } = findCodexBinary(options);
16799
17680
  if (options.binaryPath && existsSync4(options.binaryPath)) {
16800
- const binDir = dirname4(options.binaryPath);
17681
+ const binDir = dirname5(options.binaryPath);
16801
17682
  env.PATH = `${binDir}${delimiter}${env.PATH ?? ""}`;
16802
17683
  }
16803
17684
  logger.info("Spawning codex-acp process", {
@@ -17816,7 +18697,7 @@ var Saga = class {
17816
18697
 
17817
18698
  // src/sagas/apply-snapshot-saga.ts
17818
18699
  import { mkdir as mkdir4, rm as rm3, writeFile as writeFile4 } from "fs/promises";
17819
- import { join as join9 } from "path";
18700
+ import { join as join10 } from "path";
17820
18701
 
17821
18702
  // ../git/dist/sagas/tree.js
17822
18703
  import { existsSync as existsSync5 } from "fs";
@@ -18104,7 +18985,7 @@ var ApplySnapshotSaga = class extends Saga {
18104
18985
  archivePath = null;
18105
18986
  async execute(input) {
18106
18987
  const { snapshot, repositoryPath, apiClient, taskId, runId } = input;
18107
- const tmpDir = join9(repositoryPath, ".posthog", "tmp");
18988
+ const tmpDir = join10(repositoryPath, ".posthog", "tmp");
18108
18989
  if (!snapshot.archiveUrl) {
18109
18990
  throw new Error("Cannot apply snapshot: no archive URL");
18110
18991
  }
@@ -18115,7 +18996,7 @@ var ApplySnapshotSaga = class extends Saga {
18115
18996
  rollback: async () => {
18116
18997
  }
18117
18998
  });
18118
- const archivePath = join9(tmpDir, `${snapshot.treeHash}.tar.gz`);
18999
+ const archivePath = join10(tmpDir, `${snapshot.treeHash}.tar.gz`);
18119
19000
  this.archivePath = archivePath;
18120
19001
  await this.step({
18121
19002
  name: "download_archive",
@@ -18164,7 +19045,7 @@ var ApplySnapshotSaga = class extends Saga {
18164
19045
  // src/sagas/capture-tree-saga.ts
18165
19046
  import { existsSync as existsSync6 } from "fs";
18166
19047
  import { readFile as readFile4, rm as rm4 } from "fs/promises";
18167
- import { join as join10 } from "path";
19048
+ import { join as join11 } from "path";
18168
19049
  var CaptureTreeSaga2 = class extends Saga {
18169
19050
  sagaName = "CaptureTreeSaga";
18170
19051
  async execute(input) {
@@ -18176,14 +19057,14 @@ var CaptureTreeSaga2 = class extends Saga {
18176
19057
  taskId,
18177
19058
  runId
18178
19059
  } = input;
18179
- const tmpDir = join10(repositoryPath, ".posthog", "tmp");
18180
- if (existsSync6(join10(repositoryPath, ".gitmodules"))) {
19060
+ const tmpDir = join11(repositoryPath, ".posthog", "tmp");
19061
+ if (existsSync6(join11(repositoryPath, ".gitmodules"))) {
18181
19062
  this.log.warn(
18182
19063
  "Repository has submodules - snapshot may not capture submodule state"
18183
19064
  );
18184
19065
  }
18185
19066
  const shouldArchive = !!apiClient;
18186
- const archivePath = shouldArchive ? join10(tmpDir, `tree-${Date.now()}.tar.gz`) : void 0;
19067
+ const archivePath = shouldArchive ? join11(tmpDir, `tree-${Date.now()}.tar.gz`) : void 0;
18187
19068
  const gitCaptureSaga = new CaptureTreeSaga(this.log);
18188
19069
  const captureResult = await gitCaptureSaga.run({
18189
19070
  baseDir: repositoryPath,
@@ -19425,7 +20306,7 @@ var AgentServer = class _AgentServer {
19425
20306
  return app;
19426
20307
  }
19427
20308
  async start() {
19428
- await new Promise((resolve4) => {
20309
+ await new Promise((resolve6) => {
19429
20310
  this.server = serve(
19430
20311
  {
19431
20312
  fetch: this.app.fetch,
@@ -19435,7 +20316,7 @@ var AgentServer = class _AgentServer {
19435
20316
  this.logger.debug(
19436
20317
  `HTTP server listening on port ${this.config.port}`
19437
20318
  );
19438
- resolve4();
20319
+ resolve6();
19439
20320
  }
19440
20321
  );
19441
20322
  });
@@ -20174,7 +21055,7 @@ ${toolSummary}`);
20174
21055
  throw new Error(`Failed to download artifact ${artifact.name}`);
20175
21056
  }
20176
21057
  const safeName = this.getSafeArtifactName(artifact.name);
20177
- const artifactDir = join11(
21058
+ const artifactDir = join12(
20178
21059
  this.config.repositoryPath ?? "/tmp/workspace",
20179
21060
  ".posthog",
20180
21061
  "attachments",
@@ -20182,7 +21063,7 @@ ${toolSummary}`);
20182
21063
  artifact.id ?? safeName
20183
21064
  );
20184
21065
  await mkdir5(artifactDir, { recursive: true });
20185
- const artifactPath = join11(artifactDir, safeName);
21066
+ const artifactPath = join12(artifactDir, safeName);
20186
21067
  await writeFile5(artifactPath, Buffer.from(data));
20187
21068
  return resourceLink(pathToFileURL(artifactPath).toString(), artifact.name, {
20188
21069
  ...artifact.content_type ? { mimeType: artifact.content_type } : {},
@@ -20794,8 +21675,8 @@ ${attributionInstructions}
20794
21675
  options: params.options,
20795
21676
  toolCall: params.toolCall
20796
21677
  });
20797
- return new Promise((resolve4) => {
20798
- this.pendingPermissions.set(requestId, { resolve: resolve4 });
21678
+ return new Promise((resolve6) => {
21679
+ this.pendingPermissions.set(requestId, { resolve: resolve6 });
20799
21680
  });
20800
21681
  }
20801
21682
  resolvePermission(requestId, optionId, customInput, answers) {