engramx 0.2.0 → 0.2.1

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.
@@ -315,7 +315,13 @@ function truncateGraphemeSafe(s, max) {
315
315
 
316
316
  // src/graph/query.ts
317
317
  var MISTAKE_SCORE_BOOST = 2.5;
318
+ var KEYWORD_SCORE_DOWNWEIGHT = 0.5;
318
319
  var MAX_MISTAKE_LABEL_CHARS = 500;
320
+ function isHiddenKeyword(node) {
321
+ if (node.kind !== "concept") return false;
322
+ const meta = node.metadata;
323
+ return meta?.subkind === "keyword";
324
+ }
319
325
  var CHARS_PER_TOKEN = 4;
320
326
  function scoreNodes(store, terms) {
321
327
  const allNodes = store.getAllNodes();
@@ -330,6 +336,7 @@ function scoreNodes(store, terms) {
330
336
  }
331
337
  if (score > 0) {
332
338
  if (node.kind === "mistake") score *= MISTAKE_SCORE_BOOST;
339
+ if (isHiddenKeyword(node)) score *= KEYWORD_SCORE_DOWNWEIGHT;
333
340
  scored.push({ score, node });
334
341
  }
335
342
  }
@@ -346,6 +353,12 @@ function queryGraph(store, question, options = {}) {
346
353
  for (const n of startNodes) store.incrementQueryCount(n.id);
347
354
  const visited = new Set(startNodes.map((n) => n.id));
348
355
  const collectedEdges = [];
356
+ const shouldSkipEdgeFrom = (currentNodeId, edge) => {
357
+ if (edge.relation !== "triggered_by") return false;
358
+ const currentNode = store.getNode(currentNodeId);
359
+ if (!currentNode) return false;
360
+ return !isHiddenKeyword(currentNode);
361
+ };
349
362
  if (mode === "bfs") {
350
363
  let frontier = new Set(startNodes.map((n) => n.id));
351
364
  for (let d = 0; d < depth; d++) {
@@ -353,6 +366,7 @@ function queryGraph(store, question, options = {}) {
353
366
  for (const nid of frontier) {
354
367
  const neighbors = store.getNeighbors(nid);
355
368
  for (const { node, edge } of neighbors) {
369
+ if (shouldSkipEdgeFrom(nid, edge)) continue;
356
370
  if (!visited.has(node.id)) {
357
371
  nextFrontier.add(node.id);
358
372
  collectedEdges.push(edge);
@@ -369,6 +383,7 @@ function queryGraph(store, question, options = {}) {
369
383
  if (d > depth) continue;
370
384
  const neighbors = store.getNeighbors(id);
371
385
  for (const { node, edge } of neighbors) {
386
+ if (shouldSkipEdgeFrom(id, edge)) continue;
372
387
  if (!visited.has(node.id)) {
373
388
  visited.add(node.id);
374
389
  stack.push({ id: node.id, d: d + 1 });
@@ -446,7 +461,12 @@ function renderSubgraph(nodes, edges, tokenBudget) {
446
461
  const charBudget = tokenBudget * CHARS_PER_TOKEN;
447
462
  const lines = [];
448
463
  const mistakes2 = nodes.filter((n) => n.kind === "mistake");
449
- const nonMistakes = nodes.filter((n) => n.kind !== "mistake");
464
+ const visible = nodes.filter(
465
+ (n) => n.kind !== "mistake" && !isHiddenKeyword(n)
466
+ );
467
+ const hiddenKeywordIds = new Set(
468
+ nodes.filter(isHiddenKeyword).map((n) => n.id)
469
+ );
450
470
  if (mistakes2.length > 0) {
451
471
  lines.push("\u26A0\uFE0F PAST MISTAKES (relevant to your query):");
452
472
  for (const m of mistakes2) {
@@ -461,7 +481,7 @@ function renderSubgraph(nodes, edges, tokenBudget) {
461
481
  degreeMap.set(e.source, (degreeMap.get(e.source) ?? 0) + 1);
462
482
  degreeMap.set(e.target, (degreeMap.get(e.target) ?? 0) + 1);
463
483
  }
464
- const sorted = [...nonMistakes].sort(
484
+ const sorted = [...visible].sort(
465
485
  (a, b) => (degreeMap.get(b.id) ?? 0) - (degreeMap.get(a.id) ?? 0)
466
486
  );
467
487
  for (const n of sorted) {
@@ -469,7 +489,18 @@ function renderSubgraph(nodes, edges, tokenBudget) {
469
489
  `NODE ${n.label} [${n.kind}] src=${n.sourceFile} ${n.sourceLocation ?? ""}`
470
490
  );
471
491
  }
492
+ const skillConceptIds = new Set(
493
+ nodes.filter(
494
+ (n) => n.kind === "concept" && n.metadata?.subkind === "skill"
495
+ ).map((n) => n.id)
496
+ );
472
497
  for (const e of edges) {
498
+ if (hiddenKeywordIds.has(e.source) || hiddenKeywordIds.has(e.target)) {
499
+ continue;
500
+ }
501
+ if (e.relation === "similar_to" && skillConceptIds.has(e.source) && skillConceptIds.has(e.target)) {
502
+ continue;
503
+ }
473
504
  const srcNode = nodes.find((n) => n.id === e.source);
474
505
  const tgtNode = nodes.find((n) => n.id === e.target);
475
506
  if (srcNode && tgtNode) {
@@ -310,7 +310,7 @@ function writeToFile(filePath, summary) {
310
310
  writeFileSync2(filePath, newContent);
311
311
  }
312
312
  async function autogen(projectRoot, target, task) {
313
- const { getStore } = await import("./core-H72MM256.js");
313
+ const { getStore } = await import("./core-HWOM7GSU.js");
314
314
  const store = await getStore(projectRoot);
315
315
  try {
316
316
  let view = VIEWS.general;
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  install,
5
5
  status,
6
6
  uninstall
7
- } from "./chunk-QKCPFSVU.js";
7
+ } from "./chunk-YQ3FPGPC.js";
8
8
  import {
9
9
  benchmark,
10
10
  godNodes,
@@ -14,13 +14,13 @@ import {
14
14
  path,
15
15
  query,
16
16
  stats
17
- } from "./chunk-D53DRZZL.js";
17
+ } from "./chunk-22ADJYQ5.js";
18
18
 
19
19
  // src/cli.ts
20
20
  import { Command } from "commander";
21
21
  import chalk from "chalk";
22
22
  var program = new Command();
23
- program.name("engram").description("AI coding memory that learns from every session").version("0.2.0");
23
+ program.name("engram").description("AI coding memory that learns from every session").version("0.2.1");
24
24
  program.command("init").description("Scan codebase and build knowledge graph (zero LLM cost)").argument("[path]", "Project directory", ".").option(
25
25
  "--with-skills [dir]",
26
26
  "Also index Claude Code skills from ~/.claude/skills/ or a given path"
@@ -9,7 +9,7 @@ import {
9
9
  path,
10
10
  query,
11
11
  stats
12
- } from "./chunk-D53DRZZL.js";
12
+ } from "./chunk-22ADJYQ5.js";
13
13
  export {
14
14
  benchmark,
15
15
  getDbPath,
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  generateSummary,
5
5
  install,
6
6
  uninstall
7
- } from "./chunk-QKCPFSVU.js";
7
+ } from "./chunk-YQ3FPGPC.js";
8
8
  import {
9
9
  GraphStore,
10
10
  SUPPORTED_EXTENSIONS,
@@ -23,7 +23,7 @@ import {
23
23
  sliceGraphemeSafe,
24
24
  stats,
25
25
  truncateGraphemeSafe
26
- } from "./chunk-D53DRZZL.js";
26
+ } from "./chunk-22ADJYQ5.js";
27
27
  export {
28
28
  GraphStore,
29
29
  SUPPORTED_EXTENSIONS,
package/dist/serve.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  query,
9
9
  stats,
10
10
  truncateGraphemeSafe
11
- } from "./chunk-D53DRZZL.js";
11
+ } from "./chunk-22ADJYQ5.js";
12
12
 
13
13
  // src/serve.ts
14
14
  function clampInt(value, defaultValue, min, max) {
@@ -174,7 +174,7 @@ async function handleRequest(req) {
174
174
  result: {
175
175
  protocolVersion: "2024-11-05",
176
176
  capabilities: { tools: {} },
177
- serverInfo: { name: "engram", version: "0.2.0" }
177
+ serverInfo: { name: "engram", version: "0.2.1" }
178
178
  }
179
179
  };
180
180
  case "tools/list":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "engramx",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "AI coding memory that learns from every session — persistent, structural, universal",
5
5
  "type": "module",
6
6
  "bin": {