eminiar 0.6.2 → 0.8.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
@@ -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, relative9, options, skipNormalization) {
3915
+ function resolveComponent(base, relative10, options, skipNormalization) {
3916
3916
  const target = {};
3917
3917
  if (!skipNormalization) {
3918
3918
  base = parse3(serialize(base, options), options);
3919
- relative9 = parse3(serialize(relative9, options), options);
3919
+ relative10 = parse3(serialize(relative10, options), options);
3920
3920
  }
3921
3921
  options = options || {};
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;
3922
+ if (!options.tolerant && relative10.scheme) {
3923
+ target.scheme = relative10.scheme;
3924
+ target.userinfo = relative10.userinfo;
3925
+ target.host = relative10.host;
3926
+ target.port = relative10.port;
3927
+ target.path = removeDotSegments(relative10.path || "");
3928
+ target.query = relative10.query;
3929
3929
  } else {
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;
3930
+ if (relative10.userinfo !== void 0 || relative10.host !== void 0 || relative10.port !== void 0) {
3931
+ target.userinfo = relative10.userinfo;
3932
+ target.host = relative10.host;
3933
+ target.port = relative10.port;
3934
+ target.path = removeDotSegments(relative10.path || "");
3935
+ target.query = relative10.query;
3936
3936
  } else {
3937
- if (!relative9.path) {
3937
+ if (!relative10.path) {
3938
3938
  target.path = base.path;
3939
- if (relative9.query !== void 0) {
3940
- target.query = relative9.query;
3939
+ if (relative10.query !== void 0) {
3940
+ target.query = relative10.query;
3941
3941
  } else {
3942
3942
  target.query = base.query;
3943
3943
  }
3944
3944
  } else {
3945
- if (relative9.path[0] === "/") {
3946
- target.path = removeDotSegments(relative9.path);
3945
+ if (relative10.path[0] === "/") {
3946
+ target.path = removeDotSegments(relative10.path);
3947
3947
  } else {
3948
3948
  if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
3949
- target.path = "/" + relative9.path;
3949
+ target.path = "/" + relative10.path;
3950
3950
  } else if (!base.path) {
3951
- target.path = relative9.path;
3951
+ target.path = relative10.path;
3952
3952
  } else {
3953
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative9.path;
3953
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative10.path;
3954
3954
  }
3955
3955
  target.path = removeDotSegments(target.path);
3956
3956
  }
3957
- target.query = relative9.query;
3957
+ target.query = relative10.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 = relative9.fragment;
3965
+ target.fragment = relative10.fragment;
3966
3966
  return target;
3967
3967
  }
3968
3968
  function equal(uriA, uriB, options) {
@@ -10015,9 +10015,9 @@ var require_parse2 = __commonJS({
10015
10015
  const idx = prev.value.lastIndexOf("[");
10016
10016
  const pre = prev.value.slice(0, idx);
10017
10017
  const rest2 = prev.value.slice(idx + 2);
10018
- const posix = POSIX_REGEX_SOURCE[rest2];
10019
- if (posix) {
10020
- prev.value = pre + posix;
10018
+ const posix2 = POSIX_REGEX_SOURCE[rest2];
10019
+ if (posix2) {
10020
+ prev.value = pre + posix2;
10021
10021
  state.backtrack = true;
10022
10022
  advance();
10023
10023
  if (!bos.output && tokens.indexOf(prev) === 1) {
@@ -10539,7 +10539,7 @@ var require_picomatch = __commonJS({
10539
10539
  throw new TypeError("Expected pattern to be a non-empty string");
10540
10540
  }
10541
10541
  const opts = options || {};
10542
- const posix = utils.isWindows(options);
10542
+ const posix2 = utils.isWindows(options);
10543
10543
  const regex = isState ? picomatch.compileRe(glob2, options) : picomatch.makeRe(glob2, options, false, true);
10544
10544
  const state = regex.state;
10545
10545
  delete regex.state;
@@ -10549,8 +10549,8 @@ var require_picomatch = __commonJS({
10549
10549
  isIgnored = picomatch(opts.ignore, ignoreOpts, returnState);
10550
10550
  }
10551
10551
  const matcher = (input2, returnObject = false) => {
10552
- const { isMatch, match, output: output2 } = picomatch.test(input2, regex, options, { glob: glob2, posix });
10553
- const result = { glob: glob2, state, regex, posix, input: input2, output: output2, match, isMatch };
10552
+ const { isMatch, match, output: output2 } = picomatch.test(input2, regex, options, { glob: glob2, posix: posix2 });
10553
+ const result = { glob: glob2, state, regex, posix: posix2, input: input2, output: output2, match, isMatch };
10554
10554
  if (typeof opts.onResult === "function") {
10555
10555
  opts.onResult(result);
10556
10556
  }
@@ -10575,7 +10575,7 @@ var require_picomatch = __commonJS({
10575
10575
  }
10576
10576
  return matcher;
10577
10577
  };
10578
- picomatch.test = (input2, regex, options, { glob: glob2, posix } = {}) => {
10578
+ picomatch.test = (input2, regex, options, { glob: glob2, posix: posix2 } = {}) => {
10579
10579
  if (typeof input2 !== "string") {
10580
10580
  throw new TypeError("Expected input to be a string");
10581
10581
  }
@@ -10583,7 +10583,7 @@ var require_picomatch = __commonJS({
10583
10583
  return { isMatch: false, output: "" };
10584
10584
  }
10585
10585
  const opts = options || {};
10586
- const format = opts.format || (posix ? utils.toPosixSlashes : null);
10586
+ const format = opts.format || (posix2 ? utils.toPosixSlashes : null);
10587
10587
  let match = input2 === glob2;
10588
10588
  let output2 = match && format ? format(input2) : input2;
10589
10589
  if (match === false) {
@@ -10592,14 +10592,14 @@ var require_picomatch = __commonJS({
10592
10592
  }
10593
10593
  if (match === false || opts.capture === true) {
10594
10594
  if (opts.matchBase === true || opts.basename === true) {
10595
- match = picomatch.matchBase(input2, regex, options, posix);
10595
+ match = picomatch.matchBase(input2, regex, options, posix2);
10596
10596
  } else {
10597
10597
  match = regex.exec(output2);
10598
10598
  }
10599
10599
  }
10600
10600
  return { isMatch: Boolean(match), match, output: output2 };
10601
10601
  };
10602
- picomatch.matchBase = (input2, glob2, options, posix = utils.isWindows(options)) => {
10602
+ picomatch.matchBase = (input2, glob2, options, posix2 = utils.isWindows(options)) => {
10603
10603
  const regex = glob2 instanceof RegExp ? glob2 : picomatch.makeRe(glob2, options);
10604
10604
  return regex.test(path3.basename(input2));
10605
10605
  };
@@ -10790,9 +10790,9 @@ var require_micromatch = __commonJS({
10790
10790
  return [].concat(patterns).every((p) => picomatch(p, options)(str2));
10791
10791
  };
10792
10792
  micromatch.capture = (glob2, input2, options) => {
10793
- let posix = utils.isWindows(options);
10793
+ let posix2 = utils.isWindows(options);
10794
10794
  let regex = picomatch.makeRe(String(glob2), { ...options, capture: true });
10795
- let match = regex.exec(posix ? utils.toPosixSlashes(input2) : input2);
10795
+ let match = regex.exec(posix2 ? utils.toPosixSlashes(input2) : input2);
10796
10796
  if (match) {
10797
10797
  return match.slice(1).map((v) => v === void 0 ? "" : v);
10798
10798
  }
@@ -10972,15 +10972,15 @@ var require_pattern2 = __commonJS({
10972
10972
  exports.removeDuplicateSlashes = removeDuplicateSlashes;
10973
10973
  function partitionAbsoluteAndRelative(patterns) {
10974
10974
  const absolute = [];
10975
- const relative9 = [];
10975
+ const relative10 = [];
10976
10976
  for (const pattern2 of patterns) {
10977
10977
  if (isAbsolute2(pattern2)) {
10978
10978
  absolute.push(pattern2);
10979
10979
  } else {
10980
- relative9.push(pattern2);
10980
+ relative10.push(pattern2);
10981
10981
  }
10982
10982
  }
10983
- return [absolute, relative9];
10983
+ return [absolute, relative10];
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 statSync10(path3, optionsOrSettings) {
11414
+ function statSync11(path3, optionsOrSettings) {
11415
11415
  const settings = getSettings(optionsOrSettings);
11416
11416
  return sync.read(path3, settings);
11417
11417
  }
11418
- exports.statSync = statSync10;
11418
+ exports.statSync = statSync11;
11419
11419
  function getSettings(settingsOrOptions = {}) {
11420
11420
  if (settingsOrOptions instanceof settings_1.default) {
11421
11421
  return settingsOrOptions;
@@ -13295,19 +13295,19 @@ var require_out4 = __commonJS({
13295
13295
  return utils.path.convertPathToPattern(source);
13296
13296
  }
13297
13297
  FastGlob2.convertPathToPattern = convertPathToPattern;
13298
- let posix;
13299
- (function(posix2) {
13298
+ let posix2;
13299
+ (function(posix3) {
13300
13300
  function escapePath2(source) {
13301
13301
  assertPatternsInput(source);
13302
13302
  return utils.path.escapePosixPath(source);
13303
13303
  }
13304
- posix2.escapePath = escapePath2;
13304
+ posix3.escapePath = escapePath2;
13305
13305
  function convertPathToPattern2(source) {
13306
13306
  assertPatternsInput(source);
13307
13307
  return utils.path.convertPosixPathToPattern(source);
13308
13308
  }
13309
- posix2.convertPathToPattern = convertPathToPattern2;
13310
- })(posix = FastGlob2.posix || (FastGlob2.posix = {}));
13309
+ posix3.convertPathToPattern = convertPathToPattern2;
13310
+ })(posix2 = FastGlob2.posix || (FastGlob2.posix = {}));
13311
13311
  let win32;
13312
13312
  (function(win322) {
13313
13313
  function escapePath2(source) {
@@ -13790,13 +13790,14 @@ function fileOf(id) {
13790
13790
  if (kind === "sym") return rest.split("#")[0];
13791
13791
  return void 0;
13792
13792
  }
13793
- var fileId, memoryId, symId, pkgId, personId, conceptId;
13793
+ var fileId, memoryId, docId, symId, pkgId, personId, conceptId;
13794
13794
  var init_ids = __esm({
13795
13795
  "src/graph/ids.ts"() {
13796
13796
  "use strict";
13797
13797
  init_esm_shims();
13798
13798
  fileId = (rel) => `file:${rel}`;
13799
13799
  memoryId = (name) => `memory:${name}`;
13800
+ docId = (name) => `doc:${name}`;
13800
13801
  symId = (rel, name) => `sym:${rel}#${name}`;
13801
13802
  pkgId = (name) => `pkg:${name}`;
13802
13803
  personId = (name) => `person:${name}`;
@@ -18022,10 +18023,13 @@ __export(store_exports, {
18022
18023
  isValidName: () => isValidName,
18023
18024
  list: () => list,
18024
18025
  memoriesDir: () => memoriesDir,
18026
+ memoriesRel: () => memoriesRel,
18027
+ memoryLinks: () => memoryLinks,
18025
18028
  normalizeRelated: () => normalizeRelated,
18026
18029
  read: () => read,
18027
18030
  reconcile: () => reconcile,
18028
18031
  relOf: () => relOf,
18032
+ relatedTarget: () => relatedTarget,
18029
18033
  remove: () => remove,
18030
18034
  rename: () => rename,
18031
18035
  setMeta: () => setMeta,
@@ -18101,6 +18105,17 @@ function normalizeRelated(ids) {
18101
18105
  }
18102
18106
  return [...out];
18103
18107
  }
18108
+ function relatedTarget(id) {
18109
+ return id.startsWith("mem:") ? memoryId(id.slice(4)) : id;
18110
+ }
18111
+ function memoryLinks(body, self) {
18112
+ const out = /* @__PURE__ */ new Set();
18113
+ for (const m of body.matchAll(MEM_LINK_RE)) {
18114
+ const name = m[1].replace(/[.-]+$/, "");
18115
+ if (name && name !== self && isValidName(name)) out.add(name);
18116
+ }
18117
+ return [...out];
18118
+ }
18104
18119
  function writeMemoryFile(ctx, name, meta4, body) {
18105
18120
  const abs = absOf(ctx, name);
18106
18121
  mkdirSync3(dirname7(abs), { recursive: true });
@@ -18108,36 +18123,30 @@ function writeMemoryFile(ctx, name, meta4, body) {
18108
18123
  ${body.trim()}
18109
18124
  `));
18110
18125
  }
18111
- function syncGraph(db, name, rel, kind, tags, related, supersedes) {
18126
+ function syncGraph(db, name, rel, g) {
18127
+ const self = memoryId(name);
18112
18128
  db.graphDeleteForPath("curated", rel);
18113
18129
  db.graphUpsertNodes([
18114
18130
  {
18115
- id: memoryId(name),
18131
+ id: self,
18116
18132
  kind: "memory",
18117
18133
  name,
18118
18134
  path: rel,
18119
18135
  source: "curated",
18120
- meta: { kind, tags }
18136
+ meta: { kind: g.kind, tags: g.tags, ...g.status ? { status: g.status } : {} }
18121
18137
  }
18122
18138
  ]);
18123
- const edges = related.map((dst) => ({
18124
- src: memoryId(name),
18125
- dst,
18126
- kind: "mentions",
18127
- source: "curated",
18128
- confidence: 1,
18129
- weight: 1
18130
- }));
18131
- if (supersedes) {
18132
- edges.push({
18133
- src: memoryId(name),
18134
- dst: memoryId(supersedes),
18135
- kind: "supersedes",
18136
- source: "curated",
18137
- confidence: 1,
18138
- weight: 1
18139
- });
18140
- }
18139
+ const edges = [];
18140
+ const seen = /* @__PURE__ */ new Set();
18141
+ const push = (dst, kind) => {
18142
+ const key = `${kind}|${dst}`;
18143
+ if (dst === self || seen.has(key)) return;
18144
+ seen.add(key);
18145
+ edges.push({ src: self, dst, kind, source: "curated", confidence: 1, weight: 1 });
18146
+ };
18147
+ for (const id of g.related) push(relatedTarget(id), "mentions");
18148
+ for (const other of memoryLinks(g.body, name)) push(memoryId(other), "links");
18149
+ if (g.supersedes) push(memoryId(g.supersedes.replace(/^mem(?:ory)?:/, "")), "supersedes");
18141
18150
  if (edges.length) db.graphUpsertEdges(edges);
18142
18151
  }
18143
18152
  function forgetInDb(db, name, rel) {
@@ -18224,7 +18233,7 @@ tags: ${tags.join(", ")}` : ""}`,
18224
18233
  status,
18225
18234
  supersedes
18226
18235
  });
18227
- syncGraph(db, name, rel, kind, tags, related, supersedes);
18236
+ syncGraph(db, name, rel, { kind, tags, related, status, supersedes, body });
18228
18237
  return { changed: true, row: db.memoryGetByName(name) };
18229
18238
  }
18230
18239
  function setMeta(ctx, db, name, patch) {
@@ -18427,7 +18436,7 @@ function gitignoreHint(ctx) {
18427
18436
  const ignored = readFileSync8(file3, "utf8").split(/\r?\n/).map((l) => l.trim().replace(/^\//, "").replace(/\/$/, "")).some((l) => l === top || l === dir || l === `${top}/**` || l === `${dir}/**`);
18428
18437
  return ignored ? `note: .gitignore ignores ${dir}, so memories stay local to this machine (remove that line to share them with the team)` : void 0;
18429
18438
  }
18430
- var import_fast_glob3, MEMORY_KINDS, SEGMENT, NAME_RE, hinted;
18439
+ var import_fast_glob3, MEMORY_KINDS, SEGMENT, NAME_RE, MEM_LINK_RE, hinted;
18431
18440
  var init_store = __esm({
18432
18441
  "src/memory/store.ts"() {
18433
18442
  "use strict";
@@ -18449,6 +18458,7 @@ var init_store = __esm({
18449
18458
  ];
18450
18459
  SEGMENT = "[a-z0-9][a-z0-9._-]*";
18451
18460
  NAME_RE = new RegExp(`^(?:${SEGMENT}/)?${SEGMENT}$`);
18461
+ MEM_LINK_RE = /(?<![A-Za-z0-9_./-])mem:([a-z0-9][a-z0-9._-]*(?:\/[a-z0-9][a-z0-9._-]*)?)/g;
18452
18462
  hinted = /* @__PURE__ */ new Set();
18453
18463
  }
18454
18464
  });
@@ -50808,9 +50818,10 @@ function impact(db, ref, opts = {}) {
50808
50818
  frontier = next;
50809
50819
  if (!frontier.length) break;
50810
50820
  }
50811
- for (const e of db.graphEdgesTo(start, ["mentions"])) {
50821
+ for (const e of db.graphEdgesTo(start, ["mentions", "documents"])) {
50812
50822
  const via = e.dst === root.id ? root.name : e.dst.replace(/^sym:[^#]*#/, "");
50813
- add(e.src, 0.5 * e.confidence, 1, `memory mentions ${via}`);
50823
+ const who = e.kind === "documents" ? "doc documents" : "memory mentions";
50824
+ add(e.src, 0.5 * e.confidence, 1, `${who} ${via}`);
50814
50825
  }
50815
50826
  if (opts.includeGit !== false) {
50816
50827
  const file3 = toFile(root.id);
@@ -51231,7 +51242,7 @@ function architecture(ctx, db, aspects = ASPECTS) {
51231
51242
  for (const l of languages2.values()) langCounts[l] = (langCounts[l] ?? 0) + 1;
51232
51243
  const counts = db.graphCounts();
51233
51244
  const nodeCounts = db.graphNodeCounts();
51234
- const symbols = Object.entries(nodeCounts).filter(([k]) => !["file", "package", "person", "concept", "memory"].includes(k)).reduce((a, [, n]) => a + n, 0);
51245
+ const symbols = Object.entries(nodeCounts).filter(([k]) => !["file", "package", "person", "concept", "memory", "doc"].includes(k)).reduce((a, [, n]) => a + n, 0);
51235
51246
  const out = {
51236
51247
  project: {
51237
51248
  name: typeof pkg.name === "string" ? pkg.name : void 0,
@@ -55141,6 +55152,309 @@ function discoverDocs(ctx, opts = {}) {
55141
55152
  };
55142
55153
  }
55143
55154
 
55155
+ // src/docs/graph.ts
55156
+ init_esm_shims();
55157
+ init_ids();
55158
+ import { existsSync as existsSync14, statSync as statSync10 } from "fs";
55159
+ import { dirname as dirname9, posix, relative as relative8, sep as sep2 } from "path";
55160
+
55161
+ // src/docs/category.ts
55162
+ init_esm_shims();
55163
+ var DOC_CATEGORIES = [
55164
+ {
55165
+ id: "readme",
55166
+ group: "project",
55167
+ label: "Readme & guides",
55168
+ blurb: "README, CONTRIBUTING, CHANGELOG and other top-level guides"
55169
+ },
55170
+ {
55171
+ id: "guides",
55172
+ group: "project",
55173
+ label: "Docs folders",
55174
+ blurb: "docs/ directories: handbooks, how-tos, references"
55175
+ },
55176
+ {
55177
+ id: "adr",
55178
+ group: "project",
55179
+ label: "Decision records",
55180
+ blurb: "architecture decision records"
55181
+ },
55182
+ {
55183
+ id: "agent-instructions",
55184
+ group: "project",
55185
+ label: "Agent instructions",
55186
+ blurb: "Copilot, Claude and Cursor instructions, agents and skills"
55187
+ },
55188
+ {
55189
+ id: "api-specs",
55190
+ group: "project",
55191
+ label: "API specs",
55192
+ blurb: "OpenAPI, Postman, GraphQL and protobuf definitions"
55193
+ },
55194
+ {
55195
+ id: "env-reference",
55196
+ group: "project",
55197
+ label: "Environment reference",
55198
+ blurb: ".env examples: every variable the project reads"
55199
+ },
55200
+ {
55201
+ id: "deploy-config",
55202
+ group: "project",
55203
+ label: "Deploy config",
55204
+ blurb: "Terraform, Kubernetes, Helm, Compose and CI workflows"
55205
+ },
55206
+ { id: "local", group: "project", label: "Other local files", blurb: "hand-registered paths" },
55207
+ {
55208
+ id: "service",
55209
+ group: "external",
55210
+ label: "Services",
55211
+ blurb: "third-party products and APIs the project integrates"
55212
+ },
55213
+ {
55214
+ id: "api",
55215
+ group: "external",
55216
+ label: "External APIs",
55217
+ blurb: "hosts the code calls, found by probing their docs"
55218
+ },
55219
+ {
55220
+ id: "infra",
55221
+ group: "external",
55222
+ label: "Infrastructure",
55223
+ blurb: "platforms the project runs on"
55224
+ },
55225
+ { id: "library", group: "external", label: "Libraries", blurb: "frameworks and packages" },
55226
+ { id: "web", group: "external", label: "Web pages", blurb: "hand-registered URLs" }
55227
+ ];
55228
+ var BY_ID = new Map(DOC_CATEGORIES.map((c) => [c.id, c]));
55229
+ function categoryInfo(id) {
55230
+ return BY_ID.get(id) ?? BY_ID.get("local");
55231
+ }
55232
+ var GROUP_LABELS = {
55233
+ project: "Project documentation",
55234
+ external: "External documentation"
55235
+ };
55236
+ var TITLE_RULES = [
55237
+ [/^project readme/i, "readme"],
55238
+ [/^(docs|doc|documentation)\/ directory$/i, "guides"],
55239
+ [/decision records/i, "adr"],
55240
+ [/copilot|claude|cursor/i, "agent-instructions"],
55241
+ [/openapi|postman|graphql|protobuf/i, "api-specs"],
55242
+ [/environment variable/i, "env-reference"],
55243
+ [/terraform|kubernetes|helm|compose|workflow/i, "deploy-config"]
55244
+ ];
55245
+ var NAME_RULES = [
55246
+ [/(^|-)readme$/, "readme"],
55247
+ [/(^|-)docs$/, "guides"],
55248
+ [/(^|-)adrs?$/, "adr"],
55249
+ [/(^|-)agent-instructions$/, "agent-instructions"],
55250
+ [/(^|-)api-specs$/, "api-specs"],
55251
+ [/(^|-)env-example$/, "env-reference"],
55252
+ [/(^|-)deploy-config$/, "deploy-config"]
55253
+ ];
55254
+ var GLOB_RULES = [
55255
+ [/openapi|swagger|postman_collection|asyncapi|\.graphql$|\.proto$/i, "api-specs"],
55256
+ [/^\.env\./, "env-reference"],
55257
+ [
55258
+ /\.tf$|tfvars|^k8s\/|^helm\/|^charts\/|^manifests\/|compose.*\.ya?ml|\.github\/workflows/i,
55259
+ "deploy-config"
55260
+ ],
55261
+ [
55262
+ /copilot-instructions|\.github\/(instructions|agents|skills)|\.claude\/(agents|skills)|\.cursor\/rules|^(AGENTS|CLAUDE)\.md$/i,
55263
+ "agent-instructions"
55264
+ ],
55265
+ [/^(README|CONTRIBUTING|CHANGELOG|SECURITY)(\.md)?$/i, "readme"],
55266
+ [/^\*\*\/\*\.(md|mdx|rst|txt)$/i, "guides"]
55267
+ ];
55268
+ function localCategory(s) {
55269
+ const title = s.title ?? "";
55270
+ for (const [re, cat] of TITLE_RULES) if (re.test(title)) return cat;
55271
+ for (const [re, cat] of NAME_RULES) if (re.test(s.name)) return cat;
55272
+ const path3 = s.path ?? "";
55273
+ if (/(^|\/)(adrs?|decisions)$/i.test(path3)) return "adr";
55274
+ const globs = s.glob ?? [];
55275
+ const hits = /* @__PURE__ */ new Map();
55276
+ for (const g of globs)
55277
+ for (const [re, cat] of GLOB_RULES)
55278
+ if (re.test(g)) {
55279
+ hits.set(cat, (hits.get(cat) ?? 0) + 1);
55280
+ break;
55281
+ }
55282
+ if (hits.size) return [...hits.entries()].sort((a, b) => b[1] - a[1])[0][0];
55283
+ if (/(^|\/)(docs?|documentation)$/i.test(path3)) return "guides";
55284
+ if (/README|CONTRIBUTING|CHANGELOG/i.test(path3)) return "readme";
55285
+ return "local";
55286
+ }
55287
+ function docCategory(s, entry) {
55288
+ if (s.kind === "path") return localCategory(s);
55289
+ if (entry) {
55290
+ const tier = entry.tier ?? "library";
55291
+ return tier === "service" ? "service" : tier === "infra" ? "infra" : "library";
55292
+ }
55293
+ const provider = s.provider ?? "";
55294
+ const i = provider.indexOf(":");
55295
+ const kind = i === -1 ? provider : provider.slice(0, i);
55296
+ switch (kind) {
55297
+ case "api":
55298
+ return "api";
55299
+ case "env":
55300
+ return "service";
55301
+ case "image":
55302
+ case "files":
55303
+ return "infra";
55304
+ case "npm":
55305
+ case "pypi":
55306
+ case "go":
55307
+ return "library";
55308
+ default:
55309
+ return "web";
55310
+ }
55311
+ }
55312
+ function categoryRank(id) {
55313
+ const i = DOC_CATEGORIES.findIndex((c) => c.id === id);
55314
+ return i === -1 ? DOC_CATEGORIES.length : i;
55315
+ }
55316
+
55317
+ // src/docs/graph.ts
55318
+ var DOCUMENTS_EDGE = "documents";
55319
+ var MAX_PAGES = 500;
55320
+ var MAX_EDGES = 400;
55321
+ var PATH_RE = /(?:^|[\s(`'"[<])((?:\.{1,2}\/)*(?:[\w@.-]+\/)+[\w@.-]+\.[A-Za-z0-9]{1,8})(?=$|[\s)`'"\]>:#,;!?]|\.(?:\s|$))/gm;
55322
+ function manifestRel(ctx) {
55323
+ return relative8(ctx.root, manifestPath(ctx)).split(sep2).join("/");
55324
+ }
55325
+ function packageCandidates(provider) {
55326
+ if (!provider) return [];
55327
+ const i = provider.indexOf(":");
55328
+ if (i === -1) return [];
55329
+ const kind = provider.slice(0, i);
55330
+ const name = provider.slice(i + 1).trim();
55331
+ if (!name) return [];
55332
+ if (kind === "npm" || kind === "go") return [pkgId(name)];
55333
+ if (kind === "pypi") {
55334
+ const lower = name.toLowerCase();
55335
+ return [.../* @__PURE__ */ new Set([pkgId(lower.replace(/-/g, "_")), pkgId(lower), pkgId(name)])];
55336
+ }
55337
+ return [];
55338
+ }
55339
+ function pathsIn(text2, pageRel, files) {
55340
+ const out = /* @__PURE__ */ new Set();
55341
+ for (const m of text2.matchAll(PATH_RE)) {
55342
+ const raw = m[1];
55343
+ const tries = [raw.replace(/^(\.\/)+/, "")];
55344
+ if (pageRel && raw.startsWith("."))
55345
+ tries.unshift(posix.normalize(posix.join(dirname9(pageRel), raw)));
55346
+ for (const t of tries) {
55347
+ if (files.has(t)) {
55348
+ out.add(t);
55349
+ break;
55350
+ }
55351
+ }
55352
+ }
55353
+ return [...out];
55354
+ }
55355
+ function pageRelOf(ctx, uri) {
55356
+ if (!uri?.startsWith("file://")) return void 0;
55357
+ const rel = relative8(ctx.root, uri.slice("file://".length)).split(sep2).join("/");
55358
+ return rel.startsWith("..") ? void 0 : rel;
55359
+ }
55360
+ function localEdges(ctx, db, src, files) {
55361
+ const id = docId(src.name);
55362
+ const hits = /* @__PURE__ */ new Map();
55363
+ for (const page of db.documentsBySource(docsTag(src.name), MAX_PAGES)) {
55364
+ const rel = pageRelOf(ctx, page.uri);
55365
+ if (rel && files.has(rel)) hits.set(rel, { via: "covers", count: 1 });
55366
+ const text2 = db.chunksOfDocument(page.id).map((c) => c.body).join("\n");
55367
+ for (const f of pathsIn(text2, rel, files)) {
55368
+ const h = hits.get(f);
55369
+ if (h) h.count++;
55370
+ else hits.set(f, { via: "mentions", count: 1 });
55371
+ }
55372
+ if (hits.size >= MAX_EDGES) break;
55373
+ }
55374
+ return [...hits].sort((a, b) => b[1].count - a[1].count).slice(0, MAX_EDGES).map(([rel, h]) => ({
55375
+ src: id,
55376
+ dst: `file:${rel}`,
55377
+ kind: DOCUMENTS_EDGE,
55378
+ source: "curated",
55379
+ confidence: h.via === "covers" ? 1 : 0.8,
55380
+ weight: Math.min(1, 0.5 + h.count / 10),
55381
+ meta: { via: h.via, count: h.count }
55382
+ }));
55383
+ }
55384
+ function packageEdges(src, packages) {
55385
+ const id = docId(src.name);
55386
+ const cands = packageCandidates(src.provider);
55387
+ if (!cands.length) return [];
55388
+ let targets = cands.filter((c) => packages.has(c));
55389
+ if (src.provider?.startsWith("go:"))
55390
+ targets = [...targets, ...[...packages].filter((p) => p.startsWith(`${cands[0]}/`))];
55391
+ if (!targets.length) targets = [cands[0]];
55392
+ return [...new Set(targets)].map((dst) => ({
55393
+ src: id,
55394
+ dst,
55395
+ kind: DOCUMENTS_EDGE,
55396
+ source: "curated",
55397
+ confidence: 1,
55398
+ weight: 1,
55399
+ meta: { via: "provider" }
55400
+ }));
55401
+ }
55402
+ var STAMP_KEY = "docs.graph.stamp";
55403
+ function stampOf(ctx, db) {
55404
+ const file3 = manifestPath(ctx);
55405
+ const st = existsSync14(file3) ? statSync10(file3) : void 0;
55406
+ const counts = db.graphNodeCounts();
55407
+ const syncs = readManifest(ctx).sources.map((s) => syncState(db, s.name)?.at ?? 0).join(",");
55408
+ return `${st ? `${Math.floor(st.mtimeMs)}:${st.size}` : "none"}|${counts.file ?? 0}|${counts.package ?? 0}|${syncs}`;
55409
+ }
55410
+ function syncDocsGraph(ctx, db) {
55411
+ const rel = manifestRel(ctx);
55412
+ const m = readManifest(ctx);
55413
+ const catalog = mergedCatalog(ctx.config.docs.catalog);
55414
+ const files = new Set(
55415
+ db.graphFileNodes().filter((n) => n.source === "tree-sitter" && n.path).map((n) => n.path)
55416
+ );
55417
+ const packages = new Set(db.graphNodesByKind(["package"]).map((n) => n.id));
55418
+ const nodes = [];
55419
+ const edges = [];
55420
+ for (const s of m.sources) {
55421
+ const category = docCategory(
55422
+ s,
55423
+ s.provider ? catalogForProvider(s.provider, catalog) : void 0
55424
+ );
55425
+ nodes.push({
55426
+ id: docId(s.name),
55427
+ kind: "doc",
55428
+ name: s.name,
55429
+ path: rel,
55430
+ source: "curated",
55431
+ meta: {
55432
+ category,
55433
+ group: categoryInfo(category).group,
55434
+ sourceKind: s.kind,
55435
+ ...s.provider ? { provider: s.provider } : {},
55436
+ ...s.title ? { title: s.title } : {},
55437
+ ...s.tags?.length ? { tags: s.tags } : {},
55438
+ ...s.kind === "path" ? { target: s.path } : { url: s.urls?.[0] },
55439
+ documents: db.countDocuments(docsTag(s.name))
55440
+ }
55441
+ });
55442
+ edges.push(...packageEdges(s, packages));
55443
+ if (s.kind === "path") edges.push(...localEdges(ctx, db, s, files));
55444
+ }
55445
+ db.graphDeleteForPath("curated", rel, { keepFile: true });
55446
+ if (nodes.length) db.graphUpsertNodes(nodes);
55447
+ if (edges.length) db.graphUpsertEdges(edges);
55448
+ db.metaSet(STAMP_KEY, stampOf(ctx, db));
55449
+ return { sources: nodes.length, edges: edges.length };
55450
+ }
55451
+ function syncDocsGraphQuietly(ctx, db) {
55452
+ try {
55453
+ syncDocsGraph(ctx, db);
55454
+ } catch {
55455
+ }
55456
+ }
55457
+
55144
55458
  // src/docs/resolve.ts
55145
55459
  init_esm_shims();
55146
55460
  async function getJson(url2, opts) {
@@ -56009,6 +56323,7 @@ async function syncSources(ctx, db, names, opts = {}) {
56009
56323
  });
56010
56324
  }
56011
56325
  for (const src of wanted) out.push(await syncSource(ctx, db, src, opts));
56326
+ syncDocsGraphQuietly(ctx, db);
56012
56327
  return out;
56013
56328
  }
56014
56329
  function formatSync(results) {
@@ -56178,12 +56493,14 @@ async function addDocSources(ctx, db, inputs, opts = {}) {
56178
56493
  const names = [...out.added, ...out.updated];
56179
56494
  if (opts.sync !== false && names.length)
56180
56495
  out.sync = await syncSources(ctx, db, names, { force: opts.force });
56496
+ else if (names.length) syncDocsGraphQuietly(ctx, db);
56181
56497
  return out;
56182
56498
  }
56183
56499
  function removeDocSource(ctx, db, name) {
56184
56500
  const removed = removeSource(ctx, name);
56185
56501
  const documents = db.deleteDocumentsBySource(docsTag(name));
56186
56502
  clearSyncState(db, name);
56503
+ if (removed) syncDocsGraphQuietly(ctx, db);
56187
56504
  return { removed, documents };
56188
56505
  }
56189
56506
  function formatAdd(o) {
@@ -56211,162 +56528,6 @@ async function addPicked(ctx, db, pick2, opts) {
56211
56528
  );
56212
56529
  }
56213
56530
 
56214
- // src/docs/category.ts
56215
- init_esm_shims();
56216
- var DOC_CATEGORIES = [
56217
- {
56218
- id: "readme",
56219
- group: "project",
56220
- label: "Readme & guides",
56221
- blurb: "README, CONTRIBUTING, CHANGELOG and other top-level guides"
56222
- },
56223
- {
56224
- id: "guides",
56225
- group: "project",
56226
- label: "Docs folders",
56227
- blurb: "docs/ directories: handbooks, how-tos, references"
56228
- },
56229
- {
56230
- id: "adr",
56231
- group: "project",
56232
- label: "Decision records",
56233
- blurb: "architecture decision records"
56234
- },
56235
- {
56236
- id: "agent-instructions",
56237
- group: "project",
56238
- label: "Agent instructions",
56239
- blurb: "Copilot, Claude and Cursor instructions, agents and skills"
56240
- },
56241
- {
56242
- id: "api-specs",
56243
- group: "project",
56244
- label: "API specs",
56245
- blurb: "OpenAPI, Postman, GraphQL and protobuf definitions"
56246
- },
56247
- {
56248
- id: "env-reference",
56249
- group: "project",
56250
- label: "Environment reference",
56251
- blurb: ".env examples: every variable the project reads"
56252
- },
56253
- {
56254
- id: "deploy-config",
56255
- group: "project",
56256
- label: "Deploy config",
56257
- blurb: "Terraform, Kubernetes, Helm, Compose and CI workflows"
56258
- },
56259
- { id: "local", group: "project", label: "Other local files", blurb: "hand-registered paths" },
56260
- {
56261
- id: "service",
56262
- group: "external",
56263
- label: "Services",
56264
- blurb: "third-party products and APIs the project integrates"
56265
- },
56266
- {
56267
- id: "api",
56268
- group: "external",
56269
- label: "External APIs",
56270
- blurb: "hosts the code calls, found by probing their docs"
56271
- },
56272
- {
56273
- id: "infra",
56274
- group: "external",
56275
- label: "Infrastructure",
56276
- blurb: "platforms the project runs on"
56277
- },
56278
- { id: "library", group: "external", label: "Libraries", blurb: "frameworks and packages" },
56279
- { id: "web", group: "external", label: "Web pages", blurb: "hand-registered URLs" }
56280
- ];
56281
- var BY_ID = new Map(DOC_CATEGORIES.map((c) => [c.id, c]));
56282
- function categoryInfo(id) {
56283
- return BY_ID.get(id) ?? BY_ID.get("local");
56284
- }
56285
- var GROUP_LABELS = {
56286
- project: "Project documentation",
56287
- external: "External documentation"
56288
- };
56289
- var TITLE_RULES = [
56290
- [/^project readme/i, "readme"],
56291
- [/^(docs|doc|documentation)\/ directory$/i, "guides"],
56292
- [/decision records/i, "adr"],
56293
- [/copilot|claude|cursor/i, "agent-instructions"],
56294
- [/openapi|postman|graphql|protobuf/i, "api-specs"],
56295
- [/environment variable/i, "env-reference"],
56296
- [/terraform|kubernetes|helm|compose|workflow/i, "deploy-config"]
56297
- ];
56298
- var NAME_RULES = [
56299
- [/(^|-)readme$/, "readme"],
56300
- [/(^|-)docs$/, "guides"],
56301
- [/(^|-)adrs?$/, "adr"],
56302
- [/(^|-)agent-instructions$/, "agent-instructions"],
56303
- [/(^|-)api-specs$/, "api-specs"],
56304
- [/(^|-)env-example$/, "env-reference"],
56305
- [/(^|-)deploy-config$/, "deploy-config"]
56306
- ];
56307
- var GLOB_RULES = [
56308
- [/openapi|swagger|postman_collection|asyncapi|\.graphql$|\.proto$/i, "api-specs"],
56309
- [/^\.env\./, "env-reference"],
56310
- [
56311
- /\.tf$|tfvars|^k8s\/|^helm\/|^charts\/|^manifests\/|compose.*\.ya?ml|\.github\/workflows/i,
56312
- "deploy-config"
56313
- ],
56314
- [
56315
- /copilot-instructions|\.github\/(instructions|agents|skills)|\.claude\/(agents|skills)|\.cursor\/rules|^(AGENTS|CLAUDE)\.md$/i,
56316
- "agent-instructions"
56317
- ],
56318
- [/^(README|CONTRIBUTING|CHANGELOG|SECURITY)(\.md)?$/i, "readme"],
56319
- [/^\*\*\/\*\.(md|mdx|rst|txt)$/i, "guides"]
56320
- ];
56321
- function localCategory(s) {
56322
- const title = s.title ?? "";
56323
- for (const [re, cat] of TITLE_RULES) if (re.test(title)) return cat;
56324
- for (const [re, cat] of NAME_RULES) if (re.test(s.name)) return cat;
56325
- const path3 = s.path ?? "";
56326
- if (/(^|\/)(adrs?|decisions)$/i.test(path3)) return "adr";
56327
- const globs = s.glob ?? [];
56328
- const hits = /* @__PURE__ */ new Map();
56329
- for (const g of globs)
56330
- for (const [re, cat] of GLOB_RULES)
56331
- if (re.test(g)) {
56332
- hits.set(cat, (hits.get(cat) ?? 0) + 1);
56333
- break;
56334
- }
56335
- if (hits.size) return [...hits.entries()].sort((a, b) => b[1] - a[1])[0][0];
56336
- if (/(^|\/)(docs?|documentation)$/i.test(path3)) return "guides";
56337
- if (/README|CONTRIBUTING|CHANGELOG/i.test(path3)) return "readme";
56338
- return "local";
56339
- }
56340
- function docCategory(s, entry) {
56341
- if (s.kind === "path") return localCategory(s);
56342
- if (entry) {
56343
- const tier = entry.tier ?? "library";
56344
- return tier === "service" ? "service" : tier === "infra" ? "infra" : "library";
56345
- }
56346
- const provider = s.provider ?? "";
56347
- const i = provider.indexOf(":");
56348
- const kind = i === -1 ? provider : provider.slice(0, i);
56349
- switch (kind) {
56350
- case "api":
56351
- return "api";
56352
- case "env":
56353
- return "service";
56354
- case "image":
56355
- case "files":
56356
- return "infra";
56357
- case "npm":
56358
- case "pypi":
56359
- case "go":
56360
- return "library";
56361
- default:
56362
- return "web";
56363
- }
56364
- }
56365
- function categoryRank(id) {
56366
- const i = DOC_CATEGORIES.findIndex((c) => c.id === id);
56367
- return i === -1 ? DOC_CATEGORIES.length : i;
56368
- }
56369
-
56370
56531
  // src/tools/em_docs.ts
56371
56532
  init_queue();
56372
56533
  var sourceShape2 = {
@@ -56674,7 +56835,7 @@ init_esm_shims();
56674
56835
  init_esm_shims();
56675
56836
  init_paths();
56676
56837
  init_version();
56677
- import { accessSync as accessSync2, constants as constants2, existsSync as existsSync14, readFileSync as readFileSync14 } from "fs";
56838
+ import { accessSync as accessSync2, constants as constants2, existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
56678
56839
  import { createRequire as createRequire3 } from "module";
56679
56840
  import { join as join20 } from "path";
56680
56841
  var require4 = createRequire3(import.meta.url);
@@ -56705,7 +56866,7 @@ function runDoctor() {
56705
56866
  );
56706
56867
  checks.push(
56707
56868
  check2("node-path pin", () => {
56708
- if (!existsSync14(p.nodePathFile)) return "not pinned (run `eminiar install`); using PATH node";
56869
+ if (!existsSync15(p.nodePathFile)) return "not pinned (run `eminiar install`); using PATH node";
56709
56870
  const pinned = readFileSync14(p.nodePathFile, "utf8").trim();
56710
56871
  accessSync2(pinned, constants2.X_OK);
56711
56872
  return pinned;
@@ -56713,10 +56874,10 @@ function runDoctor() {
56713
56874
  );
56714
56875
  checks.push(
56715
56876
  check2("root-path pin", () => {
56716
- if (!existsSync14(p.rootPathFile))
56877
+ if (!existsSync15(p.rootPathFile))
56717
56878
  return "not pinned (run `eminiar install`); the bin/ shims run only from a directory that has node_modules";
56718
56879
  const root = readFileSync14(p.rootPathFile, "utf8").trim();
56719
- if (!existsSync14(join20(root, "dist", "server.js")))
56880
+ if (!existsSync15(join20(root, "dist", "server.js")))
56720
56881
  throw new Error(`${root} has no dist/server.js (run \`eminiar install\`)`);
56721
56882
  return root;
56722
56883
  })
@@ -56758,7 +56919,7 @@ function runDoctor() {
56758
56919
  checks.push(
56759
56920
  check2("embedding model", () => {
56760
56921
  const dir = paths().models;
56761
- return existsSync14(dir) ? `${dir} (downloaded lazily on first hybrid search)` : "not present";
56922
+ return existsSync15(dir) ? `${dir} (downloaded lazily on first hybrid search)` : "not present";
56762
56923
  })
56763
56924
  );
56764
56925
  return checks;
@@ -56783,18 +56944,18 @@ init_esm_shims();
56783
56944
  init_paths();
56784
56945
  import {
56785
56946
  copyFileSync,
56786
- existsSync as existsSync15,
56947
+ existsSync as existsSync16,
56787
56948
  mkdirSync as mkdirSync6,
56788
56949
  readdirSync as readdirSync5,
56789
56950
  readFileSync as readFileSync15,
56790
56951
  writeFileSync as writeFileSync6
56791
56952
  } from "fs";
56792
56953
  import { homedir as homedir3 } from "os";
56793
- import { dirname as dirname9, join as join21 } from "path";
56954
+ import { dirname as dirname10, join as join21 } from "path";
56794
56955
  var claudeDir = () => process.env.CLAUDE_CONFIG_DIR || join21(homedir3(), ".claude");
56795
56956
  var pluginsDir = () => join21(claudeDir(), "plugins");
56796
56957
  function readJson3(file3) {
56797
- if (!existsSync15(file3)) return {};
56958
+ if (!existsSync16(file3)) return {};
56798
56959
  try {
56799
56960
  return JSON.parse(readFileSync15(file3, "utf8"));
56800
56961
  } catch (err) {
@@ -56937,7 +57098,7 @@ init_esm_shims();
56937
57098
  // src/sandbox/file.ts
56938
57099
  init_esm_shims();
56939
57100
  import { realpathSync as realpathSync2 } from "fs";
56940
- import { isAbsolute, relative as relative8, resolve as resolve7 } from "path";
57101
+ import { isAbsolute, relative as relative9, resolve as resolve7 } from "path";
56941
57102
  function confinePath(root, target, rules) {
56942
57103
  const abs = resolve7(root, target);
56943
57104
  let real;
@@ -56946,7 +57107,7 @@ function confinePath(root, target, rules) {
56946
57107
  } catch {
56947
57108
  throw new Error(`file not found: ${target}`);
56948
57109
  }
56949
- const rel = relative8(root, real);
57110
+ const rel = relative9(root, real);
56950
57111
  const inside = rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
56951
57112
  if (inside) return real;
56952
57113
  if (rules.allow.some((r) => matchRead(r, real))) return real;
@@ -57303,7 +57464,7 @@ init_esm_shims();
57303
57464
 
57304
57465
  // src/code/symbols.ts
57305
57466
  init_esm_shims();
57306
- import { existsSync as existsSync16, readFileSync as readFileSync17 } from "fs";
57467
+ import { existsSync as existsSync17, readFileSync as readFileSync17 } from "fs";
57307
57468
  import { join as join23 } from "path";
57308
57469
 
57309
57470
  // src/code/namepath.ts
@@ -57374,7 +57535,7 @@ function children(db, parent, depth = 1) {
57374
57535
  function symbolBody(db, root, n) {
57375
57536
  if (!n.path || !n.start_line || !n.end_line) return void 0;
57376
57537
  const abs = join23(root, n.path);
57377
- if (existsSync16(abs)) {
57538
+ if (existsSync17(abs)) {
57378
57539
  try {
57379
57540
  return readFileSync17(abs, "utf8").split("\n").slice(n.start_line - 1, n.end_line).join("\n");
57380
57541
  } catch {
@@ -58386,13 +58547,13 @@ function mergeByTool(rows) {
58386
58547
  // src/tools/em_symbols.ts
58387
58548
  init_esm_shims();
58388
58549
  init_backend();
58389
- function fence(body, budget, docId) {
58550
+ function fence(body, budget, docId2) {
58390
58551
  const cut = body.length > budget;
58391
58552
  const shown = cut ? body.slice(0, budget) : body;
58392
58553
  return `\`\`\`
58393
58554
  ${shown}
58394
58555
  \`\`\`${cut ? `
58395
- \u2026 ${body.length - budget} more chars (raise max_tokens${docId ? ` or em_search {document_ids:[${docId}]}` : ""})` : ""}`;
58556
+ \u2026 ${body.length - budget} more chars (raise max_tokens${docId2 ? ` or em_search {document_ids:[${docId2}]}` : ""})` : ""}`;
58396
58557
  }
58397
58558
  function referrerLabel(db, id, nodes) {
58398
58559
  const n = nodes.get(id) ?? db.graphGetNode(id);