eminiar 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -2266,8 +2266,8 @@ var require_resolve = __commonJS({
2266
2266
  }
2267
2267
  return count;
2268
2268
  }
2269
- function getFullPath(resolver, id = "", normalize6) {
2270
- if (normalize6 !== false)
2269
+ function getFullPath(resolver, id = "", normalize7) {
2270
+ if (normalize7 !== false)
2271
2271
  id = normalizeId(id);
2272
2272
  const p = resolver.parse(id);
2273
2273
  return _getFullPath(resolver, p);
@@ -3019,7 +3019,7 @@ var require_compile = __commonJS({
3019
3019
  const schOrFunc = root.refs[ref];
3020
3020
  if (schOrFunc)
3021
3021
  return schOrFunc;
3022
- let _sch = resolve7.call(this, root, ref);
3022
+ let _sch = resolve8.call(this, root, ref);
3023
3023
  if (_sch === void 0) {
3024
3024
  const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
3025
3025
  const { schemaId } = this.opts;
@@ -3046,7 +3046,7 @@ var require_compile = __commonJS({
3046
3046
  function sameSchemaEnv(s1, s2) {
3047
3047
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
3048
3048
  }
3049
- function resolve7(root, ref) {
3049
+ function resolve8(root, ref) {
3050
3050
  let sch;
3051
3051
  while (typeof (sch = this.refs[ref]) == "string")
3052
3052
  ref = sch;
@@ -3869,7 +3869,7 @@ var require_fast_uri = __commonJS({
3869
3869
  }
3870
3870
  return decodedScheme;
3871
3871
  }
3872
- function normalize6(uri, options) {
3872
+ function normalize7(uri, options) {
3873
3873
  if (typeof uri === "string") {
3874
3874
  uri = /** @type {T} */
3875
3875
  normalizeString(uri, options);
@@ -3879,7 +3879,7 @@ var require_fast_uri = __commonJS({
3879
3879
  }
3880
3880
  return uri;
3881
3881
  }
3882
- function resolve7(baseURI, relativeURI, options) {
3882
+ function resolve8(baseURI, relativeURI, options) {
3883
3883
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3884
3884
  const {
3885
3885
  parsed: baseParsed,
@@ -3912,49 +3912,49 @@ var require_fast_uri = __commonJS({
3912
3912
  schemelessOptions.skipEscape = true;
3913
3913
  return serialize(resolved, schemelessOptions);
3914
3914
  }
3915
- function resolveComponent(base, relative8, options, skipNormalization) {
3915
+ function resolveComponent(base, relative9, options, skipNormalization) {
3916
3916
  const target = {};
3917
3917
  if (!skipNormalization) {
3918
3918
  base = parse3(serialize(base, options), options);
3919
- relative8 = parse3(serialize(relative8, options), options);
3919
+ relative9 = parse3(serialize(relative9, options), options);
3920
3920
  }
3921
3921
  options = options || {};
3922
- if (!options.tolerant && relative8.scheme) {
3923
- target.scheme = relative8.scheme;
3924
- target.userinfo = relative8.userinfo;
3925
- target.host = relative8.host;
3926
- target.port = relative8.port;
3927
- target.path = removeDotSegments(relative8.path || "");
3928
- target.query = relative8.query;
3922
+ if (!options.tolerant && relative9.scheme) {
3923
+ target.scheme = relative9.scheme;
3924
+ target.userinfo = relative9.userinfo;
3925
+ target.host = relative9.host;
3926
+ target.port = relative9.port;
3927
+ target.path = removeDotSegments(relative9.path || "");
3928
+ target.query = relative9.query;
3929
3929
  } else {
3930
- if (relative8.userinfo !== void 0 || relative8.host !== void 0 || relative8.port !== void 0) {
3931
- target.userinfo = relative8.userinfo;
3932
- target.host = relative8.host;
3933
- target.port = relative8.port;
3934
- target.path = removeDotSegments(relative8.path || "");
3935
- target.query = relative8.query;
3930
+ if (relative9.userinfo !== void 0 || relative9.host !== void 0 || relative9.port !== void 0) {
3931
+ target.userinfo = relative9.userinfo;
3932
+ target.host = relative9.host;
3933
+ target.port = relative9.port;
3934
+ target.path = removeDotSegments(relative9.path || "");
3935
+ target.query = relative9.query;
3936
3936
  } else {
3937
- if (!relative8.path) {
3937
+ if (!relative9.path) {
3938
3938
  target.path = base.path;
3939
- if (relative8.query !== void 0) {
3940
- target.query = relative8.query;
3939
+ if (relative9.query !== void 0) {
3940
+ target.query = relative9.query;
3941
3941
  } else {
3942
3942
  target.query = base.query;
3943
3943
  }
3944
3944
  } else {
3945
- if (relative8.path[0] === "/") {
3946
- target.path = removeDotSegments(relative8.path);
3945
+ if (relative9.path[0] === "/") {
3946
+ target.path = removeDotSegments(relative9.path);
3947
3947
  } else {
3948
3948
  if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
3949
- target.path = "/" + relative8.path;
3949
+ target.path = "/" + relative9.path;
3950
3950
  } else if (!base.path) {
3951
- target.path = relative8.path;
3951
+ target.path = relative9.path;
3952
3952
  } else {
3953
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative8.path;
3953
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative9.path;
3954
3954
  }
3955
3955
  target.path = removeDotSegments(target.path);
3956
3956
  }
3957
- target.query = relative8.query;
3957
+ target.query = relative9.query;
3958
3958
  }
3959
3959
  target.userinfo = base.userinfo;
3960
3960
  target.host = base.host;
@@ -3962,7 +3962,7 @@ var require_fast_uri = __commonJS({
3962
3962
  }
3963
3963
  target.scheme = base.scheme;
3964
3964
  }
3965
- target.fragment = relative8.fragment;
3965
+ target.fragment = relative9.fragment;
3966
3966
  return target;
3967
3967
  }
3968
3968
  function equal(uriA, uriB, options) {
@@ -4247,8 +4247,8 @@ var require_fast_uri = __commonJS({
4247
4247
  }
4248
4248
  var fastUri = {
4249
4249
  SCHEMES,
4250
- normalize: normalize6,
4251
- resolve: resolve7,
4250
+ normalize: normalize7,
4251
+ resolve: resolve8,
4252
4252
  resolveComponent,
4253
4253
  equal,
4254
4254
  serialize,
@@ -10972,15 +10972,15 @@ var require_pattern2 = __commonJS({
10972
10972
  exports.removeDuplicateSlashes = removeDuplicateSlashes;
10973
10973
  function partitionAbsoluteAndRelative(patterns) {
10974
10974
  const absolute = [];
10975
- const relative8 = [];
10975
+ const relative9 = [];
10976
10976
  for (const pattern2 of patterns) {
10977
10977
  if (isAbsolute2(pattern2)) {
10978
10978
  absolute.push(pattern2);
10979
10979
  } else {
10980
- relative8.push(pattern2);
10980
+ relative9.push(pattern2);
10981
10981
  }
10982
10982
  }
10983
- return [absolute, relative8];
10983
+ return [absolute, relative9];
10984
10984
  }
10985
10985
  exports.partitionAbsoluteAndRelative = partitionAbsoluteAndRelative;
10986
10986
  function isAbsolute2(pattern2) {
@@ -11411,11 +11411,11 @@ var require_out = __commonJS({
11411
11411
  async.read(path3, getSettings(optionsOrSettingsOrCallback), callback);
11412
11412
  }
11413
11413
  exports.stat = stat;
11414
- function statSync9(path3, optionsOrSettings) {
11414
+ function statSync10(path3, optionsOrSettings) {
11415
11415
  const settings = getSettings(optionsOrSettings);
11416
11416
  return sync.read(path3, settings);
11417
11417
  }
11418
- exports.statSync = statSync9;
11418
+ exports.statSync = statSync10;
11419
11419
  function getSettings(settingsOrOptions = {}) {
11420
11420
  if (settingsOrOptions instanceof settings_1.default) {
11421
11421
  return settingsOrOptions;
@@ -12096,41 +12096,41 @@ var require_queue = __commonJS({
12096
12096
  queue.drained = drained;
12097
12097
  return queue;
12098
12098
  function push(value) {
12099
- var p = new Promise(function(resolve7, reject) {
12099
+ var p = new Promise(function(resolve8, reject) {
12100
12100
  pushCb(value, function(err, result) {
12101
12101
  if (err) {
12102
12102
  reject(err);
12103
12103
  return;
12104
12104
  }
12105
- resolve7(result);
12105
+ resolve8(result);
12106
12106
  });
12107
12107
  });
12108
12108
  p.catch(noop);
12109
12109
  return p;
12110
12110
  }
12111
12111
  function unshift(value) {
12112
- var p = new Promise(function(resolve7, reject) {
12112
+ var p = new Promise(function(resolve8, reject) {
12113
12113
  unshiftCb(value, function(err, result) {
12114
12114
  if (err) {
12115
12115
  reject(err);
12116
12116
  return;
12117
12117
  }
12118
- resolve7(result);
12118
+ resolve8(result);
12119
12119
  });
12120
12120
  });
12121
12121
  p.catch(noop);
12122
12122
  return p;
12123
12123
  }
12124
12124
  function drained() {
12125
- var p = new Promise(function(resolve7) {
12125
+ var p = new Promise(function(resolve8) {
12126
12126
  process.nextTick(function() {
12127
12127
  if (queue.idle()) {
12128
- resolve7();
12128
+ resolve8();
12129
12129
  } else {
12130
12130
  var previousDrain = queue.drain;
12131
12131
  queue.drain = function() {
12132
12132
  if (typeof previousDrain === "function") previousDrain();
12133
- resolve7();
12133
+ resolve8();
12134
12134
  queue.drain = previousDrain;
12135
12135
  };
12136
12136
  }
@@ -12627,9 +12627,9 @@ var require_stream3 = __commonJS({
12627
12627
  });
12628
12628
  }
12629
12629
  _getStat(filepath) {
12630
- return new Promise((resolve7, reject) => {
12630
+ return new Promise((resolve8, reject) => {
12631
12631
  this._stat(filepath, this._fsStatSettings, (error62, stats) => {
12632
- return error62 === null ? resolve7(stats) : reject(error62);
12632
+ return error62 === null ? resolve8(stats) : reject(error62);
12633
12633
  });
12634
12634
  });
12635
12635
  }
@@ -12654,10 +12654,10 @@ var require_async5 = __commonJS({
12654
12654
  this._readerStream = new stream_1.default(this._settings);
12655
12655
  }
12656
12656
  dynamic(root, options) {
12657
- return new Promise((resolve7, reject) => {
12657
+ return new Promise((resolve8, reject) => {
12658
12658
  this._walkAsync(root, options, (error62, entries) => {
12659
12659
  if (error62 === null) {
12660
- resolve7(entries);
12660
+ resolve8(entries);
12661
12661
  } else {
12662
12662
  reject(error62);
12663
12663
  }
@@ -12667,10 +12667,10 @@ var require_async5 = __commonJS({
12667
12667
  async static(patterns, options) {
12668
12668
  const entries = [];
12669
12669
  const stream = this._readerStream.static(patterns, options);
12670
- return new Promise((resolve7, reject) => {
12670
+ return new Promise((resolve8, reject) => {
12671
12671
  stream.once("error", reject);
12672
12672
  stream.on("data", (entry) => entries.push(entry));
12673
- stream.once("end", () => resolve7(entries));
12673
+ stream.once("end", () => resolve8(entries));
12674
12674
  });
12675
12675
  }
12676
12676
  };
@@ -13845,6 +13845,40 @@ function parseRestShorthand(rest, actionName) {
13845
13845
  }
13846
13846
  return [{ method: "ALL", path: joinRoutePath(rest) }];
13847
13847
  }
13848
+ function phpRoutePath(...parts) {
13849
+ return normalizeRoutePath(
13850
+ joinRoutePath(...parts).replace(/\{(\w+)\s*:[^{}]*(?:\{[^{}]*\}[^{}]*)*\}/g, "{$1}").replace(/\{(\w+)<[^>]*>[^}]*\}/g, "{$1}")
13851
+ );
13852
+ }
13853
+ function resourceParam(segment) {
13854
+ return segment.replace(/-/g, "_").replace(/ies$/, "y").replace(/(s|x|z|ch|sh)es$/, "$1").replace(/([^s])s$/, "$1");
13855
+ }
13856
+ function laravelResource(name, api = false, only, except) {
13857
+ const segs = name.split(".").filter(Boolean);
13858
+ const last = segs.pop();
13859
+ if (!last) return [];
13860
+ const base = joinRoutePath(...segs.map((s) => `${s}/:${resourceParam(s)}`), last);
13861
+ const param = `:${resourceParam(last)}`;
13862
+ return RESOURCE_ACTIONS.filter(
13863
+ ([, , action]) => !(api && (action === "create" || action === "edit")) && (!only || only.includes(action)) && !except?.includes(action)
13864
+ ).map(([method, suffix, action]) => ({
13865
+ method,
13866
+ path: `${base === "/" ? "" : base}${suffix.replace("{p}", param)}` || "/",
13867
+ action
13868
+ }));
13869
+ }
13870
+ function parseRouteAnnotations(doc) {
13871
+ const out = [];
13872
+ for (const m of doc.matchAll(/@Route\(([^)]*)\)/g)) {
13873
+ const body = m[1] ?? "";
13874
+ const path3 = /^\s*"([^"]*)"/.exec(body)?.[1] ?? /\bpath\s*=\s*"([^"]*)"/.exec(body)?.[1];
13875
+ if (path3 === void 0) continue;
13876
+ const list2 = /\bmethods\s*=\s*(\{[^}]*\}|"[^"]*")/.exec(body)?.[1] ?? "";
13877
+ const methods = [...list2.matchAll(/"([^"]+)"/g)].map((x) => httpMethod(x[1])).filter((x) => !!x);
13878
+ for (const method of methods.length ? methods : ["ALL"]) out.push({ method, path: path3 });
13879
+ }
13880
+ return out;
13881
+ }
13848
13882
  function frameworkOf(importedPackages) {
13849
13883
  for (const p of importedPackages) {
13850
13884
  const f = FRAMEWORK_PKGS[p];
@@ -13889,7 +13923,7 @@ function fileRoutes(rel, exportedNames, defaultExport) {
13889
13923
  }
13890
13924
  return out;
13891
13925
  }
13892
- var ROUTE_METHODS, JS_METHOD_ALIASES, REST_ALIASES, FRAMEWORK_PKGS, routeId, NEXT_APP_ROUTE, NEXT_PAGES_API, HTTP_EXPORTS;
13926
+ var ROUTE_METHODS, JS_METHOD_ALIASES, REST_ALIASES, RESOURCE_ACTIONS, FRAMEWORK_PKGS, routeId, NEXT_APP_ROUTE, NEXT_PAGES_API, HTTP_EXPORTS;
13893
13927
  var init_routes = __esm({
13894
13928
  "src/graph/routes.ts"() {
13895
13929
  "use strict";
@@ -13913,6 +13947,16 @@ var init_routes = __esm({
13913
13947
  ["PATCH", "/:id", "patch"],
13914
13948
  ["DELETE", "/:id", "remove"]
13915
13949
  ];
13950
+ RESOURCE_ACTIONS = [
13951
+ ["GET", "", "index"],
13952
+ ["GET", "/create", "create"],
13953
+ ["POST", "", "store"],
13954
+ ["GET", "/{p}", "show"],
13955
+ ["GET", "/{p}/edit", "edit"],
13956
+ ["PUT", "/{p}", "update"],
13957
+ ["PATCH", "/{p}", "update"],
13958
+ ["DELETE", "/{p}", "destroy"]
13959
+ ];
13916
13960
  FRAMEWORK_PKGS = {
13917
13961
  express: "express",
13918
13962
  fastify: "fastify",
@@ -13943,7 +13987,18 @@ var init_routes = __esm({
13943
13987
  "github.com/labstack/echo": "echo",
13944
13988
  "github.com/gorilla/mux": "gorilla",
13945
13989
  "github.com/gofiber/fiber": "fiber",
13946
- "github.com/julienschmidt/httprouter": "httprouter"
13990
+ "github.com/julienschmidt/httprouter": "httprouter",
13991
+ // PHP (top-level namespace of a `use` the project cannot resolve)
13992
+ Illuminate: "laravel",
13993
+ Symfony: "symfony",
13994
+ Slim: "slim",
13995
+ CodeIgniter: "codeigniter",
13996
+ // PHP (composer.json `require`, when no `use` in the file names the framework)
13997
+ "laravel/lumen-framework": "lumen",
13998
+ "laravel/framework": "laravel",
13999
+ "symfony/framework-bundle": "symfony",
14000
+ "slim/slim": "slim",
14001
+ "codeigniter4/framework": "codeigniter"
13947
14002
  };
13948
14003
  routeId = (method, path3) => `route:${method} ${path3}`;
13949
14004
  NEXT_APP_ROUTE = /(?:^|\/)app\/(.*?)(?:\/)?route\.(?:ts|tsx|js|jsx|mjs)$/;
@@ -13999,6 +14054,8 @@ function grammarFor(path3) {
13999
14054
  return "python";
14000
14055
  case ".go":
14001
14056
  return "go";
14057
+ case ".php":
14058
+ return "php";
14002
14059
  default:
14003
14060
  return void 0;
14004
14061
  }
@@ -14503,28 +14560,1095 @@ var init_go = __esm({
14503
14560
  }
14504
14561
  });
14505
14562
 
14506
- // src/graph/languages/python.ts
14507
- import { existsSync as existsSync5, statSync } from "fs";
14563
+ // src/graph/languages/php.ts
14564
+ import { readdirSync as readdirSync2, readFileSync as readFileSync4, statSync } from "fs";
14508
14565
  import { dirname as dirname4, join as join7, normalize as normalize2, relative as relative2, resolve as resolve3 } from "path";
14566
+ function readComposer(dir) {
14567
+ const file3 = join7(dir, "composer.json");
14568
+ if (!isFile(file3)) return null;
14569
+ try {
14570
+ const json2 = JSON.parse(readFileSync4(file3, "utf8"));
14571
+ const info = { dir, psr4: [], psr0: [], classmap: [], files: [], require: [] };
14572
+ for (const key of ["autoload", "autoload-dev"]) {
14573
+ const section = json2[key];
14574
+ for (const [prefix, dirs] of Object.entries(section?.["psr-4"] ?? {})) {
14575
+ info.psr4.push({
14576
+ prefix: prefix && !prefix.endsWith("\\") ? `${prefix}\\` : prefix,
14577
+ dirs: asList(dirs)
14578
+ });
14579
+ }
14580
+ for (const [prefix, dirs] of Object.entries(section?.["psr-0"] ?? {}))
14581
+ info.psr0.push({ prefix, dirs: asList(dirs) });
14582
+ info.classmap.push(...section?.classmap ?? []);
14583
+ info.files.push(...section?.files ?? []);
14584
+ }
14585
+ info.require = Object.keys(json2.require ?? {});
14586
+ info.psr4.sort((a, b) => b.prefix.length - a.prefix.length);
14587
+ info.psr0.sort((a, b) => b.prefix.length - a.prefix.length);
14588
+ const empty2 = !info.psr4.length && !info.psr0.length && !info.classmap.length && !info.files.length && !info.require.length;
14589
+ return empty2 ? null : info;
14590
+ } catch {
14591
+ return null;
14592
+ }
14593
+ }
14594
+ function composerAutoload(root, fromAbs) {
14595
+ let dir = dirname4(fromAbs);
14596
+ while (dir.startsWith(root)) {
14597
+ let hit = composerCache.get(dir);
14598
+ if (hit === void 0) {
14599
+ hit = readComposer(dir);
14600
+ composerCache.set(dir, hit);
14601
+ }
14602
+ if (hit) return hit;
14603
+ if (dir === root) break;
14604
+ dir = dirname4(dir);
14605
+ }
14606
+ return void 0;
14607
+ }
14608
+ function phpFilesUnder(abs, budget) {
14609
+ if (isFile(abs)) return abs.endsWith(".php") ? [abs] : [];
14610
+ let entries;
14611
+ try {
14612
+ entries = readdirSync2(abs, { recursive: true, encoding: "utf8" });
14613
+ } catch {
14614
+ return [];
14615
+ }
14616
+ const out = [];
14617
+ for (const e of entries) {
14618
+ if (budget.left <= 0) break;
14619
+ if (!e.endsWith(".php") || e.split(/[\\/]/).includes("vendor")) continue;
14620
+ out.push(join7(abs, e));
14621
+ budget.left--;
14622
+ }
14623
+ return out;
14624
+ }
14625
+ function classmapClasses(root, auto) {
14626
+ if (auto.classes) return auto.classes;
14627
+ const classes = /* @__PURE__ */ new Map();
14628
+ const budget = { left: CLASSMAP_MAX_FILES };
14629
+ for (const entry of auto.classmap) {
14630
+ for (const f of phpFilesUnder(join7(auto.dir, entry), budget)) {
14631
+ if (relative2(root, f).startsWith("..")) continue;
14632
+ let code;
14633
+ try {
14634
+ code = readFileSync4(f, "utf8");
14635
+ } catch {
14636
+ continue;
14637
+ }
14638
+ const ns = /^\s*namespace\s+([\w\\]+)\s*[;{]/m.exec(code)?.[1];
14639
+ for (const m of code.matchAll(
14640
+ /^\s*(?:(?:abstract|final|readonly)\s+)*(?:class|interface|trait|enum)\s+(\w+)/gm
14641
+ )) {
14642
+ const fq = ns ? `${ns}\\${m[1]}` : m[1];
14643
+ if (!classes.has(fq)) classes.set(fq, toRel(root, f));
14644
+ }
14645
+ }
14646
+ }
14647
+ auto.classes = classes;
14648
+ return classes;
14649
+ }
14650
+ function autoloadedFunctions(root, auto) {
14651
+ if (auto.functions) return auto.functions;
14652
+ const functions = /* @__PURE__ */ new Map();
14653
+ for (const entry of auto.files) {
14654
+ const f = join7(auto.dir, entry);
14655
+ if (!isFile(f) || relative2(root, f).startsWith("..")) continue;
14656
+ let code;
14657
+ try {
14658
+ code = readFileSync4(f, "utf8");
14659
+ } catch {
14660
+ continue;
14661
+ }
14662
+ if (/^\s*namespace\s+[\w\\]+\s*[;{]/m.test(code)) continue;
14663
+ for (const m of code.matchAll(/^\s*function\s+&?\s*(\w+)\s*\(/gm))
14664
+ if (!functions.has(m[1])) functions.set(m[1], toRel(root, f));
14665
+ }
14666
+ auto.functions = functions;
14667
+ return functions;
14668
+ }
14669
+ function resolvePhpClass(root, fromRel, fqcn) {
14670
+ const name = fqcn.replace(/^\\+/, "");
14671
+ if (!name) return void 0;
14672
+ const candidates2 = [];
14673
+ const auto = composerAutoload(root, resolve3(root, fromRel));
14674
+ if (auto?.psr4.length || auto?.psr0.length) {
14675
+ for (const { prefix, dirs } of auto.psr4) {
14676
+ if (!name.startsWith(prefix)) continue;
14677
+ const rest = name.slice(prefix.length).split("\\");
14678
+ for (const d of dirs) candidates2.push(join7(auto.dir, d, ...rest));
14679
+ }
14680
+ for (const { prefix, dirs } of auto.psr0) {
14681
+ if (!name.startsWith(prefix)) continue;
14682
+ const cut = name.lastIndexOf("\\");
14683
+ const ns = cut === -1 ? [] : name.slice(0, cut).split("\\");
14684
+ const cls = name.slice(cut + 1).split("_");
14685
+ for (const d of dirs) candidates2.push(join7(auto.dir, d, ...ns, ...cls));
14686
+ }
14687
+ } else {
14688
+ const parts = name.split("\\");
14689
+ candidates2.push(resolve3(root, ...parts), resolve3(root, "src", ...parts));
14690
+ }
14691
+ for (const c of candidates2) {
14692
+ const f = `${c}.php`;
14693
+ if (isFile(f) && !relative2(root, f).startsWith("..")) return toRel(root, f);
14694
+ }
14695
+ return auto?.classmap.length ? classmapClasses(root, auto).get(name) : void 0;
14696
+ }
14697
+ function phpString(n) {
14698
+ if (!n || n.type !== "string" && n.type !== "encapsed_string") return void 0;
14699
+ if (n.namedChildren.some((c) => c && c.type !== "string_content" && c.type !== "escape_sequence"))
14700
+ return void 0;
14701
+ return literalText(n)?.replace(/\\(\\|')/g, "$1");
14702
+ }
14703
+ function argsOf(call) {
14704
+ const list2 = call.childForFieldName("arguments") ?? call.childForFieldName("parameters");
14705
+ return (list2?.namedChildren ?? []).filter((a) => a?.type === "argument").map((a) => a.namedChildren[a.namedChildren.length - 1]).filter((a) => !!a);
14706
+ }
14707
+ function positionalArgs(call) {
14708
+ const list2 = call.childForFieldName("arguments") ?? call.childForFieldName("parameters");
14709
+ return (list2?.namedChildren ?? []).filter((a) => a?.type === "argument" && !a.childForFieldName("name")).map((a) => a.namedChildren[0]).filter((a) => !!a);
14710
+ }
14711
+ function namedArg(call, name) {
14712
+ const list2 = call.childForFieldName("arguments") ?? call.childForFieldName("parameters");
14713
+ for (const a of list2?.namedChildren ?? []) {
14714
+ if (a?.type === "argument" && a.childForFieldName("name")?.text === name)
14715
+ return a.namedChildren[a.namedChildren.length - 1] ?? void 0;
14716
+ }
14717
+ return void 0;
14718
+ }
14719
+ function stringsOf(n) {
14720
+ if (!n) return [];
14721
+ if (n.type !== "array_creation_expression") {
14722
+ const s = phpString(n);
14723
+ return s === void 0 ? [] : [s];
14724
+ }
14725
+ return n.namedChildren.flatMap((el) => {
14726
+ const s = el?.namedChildren.length === 1 ? phpString(el.namedChildren[0]) : void 0;
14727
+ return s === void 0 ? [] : [s];
14728
+ });
14729
+ }
14730
+ function arrayElements(arr2) {
14731
+ const out = [];
14732
+ for (const el of arr2.namedChildren) {
14733
+ if (el?.type !== "array_element_initializer") continue;
14734
+ const kids = el.namedChildren.filter((c) => !!c);
14735
+ if (kids.length === 1) out.push({ value: kids[0] });
14736
+ else if (kids.length === 2) out.push({ key: phpString(kids[0]), value: kids[1] });
14737
+ }
14738
+ return out;
14739
+ }
14740
+ function handlerShaped(a) {
14741
+ if (!a) return false;
14742
+ switch (a.type) {
14743
+ case "anonymous_function":
14744
+ case "arrow_function":
14745
+ case "class_constant_access_expression":
14746
+ return true;
14747
+ case "string":
14748
+ case "encapsed_string":
14749
+ return CONTROLLER_STRING.test(phpString(a) ?? "");
14750
+ case "array_creation_expression":
14751
+ return arrayElements(a).some((e) => e.key ? e.key === "uses" : handlerShaped(e.value));
14752
+ default:
14753
+ return false;
14754
+ }
14755
+ }
14756
+ async function parsePhp(root, rel, code) {
14757
+ const p = await getParser("php");
14758
+ const tree = p.parse(code);
14759
+ if (!tree) return { nodes: [], edges: [], exports: [] };
14760
+ const fid = fileId(rel);
14761
+ const fileNode = {
14762
+ id: fid,
14763
+ kind: "file",
14764
+ name: rel,
14765
+ path: rel,
14766
+ source: "tree-sitter"
14767
+ };
14768
+ const nodes = [fileNode];
14769
+ const edges = [];
14770
+ const exportsList = [];
14771
+ const scope = /* @__PURE__ */ new Map();
14772
+ let classUses = /* @__PURE__ */ new Map();
14773
+ const usesByBlock = /* @__PURE__ */ new Map();
14774
+ const declared = /* @__PURE__ */ new Set();
14775
+ const localSyms = /* @__PURE__ */ new Map();
14776
+ const varTypes = /* @__PURE__ */ new Map();
14777
+ const propTypes = /* @__PURE__ */ new Map();
14778
+ const parents = /* @__PURE__ */ new Map();
14779
+ const imports = /* @__PURE__ */ new Map();
14780
+ const resolvedClasses = /* @__PURE__ */ new Map();
14781
+ const importedPkgs = /* @__PURE__ */ new Set();
14782
+ const refs = new RefCollector();
14783
+ let complexity = 0;
14784
+ let namespace = "";
14785
+ const namespaces = [];
14786
+ const pushEdge = (e) => edges.push({ confidence: 1, weight: 1, ...e });
14787
+ const auto = composerAutoload(root, resolve3(root, rel));
14788
+ const stmts = [];
14789
+ let block = 0;
14790
+ for (const stmt of tree.rootNode.namedChildren) {
14791
+ if (!stmt) continue;
14792
+ if (stmt.type === "namespace_definition") {
14793
+ block++;
14794
+ namespace = stmt.childForFieldName("name")?.text ?? "";
14795
+ if (namespace) addNamespace(stmt, namespace);
14796
+ for (const s of stmt.childForFieldName("body")?.namedChildren ?? [])
14797
+ if (s) stmts.push([s, namespace, block]);
14798
+ } else stmts.push([stmt, namespace, block]);
14799
+ }
14800
+ const enter = (ns, b) => {
14801
+ namespace = ns;
14802
+ let uses = usesByBlock.get(b);
14803
+ if (!uses) {
14804
+ uses = /* @__PURE__ */ new Map();
14805
+ usesByBlock.set(b, uses);
14806
+ }
14807
+ classUses = uses;
14808
+ };
14809
+ for (const [stmt] of stmts) {
14810
+ const name = CLASS_KINDS[stmt.type] ? stmt.childForFieldName("name")?.text : void 0;
14811
+ if (name) declared.add(name);
14812
+ }
14813
+ for (const [stmt, ns, b] of stmts) {
14814
+ enter(ns, b);
14815
+ if (stmt.type === "namespace_use_declaration") handleUse(stmt);
14816
+ }
14817
+ for (const [stmt, ns, b] of stmts) {
14818
+ enter(ns, b);
14819
+ if (stmt.type !== "namespace_use_declaration") collectDecls(stmt);
14820
+ }
14821
+ for (const [stmt, ns, b] of stmts) {
14822
+ enter(ns, b);
14823
+ if (stmt.type !== "namespace_use_declaration") walkRefs(stmt);
14824
+ }
14825
+ handleIncludes(tree.rootNode);
14826
+ edges.push(...imports.values());
14827
+ edges.push(...refs.edges());
14828
+ const errors = tree.rootNode.hasError ? tree.rootNode.descendantsOfType("ERROR").length : 0;
14829
+ fileNode.meta = {
14830
+ loc: tree.rootNode.endPosition.row + 1,
14831
+ complexity,
14832
+ ...namespaces.length ? { php_namespace: namespaces[0] } : {},
14833
+ ...errors ? { parse_errors: errors } : {}
14834
+ };
14835
+ return { nodes, edges, exports: exportsList, errors };
14836
+ function addNamespace(n, name) {
14837
+ if (namespaces.includes(name)) return;
14838
+ namespaces.push(name);
14839
+ const id = symId(rel, name);
14840
+ nodes.push({
14841
+ id,
14842
+ kind: "namespace",
14843
+ name,
14844
+ path: rel,
14845
+ startLine: n.startPosition.row + 1,
14846
+ endLine: n.endPosition.row + 1,
14847
+ source: "tree-sitter"
14848
+ });
14849
+ pushEdge({ src: fid, dst: id, kind: "defines", source: "tree-sitter" });
14850
+ }
14851
+ function addImport(dst, name, spec, line, conf) {
14852
+ const cur = imports.get(dst);
14853
+ if (cur?.meta) {
14854
+ const names = cur.meta.names;
14855
+ if (!names.includes(name)) names.push(name);
14856
+ return;
14857
+ }
14858
+ imports.set(dst, {
14859
+ src: fid,
14860
+ dst,
14861
+ kind: "imports",
14862
+ source: "tree-sitter",
14863
+ confidence: conf,
14864
+ weight: 1,
14865
+ meta: { names: [name], spec, line }
14866
+ });
14867
+ }
14868
+ function handleUse(decl) {
14869
+ const group = decl.childForFieldName("body");
14870
+ const prefix = group ? decl.namedChildren.find((c) => c?.type === "namespace_name")?.text : void 0;
14871
+ const declKind = decl.children.find((c) => c?.type === "function" || c?.type === "const")?.type;
14872
+ for (const c of (group ?? decl).namedChildren) {
14873
+ if (c?.type !== "namespace_use_clause") continue;
14874
+ const alias = c.childForFieldName("alias");
14875
+ const target = c.namedChildren.find(
14876
+ (x) => x && x.id !== alias?.id && (x.type === "qualified_name" || x.type === "name")
14877
+ );
14878
+ if (!target) continue;
14879
+ const fqn = (prefix ? `${prefix}\\${target.text}` : target.text).replace(/^\\+/, "");
14880
+ const local = alias?.text ?? lastSegment(fqn);
14881
+ const kind = c.children.find((x) => x?.type === "function" || x?.type === "const")?.type ?? declKind;
14882
+ const line = c.startPosition.row + 1;
14883
+ const label = alias ? `${fqn} as ${alias.text}` : fqn;
14884
+ const file3 = kind ? void 0 : classFile(fqn);
14885
+ if (file3) {
14886
+ if (file3 !== rel) addImport(fileId(file3), label, fqn, line, 0.95);
14887
+ } else {
14888
+ const top = fqn.split("\\")[0];
14889
+ importedPkgs.add(top);
14890
+ if (!imports.has(pkgId(top)))
14891
+ nodes.push({ id: pkgId(top), kind: "package", name: top, source: "tree-sitter" });
14892
+ addImport(pkgId(top), label, fqn, line, 1);
14893
+ }
14894
+ if (kind) scope.set(local, { id: pkgId(fqn.split("\\")[0]), confidence: 0.6 });
14895
+ else classUses.set(local, fqn);
14896
+ }
14897
+ }
14898
+ function handleIncludes(rootNode) {
14899
+ const here = dirname4(resolve3(root, rel));
14900
+ for (const inc of rootNode.descendantsOfType([
14901
+ "require_expression",
14902
+ "require_once_expression",
14903
+ "include_expression",
14904
+ "include_once_expression"
14905
+ ])) {
14906
+ const arg = inc.namedChildren[0];
14907
+ if (!arg) continue;
14908
+ const candidates2 = [];
14909
+ const plain = phpString(arg);
14910
+ if (plain !== void 0) candidates2.push(resolve3(here, plain), resolve3(root, plain));
14911
+ else if (arg.type === "binary_expression") {
14912
+ const left = arg.childForFieldName("left")?.text.replace(/\s+/g, "") ?? "";
14913
+ const right = phpString(arg.childForFieldName("right"));
14914
+ const up = /^dirname\(__(?:DIR|FILE)__(?:,(\d+))?\)$/.exec(left);
14915
+ let base;
14916
+ if (left === "__DIR__" || left === "dirname(__FILE__)") base = here;
14917
+ else if (up) {
14918
+ base = here;
14919
+ for (let i = left.includes("__FILE__") ? 1 : 0; i < Number(up[1] ?? 1); i++)
14920
+ base = dirname4(base);
14921
+ }
14922
+ if (base && right !== void 0) candidates2.push(join7(base, right));
14923
+ }
14924
+ const hit = candidates2.find((c) => isFile(c) && !relative2(root, c).startsWith(".."));
14925
+ if (!hit) continue;
14926
+ const file3 = toRel(root, hit);
14927
+ if (file3 !== rel) addImport(fileId(file3), "*", arg.text, inc.startPosition.row + 1, 0.9);
14928
+ }
14929
+ }
14930
+ function classFile(fqcn) {
14931
+ let hit = resolvedClasses.get(fqcn);
14932
+ if (hit === void 0) {
14933
+ hit = resolvePhpClass(root, rel, fqcn) ?? null;
14934
+ resolvedClasses.set(fqcn, hit);
14935
+ }
14936
+ return hit ?? void 0;
14937
+ }
14938
+ function fqcnOf(name) {
14939
+ if (name.startsWith("\\")) return name.slice(1);
14940
+ const [head, ...rest] = name.split("\\");
14941
+ const used = classUses.get(head);
14942
+ if (used) return [used, ...rest].join("\\");
14943
+ return namespace ? `${namespace}\\${name}` : name;
14944
+ }
14945
+ function classRef(name) {
14946
+ if (!name || RELATIVE.has(name.toLowerCase())) return void 0;
14947
+ if (!name.includes("\\") && !classUses.has(name) && declared.has(name))
14948
+ return { id: symId(rel, name), confidence: 0.9 };
14949
+ const fqcn = fqcnOf(name);
14950
+ const file3 = classFile(fqcn);
14951
+ if (file3) return { id: symId(file3, lastSegment(fqcn)), confidence: file3 === rel ? 0.9 : 0.85 };
14952
+ const used = classUses.get(name.replace(/^\\/, "").split("\\")[0]);
14953
+ if (used && !name.startsWith("\\")) return { id: pkgId(used.split("\\")[0]), confidence: 0.6 };
14954
+ return void 0;
14955
+ }
14956
+ function typeRef(n) {
14957
+ if (!n) return void 0;
14958
+ const named = n.type === "named_type" ? n : n.descendantsOfType("named_type")[0];
14959
+ const t = named ? classRef(named.text) : void 0;
14960
+ return t?.id.startsWith("sym:") ? t.id : void 0;
14961
+ }
14962
+ function collectDecls(n) {
14963
+ if (CLASS_KINDS[n.type]) {
14964
+ collectClass(n);
14965
+ return;
14966
+ }
14967
+ switch (n.type) {
14968
+ case "function_definition": {
14969
+ const name = n.childForFieldName("name")?.text;
14970
+ if (name) addFunction(name, n);
14971
+ return;
14972
+ }
14973
+ case "if_statement": {
14974
+ for (const f of n.descendantsOfType("function_definition")) {
14975
+ const name = f.childForFieldName("name")?.text;
14976
+ if (name && !insideDecl(f, n)) addFunction(name, f);
14977
+ }
14978
+ return;
14979
+ }
14980
+ case "const_declaration": {
14981
+ for (const el of n.namedChildren) {
14982
+ const name = el?.type === "const_element" ? el.namedChildren[0]?.text : void 0;
14983
+ if (name) addSym(name, "variable", el, true);
14984
+ }
14985
+ return;
14986
+ }
14987
+ case "expression_statement": {
14988
+ const call = n.namedChildren[0];
14989
+ if (call?.type !== "function_call_expression") return;
14990
+ if (call.childForFieldName("function")?.text !== "define") return;
14991
+ const name = phpString(argsOf(call)[0]);
14992
+ if (name && /^\w+$/.test(name)) addSym(name, "variable", call, true);
14993
+ return;
14994
+ }
14995
+ default:
14996
+ return;
14997
+ }
14998
+ }
14999
+ function insideDecl(n, top) {
15000
+ for (let cur = n.parent; cur && cur.id !== top.id; cur = cur.parent) {
15001
+ if (cur.type === "function_definition" || cur.type === "method_declaration") return true;
15002
+ if (CLASS_KINDS[cur.type]) return true;
15003
+ }
15004
+ return false;
15005
+ }
15006
+ function addFunction(name, n) {
15007
+ addSym(name, "function", n, true);
15008
+ scope.set(name, { id: symId(rel, name), confidence: 0.9 });
15009
+ }
15010
+ function collectClass(n) {
15011
+ const name = n.childForFieldName("name")?.text;
15012
+ const kind = CLASS_KINDS[n.type];
15013
+ if (!name || !kind) return;
15014
+ addSym(name, kind, n, true);
15015
+ const self = symId(rel, name);
15016
+ for (const h of n.namedChildren) {
15017
+ if (h?.type !== "base_clause" && h?.type !== "class_interface_clause") continue;
15018
+ for (const b of h.namedChildren) {
15019
+ if (b?.type !== "name" && b?.type !== "qualified_name") continue;
15020
+ const target = heritage(self, b.text, h.type === "base_clause" ? "extends" : "implements");
15021
+ if (target && h.type === "base_clause" && kind === "class") parents.set(name, target);
15022
+ }
15023
+ }
15024
+ const body = n.childForFieldName("body");
15025
+ for (const m of body?.namedChildren ?? []) {
15026
+ if (!m) continue;
15027
+ switch (m.type) {
15028
+ case "method_declaration": {
15029
+ const mname = m.childForFieldName("name")?.text;
15030
+ if (!mname) break;
15031
+ addSym(`${name}.${mname}`, "method", m, isPublic(m));
15032
+ const params = m.childForFieldName("parameters")?.namedChildren ?? [];
15033
+ for (const prm of params) {
15034
+ if (prm?.type !== "property_promotion_parameter") continue;
15035
+ const pname = prm.childForFieldName("name")?.text.replace(/^\$/, "");
15036
+ if (!pname) continue;
15037
+ addSym(`${name}.${pname}`, "field", prm, isPublic(prm));
15038
+ const t = typeRef(prm.childForFieldName("type"));
15039
+ if (t) propTypes.set(`${name}.${pname}`, t);
15040
+ }
15041
+ break;
15042
+ }
15043
+ case "property_declaration": {
15044
+ const t = typeRef(m.childForFieldName("type"));
15045
+ for (const el of m.namedChildren) {
15046
+ if (el?.type !== "property_element") continue;
15047
+ const pname = el.childForFieldName("name")?.text.replace(/^\$/, "");
15048
+ if (!pname) continue;
15049
+ addSym(`${name}.${pname}`, "field", el, isPublic(m));
15050
+ if (t) propTypes.set(`${name}.${pname}`, t);
15051
+ }
15052
+ break;
15053
+ }
15054
+ case "const_declaration": {
15055
+ for (const el of m.namedChildren) {
15056
+ const cname = el?.type === "const_element" ? el.namedChildren[0]?.text : void 0;
15057
+ if (cname) addSym(`${name}.${cname}`, "field", el, isPublic(m));
15058
+ }
15059
+ break;
15060
+ }
15061
+ case "enum_case": {
15062
+ const cname = m.childForFieldName("name")?.text;
15063
+ if (cname) addSym(`${name}.${cname}`, "field", m, true);
15064
+ break;
15065
+ }
15066
+ case "use_declaration": {
15067
+ for (const t of m.namedChildren) {
15068
+ if (t?.type === "name" || t?.type === "qualified_name")
15069
+ heritage(self, t.text, "extends", { trait: true });
15070
+ }
15071
+ break;
15072
+ }
15073
+ default:
15074
+ break;
15075
+ }
15076
+ }
15077
+ attributeRoutes(n, name);
15078
+ }
15079
+ function heritage(src, name, kind, meta4) {
15080
+ const ref = classRef(name) ?? (name.startsWith("\\") && !name.slice(1).includes("\\") ? void 0 : { id: symId(rel, lastSegment(name)), confidence: 0.5 });
15081
+ if (!ref) return void 0;
15082
+ pushEdge({
15083
+ src,
15084
+ dst: ref.id,
15085
+ kind,
15086
+ source: "tree-sitter",
15087
+ confidence: ref.confidence,
15088
+ ...meta4 ? { meta: meta4 } : {}
15089
+ });
15090
+ return ref.id.startsWith("sym:") ? ref.id : void 0;
15091
+ }
15092
+ function addSym(qualified, kind, n, exported) {
15093
+ const id = symId(rel, qualified);
15094
+ const c = kind === "function" || kind === "method" ? complexityOf(n, BRANCHES2, BOOL_OPS2) : 0;
15095
+ complexity += c;
15096
+ nodes.push({
15097
+ id,
15098
+ kind,
15099
+ name: qualified,
15100
+ path: rel,
15101
+ startLine: n.startPosition.row + 1,
15102
+ endLine: n.endPosition.row + 1,
15103
+ source: "tree-sitter",
15104
+ meta: {
15105
+ ...exported ? { exported: true } : {},
15106
+ loc: n.endPosition.row - n.startPosition.row + 1,
15107
+ ...c ? { complexity: c } : {}
15108
+ }
15109
+ });
15110
+ pushEdge({ src: fid, dst: id, kind: "defines", source: "tree-sitter" });
15111
+ if (exported) {
15112
+ exportsList.push(qualified);
15113
+ pushEdge({ src: fid, dst: id, kind: "exports", source: "tree-sitter" });
15114
+ }
15115
+ localSyms.set(qualified, id);
15116
+ }
15117
+ function enclosing(n) {
15118
+ let cur = n.parent;
15119
+ while (cur) {
15120
+ if (cur.type === "method_declaration") {
15121
+ const name = cur.childForFieldName("name")?.text;
15122
+ const owner = cur.parent?.parent?.childForFieldName("name")?.text;
15123
+ const q = owner && name ? `${owner}.${name}` : void 0;
15124
+ if (q && localSyms.has(q)) return q;
15125
+ }
15126
+ if (cur.type === "function_definition") {
15127
+ const name = cur.childForFieldName("name")?.text;
15128
+ if (name && localSyms.has(name)) return name;
15129
+ }
15130
+ cur = cur.parent;
15131
+ }
15132
+ return void 0;
15133
+ }
15134
+ function objectType2(obj, caller) {
15135
+ const cls = classOf(caller);
15136
+ if (obj.type === "variable_name") {
15137
+ if (obj.text === "$this") return cls ? { id: symId(rel, cls), confidence: 0.9 } : void 0;
15138
+ const t = varTypes.get(`${caller ?? ""}\0${obj.text}`);
15139
+ return t ? { id: t, confidence: 0.8 } : void 0;
15140
+ }
15141
+ if (obj.type === "member_access_expression" || obj.type === "nullsafe_member_access_expression") {
15142
+ const inner = obj.childForFieldName("object");
15143
+ const prop = obj.childForFieldName("name")?.text;
15144
+ if (inner?.text !== "$this" || !cls || !prop) return void 0;
15145
+ const t = propTypes.get(`${cls}.${prop}`);
15146
+ return t ? { id: t, confidence: 0.8 } : void 0;
15147
+ }
15148
+ return void 0;
15149
+ }
15150
+ function scopeType(s, caller) {
15151
+ const cls = classOf(caller);
15152
+ if (s.type === "relative_scope" || RELATIVE.has(s.text.toLowerCase())) {
15153
+ const word = s.text.toLowerCase();
15154
+ if (!cls) return void 0;
15155
+ if (word === "parent") {
15156
+ const p2 = parents.get(cls);
15157
+ return p2 ? { id: p2, confidence: 0.8 } : void 0;
15158
+ }
15159
+ return { id: symId(rel, cls), confidence: 0.9 };
15160
+ }
15161
+ if (s.type === "name" || s.type === "qualified_name") return classRef(s.text);
15162
+ return void 0;
15163
+ }
15164
+ function callTarget(call, caller) {
15165
+ switch (call.type) {
15166
+ case "function_call_expression": {
15167
+ const fn = call.childForFieldName("function");
15168
+ if (fn?.type !== "name") return void 0;
15169
+ const local = scope.get(fn.text);
15170
+ if (local || !auto?.files.length) return local;
15171
+ const file3 = autoloadedFunctions(root, auto).get(fn.text);
15172
+ return file3 && file3 !== rel ? { id: symId(file3, fn.text), confidence: 0.8 } : void 0;
15173
+ }
15174
+ case "member_call_expression":
15175
+ case "nullsafe_member_call_expression": {
15176
+ const obj = call.childForFieldName("object");
15177
+ const m = call.childForFieldName("name");
15178
+ if (!obj || m?.type !== "name") return void 0;
15179
+ const t = objectType2(obj, caller);
15180
+ return t ? { id: `${t.id}.${m.text}`, confidence: t.confidence } : void 0;
15181
+ }
15182
+ case "scoped_call_expression": {
15183
+ const s = call.childForFieldName("scope");
15184
+ const m = call.childForFieldName("name");
15185
+ if (!s || m?.type !== "name") return void 0;
15186
+ const t = scopeType(s, caller);
15187
+ if (t?.id.startsWith("pkg:")) return t;
15188
+ return t ? { id: `${t.id}.${m.text}`, confidence: t.confidence } : void 0;
15189
+ }
15190
+ case "object_creation_expression": {
15191
+ const cls = call.namedChildren.find(
15192
+ (c) => c?.type === "name" || c?.type === "qualified_name"
15193
+ );
15194
+ return cls ? classRef(cls.text) : void 0;
15195
+ }
15196
+ default:
15197
+ return void 0;
15198
+ }
15199
+ }
15200
+ function noteVarTypes(n) {
15201
+ for (const prm of n.descendantsOfType("simple_parameter")) {
15202
+ const t = typeRef(prm.childForFieldName("type"));
15203
+ const v = prm.childForFieldName("name")?.text;
15204
+ if (t && v) varTypes.set(`${enclosing(prm) ?? ""}\0${v}`, t);
15205
+ }
15206
+ for (const a of n.descendantsOfType("assignment_expression")) {
15207
+ const left = a.childForFieldName("left");
15208
+ const right = a.childForFieldName("right");
15209
+ if (left?.type !== "variable_name" || right?.type !== "object_creation_expression") continue;
15210
+ const cls = right.namedChildren.find(
15211
+ (c) => c?.type === "name" || c?.type === "qualified_name"
15212
+ );
15213
+ const t = cls ? classRef(cls.text) : void 0;
15214
+ if (t?.id.startsWith("sym:")) varTypes.set(`${enclosing(a) ?? ""}\0${left.text}`, t.id);
15215
+ }
15216
+ }
15217
+ function addRoute(method, path3, framework, line, handlers, confidence, extra = {}) {
15218
+ const id = routeId(method, path3);
15219
+ if (!nodes.some((n) => n.id === id)) {
15220
+ nodes.push({
15221
+ id,
15222
+ kind: "route",
15223
+ name: `${method} ${path3}`,
15224
+ path: rel,
15225
+ startLine: line,
15226
+ endLine: line,
15227
+ source: "tree-sitter",
15228
+ meta: { method, route: path3, framework, ...extra }
15229
+ });
15230
+ pushEdge({ src: fid, dst: id, kind: "defines", source: "tree-sitter" });
15231
+ }
15232
+ for (const h of handlers)
15233
+ pushEdge({ src: h, dst: id, kind: "handles", source: "tree-sitter", confidence });
15234
+ }
15235
+ function controllerRef(name, literal2 = false) {
15236
+ if (!literal2) {
15237
+ const direct = classRef(name);
15238
+ if (direct?.id.startsWith("sym:")) return direct;
15239
+ }
15240
+ const fq = name.replace(/^\\+/, "");
15241
+ const candidates2 = CONTROLLER_NAMESPACES.map((ns) => `${ns}\\${fq}`);
15242
+ if (literal2) candidates2.push(fq);
15243
+ for (const c of candidates2) {
15244
+ const file3 = classFile(c);
15245
+ if (file3) return { id: symId(file3, lastSegment(fq)), confidence: 0.85 };
15246
+ }
15247
+ return void 0;
15248
+ }
15249
+ function classConstant(n) {
15250
+ if (n.type !== "class_constant_access_expression") return void 0;
15251
+ const [cls, member] = n.namedChildren;
15252
+ if (!cls || member?.text !== "class") return void 0;
15253
+ const t = controllerRef(cls.text);
15254
+ return t?.id.startsWith("sym:") ? t : void 0;
15255
+ }
15256
+ function handlersOf(arg, caller, controller) {
15257
+ const handlers = [];
15258
+ let confidence = 0.9;
15259
+ const self = caller ? symId(rel, caller) : fid;
15260
+ const visit2 = (a) => {
15261
+ if (!a) return;
15262
+ if (a.type === "anonymous_function" || a.type === "arrow_function") {
15263
+ handlers.push(self);
15264
+ confidence = Math.min(confidence, 0.7);
15265
+ } else if (a.type === "class_constant_access_expression") {
15266
+ const t = classConstant(a);
15267
+ if (t) handlers.push(t.id);
15268
+ } else if (a.type === "string" || a.type === "encapsed_string") {
15269
+ const s = phpString(a) ?? "";
15270
+ const m = CONTROLLER_STRING.exec(s);
15271
+ const t = m ? controllerRef(m[1], true) : void 0;
15272
+ if (t && m) handlers.push(`${t.id}.${m[2]}`);
15273
+ else if (controller && /^\w+$/.test(s)) handlers.push(`${controller.id}.${s}`);
15274
+ } else if (a.type === "array_creation_expression") {
15275
+ const els = arrayElements(a);
15276
+ const [first, second] = els;
15277
+ const method = second && !second.key ? phpString(second.value) : void 0;
15278
+ const cls = first && !first.key ? classConstant(first.value) : void 0;
15279
+ if (els.length === 2 && cls && method) handlers.push(`${cls.id}.${method}`);
15280
+ else for (const el of els) if (!el.key || el.key === "uses") visit2(el.value);
15281
+ }
15282
+ };
15283
+ visit2(arg);
15284
+ if (!handlers.length) {
15285
+ handlers.push(self);
15286
+ confidence = 0.5;
15287
+ }
15288
+ return { handlers: [...new Set(handlers)], confidence };
15289
+ }
15290
+ function groupContext(n) {
15291
+ const prefixes = [];
15292
+ let controller;
15293
+ for (let cur = n.parent; cur; cur = cur.parent) {
15294
+ if (cur.type !== "anonymous_function" && cur.type !== "arrow_function") continue;
15295
+ const call = cur.parent?.type === "argument" ? cur.parent.parent?.parent : void 0;
15296
+ if (!call || !isCall(call) || call.childForFieldName("name")?.text !== "group") continue;
15297
+ const own2 = [];
15298
+ const first = argsOf(call)[0];
15299
+ const direct = first && first.id !== cur.id ? phpString(first) : void 0;
15300
+ if (direct !== void 0) own2.push(direct);
15301
+ else if (first?.type === "array_creation_expression") {
15302
+ const prefix = arrayElements(first).find((e) => e.key === "prefix");
15303
+ const s = prefix ? phpString(prefix.value) : void 0;
15304
+ if (s !== void 0) own2.push(s);
15305
+ }
15306
+ for (let link = call.childForFieldName("object"); link && isCall(link); ) {
15307
+ const name = link.childForFieldName("name")?.text;
15308
+ const a0 = argsOf(link)[0];
15309
+ if (name === "prefix") {
15310
+ const s = phpString(a0);
15311
+ if (s !== void 0) own2.unshift(s);
15312
+ } else if (name === "controller" && a0 && !controller) {
15313
+ const s = phpString(a0);
15314
+ controller = classConstant(a0) ?? (s ? controllerRef(s, true) : void 0);
15315
+ }
15316
+ link = link.childForFieldName("object");
15317
+ }
15318
+ prefixes.unshift(...own2);
15319
+ }
15320
+ return { prefixes, controller };
15321
+ }
15322
+ function laravelBase() {
15323
+ return /(^|\/)routes\/api\.php$/.test(rel) ? "/api" : void 0;
15324
+ }
15325
+ function routeFromCall(call, caller) {
15326
+ let facade = false;
15327
+ const chained = [];
15328
+ for (let link = call; link && isCall(link); ) {
15329
+ if (link.type === "scoped_call_expression") {
15330
+ facade = lastSegment(link.childForFieldName("scope")?.text ?? "") === "Route";
15331
+ break;
15332
+ }
15333
+ link = link.childForFieldName("object");
15334
+ if (link && isCall(link) && link.childForFieldName("name")?.text === "prefix") {
15335
+ const s = phpString(argsOf(link)[0]);
15336
+ if (s !== void 0) chained.unshift(s);
15337
+ }
15338
+ }
15339
+ const obj = call.type === "member_call_expression" ? call.childForFieldName("object") : null;
15340
+ const member = !facade && obj?.type === "variable_name" && obj.text !== "$this";
15341
+ if (!facade && !member) return;
15342
+ const verb = call.childForFieldName("name")?.text ?? "";
15343
+ const lower = verb.toLowerCase();
15344
+ const args = argsOf(call);
15345
+ if (facade && (verb === "resource" || verb === "apiResource")) {
15346
+ const name = phpString(args[0]);
15347
+ if (name) resourceRoutes(call, verb === "apiResource", name, args, caller, chained);
15348
+ return;
15349
+ }
15350
+ if (facade && (verb === "resources" || verb === "apiResources")) {
15351
+ if (args[0]?.type !== "array_creation_expression") return;
15352
+ for (const el of arrayElements(args[0])) {
15353
+ if (el.key)
15354
+ resourceRoutes(
15355
+ call,
15356
+ verb === "apiResources",
15357
+ el.key,
15358
+ [void 0, el.value, args[1]],
15359
+ caller,
15360
+ chained
15361
+ );
15362
+ }
15363
+ return;
15364
+ }
15365
+ let methods;
15366
+ let rest;
15367
+ if (facade && lower === "view") {
15368
+ methods = ["GET"];
15369
+ rest = args.slice(0, 1);
15370
+ } else if (facade && (lower === "redirect" || lower === "permanentredirect")) {
15371
+ methods = ["ALL"];
15372
+ rest = args.slice(0, 1);
15373
+ } else if (lower === "match" || lower === "map") {
15374
+ methods = stringsOf(args[0]).map((m) => httpMethod(m)).filter((m) => !!m);
15375
+ rest = args.slice(1);
15376
+ } else if (lower === "any") {
15377
+ methods = ["ALL"];
15378
+ rest = args;
15379
+ } else if (ROUTE_METHODS.has(lower) && lower !== "all") {
15380
+ methods = [lower.toUpperCase()];
15381
+ rest = args;
15382
+ } else return;
15383
+ const raw = phpString(rest[0]);
15384
+ if (raw === void 0 || !methods.length) return;
15385
+ if (member && (!handlerShaped(rest[1]) || !raw.startsWith("/") && !ROUTER_VARS.has(obj.text)))
15386
+ return;
15387
+ const ctx = groupContext(call);
15388
+ const { handlers, confidence } = handlersOf(rest[1], caller, ctx.controller);
15389
+ const path3 = phpRoutePath(facade ? laravelBase() : void 0, ...ctx.prefixes, ...chained, raw);
15390
+ const framework = facade ? "laravel" : frameworkOf(importedPkgs) ?? frameworkOf(auto?.require ?? []) ?? "http";
15391
+ for (const m of methods)
15392
+ addRoute(m, path3, framework, call.startPosition.row + 1, handlers, confidence);
15393
+ }
15394
+ function resourceRoutes(call, api, name, args, caller, chained) {
15395
+ let only;
15396
+ let except;
15397
+ if (args[2]?.type === "array_creation_expression") {
15398
+ for (const opt of arrayElements(args[2])) {
15399
+ if (opt.key === "only") only = stringsOf(opt.value);
15400
+ if (opt.key === "except") except = stringsOf(opt.value);
15401
+ }
15402
+ }
15403
+ for (let cur = call; cur.parent?.type === "member_call_expression"; cur = cur.parent) {
15404
+ if (cur.parent.childForFieldName("object")?.id !== cur.id) break;
15405
+ const m = cur.parent.childForFieldName("name")?.text;
15406
+ if (m === "only") only = stringsOf(argsOf(cur.parent)[0]);
15407
+ if (m === "except") except = stringsOf(argsOf(cur.parent)[0]);
15408
+ }
15409
+ const ctx = groupContext(call);
15410
+ const literal2 = phpString(args[1]);
15411
+ const cls = args[1] ? classConstant(args[1]) ?? (literal2 ? controllerRef(literal2, true) : void 0) : void 0;
15412
+ const self = caller ? symId(rel, caller) : fid;
15413
+ for (const spec of laravelResource(name, api, only, except)) {
15414
+ addRoute(
15415
+ spec.method,
15416
+ phpRoutePath(laravelBase(), ...ctx.prefixes, ...chained, spec.path),
15417
+ "laravel",
15418
+ call.startPosition.row + 1,
15419
+ [cls ? `${cls.id}.${spec.action}` : self],
15420
+ cls ? 0.9 : 0.5
15421
+ );
15422
+ }
15423
+ }
15424
+ function attributesOf(n) {
15425
+ return (n.childForFieldName("attributes")?.descendantsOfType("attribute") ?? []).map(
15426
+ (attr) => ({ attr, fq: fqcnOf(attr.namedChildren[0]?.text ?? "") })
15427
+ );
15428
+ }
15429
+ function routeSpecs(n) {
15430
+ const out = [];
15431
+ for (const { attr, fq } of attributesOf(n)) {
15432
+ const short = lastSegment(fq);
15433
+ if (fq.startsWith(SPATIE_ATTRIBUTES)) {
15434
+ const verb = short === "Any" ? "ALL" : httpMethod(short);
15435
+ const pos = positionalArgs(attr);
15436
+ const methods2 = short === "Route" ? stringsOf(namedArg(attr, "method") ?? pos.shift()).map((m) => httpMethod(m)).filter((m) => !!m) : verb ? [verb] : [];
15437
+ const path4 = phpString(namedArg(attr, "uri") ?? pos[0]);
15438
+ if (path4 === void 0) continue;
15439
+ for (const method of methods2) out.push({ method, path: path4, spatie: true });
15440
+ continue;
15441
+ }
15442
+ if (short !== "Route") continue;
15443
+ const path3 = phpString(namedArg(attr, "path")) ?? phpString(positionalArgs(attr)[0]);
15444
+ if (path3 === void 0) continue;
15445
+ const methods = stringsOf(namedArg(attr, "methods")).map((m) => httpMethod(m)).filter((m) => !!m);
15446
+ for (const method of methods.length ? methods : ["ALL"]) out.push({ method, path: path3 });
15447
+ }
15448
+ const doc = n.previousNamedSibling;
15449
+ if (doc?.type === "comment" && doc.text.includes("@Route"))
15450
+ out.push(...parseRouteAnnotations(doc.text));
15451
+ return out;
15452
+ }
15453
+ function attributeRoutes(cls, className) {
15454
+ const classSpecs = routeSpecs(cls);
15455
+ let prefix = classSpecs[0]?.path;
15456
+ const framework = frameworkOf(importedPkgs) ?? "symfony";
15457
+ const line = cls.startPosition.row + 1;
15458
+ for (const { attr, fq } of attributesOf(cls)) {
15459
+ if (!fq.startsWith(SPATIE_ATTRIBUTES)) continue;
15460
+ const short = lastSegment(fq);
15461
+ const pos = positionalArgs(attr);
15462
+ if (short === "Prefix") prefix = phpString(namedArg(attr, "prefix") ?? pos[0]) ?? prefix;
15463
+ if (short !== "Resource") continue;
15464
+ const name = phpString(namedArg(attr, "resource") ?? pos[0]);
15465
+ if (!name) continue;
15466
+ const api = (namedArg(attr, "apiResource") ?? pos[1])?.text === "true";
15467
+ const only = namedArg(attr, "only");
15468
+ const except = namedArg(attr, "except");
15469
+ for (const spec of laravelResource(
15470
+ name,
15471
+ api,
15472
+ only ? stringsOf(only) : void 0,
15473
+ except ? stringsOf(except) : void 0
15474
+ ))
15475
+ addRoute(
15476
+ spec.method,
15477
+ phpRoutePath(prefix, spec.path),
15478
+ "laravel",
15479
+ line,
15480
+ [symId(rel, `${className}.${spec.action}`)],
15481
+ 0.95
15482
+ );
15483
+ }
15484
+ for (const m of cls.childForFieldName("body")?.namedChildren ?? []) {
15485
+ if (m?.type !== "method_declaration") continue;
15486
+ const mname = m.childForFieldName("name")?.text;
15487
+ if (!mname) continue;
15488
+ const specs = routeSpecs(m);
15489
+ if (!specs.length && mname === "__invoke" && classSpecs.length) {
15490
+ for (const s of classSpecs)
15491
+ addRoute(
15492
+ s.method,
15493
+ phpRoutePath(s.path),
15494
+ framework,
15495
+ line,
15496
+ [symId(rel, `${className}.${mname}`)],
15497
+ 0.95
15498
+ );
15499
+ continue;
15500
+ }
15501
+ for (const s of specs) {
15502
+ addRoute(
15503
+ s.method,
15504
+ phpRoutePath(prefix, s.path),
15505
+ s.spatie ? "laravel" : framework,
15506
+ m.startPosition.row + 1,
15507
+ [symId(rel, `${className}.${mname}`)],
15508
+ 0.95
15509
+ );
15510
+ }
15511
+ }
15512
+ }
15513
+ function walkRefs(n) {
15514
+ noteVarTypes(n);
15515
+ for (const call of n.descendantsOfType(CALLS)) {
15516
+ const caller = enclosing(call);
15517
+ routeFromCall(call, caller);
15518
+ const target = callTarget(call, caller);
15519
+ if (!target) continue;
15520
+ refs.push(
15521
+ caller ? symId(rel, caller) : fid,
15522
+ target.id,
15523
+ "calls",
15524
+ target.confidence,
15525
+ call.startPosition.row + 1
15526
+ );
15527
+ }
15528
+ const named = [];
15529
+ for (const t of n.descendantsOfType("named_type")) named.push(t);
15530
+ for (const a of n.descendantsOfType([
15531
+ "class_constant_access_expression",
15532
+ "scoped_property_access_expression"
15533
+ ])) {
15534
+ const s = a.namedChildren[0];
15535
+ if (s && (s.type === "name" || s.type === "qualified_name")) named.push(s);
15536
+ }
15537
+ for (const b of n.descendantsOfType("binary_expression")) {
15538
+ const right = b.childForFieldName("right");
15539
+ if (b.childForFieldName("operator")?.type === "instanceof" && right) named.push(right);
15540
+ }
15541
+ for (const t of named) {
15542
+ const target = classRef(t.text);
15543
+ if (!target) continue;
15544
+ const caller = enclosing(t);
15545
+ refs.push(
15546
+ caller ? symId(rel, caller) : fid,
15547
+ target.id,
15548
+ "references",
15549
+ target.confidence * 0.9,
15550
+ t.startPosition.row + 1
15551
+ );
15552
+ }
15553
+ for (const me of n.descendantsOfType([
15554
+ "member_access_expression",
15555
+ "nullsafe_member_access_expression"
15556
+ ])) {
15557
+ if (me.childForFieldName("object")?.text !== "$this") continue;
15558
+ const caller = enclosing(me);
15559
+ const cls = classOf(caller);
15560
+ const prop = me.childForFieldName("name")?.text;
15561
+ if (!cls || !prop || !localSyms.has(`${cls}.${prop}`)) continue;
15562
+ refs.push(
15563
+ symId(rel, caller),
15564
+ symId(rel, `${cls}.${prop}`),
15565
+ "references",
15566
+ 0.81,
15567
+ me.startPosition.row + 1
15568
+ );
15569
+ }
15570
+ }
15571
+ }
15572
+ var BRANCHES2, BOOL_OPS2, CALLS, CLASS_KINDS, RELATIVE, ROUTER_VARS, CONTROLLER_NAMESPACES, SPATIE_ATTRIBUTES, isFile, toRel, CLASSMAP_MAX_FILES, composerCache, asList, CONTROLLER_STRING, isPublic, classOf, lastSegment, isCall;
15573
+ var init_php = __esm({
15574
+ "src/graph/languages/php.ts"() {
15575
+ "use strict";
15576
+ init_esm_shims();
15577
+ init_ids();
15578
+ init_routes();
15579
+ init_parser();
15580
+ BRANCHES2 = [
15581
+ "if_statement",
15582
+ "else_if_clause",
15583
+ "for_statement",
15584
+ "foreach_statement",
15585
+ "while_statement",
15586
+ "do_statement",
15587
+ "case_statement",
15588
+ "catch_clause",
15589
+ "conditional_expression",
15590
+ "match_conditional_expression",
15591
+ "binary_expression"
15592
+ ];
15593
+ BOOL_OPS2 = /* @__PURE__ */ new Set(["&&", "||", "and", "or", "??"]);
15594
+ CALLS = [
15595
+ "function_call_expression",
15596
+ "member_call_expression",
15597
+ "nullsafe_member_call_expression",
15598
+ "scoped_call_expression",
15599
+ "object_creation_expression"
15600
+ ];
15601
+ CLASS_KINDS = {
15602
+ class_declaration: "class",
15603
+ interface_declaration: "interface",
15604
+ trait_declaration: "trait",
15605
+ enum_declaration: "enum"
15606
+ };
15607
+ RELATIVE = /* @__PURE__ */ new Set(["self", "static", "parent"]);
15608
+ ROUTER_VARS = /* @__PURE__ */ new Set(["$app", "$router", "$routes", "$route", "$group", "$r"]);
15609
+ CONTROLLER_NAMESPACES = ["App\\Http\\Controllers", "App\\Controllers"];
15610
+ SPATIE_ATTRIBUTES = "Spatie\\RouteAttributes\\Attributes\\";
15611
+ isFile = (p) => {
15612
+ try {
15613
+ return statSync(p).isFile();
15614
+ } catch {
15615
+ return false;
15616
+ }
15617
+ };
15618
+ toRel = (root, abs) => normalize2(relative2(root, abs)).split("\\").join("/");
15619
+ CLASSMAP_MAX_FILES = 5e3;
15620
+ composerCache = /* @__PURE__ */ new Map();
15621
+ asList = (v) => Array.isArray(v) ? v : [v];
15622
+ CONTROLLER_STRING = /^\\?([\w\\]+?)(?:@|::?)(\w+)$/;
15623
+ isPublic = (m) => !m.namedChildren.some((c) => c?.type === "visibility_modifier" && c.text !== "public");
15624
+ classOf = (caller) => caller?.includes(".") ? caller.split(".")[0] : void 0;
15625
+ lastSegment = (name) => name.split("\\").pop() ?? name;
15626
+ isCall = (n) => n.type === "member_call_expression" || n.type === "scoped_call_expression";
15627
+ }
15628
+ });
15629
+
15630
+ // src/graph/languages/python.ts
15631
+ import { existsSync as existsSync5, statSync as statSync2 } from "fs";
15632
+ import { dirname as dirname5, join as join8, normalize as normalize3, relative as relative3, resolve as resolve4 } from "path";
14509
15633
  function resolvePython(root, fromRel, module, level) {
14510
15634
  const parts = module ? module.split(".") : [];
14511
15635
  const candidates2 = [];
14512
15636
  if (level > 0) {
14513
- let base = dirname4(resolve3(root, fromRel));
14514
- for (let i = 1; i < level; i++) base = dirname4(base);
14515
- candidates2.push(join7(base, ...parts));
15637
+ let base = dirname5(resolve4(root, fromRel));
15638
+ for (let i = 1; i < level; i++) base = dirname5(base);
15639
+ candidates2.push(join8(base, ...parts));
14516
15640
  } else {
14517
- candidates2.push(resolve3(root, ...parts), resolve3(root, "src", ...parts));
14518
- let dir = dirname4(resolve3(root, fromRel));
15641
+ candidates2.push(resolve4(root, ...parts), resolve4(root, "src", ...parts));
15642
+ let dir = dirname5(resolve4(root, fromRel));
14519
15643
  while (dir.startsWith(root) && dir !== root) {
14520
- candidates2.push(join7(dir, ...parts));
14521
- dir = dirname4(dir);
15644
+ candidates2.push(join8(dir, ...parts));
15645
+ dir = dirname5(dir);
14522
15646
  }
14523
15647
  }
14524
15648
  for (const c of candidates2) {
14525
- for (const f of [`${c}.py`, join7(c, "__init__.py"), `${c}.pyi`]) {
14526
- if (isFile(f) && !relative2(root, f).startsWith(".."))
14527
- return normalize2(relative2(root, f)).split("\\").join("/");
15649
+ for (const f of [`${c}.py`, join8(c, "__init__.py"), `${c}.pyi`]) {
15650
+ if (isFile2(f) && !relative3(root, f).startsWith(".."))
15651
+ return normalize3(relative3(root, f)).split("\\").join("/");
14528
15652
  }
14529
15653
  }
14530
15654
  return void 0;
@@ -14561,7 +15685,7 @@ async function parsePython(root, rel, code) {
14561
15685
  walkRefs(stmt);
14562
15686
  }
14563
15687
  edges.push(...refs.edges());
14564
- if (!existsSync5(join7(root, rel))) {
15688
+ if (!existsSync5(join8(root, rel))) {
14565
15689
  }
14566
15690
  const errors = tree.rootNode.hasError ? tree.rootNode.descendantsOfType("ERROR").length : 0;
14567
15691
  fileNode.meta = {
@@ -14714,7 +15838,7 @@ async function parsePython(root, rel, code) {
14714
15838
  }
14715
15839
  function addSym(qualified, kind, n, exported) {
14716
15840
  const id = symId(rel, qualified);
14717
- const c = kind === "function" || kind === "method" ? complexityOf(n, BRANCHES2, BOOL_OPS2) : 0;
15841
+ const c = kind === "function" || kind === "method" ? complexityOf(n, BRANCHES3, BOOL_OPS3) : 0;
14718
15842
  complexity += c;
14719
15843
  nodes.push({
14720
15844
  id,
@@ -14857,7 +15981,7 @@ async function parsePython(root, rel, code) {
14857
15981
  }
14858
15982
  }
14859
15983
  }
14860
- var BRANCHES2, BOOL_OPS2, isFile, topModule, REF_SKIP_PARENT;
15984
+ var BRANCHES3, BOOL_OPS3, isFile2, topModule, REF_SKIP_PARENT;
14861
15985
  var init_python = __esm({
14862
15986
  "src/graph/languages/python.ts"() {
14863
15987
  "use strict";
@@ -14865,7 +15989,7 @@ var init_python = __esm({
14865
15989
  init_ids();
14866
15990
  init_routes();
14867
15991
  init_parser();
14868
- BRANCHES2 = [
15992
+ BRANCHES3 = [
14869
15993
  "if_statement",
14870
15994
  "elif_clause",
14871
15995
  "for_statement",
@@ -14876,10 +16000,10 @@ var init_python = __esm({
14876
16000
  "case_clause",
14877
16001
  "for_in_clause"
14878
16002
  ];
14879
- BOOL_OPS2 = /* @__PURE__ */ new Set(["and", "or"]);
14880
- isFile = (p) => {
16003
+ BOOL_OPS3 = /* @__PURE__ */ new Set(["and", "or"]);
16004
+ isFile2 = (p) => {
14881
16005
  try {
14882
- return statSync(p).isFile();
16006
+ return statSync2(p).isFile();
14883
16007
  } catch {
14884
16008
  return false;
14885
16009
  }
@@ -14908,21 +16032,21 @@ var init_python = __esm({
14908
16032
  });
14909
16033
 
14910
16034
  // src/graph/resolve.ts
14911
- import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
14912
- import { dirname as dirname5, join as join8, normalize as normalize3, relative as relative3, resolve as resolve4 } from "path";
16035
+ import { existsSync as existsSync6, readdirSync as readdirSync3, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
16036
+ import { dirname as dirname6, join as join9, normalize as normalize4, relative as relative4, resolve as resolve5 } from "path";
14913
16037
  function loadTsPaths(root) {
14914
16038
  const hit = tsPathsCache.get(root);
14915
16039
  if (hit !== void 0) return hit;
14916
16040
  let out = null;
14917
16041
  try {
14918
- const file3 = join8(root, "tsconfig.json");
16042
+ const file3 = join9(root, "tsconfig.json");
14919
16043
  if (existsSync6(file3)) {
14920
- const raw = readFileSync4(file3, "utf8").replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "").replace(/,(\s*[}\]])/g, "$1");
16044
+ const raw = readFileSync5(file3, "utf8").replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "").replace(/,(\s*[}\]])/g, "$1");
14921
16045
  const cfg = JSON.parse(raw);
14922
16046
  const co = cfg.compilerOptions ?? {};
14923
16047
  if (co.paths) {
14924
16048
  out = {
14925
- baseUrl: resolve4(root, co.baseUrl ?? "."),
16049
+ baseUrl: resolve5(root, co.baseUrl ?? "."),
14926
16050
  paths: Object.entries(co.paths).map(([k, v]) => {
14927
16051
  const star = k.indexOf("*");
14928
16052
  return star === -1 ? { prefix: k, suffix: "\0", targets: v } : { prefix: k.slice(0, star), suffix: k.slice(star + 1), targets: v };
@@ -14939,7 +16063,7 @@ function loadTsPaths(root) {
14939
16063
  function probe(abs) {
14940
16064
  const tryFile = (p) => {
14941
16065
  try {
14942
- return statSync2(p).isFile() ? p : void 0;
16066
+ return statSync3(p).isFile() ? p : void 0;
14943
16067
  } catch {
14944
16068
  return void 0;
14945
16069
  }
@@ -14955,16 +16079,16 @@ function probe(abs) {
14955
16079
  if (tryFile(abs + ext)) return abs + ext;
14956
16080
  }
14957
16081
  for (const ext of EXTS) {
14958
- const idx = join8(abs, `index${ext}`);
16082
+ const idx = join9(abs, `index${ext}`);
14959
16083
  if (tryFile(idx)) return idx;
14960
16084
  }
14961
16085
  return void 0;
14962
16086
  }
14963
16087
  function readPackageJson(dir) {
14964
16088
  try {
14965
- const file3 = join8(dir, "package.json");
16089
+ const file3 = join9(dir, "package.json");
14966
16090
  if (!existsSync6(file3)) return void 0;
14967
- return JSON.parse(readFileSync4(file3, "utf8"));
16091
+ return JSON.parse(readFileSync5(file3, "utf8"));
14968
16092
  } catch {
14969
16093
  return void 0;
14970
16094
  }
@@ -14980,9 +16104,9 @@ function loadWorkspaces(root) {
14980
16104
  if (Array.isArray(ws)) globs.push(...ws);
14981
16105
  else if (ws?.packages) globs.push(...ws.packages);
14982
16106
  try {
14983
- const yaml = join8(root, "pnpm-workspace.yaml");
16107
+ const yaml = join9(root, "pnpm-workspace.yaml");
14984
16108
  if (existsSync6(yaml)) {
14985
- for (const m of readFileSync4(yaml, "utf8").matchAll(/^\s*-\s*['"]?([^'"\n#]+?)['"]?\s*$/gm))
16109
+ for (const m of readFileSync5(yaml, "utf8").matchAll(/^\s*-\s*['"]?([^'"\n#]+?)['"]?\s*$/gm))
14986
16110
  globs.push(m[1].trim());
14987
16111
  }
14988
16112
  } catch {
@@ -14991,12 +16115,12 @@ function loadWorkspaces(root) {
14991
16115
  if (g.startsWith("!")) continue;
14992
16116
  const star = g.indexOf("*");
14993
16117
  const dirs = [];
14994
- if (star === -1) dirs.push(resolve4(root, g));
16118
+ if (star === -1) dirs.push(resolve5(root, g));
14995
16119
  else {
14996
- const base = resolve4(root, g.slice(0, star));
16120
+ const base = resolve5(root, g.slice(0, star));
14997
16121
  try {
14998
- for (const d of readdirSync2(base, { withFileTypes: true })) {
14999
- if (d.isDirectory()) dirs.push(join8(base, d.name));
16122
+ for (const d of readdirSync3(base, { withFileTypes: true })) {
16123
+ if (d.isDirectory()) dirs.push(join9(base, d.name));
15000
16124
  }
15001
16125
  } catch {
15002
16126
  }
@@ -15050,16 +16174,16 @@ function resolvePackageEntry(dir, sub) {
15050
16174
  } else candidates2.push(sub, `src/${sub}`, `lib/${sub}`);
15051
16175
  for (const c of candidates2) {
15052
16176
  if (c.includes("*")) continue;
15053
- const hit = probe(resolve4(dir, c));
16177
+ const hit = probe(resolve5(dir, c));
15054
16178
  if (hit) return hit;
15055
16179
  }
15056
16180
  return void 0;
15057
16181
  }
15058
16182
  function resolveImport(root, fromRel, spec) {
15059
16183
  if (spec.startsWith(".") || spec.startsWith("/")) {
15060
- const abs = spec.startsWith("/") ? spec : resolve4(root, dirname5(fromRel), spec);
16184
+ const abs = spec.startsWith("/") ? spec : resolve5(root, dirname6(fromRel), spec);
15061
16185
  const hit = probe(abs);
15062
- return hit ? normalize3(relative3(root, hit)) : void 0;
16186
+ return hit ? normalize4(relative4(root, hit)) : void 0;
15063
16187
  }
15064
16188
  const tp = loadTsPaths(root);
15065
16189
  if (tp) {
@@ -15068,8 +16192,8 @@ function resolveImport(root, fromRel, spec) {
15068
16192
  if (exact ? spec === p.prefix : spec.startsWith(p.prefix) && spec.endsWith(p.suffix)) {
15069
16193
  const star = exact ? "" : spec.slice(p.prefix.length, spec.length - p.suffix.length);
15070
16194
  for (const t of p.targets) {
15071
- const hit = probe(resolve4(tp.baseUrl, t.replace("*", star)));
15072
- if (hit) return normalize3(relative3(root, hit));
16195
+ const hit = probe(resolve5(tp.baseUrl, t.replace("*", star)));
16196
+ if (hit) return normalize4(relative4(root, hit));
15073
16197
  }
15074
16198
  }
15075
16199
  }
@@ -15078,7 +16202,7 @@ function resolveImport(root, fromRel, spec) {
15078
16202
  const dir = loadWorkspaces(root).get(name);
15079
16203
  if (dir) {
15080
16204
  const hit = resolvePackageEntry(dir, spec.slice(name.length + 1));
15081
- if (hit && !relative3(root, hit).startsWith("..")) return normalize3(relative3(root, hit));
16205
+ if (hit && !relative4(root, hit).startsWith("..")) return normalize4(relative4(root, hit));
15082
16206
  }
15083
16207
  return void 0;
15084
16208
  }
@@ -15142,6 +16266,7 @@ async function parseFile(root, rel, code) {
15142
16266
  if (!grammar) return { nodes: [], edges: [], exports: [] };
15143
16267
  if (grammar === "python") return parsePython(root, rel, code);
15144
16268
  if (grammar === "go") return parseGo(root, rel, code);
16269
+ if (grammar === "php") return parsePhp(root, rel, code);
15145
16270
  const p = await getParser(grammar);
15146
16271
  const tree = p.parse(code);
15147
16272
  if (!tree) return { nodes: [], edges: [], exports: [] };
@@ -15734,6 +16859,7 @@ var init_treesitter = __esm({
15734
16859
  init_ids();
15735
16860
  init_go();
15736
16861
  init_parser();
16862
+ init_php();
15737
16863
  init_python();
15738
16864
  init_resolve();
15739
16865
  init_routes();
@@ -15822,8 +16948,8 @@ __export(indexer_exports, {
15822
16948
  indexContent: () => indexContent,
15823
16949
  indexPath: () => indexPath
15824
16950
  });
15825
- import { readFileSync as readFileSync5, statSync as statSync3 } from "fs";
15826
- import { relative as relative4, resolve as resolve5 } from "path";
16951
+ import { readFileSync as readFileSync6, statSync as statSync4 } from "fs";
16952
+ import { relative as relative5, resolve as resolve6 } from "path";
15827
16953
  function indexContent(db, input2) {
15828
16954
  const kind = input2.kind ?? (input2.contentType === "code" ? "code" : input2.contentType === "json" ? "json" : void 0);
15829
16955
  const { chunks, kind: k } = input2.chunks ? { chunks: finalize2(input2.chunks, input2.contentType ?? "code"), kind: kind ?? "code" } : chunk(input2.content, input2.title, kind, input2.uri);
@@ -15856,9 +16982,9 @@ function indexContent(db, input2) {
15856
16982
  return { documentId: id, created, chunks: chunks.length, chars: input2.content.length, kind: k };
15857
16983
  }
15858
16984
  function indexPath(db, root, target, opts = {}) {
15859
- const abs = resolve5(root, target);
16985
+ const abs = resolve6(root, target);
15860
16986
  const summary = { files: 0, indexed: 0, unchanged: 0, skipped: [], chunks: 0 };
15861
- const st = statSync3(abs);
16987
+ const st = statSync4(abs);
15862
16988
  const files = st.isDirectory() ? import_fast_glob.default.sync(opts.globs ?? ["**/*.md"], {
15863
16989
  cwd: abs,
15864
16990
  absolute: true,
@@ -15869,14 +16995,14 @@ function indexPath(db, root, target, opts = {}) {
15869
16995
  }) : [abs];
15870
16996
  for (const file3 of files) {
15871
16997
  summary.files++;
15872
- const rel = relative4(root, file3) || file3;
16998
+ const rel = relative5(root, file3) || file3;
15873
16999
  try {
15874
- const size = statSync3(file3).size;
17000
+ const size = statSync4(file3).size;
15875
17001
  if (size > MAX_FILE_BYTES) {
15876
17002
  summary.skipped.push({ path: rel, reason: `too large (${size} bytes)` });
15877
17003
  continue;
15878
17004
  }
15879
- const content = readFileSync5(file3, "utf8");
17005
+ const content = readFileSync6(file3, "utf8");
15880
17006
  if (content.includes("\0")) {
15881
17007
  summary.skipped.push({ path: rel, reason: "binary" });
15882
17008
  continue;
@@ -16094,6 +17220,11 @@ function inherited(db, classId, member, depth) {
16094
17220
  }
16095
17221
  return void 0;
16096
17222
  }
17223
+ function ownerAncestor(db, path3, name) {
17224
+ const dot = name.indexOf(".");
17225
+ const owner = symId(path3, name.slice(0, dot));
17226
+ return db.graphGetNode(owner) ? inherited(db, owner, name.slice(dot + 1), 0) : void 0;
17227
+ }
16097
17228
  function defaultExportOf(db, path3) {
16098
17229
  const f = db.graphGetNode(fileId(path3));
16099
17230
  if (!f?.meta) return void 0;
@@ -16142,6 +17273,10 @@ function linkGraph(db) {
16142
17273
  direct = true;
16143
17274
  } else target = goSibling(db, path3, head);
16144
17275
  }
17276
+ if (!target && name.includes(".")) {
17277
+ target = ownerAncestor(db, path3, name);
17278
+ direct = true;
17279
+ }
16145
17280
  if (target && name.includes(".") && !direct) {
16146
17281
  const rest2 = name.slice(name.indexOf(".") + 1);
16147
17282
  const member = `${target}.${rest2}`;
@@ -16180,7 +17315,7 @@ function linkGraph(db) {
16180
17315
  const name = meta4.unresolved;
16181
17316
  if (!name) continue;
16182
17317
  const id = symId(e.dst.slice(5), name);
16183
- const target = db.graphGetNode(id) ? id : viaReexports(db, e.dst.slice(5), name.split(".")[0], 0, /* @__PURE__ */ new Set());
17318
+ const target = db.graphGetNode(id) ? id : viaReexports(db, e.dst.slice(5), name.split(".")[0], 0, /* @__PURE__ */ new Set()) ?? (name.includes(".") ? ownerAncestor(db, e.dst.slice(5), name) : void 0);
16184
17319
  if (!target || target === e.src) continue;
16185
17320
  const { unresolved: _u, ...rest } = meta4;
16186
17321
  replace(db, e, {
@@ -16503,6 +17638,7 @@ var init_metrics = __esm({
16503
17638
  "class",
16504
17639
  "method",
16505
17640
  "interface",
17641
+ "trait",
16506
17642
  "type",
16507
17643
  "enum",
16508
17644
  "field",
@@ -16532,8 +17668,8 @@ __export(reindex_exports, {
16532
17668
  reindexCode: () => reindexCode,
16533
17669
  reindexGitSignals: () => reindexGitSignals
16534
17670
  });
16535
- import { readFileSync as readFileSync6, statSync as statSync4 } from "fs";
16536
- import { join as join9 } from "path";
17671
+ import { readFileSync as readFileSync7, statSync as statSync5 } from "fs";
17672
+ import { join as join10 } from "path";
16537
17673
  function listCodeFiles(ctx) {
16538
17674
  return import_fast_glob2.default.sync(ctx.config.graph.include, {
16539
17675
  cwd: ctx.root,
@@ -16544,8 +17680,8 @@ function listCodeFiles(ctx) {
16544
17680
  });
16545
17681
  }
16546
17682
  async function indexOne(ctx, db, rel, force) {
16547
- const abs = join9(ctx.root, rel);
16548
- const st = statSync4(abs);
17683
+ const abs = join10(ctx.root, rel);
17684
+ const st = statSync5(abs);
16549
17685
  const backend = getCodeBackend(ctx);
16550
17686
  const language = backend.languageOf(rel) ?? null;
16551
17687
  if (st.size > MAX_CODE_BYTES) {
@@ -16564,7 +17700,7 @@ async function indexOne(ctx, db, rel, force) {
16564
17700
  }
16565
17701
  return "skipped";
16566
17702
  }
16567
- const code = readFileSync6(abs, "utf8");
17703
+ const code = readFileSync7(abs, "utf8");
16568
17704
  const hash2 = hashText(code);
16569
17705
  const prev = db.fileIndexGet(rel);
16570
17706
  if (!force && prev?.hash === hash2 && prev.status !== "skipped") return "unchanged";
@@ -16645,7 +17781,7 @@ async function reindexCode(ctx, db, opts = {}) {
16645
17781
  summary.unsupported++;
16646
17782
  if (db.fileIndexGet(rel)?.status === "unsupported") continue;
16647
17783
  try {
16648
- const st = statSync4(join9(ctx.root, rel));
17784
+ const st = statSync5(join10(ctx.root, rel));
16649
17785
  db.fileIndexSet({
16650
17786
  path: rel,
16651
17787
  hash: "",
@@ -16661,7 +17797,7 @@ async function reindexCode(ctx, db, opts = {}) {
16661
17797
  }
16662
17798
  for (const rel of targets) {
16663
17799
  try {
16664
- if (!statSafe(join9(ctx.root, rel))) {
17800
+ if (!statSafe(join10(ctx.root, rel))) {
16665
17801
  if (db.fileIndexGet(rel)) {
16666
17802
  removeOne(db, rel);
16667
17803
  summary.removed++;
@@ -16673,7 +17809,7 @@ async function reindexCode(ctx, db, opts = {}) {
16673
17809
  const error62 = err.message;
16674
17810
  summary.errors.push({ path: rel, error: error62 });
16675
17811
  try {
16676
- const st = statSync4(join9(ctx.root, rel));
17812
+ const st = statSync5(join10(ctx.root, rel));
16677
17813
  db.fileIndexSet({
16678
17814
  path: rel,
16679
17815
  hash: "",
@@ -16736,7 +17872,7 @@ async function reindexCode(ctx, db, opts = {}) {
16736
17872
  }
16737
17873
  function statSafe(p) {
16738
17874
  try {
16739
- return statSync4(p).isFile();
17875
+ return statSync5(p).isFile();
16740
17876
  } catch {
16741
17877
  return false;
16742
17878
  }
@@ -16776,10 +17912,10 @@ function indexFreshness(ctx, db) {
16776
17912
  const dirty = [];
16777
17913
  for (const r of rows.slice(0, 400)) {
16778
17914
  try {
16779
- const abs = join9(ctx.root, r.path);
16780
- const st = statSync4(abs);
17915
+ const abs = join10(ctx.root, r.path);
17916
+ const st = statSync5(abs);
16781
17917
  if (r.mtime !== null && Math.abs(st.mtimeMs - r.mtime) < 1 && st.size === r.size) continue;
16782
- if (hashText(readFileSync6(abs, "utf8")) !== r.hash) dirty.push(r.path);
17918
+ if (hashText(readFileSync7(abs, "utf8")) !== r.hash) dirty.push(r.path);
16783
17919
  } catch {
16784
17920
  dirty.push(r.path);
16785
17921
  }
@@ -16899,13 +18035,13 @@ __export(store_exports, {
16899
18035
  import {
16900
18036
  existsSync as existsSync8,
16901
18037
  mkdirSync as mkdirSync3,
16902
- readFileSync as readFileSync7,
18038
+ readFileSync as readFileSync8,
16903
18039
  renameSync,
16904
- statSync as statSync5,
18040
+ statSync as statSync6,
16905
18041
  unlinkSync,
16906
18042
  writeFileSync as writeFileSync2
16907
18043
  } from "fs";
16908
- import { dirname as dirname6, join as join11, relative as relative5, sep } from "path";
18044
+ import { dirname as dirname7, join as join12, relative as relative6, sep } from "path";
16909
18045
  function isStatus(s) {
16910
18046
  return typeof s === "string" && MEMORY_STATUSES.includes(s);
16911
18047
  }
@@ -16919,16 +18055,16 @@ function memoriesRel(ctx) {
16919
18055
  return ctx.config.memories.dir.replace(/^\.\//, "").replace(/\/+$/, "");
16920
18056
  }
16921
18057
  function memoriesDir(ctx) {
16922
- return join11(ctx.root, memoriesRel(ctx));
18058
+ return join12(ctx.root, memoriesRel(ctx));
16923
18059
  }
16924
18060
  function relOf(ctx, name) {
16925
18061
  return `${memoriesRel(ctx)}/${name}.md`;
16926
18062
  }
16927
18063
  function absOf(ctx, name) {
16928
- return join11(ctx.root, relOf(ctx, name));
18064
+ return join12(ctx.root, relOf(ctx, name));
16929
18065
  }
16930
18066
  function nameOfFile(ctx, abs) {
16931
- const rel = relative5(memoriesDir(ctx), abs).split(sep).join("/");
18067
+ const rel = relative6(memoriesDir(ctx), abs).split(sep).join("/");
16932
18068
  if (!rel.endsWith(".md")) return void 0;
16933
18069
  const name = rel.slice(0, -3);
16934
18070
  return isValidName(name) ? name : void 0;
@@ -16967,7 +18103,7 @@ function normalizeRelated(ids) {
16967
18103
  }
16968
18104
  function writeMemoryFile(ctx, name, meta4, body) {
16969
18105
  const abs = absOf(ctx, name);
16970
- mkdirSync3(dirname6(abs), { recursive: true });
18106
+ mkdirSync3(dirname7(abs), { recursive: true });
16971
18107
  writeFileSync2(abs, serializeMemoryFile(meta4, `
16972
18108
  ${body.trim()}
16973
18109
  `));
@@ -17012,12 +18148,12 @@ function syncFile(ctx, db, name, opts = {}) {
17012
18148
  const abs = absOf(ctx, name);
17013
18149
  const rel = relOf(ctx, name);
17014
18150
  if (!existsSync8(abs)) return void 0;
17015
- let st = statSync5(abs);
18151
+ let st = statSync6(abs);
17016
18152
  const row = db.memoryGetByName(name);
17017
18153
  const mtime = Math.floor(st.mtimeMs);
17018
18154
  if (!opts.force && row && row.file_mtime === mtime && row.file_size === st.size)
17019
18155
  return { changed: false, row };
17020
- let text2 = readFileSync7(abs, "utf8");
18156
+ let text2 = readFileSync8(abs, "utf8");
17021
18157
  let hash2 = hashText(text2);
17022
18158
  if (!opts.force && row && row.file_hash === hash2) {
17023
18159
  db.memoryUpsertByName({
@@ -17056,7 +18192,7 @@ function syncFile(ctx, db, name, opts = {}) {
17056
18192
  ${parsed.body.replace(/^\s*\n/, "")}`
17057
18193
  );
17058
18194
  writeFileSync2(abs, text2);
17059
- st = statSync5(abs);
18195
+ st = statSync6(abs);
17060
18196
  hash2 = hashText(text2);
17061
18197
  }
17062
18198
  const body = parsed.body.trim();
@@ -17094,7 +18230,7 @@ tags: ${tags.join(", ")}` : ""}`,
17094
18230
  function setMeta(ctx, db, name, patch) {
17095
18231
  const abs = absOf(ctx, name);
17096
18232
  if (!existsSync8(abs)) return false;
17097
- const parsed = parseMemoryFile(readFileSync7(abs, "utf8"));
18233
+ const parsed = parseMemoryFile(readFileSync8(abs, "utf8"));
17098
18234
  const meta4 = { ...parsed.meta };
17099
18235
  for (const [k, v] of Object.entries(patch)) {
17100
18236
  if (v === void 0) delete meta4[k];
@@ -17143,7 +18279,7 @@ function reconcile(ctx, db) {
17143
18279
  for (const f of files) {
17144
18280
  const name = nameOfFile(ctx, f);
17145
18281
  if (!name) {
17146
- out.skipped.push(relative5(ctx.root, f));
18282
+ out.skipped.push(relative6(ctx.root, f));
17147
18283
  continue;
17148
18284
  }
17149
18285
  seen.add(name);
@@ -17175,7 +18311,7 @@ function write(ctx, db, input2) {
17175
18311
  let extra = {};
17176
18312
  if (exists) {
17177
18313
  try {
17178
- extra = parseMemoryFile(readFileSync7(abs, "utf8")).meta;
18314
+ extra = parseMemoryFile(readFileSync8(abs, "utf8")).meta;
17179
18315
  } catch {
17180
18316
  }
17181
18317
  }
@@ -17202,7 +18338,7 @@ function write(ctx, db, input2) {
17202
18338
  function read(ctx, db, name) {
17203
18339
  const synced = syncFile(ctx, db, name);
17204
18340
  if (!synced) return void 0;
17205
- const parsed = parseMemoryFile(readFileSync7(absOf(ctx, name), "utf8"));
18341
+ const parsed = parseMemoryFile(readFileSync8(absOf(ctx, name), "utf8"));
17206
18342
  return {
17207
18343
  name,
17208
18344
  kind: synced.row.kind,
@@ -17229,7 +18365,7 @@ function edit(ctx, db, name, opts) {
17229
18365
  const abs = absOf(ctx, name);
17230
18366
  if (!existsSync8(abs)) throw new Error(`memory "${name}" does not exist`);
17231
18367
  syncFile(ctx, db, name);
17232
- const parsed = parseMemoryFile(readFileSync7(abs, "utf8"));
18368
+ const parsed = parseMemoryFile(readFileSync8(abs, "utf8"));
17233
18369
  const re = new RegExp(opts.regex ? opts.find : escapeRe(opts.find), "g");
17234
18370
  const count = (parsed.body.match(re) ?? []).length;
17235
18371
  if (!count) return 0;
@@ -17247,9 +18383,9 @@ function rename(ctx, db, from, to) {
17247
18383
  const absTo = absOf(ctx, to);
17248
18384
  if (!existsSync8(absFrom)) throw new Error(`memory "${from}" does not exist`);
17249
18385
  if (existsSync8(absTo) || db.memoryGetByName(to)) throw new Error(`memory "${to}" already exists`);
17250
- mkdirSync3(dirname6(absTo), { recursive: true });
18386
+ mkdirSync3(dirname7(absTo), { recursive: true });
17251
18387
  renameSync(absFrom, absTo);
17252
- const parsed = parseMemoryFile(readFileSync7(absTo, "utf8"));
18388
+ const parsed = parseMemoryFile(readFileSync8(absTo, "utf8"));
17253
18389
  writeFileSync2(
17254
18390
  absTo,
17255
18391
  serializeMemoryFile(
@@ -17265,7 +18401,7 @@ function rename(ctx, db, from, to) {
17265
18401
  if (!row.name || row.name === to) continue;
17266
18402
  const abs = absOf(ctx, row.name);
17267
18403
  if (!existsSync8(abs)) continue;
17268
- const text2 = readFileSync7(abs, "utf8");
18404
+ const text2 = readFileSync8(abs, "utf8");
17269
18405
  if (!ref.test(text2)) continue;
17270
18406
  ref.lastIndex = 0;
17271
18407
  writeFileSync2(abs, text2.replace(ref, `mem:${to}`));
@@ -17284,11 +18420,11 @@ function remove(ctx, db, name) {
17284
18420
  function gitignoreHint(ctx) {
17285
18421
  if (hinted.has(ctx.root)) return void 0;
17286
18422
  hinted.add(ctx.root);
17287
- const file3 = join11(ctx.root, ".gitignore");
18423
+ const file3 = join12(ctx.root, ".gitignore");
17288
18424
  if (!existsSync8(file3)) return void 0;
17289
18425
  const dir = memoriesRel(ctx);
17290
18426
  const top = dir.split("/")[0];
17291
- const ignored = readFileSync7(file3, "utf8").split(/\r?\n/).map((l) => l.trim().replace(/^\//, "").replace(/\/$/, "")).some((l) => l === top || l === dir || l === `${top}/**` || l === `${dir}/**`);
18427
+ const ignored = readFileSync8(file3, "utf8").split(/\r?\n/).map((l) => l.trim().replace(/^\//, "").replace(/\/$/, "")).some((l) => l === top || l === dir || l === `${top}/**` || l === `${dir}/**`);
17292
18428
  return ignored ? `note: .gitignore ignores ${dir}, so memories stay local to this machine (remove that line to share them with the team)` : void 0;
17293
18429
  }
17294
18430
  var import_fast_glob3, MEMORY_KINDS, SEGMENT, NAME_RE, hinted;
@@ -17815,14 +18951,14 @@ function buildHistory(ctx, db, opts = {}) {
17815
18951
  };
17816
18952
  });
17817
18953
  const bySha = new Map(commits.map((c) => [c.sha, c]));
17818
- const resolve7 = (prefix) => {
18954
+ const resolve8 = (prefix) => {
17819
18955
  if (bySha.has(prefix)) return bySha.get(prefix);
17820
18956
  for (const c of commits) if (c.sha.startsWith(prefix)) return c;
17821
18957
  return void 0;
17822
18958
  };
17823
18959
  for (const c of commits) {
17824
18960
  if (c.kind !== "revert" || !c.revertOf) continue;
17825
- const target = resolve7(c.revertOf);
18961
+ const target = resolve8(c.revertOf);
17826
18962
  if (target) {
17827
18963
  target.revertedBy = c.sha;
17828
18964
  c.origins.push(target.sha);
@@ -27085,7 +28221,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
27085
28221
  var NONE = 0;
27086
28222
  var ASSUMED = 1;
27087
28223
  var PROVEN = 2;
27088
- function isRecursive(inst, stack, resolve7) {
28224
+ function isRecursive(inst, stack, resolve8) {
27089
28225
  const cached5 = recursive.get(inst);
27090
28226
  if (cached5 !== void 0)
27091
28227
  return cached5 ? PROVEN : NONE;
@@ -27095,7 +28231,7 @@ function isRecursive(inst, stack, resolve7) {
27095
28231
  let result = NONE;
27096
28232
  const check3 = (child) => {
27097
28233
  if (result !== PROVEN && child?._zod) {
27098
- const answer = isRecursive(child, stack, resolve7);
28234
+ const answer = isRecursive(child, stack, resolve8);
27099
28235
  if (answer > result)
27100
28236
  result = answer;
27101
28237
  }
@@ -27106,7 +28242,7 @@ function isRecursive(inst, stack, resolve7) {
27106
28242
  const desc = Object.getOwnPropertyDescriptor(sh, key);
27107
28243
  if (spread && !desc.enumerable)
27108
28244
  continue;
27109
- const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve7) : NONE;
28245
+ const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve8) : NONE;
27110
28246
  if (child > answer)
27111
28247
  answer = child;
27112
28248
  }
@@ -27170,7 +28306,7 @@ function isRecursive(inst, stack, resolve7) {
27170
28306
  break;
27171
28307
  // `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
27172
28308
  case "lazy": {
27173
- const inner = def._cachedInner ?? (resolve7 ? inst._zod.innerType : void 0);
28309
+ const inner = def._cachedInner ?? (resolve8 ? inst._zod.innerType : void 0);
27174
28310
  merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
27175
28311
  break;
27176
28312
  }
@@ -45763,7 +46899,7 @@ var Protocol = class {
45763
46899
  return;
45764
46900
  }
45765
46901
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
45766
- await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
46902
+ await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
45767
46903
  options?.signal?.throwIfAborted();
45768
46904
  }
45769
46905
  } catch (error62) {
@@ -45780,7 +46916,7 @@ var Protocol = class {
45780
46916
  */
45781
46917
  request(request, resultSchema, options) {
45782
46918
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
45783
- return new Promise((resolve7, reject) => {
46919
+ return new Promise((resolve8, reject) => {
45784
46920
  const earlyReject = (error62) => {
45785
46921
  reject(error62);
45786
46922
  };
@@ -45858,7 +46994,7 @@ var Protocol = class {
45858
46994
  if (!parseResult.success) {
45859
46995
  reject(parseResult.error);
45860
46996
  } else {
45861
- resolve7(parseResult.data);
46997
+ resolve8(parseResult.data);
45862
46998
  }
45863
46999
  } catch (error62) {
45864
47000
  reject(error62);
@@ -46120,12 +47256,12 @@ var Protocol = class {
46120
47256
  }
46121
47257
  } catch {
46122
47258
  }
46123
- return new Promise((resolve7, reject) => {
47259
+ return new Promise((resolve8, reject) => {
46124
47260
  if (signal.aborted) {
46125
47261
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
46126
47262
  return;
46127
47263
  }
46128
- const timeoutId = setTimeout(resolve7, interval);
47264
+ const timeoutId = setTimeout(resolve8, interval);
46129
47265
  signal.addEventListener("abort", () => {
46130
47266
  clearTimeout(timeoutId);
46131
47267
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -47268,7 +48404,7 @@ var McpServer = class {
47268
48404
  let task = createTaskResult.task;
47269
48405
  const pollInterval = task.pollInterval ?? 5e3;
47270
48406
  while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
47271
- await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
48407
+ await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
47272
48408
  const updatedTask = await extra.taskStore.getTask(taskId);
47273
48409
  if (!updatedTask) {
47274
48410
  throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
@@ -47934,12 +49070,12 @@ var StdioServerTransport = class {
47934
49070
  this.onclose?.();
47935
49071
  }
47936
49072
  send(message) {
47937
- return new Promise((resolve7) => {
49073
+ return new Promise((resolve8) => {
47938
49074
  const json2 = serializeMessage(message);
47939
49075
  if (this._stdout.write(json2)) {
47940
- resolve7();
49076
+ resolve8();
47941
49077
  } else {
47942
- this._stdout.once("drain", resolve7);
49078
+ this._stdout.once("drain", resolve8);
47943
49079
  }
47944
49080
  });
47945
49081
  }
@@ -47988,7 +49124,8 @@ var ConfigSchema = external_exports.object({
47988
49124
  "**/*.mjs",
47989
49125
  "**/*.cjs",
47990
49126
  "**/*.py",
47991
- "**/*.go"
49127
+ "**/*.go",
49128
+ "**/*.php"
47992
49129
  ]),
47993
49130
  exclude: external_exports.array(external_exports.string()).default([
47994
49131
  "**/node_modules/**",
@@ -48002,7 +49139,8 @@ var ConfigSchema = external_exports.object({
48002
49139
  "**/__pycache__/**",
48003
49140
  "**/site-packages/**",
48004
49141
  "**/vendor/**",
48005
- "**/*.min.js"
49142
+ "**/*.min.js",
49143
+ "**/*.blade.php"
48006
49144
  ])
48007
49145
  }).prefault({}),
48008
49146
  git: external_exports.object({
@@ -48200,15 +49338,15 @@ init_reindex();
48200
49338
  // src/session/server-alive.ts
48201
49339
  init_esm_shims();
48202
49340
  init_paths();
48203
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync as readdirSync3, rmSync, writeFileSync } from "fs";
48204
- import { join as join10 } from "path";
49341
+ import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync as readdirSync4, rmSync, writeFileSync } from "fs";
49342
+ import { join as join11 } from "path";
48205
49343
  function markersDir(ctx) {
48206
- return join10(projectDir(ctx.id), "servers");
49344
+ return join11(projectDir(ctx.id), "servers");
48207
49345
  }
48208
49346
  function markServerAlive(ctx, pid = process.pid) {
48209
49347
  const dir = markersDir(ctx);
48210
49348
  mkdirSync2(dir, { recursive: true });
48211
- const file3 = join10(dir, String(pid));
49349
+ const file3 = join11(dir, String(pid));
48212
49350
  writeFileSync(file3, (/* @__PURE__ */ new Date()).toISOString());
48213
49351
  return () => {
48214
49352
  try {
@@ -48229,11 +49367,11 @@ function liveServers(ctx) {
48229
49367
  const dir = markersDir(ctx);
48230
49368
  if (!existsSync7(dir)) return [];
48231
49369
  const live = [];
48232
- for (const name of readdirSync3(dir)) {
49370
+ for (const name of readdirSync4(dir)) {
48233
49371
  const pid = Number(name);
48234
49372
  if (!Number.isInteger(pid) || pid <= 0) continue;
48235
49373
  if (processAlive(pid)) live.push(pid);
48236
- else rmSync(join10(dir, name), { force: true });
49374
+ else rmSync(join11(dir, name), { force: true });
48237
49375
  }
48238
49376
  return live;
48239
49377
  }
@@ -49237,12 +50375,18 @@ var SqliteAdapter = class _SqliteAdapter {
49237
50375
  const ids = this.db.prepare("SELECT id FROM graph_nodes WHERE source = ? AND path = ?").all(source, path3).map((r) => r.id);
49238
50376
  const fileId2 = `file:${path3}`;
49239
50377
  const all = ids.includes(fileId2) ? ids : [...ids, fileId2];
50378
+ this.db.prepare(
50379
+ "DELETE FROM graph_edges WHERE source = ? AND kind = 'handles' AND dst IN (SELECT id FROM graph_nodes WHERE source = ? AND path = ? AND kind = 'route')"
50380
+ ).run(source, source, path3);
50381
+ const foreignRoute = "AND NOT (kind = 'handles' AND dst IN (SELECT id FROM graph_nodes WHERE kind = 'route' AND path IS NOT ?))";
49240
50382
  for (let i = 0; i < all.length; i += 400) {
49241
50383
  const slice = all.slice(i, i + 400);
49242
50384
  const ph = slice.map(() => "?").join(",");
49243
- this.db.prepare(`DELETE FROM graph_edges WHERE source = ? AND src IN (${ph})`).run(source, ...slice);
50385
+ this.db.prepare(`DELETE FROM graph_edges WHERE source = ? AND src IN (${ph}) ${foreignRoute}`).run(source, ...slice, path3);
49244
50386
  }
49245
- this.db.prepare("DELETE FROM graph_edges WHERE source = ? AND src LIKE ? ESCAPE '\\'").run(source, `sym:${path3.replace(/[%_\\]/g, "\\$&")}#%`);
50387
+ this.db.prepare(
50388
+ `DELETE FROM graph_edges WHERE source = ? AND src LIKE ? ESCAPE '\\' ${foreignRoute}`
50389
+ ).run(source, `sym:${path3.replace(/[%_\\]/g, "\\$&")}#%`, path3);
49246
50390
  if (opts.keepFile) {
49247
50391
  this.db.prepare("DELETE FROM graph_nodes WHERE source = ? AND path = ? AND kind != 'file'").run(source, path3);
49248
50392
  } else {
@@ -49589,8 +50733,8 @@ init_esm_shims();
49589
50733
  init_esm_shims();
49590
50734
  init_store();
49591
50735
  init_metrics();
49592
- import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
49593
- import { join as join12 } from "path";
50736
+ import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
50737
+ import { join as join13 } from "path";
49594
50738
 
49595
50739
  // src/graph/query.ts
49596
50740
  init_esm_shims();
@@ -50009,8 +51153,8 @@ var ASPECTS = [
50009
51153
  ];
50010
51154
  function pkgJson(root) {
50011
51155
  try {
50012
- const f = join12(root, "package.json");
50013
- return existsSync9(f) ? JSON.parse(readFileSync8(f, "utf8")) : {};
51156
+ const f = join13(root, "package.json");
51157
+ return existsSync9(f) ? JSON.parse(readFileSync9(f, "utf8")) : {};
50014
51158
  } catch {
50015
51159
  return {};
50016
51160
  }
@@ -50188,10 +51332,10 @@ init_esm_shims();
50188
51332
  // src/session/current.ts
50189
51333
  init_esm_shims();
50190
51334
  init_paths();
50191
- import { readFileSync as readFileSync9, statSync as statSync6, writeFileSync as writeFileSync3 } from "fs";
50192
- import { join as join13 } from "path";
51335
+ import { readFileSync as readFileSync10, statSync as statSync7, writeFileSync as writeFileSync3 } from "fs";
51336
+ import { join as join14 } from "path";
50193
51337
  function file2(ctx) {
50194
- return join13(projectDir(ctx.id), "current-session");
51338
+ return join14(projectDir(ctx.id), "current-session");
50195
51339
  }
50196
51340
  var cached3;
50197
51341
  function getCurrentSession(ctx) {
@@ -50199,12 +51343,12 @@ function getCurrentSession(ctx) {
50199
51343
  const f = file2(ctx);
50200
51344
  let mtimeMs;
50201
51345
  try {
50202
- mtimeMs = statSync6(f).mtimeMs;
51346
+ mtimeMs = statSync7(f).mtimeMs;
50203
51347
  } catch {
50204
51348
  return "unknown";
50205
51349
  }
50206
51350
  if (cached3 && cached3.file === f && cached3.mtimeMs === mtimeMs) return cached3.id;
50207
- const id = readFileSync9(f, "utf8").trim() || "unknown";
51351
+ const id = readFileSync10(f, "utf8").trim() || "unknown";
50208
51352
  cached3 = { file: f, mtimeMs, id };
50209
51353
  return id;
50210
51354
  }
@@ -50417,7 +51561,7 @@ var NodeFilterSchema = external_exports.object({
50417
51561
  });
50418
51562
  var emGraphQuery = defineTool({
50419
51563
  name: "em_graph_query",
50420
- description: 'Look up nodes in the project knowledge graph (files, functions, classes, routes, packages, people, concepts, memories) by name/path, run a preset (hotspots, coupled, orphans, dead_code, routes, cycles, clusters, stats), or run a structured pattern: start at nodes matching `from`, walk `edge.kinds` in `edge.direction` for `edge.depth` hops, keep what matches `to` \u2014 e.g. {from:{kind:"route"}, edge:{kinds:["handles"], direction:"in"}} lists every route handler, {from:{name:"^parseFile$"}, edge:{kinds:["calls"], direction:"in", depth:2}} its callers two levels up. Built from tree-sitter (TS/JS, Python, Go), git history, memories and em_graph_add.',
51564
+ description: 'Look up nodes in the project knowledge graph (files, functions, classes, routes, packages, people, concepts, memories) by name/path, run a preset (hotspots, coupled, orphans, dead_code, routes, cycles, clusters, stats), or run a structured pattern: start at nodes matching `from`, walk `edge.kinds` in `edge.direction` for `edge.depth` hops, keep what matches `to` \u2014 e.g. {from:{kind:"route"}, edge:{kinds:["handles"], direction:"in"}} lists every route handler, {from:{name:"^parseFile$"}, edge:{kinds:["calls"], direction:"in", depth:2}} its callers two levels up. Built from tree-sitter (TS/JS, Python, Go, PHP), git history, memories and em_graph_add.',
50421
51565
  schema: {
50422
51566
  query: external_exports.string().optional().describe("Substring of a name, path or id"),
50423
51567
  kind: external_exports.string().optional().describe(
@@ -50778,13 +51922,13 @@ init_esm_shims();
50778
51922
  // src/sandbox/execute.ts
50779
51923
  init_esm_shims();
50780
51924
  import { unlinkSync as unlinkSync2 } from "fs";
50781
- import { join as join16 } from "path";
51925
+ import { join as join17 } from "path";
50782
51926
 
50783
51927
  // src/permissions/settings.ts
50784
51928
  init_esm_shims();
50785
- import { existsSync as existsSync10, readFileSync as readFileSync10, statSync as statSync7 } from "fs";
51929
+ import { existsSync as existsSync10, readFileSync as readFileSync11, statSync as statSync8 } from "fs";
50786
51930
  import { homedir as homedir2 } from "os";
50787
- import { join as join14 } from "path";
51931
+ import { join as join15 } from "path";
50788
51932
 
50789
51933
  // src/permissions/rules.ts
50790
51934
  init_esm_shims();
@@ -50911,7 +52055,7 @@ function splitCommand(line) {
50911
52055
  i++;
50912
52056
  }
50913
52057
  flush();
50914
- return segments.map(normalize4).filter(Boolean);
52058
+ return segments.map(normalize5).filter(Boolean);
50915
52059
  }
50916
52060
  function matchParen(s, open3) {
50917
52061
  let d = 0;
@@ -50924,7 +52068,7 @@ function matchParen(s, open3) {
50924
52068
  }
50925
52069
  return s.length;
50926
52070
  }
50927
- function normalize4(seg) {
52071
+ function normalize5(seg) {
50928
52072
  let s = seg.trim();
50929
52073
  for (; ; ) {
50930
52074
  const before = s;
@@ -50940,7 +52084,7 @@ function normalize4(seg) {
50940
52084
  function readRules(file3) {
50941
52085
  if (!existsSync10(file3)) return {};
50942
52086
  try {
50943
- const s = JSON.parse(readFileSync10(file3, "utf8"));
52087
+ const s = JSON.parse(readFileSync11(file3, "utf8"));
50944
52088
  return s.permissions ?? {};
50945
52089
  } catch {
50946
52090
  return {};
@@ -50948,7 +52092,7 @@ function readRules(file3) {
50948
52092
  }
50949
52093
  function stamp(file3) {
50950
52094
  try {
50951
- return statSync7(file3).mtimeMs;
52095
+ return statSync8(file3).mtimeMs;
50952
52096
  } catch {
50953
52097
  return -1;
50954
52098
  }
@@ -50956,9 +52100,9 @@ function stamp(file3) {
50956
52100
  var cache2 = /* @__PURE__ */ new Map();
50957
52101
  function loadPermissionRules(root, extraDeny = []) {
50958
52102
  const files = [
50959
- join14(homedir2(), ".claude", "settings.json"),
50960
- join14(root, ".claude", "settings.json"),
50961
- join14(root, ".claude", "settings.local.json")
52103
+ join15(homedir2(), ".claude", "settings.json"),
52104
+ join15(root, ".claude", "settings.json"),
52105
+ join15(root, ".claude", "settings.local.json")
50962
52106
  ];
50963
52107
  const key = `${root}\0${extraDeny.join("\0")}`;
50964
52108
  const stamps = files.map(stamp);
@@ -51068,12 +52212,12 @@ init_esm_shims();
51068
52212
  init_paths();
51069
52213
  import { accessSync, constants, existsSync as existsSync11, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
51070
52214
  import { createRequire } from "module";
51071
- import { delimiter, join as join15 } from "path";
52215
+ import { delimiter, join as join16 } from "path";
51072
52216
  var require2 = createRequire(import.meta.url);
51073
52217
  function findOnPath(bin) {
51074
52218
  for (const dir of (process.env.PATH ?? "").split(delimiter)) {
51075
52219
  if (!dir) continue;
51076
- const p = join15(dir, bin);
52220
+ const p = join16(dir, bin);
51077
52221
  try {
51078
52222
  accessSync(p, constants.X_OK);
51079
52223
  return p;
@@ -51208,7 +52352,7 @@ function writeScratch(code, ext) {
51208
52352
  mkdirSync4(dir, { recursive: true });
51209
52353
  scratchDir = dir;
51210
52354
  }
51211
- const file3 = join15(dir, `em-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`);
52355
+ const file3 = join16(dir, `em-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`);
51212
52356
  try {
51213
52357
  writeFileSync4(file3, code, { mode: 384 });
51214
52358
  } catch (err) {
@@ -51224,7 +52368,7 @@ init_esm_shims();
51224
52368
  import { spawn } from "child_process";
51225
52369
  function runProcess(argv, opts) {
51226
52370
  const started = Date.now();
51227
- return new Promise((resolve7) => {
52371
+ return new Promise((resolve8) => {
51228
52372
  const [cmd, ...args] = argv;
51229
52373
  const child = spawn(cmd, args, {
51230
52374
  cwd: opts.cwd,
@@ -51267,7 +52411,7 @@ function runProcess(argv, opts) {
51267
52411
  if (done) return;
51268
52412
  done = true;
51269
52413
  clearTimeout(timer);
51270
- resolve7({
52414
+ resolve8({
51271
52415
  stdout: Buffer.concat(out).toString("utf8"),
51272
52416
  stderr: errTail,
51273
52417
  exitCode,
@@ -51310,7 +52454,7 @@ async function execute(ctx, input2) {
51310
52454
  const file3 = writeScratch(input2.code, lang.ext);
51311
52455
  const env = buildEnv(ctx.config.sandbox.envAllow, {
51312
52456
  EMINIAR_PROJECT_ROOT: ctx.root,
51313
- NODE_PATH: [join16(ctx.root, "node_modules"), process.env.NODE_PATH].filter(Boolean).join(":"),
52457
+ NODE_PATH: [join17(ctx.root, "node_modules"), process.env.NODE_PATH].filter(Boolean).join(":"),
51314
52458
  ...input2.env
51315
52459
  });
51316
52460
  try {
@@ -52882,13 +54026,13 @@ function catalogForProvider(provider, catalog = CATALOG) {
52882
54026
  // src/docs/discover.ts
52883
54027
  init_esm_shims();
52884
54028
  var import_fast_glob4 = __toESM(require_out4(), 1);
52885
- import { existsSync as existsSync13, readFileSync as readFileSync12, statSync as statSync8 } from "fs";
52886
- import { basename, join as join18, relative as relative6 } from "path";
54029
+ import { existsSync as existsSync13, readFileSync as readFileSync13, statSync as statSync9 } from "fs";
54030
+ import { basename, join as join19, relative as relative7 } from "path";
52887
54031
 
52888
54032
  // src/docs/manifest.ts
52889
54033
  init_esm_shims();
52890
- import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "fs";
52891
- import { dirname as dirname7, join as join17 } from "path";
54034
+ import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "fs";
54035
+ import { dirname as dirname8, join as join18 } from "path";
52892
54036
  var DOCS_PREFIX = "docs:";
52893
54037
  var NAME_RE2 = /^[a-z0-9][a-z0-9._-]{0,63}$/;
52894
54038
  function docsTag(name) {
@@ -52902,7 +54046,7 @@ function slugify3(input2) {
52902
54046
  return (s || "source").slice(0, 64);
52903
54047
  }
52904
54048
  function manifestPathAt(root, rel = ".eminiar/docs.json") {
52905
- return join17(root, rel);
54049
+ return join18(root, rel);
52906
54050
  }
52907
54051
  function manifestPath(ctx) {
52908
54052
  return manifestPathAt(ctx.root, ctx.config.docs.manifest);
@@ -52910,7 +54054,7 @@ function manifestPath(ctx) {
52910
54054
  function empty() {
52911
54055
  return { version: 1, sources: [] };
52912
54056
  }
52913
- function normalize5(raw) {
54057
+ function normalize6(raw) {
52914
54058
  if (!raw || typeof raw !== "object") return empty();
52915
54059
  const sources = Array.isArray(raw.sources) ? raw.sources : [];
52916
54060
  const out = [];
@@ -52932,7 +54076,7 @@ function normalize5(raw) {
52932
54076
  function readManifestAt(file3) {
52933
54077
  if (!existsSync12(file3)) return empty();
52934
54078
  try {
52935
- return normalize5(JSON.parse(readFileSync11(file3, "utf8")));
54079
+ return normalize6(JSON.parse(readFileSync12(file3, "utf8")));
52936
54080
  } catch {
52937
54081
  return empty();
52938
54082
  }
@@ -52942,7 +54086,7 @@ function readManifest(ctx) {
52942
54086
  }
52943
54087
  function writeManifest(ctx, m) {
52944
54088
  const file3 = manifestPath(ctx);
52945
- mkdirSync5(dirname7(file3), { recursive: true });
54089
+ mkdirSync5(dirname8(file3), { recursive: true });
52946
54090
  const sorted = {
52947
54091
  version: 1,
52948
54092
  sources: [...m.sources].sort((a, b) => a.name.localeCompare(b.name))
@@ -53193,7 +54337,7 @@ var GENERIC_ENV = /* @__PURE__ */ new Set([
53193
54337
  var SKIP_EXT = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".svg", ".pdf", ".zip", ".ico"]);
53194
54338
  function readText(file3) {
53195
54339
  try {
53196
- return readFileSync12(file3, "utf8");
54340
+ return readFileSync13(file3, "utf8");
53197
54341
  } catch {
53198
54342
  return void 0;
53199
54343
  }
@@ -53211,7 +54355,7 @@ function sizeOf(files) {
53211
54355
  let n = 0;
53212
54356
  for (const f of files) {
53213
54357
  try {
53214
- n += statSync8(f).size;
54358
+ n += statSync9(f).size;
53215
54359
  } catch {
53216
54360
  }
53217
54361
  }
@@ -53219,7 +54363,7 @@ function sizeOf(files) {
53219
54363
  }
53220
54364
  var VISIBLE_DOT_DIRS = /* @__PURE__ */ new Set([".github", ".claude", ".cursor", ".gitlab", ".circleci"]);
53221
54365
  function hiddenPath(cwd, file3) {
53222
- const parts = relative6(cwd, file3).split("/");
54366
+ const parts = relative7(cwd, file3).split("/");
53223
54367
  return parts.slice(0, -1).some((p, i) => {
53224
54368
  if (!p.startsWith(".")) return false;
53225
54369
  if (p === ".claude") return !["agents", "skills", "commands"].includes(parts[i + 1] ?? "");
@@ -53248,8 +54392,8 @@ function findProjects(root, opts) {
53248
54392
  const found = /* @__PURE__ */ new Set();
53249
54393
  for (const m of markers) {
53250
54394
  for (const f of glob(root, [`*/${m}`, `*/*/${m}`], 3)) {
53251
- const dir = join18(f, "..");
53252
- const rel = relative6(root, dir);
54395
+ const dir = join19(f, "..");
54396
+ const rel = relative7(root, dir);
53253
54397
  if (!rel || rel.split("/").some((p) => p.startsWith(".") || p === "node_modules")) continue;
53254
54398
  found.add(dir);
53255
54399
  }
@@ -53257,7 +54401,7 @@ function findProjects(root, opts) {
53257
54401
  const max = opts.maxProjects ?? 40;
53258
54402
  const seenNames = /* @__PURE__ */ new Set();
53259
54403
  const nameOf = (dir) => {
53260
- const pkg = readJson2(join18(dir, "package.json"));
54404
+ const pkg = readJson2(join19(dir, "package.json"));
53261
54405
  return typeof pkg?.name === "string" ? pkg.name : void 0;
53262
54406
  };
53263
54407
  const rootName = nameOf(root);
@@ -53275,7 +54419,7 @@ function findProjects(root, opts) {
53275
54419
  return out;
53276
54420
  }
53277
54421
  function npmSignals(dir, includeDev, project) {
53278
- const pkg = readJson2(join18(dir, "package.json"));
54422
+ const pkg = readJson2(join19(dir, "package.json"));
53279
54423
  if (!pkg) return [];
53280
54424
  const sections = ["dependencies", ...includeDev ? ["devDependencies"] : []];
53281
54425
  const out = [];
@@ -53292,13 +54436,13 @@ function npmSignals(dir, includeDev, project) {
53292
54436
  }
53293
54437
  function pythonSignals(dir, project) {
53294
54438
  const out = [];
53295
- const py = readText(join18(dir, "pyproject.toml"));
54439
+ const py = readText(join19(dir, "pyproject.toml"));
53296
54440
  if (py) {
53297
54441
  const block = /dependencies\s*=\s*\[([\s\S]*?)\]/.exec(py)?.[1] ?? "";
53298
54442
  for (const m of block.matchAll(/["']([A-Za-z0-9_.-]+)/g))
53299
54443
  out.push({ kind: "pypi", key: m[1].toLowerCase(), project });
53300
54444
  }
53301
- const req = readText(join18(dir, "requirements.txt"));
54445
+ const req = readText(join19(dir, "requirements.txt"));
53302
54446
  if (req) {
53303
54447
  for (const line of req.split("\n")) {
53304
54448
  const name = /^\s*([A-Za-z0-9_.-]+)/.exec(line)?.[1];
@@ -53309,7 +54453,7 @@ function pythonSignals(dir, project) {
53309
54453
  return out;
53310
54454
  }
53311
54455
  function goSignals(dir, project) {
53312
- const mod = readText(join18(dir, "go.mod"));
54456
+ const mod = readText(join19(dir, "go.mod"));
53313
54457
  if (!mod) return [];
53314
54458
  const out = [];
53315
54459
  const block = /require\s*\(([\s\S]*?)\)/g;
@@ -53494,62 +54638,67 @@ var DOC_HOST_RE = /^(docs?|developer|developers|devdocs|apidocs|api-docs|help|su
53494
54638
  var DOC_HOST_SUFFIX = /\.(readthedocs\.io|gitbook\.io|github\.io|gitlab\.io|netlify\.app|vercel\.app|mintlify\.app|readme\.io|redoc\.ly|stoplight\.io)$/i;
53495
54639
  var DOC_PATH_RE = /^\/(docs?|documentation|developers?|guides?|learn|reference|manual|wiki|help|en|latest|stable|v\d+(\.\d+)*\/docs)(\/|$)/i;
53496
54640
  var COMMENT_RE = /^\s*(\/\/|#|\*|\/\*|<!--|--|;|'''|""")/;
54641
+ var PLACEHOLDER_RE = /\bplaceholder\b/i;
54642
+ var REFERENCE_TABLE_HOSTS = 15;
53497
54643
  function isDocLink(host, path3) {
53498
54644
  return DOC_HOST_RE.test(host) || DOC_HOST_SUFFIX.test(host) || DOC_PATH_RE.test(path3) && !API_HOST_RE.test(host);
53499
54645
  }
53500
54646
  function apiSignals(dir, project) {
53501
54647
  const hits = /* @__PURE__ */ new Map();
53502
54648
  const docLinks = /* @__PURE__ */ new Map();
53503
- const files = glob(dir, CODE_GLOBS, 8).filter((f) => !/\.min\.(js|mjs|cjs)$/.test(f)).filter((f) => !TEST_PATH_RE.test(relative6(dir, f))).slice(0, 4e3);
54649
+ const files = glob(dir, CODE_GLOBS, 8).filter((f) => !/\.min\.(js|mjs|cjs)$/.test(f)).filter((f) => !TEST_PATH_RE.test(relative7(dir, f))).slice(0, 4e3);
53504
54650
  for (const file3 of files) {
53505
54651
  let size = 0;
53506
54652
  try {
53507
- size = statSync8(file3).size;
54653
+ size = statSync9(file3).size;
53508
54654
  } catch {
53509
54655
  continue;
53510
54656
  }
53511
54657
  if (size > 400 * 1024) continue;
53512
54658
  const text2 = readText(file3);
53513
54659
  if (!text2 || text2.includes("\0")) continue;
53514
- const rel = relative6(dir, file3).split("\\").join("/");
54660
+ const rel = relative7(dir, file3).split("\\").join("/");
53515
54661
  const isEnv = basename(file3).startsWith(".env");
53516
54662
  const lines = text2.split("\n");
54663
+ const found = [];
53517
54664
  for (let i = 0; i < lines.length; i++) {
53518
54665
  const line = lines[i];
53519
- if (!line.includes("http")) continue;
53520
- const comment = COMMENT_RE.test(line);
54666
+ if (!line.includes("http") || PLACEHOLDER_RE.test(line)) continue;
53521
54667
  for (const m of line.matchAll(URL_RE)) {
53522
54668
  const host = m[1].toLowerCase();
53523
- const path3 = m[2] ?? "/";
53524
- if (!isApiHostCandidate(host)) continue;
53525
- const spec = SPEC_URL_RE.test(path3);
53526
- if (!spec && isDocLink(host, path3)) {
53527
- if (comment && !isEnv) continue;
53528
- const link = docLinks.get(host) ?? { host, urls: [], samples: [], project };
53529
- const full = `https://${host}${path3.replace(/[#?].*$/, "")}`;
53530
- if (!link.urls.includes(full) && link.urls.length < 3) link.urls.push(full);
53531
- if (link.samples.length < 3) link.samples.push(`${rel}:${i + 1}`);
53532
- docLinks.set(host, link);
53533
- continue;
53534
- }
53535
- const callLike = !comment && (spec || isEnv || CALL_RE.test(line) || API_PATH_RE.test(path3) || API_HOST_RE.test(host));
53536
- const cur = hits.get(host) ?? {
53537
- host,
53538
- calls: 0,
53539
- mentions: 0,
53540
- samples: [],
53541
- specUrls: [],
53542
- project
53543
- };
53544
- if (callLike) cur.calls++;
53545
- else cur.mentions++;
53546
- if (callLike && cur.samples.length < 3) cur.samples.push(`${rel}:${i + 1}`);
53547
- if (spec) {
53548
- const full = `https://${host}${path3}`;
53549
- if (!cur.specUrls.includes(full) && cur.specUrls.length < 4) cur.specUrls.push(full);
53550
- }
53551
- hits.set(host, cur);
54669
+ if (isApiHostCandidate(host)) found.push({ host, path: m[2] ?? "/", line, i });
54670
+ }
54671
+ }
54672
+ if (new Set(found.map((f) => f.host)).size >= REFERENCE_TABLE_HOSTS) continue;
54673
+ for (const { host, path: path3, line, i } of found) {
54674
+ const comment = COMMENT_RE.test(line);
54675
+ const spec = SPEC_URL_RE.test(path3);
54676
+ if (!spec && isDocLink(host, path3)) {
54677
+ if (comment && !isEnv) continue;
54678
+ const link = docLinks.get(host) ?? { host, urls: [], samples: [], project };
54679
+ const full = `https://${host}${path3.replace(/[#?].*$/, "")}`;
54680
+ if (!link.urls.includes(full) && link.urls.length < 3) link.urls.push(full);
54681
+ if (link.samples.length < 3) link.samples.push(`${rel}:${i + 1}`);
54682
+ docLinks.set(host, link);
54683
+ continue;
54684
+ }
54685
+ const callLike = !comment && (spec || isEnv || CALL_RE.test(line) || API_PATH_RE.test(path3) || API_HOST_RE.test(host));
54686
+ const cur = hits.get(host) ?? {
54687
+ host,
54688
+ calls: 0,
54689
+ mentions: 0,
54690
+ samples: [],
54691
+ specUrls: [],
54692
+ project
54693
+ };
54694
+ if (callLike) cur.calls++;
54695
+ else cur.mentions++;
54696
+ if (callLike && cur.samples.length < 3) cur.samples.push(`${rel}:${i + 1}`);
54697
+ if (spec) {
54698
+ const full = `https://${host}${path3}`;
54699
+ if (!cur.specUrls.includes(full) && cur.specUrls.length < 4) cur.specUrls.push(full);
53552
54700
  }
54701
+ hits.set(host, cur);
53553
54702
  }
53554
54703
  }
53555
54704
  return { hits, docLinks };
@@ -53598,7 +54747,7 @@ function fileSignals(dir, project) {
53598
54747
  function localCandidates(root, dir, project, isRegistered) {
53599
54748
  const out = [];
53600
54749
  const prefix = project ? `${slugify3(basename(dir))}-` : "";
53601
- const rel = (abs) => relative6(root, abs).split("\\").join("/");
54750
+ const rel = (abs) => relative7(root, abs).split("\\").join("/");
53602
54751
  const push = (c) => {
53603
54752
  if (!c.files) return;
53604
54753
  out.push({ ...c, project, registered: isRegistered(c) });
@@ -53628,7 +54777,7 @@ function localCandidates(root, dir, project, isRegistered) {
53628
54777
  why: "project readme and top-level guides"
53629
54778
  });
53630
54779
  for (const d of ["docs", "doc", "documentation"]) {
53631
- const abs = join18(dir, d);
54780
+ const abs = join19(dir, d);
53632
54781
  if (!existsSync13(abs)) continue;
53633
54782
  const files = glob(abs, ["**/*.md", "**/*.mdx", "**/*.rst", "**/*.txt"]).filter(
53634
54783
  (f) => !SKIP_EXT.has(f.slice(f.lastIndexOf(".")))
@@ -53652,7 +54801,7 @@ function localCandidates(root, dir, project, isRegistered) {
53652
54801
  "docs/decisions",
53653
54802
  "decisions"
53654
54803
  ]) {
53655
- const abs = join18(dir, d);
54804
+ const abs = join19(dir, d);
53656
54805
  if (!existsSync13(abs)) continue;
53657
54806
  if (out.some((c) => c.path && rel(abs).startsWith(`${c.path}/`))) break;
53658
54807
  const files = glob(abs, ["**/*.md"]);
@@ -53712,7 +54861,7 @@ function localCandidates(root, dir, project, isRegistered) {
53712
54861
  push({
53713
54862
  name: `${prefix}api-specs`,
53714
54863
  path: rel(dir) || ".",
53715
- glob: api.map((f) => relative6(dir, f).split("\\").join("/")),
54864
+ glob: api.map((f) => relative7(dir, f).split("\\").join("/")),
53716
54865
  files: api.length,
53717
54866
  bytes: sizeOf(api),
53718
54867
  why: "OpenAPI / Postman / GraphQL / protobuf specs"
@@ -53786,7 +54935,7 @@ function discoverDocs(ctx, opts = {}) {
53786
54935
  const apiHits = /* @__PURE__ */ new Map();
53787
54936
  const docLinks = /* @__PURE__ */ new Map();
53788
54937
  for (const dir of projects) {
53789
- const project = dir === root ? "" : relative6(root, dir).split("\\").join("/");
54938
+ const project = dir === root ? "" : relative7(root, dir).split("\\").join("/");
53790
54939
  const own2 = dir === root && projects.length > 1 ? void 0 : dir;
53791
54940
  local.push(...localCandidates(root, dir, project, isRegistered));
53792
54941
  signals.push(...npmSignals(dir, includeDev, project));
@@ -53796,7 +54945,7 @@ function discoverDocs(ctx, opts = {}) {
53796
54945
  signals.push(...fileSignals(dir, project));
53797
54946
  const api = apiSignals(own2 ?? dir, project);
53798
54947
  const inSubproject = (samples) => own2 === void 0 && projects.some(
53799
- (p) => p !== root && samples.some((s) => s.startsWith(`${relative6(root, p)}/`))
54948
+ (p) => p !== root && samples.some((s) => s.startsWith(`${relative7(root, p)}/`))
53800
54949
  );
53801
54950
  for (const hit of api.hits.values()) {
53802
54951
  if (inSubproject(hit.samples)) continue;
@@ -53986,7 +55135,7 @@ function discoverDocs(ctx, opts = {}) {
53986
55135
  );
53987
55136
  return {
53988
55137
  root,
53989
- projects: projects.map((p) => p === root ? "." : relative6(root, p)),
55138
+ projects: projects.map((p) => p === root ? "." : relative7(root, p)),
53990
55139
  local,
53991
55140
  providers
53992
55141
  };
@@ -55525,9 +56674,9 @@ init_esm_shims();
55525
56674
  init_esm_shims();
55526
56675
  init_paths();
55527
56676
  init_version();
55528
- import { accessSync as accessSync2, constants as constants2, existsSync as existsSync14, readFileSync as readFileSync13 } from "fs";
56677
+ import { accessSync as accessSync2, constants as constants2, existsSync as existsSync14, readFileSync as readFileSync14 } from "fs";
55529
56678
  import { createRequire as createRequire3 } from "module";
55530
- import { join as join19 } from "path";
56679
+ import { join as join20 } from "path";
55531
56680
  var require4 = createRequire3(import.meta.url);
55532
56681
  function check2(name, fn) {
55533
56682
  try {
@@ -55557,7 +56706,7 @@ function runDoctor() {
55557
56706
  checks.push(
55558
56707
  check2("node-path pin", () => {
55559
56708
  if (!existsSync14(p.nodePathFile)) return "not pinned (run `eminiar install`); using PATH node";
55560
- const pinned = readFileSync13(p.nodePathFile, "utf8").trim();
56709
+ const pinned = readFileSync14(p.nodePathFile, "utf8").trim();
55561
56710
  accessSync2(pinned, constants2.X_OK);
55562
56711
  return pinned;
55563
56712
  })
@@ -55566,8 +56715,8 @@ function runDoctor() {
55566
56715
  check2("root-path pin", () => {
55567
56716
  if (!existsSync14(p.rootPathFile))
55568
56717
  return "not pinned (run `eminiar install`); the bin/ shims run only from a directory that has node_modules";
55569
- const root = readFileSync13(p.rootPathFile, "utf8").trim();
55570
- if (!existsSync14(join19(root, "dist", "server.js")))
56718
+ const root = readFileSync14(p.rootPathFile, "utf8").trim();
56719
+ if (!existsSync14(join20(root, "dist", "server.js")))
55571
56720
  throw new Error(`${root} has no dist/server.js (run \`eminiar install\`)`);
55572
56721
  return root;
55573
56722
  })
@@ -55626,8 +56775,8 @@ init_queue();
55626
56775
 
55627
56776
  // src/hooks/coexist.ts
55628
56777
  init_esm_shims();
55629
- import { readFileSync as readFileSync15 } from "fs";
55630
- import { join as join21 } from "path";
56778
+ import { readFileSync as readFileSync16 } from "fs";
56779
+ import { join as join22 } from "path";
55631
56780
 
55632
56781
  // src/install/claude-config.ts
55633
56782
  init_esm_shims();
@@ -55636,24 +56785,24 @@ import {
55636
56785
  copyFileSync,
55637
56786
  existsSync as existsSync15,
55638
56787
  mkdirSync as mkdirSync6,
55639
- readdirSync as readdirSync4,
55640
- readFileSync as readFileSync14,
56788
+ readdirSync as readdirSync5,
56789
+ readFileSync as readFileSync15,
55641
56790
  writeFileSync as writeFileSync6
55642
56791
  } from "fs";
55643
56792
  import { homedir as homedir3 } from "os";
55644
- import { dirname as dirname8, join as join20 } from "path";
55645
- var claudeDir = () => process.env.CLAUDE_CONFIG_DIR || join20(homedir3(), ".claude");
55646
- var pluginsDir = () => join20(claudeDir(), "plugins");
56793
+ import { dirname as dirname9, join as join21 } from "path";
56794
+ var claudeDir = () => process.env.CLAUDE_CONFIG_DIR || join21(homedir3(), ".claude");
56795
+ var pluginsDir = () => join21(claudeDir(), "plugins");
55647
56796
  function readJson3(file3) {
55648
56797
  if (!existsSync15(file3)) return {};
55649
56798
  try {
55650
- return JSON.parse(readFileSync14(file3, "utf8"));
56799
+ return JSON.parse(readFileSync15(file3, "utf8"));
55651
56800
  } catch (err) {
55652
56801
  throw new Error(`${file3} is not valid JSON: ${err.message}`);
55653
56802
  }
55654
56803
  }
55655
56804
  var PLUGIN_SERVER_ID = "plugin:eminiar:eminiar";
55656
- var mcpNeedsAuthPath = () => join20(claudeDir(), "mcp-needs-auth-cache.json");
56805
+ var mcpNeedsAuthPath = () => join21(claudeDir(), "mcp-needs-auth-cache.json");
55657
56806
  function needsAuthEntry(id = PLUGIN_SERVER_ID) {
55658
56807
  try {
55659
56808
  const entry = readJson3(mcpNeedsAuthPath())[id];
@@ -55668,7 +56817,7 @@ var cached4;
55668
56817
  function contextModeInstalled() {
55669
56818
  if (cached4 !== void 0) return cached4;
55670
56819
  try {
55671
- const reg = JSON.parse(readFileSync15(join21(pluginsDir(), "installed_plugins.json"), "utf8"));
56820
+ const reg = JSON.parse(readFileSync16(join22(pluginsDir(), "installed_plugins.json"), "utf8"));
55672
56821
  cached4 = Object.keys(reg.plugins ?? {}).some((id) => id.startsWith("context-mode@"));
55673
56822
  } catch {
55674
56823
  cached4 = false;
@@ -55788,16 +56937,16 @@ init_esm_shims();
55788
56937
  // src/sandbox/file.ts
55789
56938
  init_esm_shims();
55790
56939
  import { realpathSync as realpathSync2 } from "fs";
55791
- import { isAbsolute, relative as relative7, resolve as resolve6 } from "path";
56940
+ import { isAbsolute, relative as relative8, resolve as resolve7 } from "path";
55792
56941
  function confinePath(root, target, rules) {
55793
- const abs = resolve6(root, target);
56942
+ const abs = resolve7(root, target);
55794
56943
  let real;
55795
56944
  try {
55796
56945
  real = realpathSync2(abs);
55797
56946
  } catch {
55798
56947
  throw new Error(`file not found: ${target}`);
55799
56948
  }
55800
- const rel = relative7(root, real);
56949
+ const rel = relative8(root, real);
55801
56950
  const inside = rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
55802
56951
  if (inside) return real;
55803
56952
  if (rules.allow.some((r) => matchRead(r, real))) return real;
@@ -56154,8 +57303,8 @@ init_esm_shims();
56154
57303
 
56155
57304
  // src/code/symbols.ts
56156
57305
  init_esm_shims();
56157
- import { existsSync as existsSync16, readFileSync as readFileSync16 } from "fs";
56158
- import { join as join22 } from "path";
57306
+ import { existsSync as existsSync16, readFileSync as readFileSync17 } from "fs";
57307
+ import { join as join23 } from "path";
56159
57308
 
56160
57309
  // src/code/namepath.ts
56161
57310
  init_esm_shims();
@@ -56224,10 +57373,10 @@ function children(db, parent, depth = 1) {
56224
57373
  }
56225
57374
  function symbolBody(db, root, n) {
56226
57375
  if (!n.path || !n.start_line || !n.end_line) return void 0;
56227
- const abs = join22(root, n.path);
57376
+ const abs = join23(root, n.path);
56228
57377
  if (existsSync16(abs)) {
56229
57378
  try {
56230
- return readFileSync16(abs, "utf8").split("\n").slice(n.start_line - 1, n.end_line).join("\n");
57379
+ return readFileSync17(abs, "utf8").split("\n").slice(n.start_line - 1, n.end_line).join("\n");
56231
57380
  } catch {
56232
57381
  }
56233
57382
  }
@@ -57253,7 +58402,7 @@ function referrerLabel(db, id, nodes) {
57253
58402
  }
57254
58403
  var emSymbols = defineTool({
57255
58404
  name: "em_symbols",
57256
- description: "Symbol-level code navigation on the tree-sitter graph (TS/JS, Python, Go): overview lists every symbol in a file with kinds and line ranges; find matches a name path (`method`, `Class/method`, `Class.method`, `/Class/method` for whole-name, `src/x.ts#Class.method`), optionally with the body; references lists what calls, references, extends or implements a symbol, grouped by the referencing symbol. Compact output; prefer this over reading whole files.",
58405
+ description: "Symbol-level code navigation on the tree-sitter graph (TS/JS, Python, Go, PHP): overview lists every symbol in a file with kinds and line ranges; find matches a name path (`method`, `Class/method`, `Class.method`, `/Class/method` for whole-name, `src/x.ts#Class.method`), optionally with the body; references lists what calls, references, extends or implements a symbol, grouped by the referencing symbol. Compact output; prefer this over reading whole files.",
57257
58406
  schema: {
57258
58407
  mode: external_exports.enum(["overview", "find", "references"]).optional().describe("default find"),
57259
58408
  file: external_exports.string().optional().describe("overview: the file; find/references: restrict to (or referrers in) this path"),