code-kg 0.1.1 → 0.1.2

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/ui.js CHANGED
@@ -572,14 +572,22 @@ function renderUiHtml() {
572
572
  extremeEdges: ${graph_performance_1.GRAPH_PERFORMANCE_THRESHOLDS.extremeEdges}
573
573
  };
574
574
  const SEARCH_DEBOUNCE_MS = 150;
575
+ const RENDER_BUDGETS = {
576
+ normal: { nodes: Number.POSITIVE_INFINITY, edges: Number.POSITIVE_INFINITY },
577
+ degraded: { nodes: 18000, edges: 40000 },
578
+ extreme: { nodes: 9000, edges: 16000 }
579
+ };
580
+ const STATIC_LAYOUT_SPACING = 8.4;
575
581
 
576
582
  const state = {
577
583
  view: 'fileDeps',
578
584
  graph: null,
579
- graphData: { nodes: [], links: [] },
585
+ graphData: { nodes: [], links: [], nodeById: new Map() },
580
586
  graphMeta: null,
581
587
  perfMode: 'normal',
582
588
  lastAppliedPerfMode: '',
589
+ defaultChargeForce: null,
590
+ staticLayoutApplied: false,
583
591
  selectedNodeId: '',
584
592
  searchTerm: '',
585
593
  searchTimer: null,
@@ -693,6 +701,116 @@ function renderUiHtml() {
693
701
  return 1;
694
702
  }
695
703
 
704
+ function stableHash(value) {
705
+ const text = String(value || '');
706
+ let hash = 2166136261;
707
+ for (let index = 0; index < text.length; index += 1) {
708
+ hash ^= text.charCodeAt(index);
709
+ hash = Math.imul(hash, 16777619);
710
+ }
711
+ return hash >>> 0;
712
+ }
713
+
714
+ function shouldRenderByBudget(id, limit, total) {
715
+ if (!Number.isFinite(limit) || limit >= total) {
716
+ return true;
717
+ }
718
+ if (limit <= 0 || total <= 0) {
719
+ return false;
720
+ }
721
+ const sampleRatio = limit / total;
722
+ const threshold = Math.max(1, Math.floor(sampleRatio * 1000000));
723
+ return (stableHash(id) % 1000000) < threshold;
724
+ }
725
+
726
+ function applyStaticLayout() {
727
+ if (state.staticLayoutApplied || !state.graphData || !Array.isArray(state.graphData.nodes)) {
728
+ return;
729
+ }
730
+ const nodes = state.graphData.nodes;
731
+ for (let index = 0; index < nodes.length; index += 1) {
732
+ const node = nodes[index];
733
+ const radius = Math.sqrt(index + 1) * STATIC_LAYOUT_SPACING;
734
+ const angle = index * 2.399963229728653;
735
+ const x = Math.cos(angle) * radius;
736
+ const y = Math.sin(angle) * radius;
737
+ const z = ((index % 27) - 13) * (STATIC_LAYOUT_SPACING * 0.28);
738
+ node.x = x;
739
+ node.y = y;
740
+ node.z = z;
741
+ node.fx = x;
742
+ node.fy = y;
743
+ node.fz = z;
744
+ }
745
+ state.staticLayoutApplied = true;
746
+ }
747
+
748
+ function clearStaticLayout() {
749
+ if (!state.staticLayoutApplied || !state.graphData || !Array.isArray(state.graphData.nodes)) {
750
+ return;
751
+ }
752
+ for (const node of state.graphData.nodes) {
753
+ delete node.fx;
754
+ delete node.fy;
755
+ delete node.fz;
756
+ }
757
+ state.staticLayoutApplied = false;
758
+ }
759
+
760
+ function applyRenderBudget() {
761
+ if (!state.graphData || !Array.isArray(state.graphData.nodes) || !Array.isArray(state.graphData.links)) {
762
+ return;
763
+ }
764
+
765
+ const mode = state.perfMode;
766
+ const budget = RENDER_BUDGETS[mode] || RENDER_BUDGETS.normal;
767
+ const totalNodes = state.graphData.nodes.length;
768
+ const totalEdges = state.graphData.links.length;
769
+ const nodeById = state.graphData.nodeById instanceof Map ? state.graphData.nodeById : new Map();
770
+
771
+ for (const node of state.graphData.nodes) {
772
+ const pinned = Boolean(node.__selected || node.__matched);
773
+ const sampled = shouldRenderByBudget(node.id, budget.nodes, totalNodes);
774
+ node.__renderVisible = pinned || sampled;
775
+ }
776
+
777
+ for (const link of state.graphData.links) {
778
+ const sourceId = String(link.__sourceId || '');
779
+ const targetId = String(link.__targetId || '');
780
+ const sourceNode = nodeById.get(sourceId);
781
+ const targetNode = nodeById.get(targetId);
782
+ const forceVisible = Boolean(
783
+ link.__highlight ||
784
+ sourceId === state.selectedNodeId ||
785
+ targetId === state.selectedNodeId
786
+ );
787
+
788
+ if (forceVisible) {
789
+ if (sourceNode) {
790
+ sourceNode.__renderVisible = true;
791
+ }
792
+ if (targetNode) {
793
+ targetNode.__renderVisible = true;
794
+ }
795
+ }
796
+ }
797
+
798
+ for (const link of state.graphData.links) {
799
+ const sourceId = String(link.__sourceId || '');
800
+ const targetId = String(link.__targetId || '');
801
+ const sourceNode = nodeById.get(sourceId);
802
+ const targetNode = nodeById.get(targetId);
803
+ const forceVisible = Boolean(
804
+ link.__highlight ||
805
+ sourceId === state.selectedNodeId ||
806
+ targetId === state.selectedNodeId
807
+ );
808
+ const sampled = shouldRenderByBudget(link.id || (sourceId + ':' + targetId), budget.edges, totalEdges);
809
+ const endpointsVisible = Boolean(sourceNode && targetNode && sourceNode.__renderVisible && targetNode.__renderVisible);
810
+ link.__renderVisible = forceVisible || (sampled && endpointsVisible);
811
+ }
812
+ }
813
+
696
814
  function setStatus(text, tone) {
697
815
  els.status.textContent = text;
698
816
  if (tone === 'error') {
@@ -737,18 +855,47 @@ function renderUiHtml() {
737
855
 
738
856
  const mode = state.perfMode;
739
857
  const graph = state.graph;
858
+ if (mode === 'extreme') {
859
+ applyStaticLayout();
860
+ } else {
861
+ clearStaticLayout();
862
+ }
863
+
864
+ if (typeof graph.numDimensions === 'function') {
865
+ graph.numDimensions(mode === 'normal' ? 3 : 2);
866
+ }
740
867
  if (typeof graph.cooldownTicks === 'function') {
741
- graph.cooldownTicks(mode === 'normal' ? 240 : mode === 'degraded' ? 110 : 70);
868
+ graph.cooldownTicks(mode === 'normal' ? 240 : mode === 'degraded' ? 40 : 2);
742
869
  }
743
870
  if (typeof graph.cooldownTime === 'function') {
744
- graph.cooldownTime(mode === 'normal' ? 15000 : mode === 'degraded' ? 5500 : 2600);
871
+ graph.cooldownTime(mode === 'normal' ? 15000 : mode === 'degraded' ? 1800 : 100);
872
+ }
873
+ if (typeof graph.warmupTicks === 'function') {
874
+ graph.warmupTicks(mode === 'normal' ? 90 : mode === 'degraded' ? 20 : 0);
745
875
  }
746
876
  if (typeof graph.d3VelocityDecay === 'function') {
747
- graph.d3VelocityDecay(mode === 'normal' ? 0.25 : mode === 'degraded' ? 0.34 : 0.44);
877
+ graph.d3VelocityDecay(mode === 'normal' ? 0.25 : mode === 'degraded' ? 0.52 : 0.9);
878
+ }
879
+ if (typeof graph.nodeResolution === 'function') {
880
+ graph.nodeResolution(mode === 'normal' ? 8 : mode === 'degraded' ? 5 : 3);
748
881
  }
882
+ if (typeof graph.linkResolution === 'function') {
883
+ graph.linkResolution(mode === 'normal' ? 6 : mode === 'degraded' ? 2 : 1);
884
+ }
885
+
886
+ graph.linkOpacity(mode === 'normal' ? 0.66 : mode === 'degraded' ? 0.38 : 0.26);
887
+ graph.nodeRelSize(mode === 'normal' ? 3.2 : mode === 'degraded' ? 2.45 : 2.1);
749
888
 
750
- graph.linkOpacity(mode === 'normal' ? 0.66 : mode === 'degraded' ? 0.48 : 0.36);
751
- graph.nodeRelSize(mode === 'normal' ? 3.2 : mode === 'degraded' ? 2.7 : 2.3);
889
+ if (typeof graph.d3Force === 'function') {
890
+ const currentCharge = graph.d3Force('charge');
891
+ if (mode === 'normal') {
892
+ if (state.defaultChargeForce && currentCharge == null) {
893
+ graph.d3Force('charge', state.defaultChargeForce);
894
+ }
895
+ } else if (currentCharge != null) {
896
+ graph.d3Force('charge', null);
897
+ }
898
+ }
752
899
 
753
900
  try {
754
901
  const renderer = typeof graph.renderer === 'function' ? graph.renderer() : null;
@@ -814,7 +961,8 @@ function renderUiHtml() {
814
961
  __targetId: target,
815
962
  type: edge.type,
816
963
  __color: colorForEdge(edge.type),
817
- __highlight: false
964
+ __highlight: false,
965
+ __renderVisible: true
818
966
  };
819
967
  }
820
968
 
@@ -836,11 +984,17 @@ function renderUiHtml() {
836
984
  __color: colorForNode(type),
837
985
  __searchText: (String(name) + ' ' + String(path) + ' ' + String(type)).toLowerCase(),
838
986
  __matched: false,
839
- __selected: false
987
+ __selected: false,
988
+ __renderVisible: true
840
989
  };
841
990
  }
842
991
 
843
- return { nodes, links };
992
+ const nodeById = new Map();
993
+ for (const node of nodes) {
994
+ nodeById.set(node.id, node);
995
+ }
996
+
997
+ return { nodes, links, nodeById };
844
998
  }
845
999
 
846
1000
  function ensureGraph() {
@@ -858,6 +1012,7 @@ function renderUiHtml() {
858
1012
  .backgroundColor('#05060f')
859
1013
  .showNavInfo(false)
860
1014
  .nodeOpacity(0.95)
1015
+ .nodeVisibility((node) => node.__renderVisible !== false)
861
1016
  .nodeLabel((node) => {
862
1017
  if (state.perfMode === 'extreme' && !node.__selected) {
863
1018
  return '';
@@ -892,8 +1047,9 @@ function renderUiHtml() {
892
1047
  .linkWidth((link) => {
893
1048
  const base = state.perfMode === 'normal' ? 0.75 : state.perfMode === 'degraded' ? 0.46 : 0.34;
894
1049
  const highlight = state.perfMode === 'normal' ? 2.2 : state.perfMode === 'degraded' ? 1.35 : 1.05;
895
- return link.__highlight ? highlight : base;
896
- })
1050
+ return link.__highlight ? highlight : base;
1051
+ })
1052
+ .linkVisibility((link) => link.__renderVisible !== false)
897
1053
  .linkDirectionalParticles((link) => {
898
1054
  if (state.perfMode !== 'normal') {
899
1055
  return 0;
@@ -916,6 +1072,9 @@ function renderUiHtml() {
916
1072
  });
917
1073
 
918
1074
  state.graph = graph;
1075
+ if (typeof graph.d3Force === 'function') {
1076
+ state.defaultChargeForce = graph.d3Force('charge');
1077
+ }
919
1078
  applyGraphQualitySettings();
920
1079
  state.lastAppliedPerfMode = state.perfMode;
921
1080
 
@@ -968,9 +1127,24 @@ function renderUiHtml() {
968
1127
  state.lastAppliedPerfMode = state.perfMode;
969
1128
  clearSearchTimer();
970
1129
  }
1130
+ applyRenderBudget();
971
1131
 
1132
+ let visibleNodes = 0;
1133
+ for (const node of state.graphData.nodes) {
1134
+ if (node.__renderVisible !== false) {
1135
+ visibleNodes += 1;
1136
+ }
1137
+ }
1138
+ let visibleEdges = 0;
1139
+ for (const link of state.graphData.links) {
1140
+ if (link.__renderVisible !== false) {
1141
+ visibleEdges += 1;
1142
+ }
1143
+ }
972
1144
  els.graphCounts.textContent =
973
- 'nodes: ' + nodeCount + ' | edges: ' + edgeCount + ' | mode: ' + String(state.perfMode).toUpperCase();
1145
+ 'nodes: ' + visibleNodes + '/' + nodeCount +
1146
+ ' | edges: ' + visibleEdges + '/' + edgeCount +
1147
+ ' | mode: ' + String(state.perfMode).toUpperCase();
974
1148
 
975
1149
  if (nodeCount === 0) {
976
1150
  els.graphEmpty.style.display = 'grid';
@@ -1040,6 +1214,7 @@ function renderUiHtml() {
1040
1214
  const view = state.view === 'all' ? 'all' : state.view;
1041
1215
  const data = await readEnvelope('/api/graph?view=' + encodeURIComponent(view));
1042
1216
  state.graphData = toGraphData(data);
1217
+ state.staticLayoutApplied = false;
1043
1218
  state.graphMeta = normalizeGraphMeta(
1044
1219
  data && data.meta ? data.meta : null,
1045
1220
  state.graphData.nodes.length,
@@ -1239,6 +1414,7 @@ function renderUiHtml() {
1239
1414
  '&direction=both'
1240
1415
  );
1241
1416
  state.graphData = toGraphData(data);
1417
+ state.staticLayoutApplied = false;
1242
1418
  state.graphMeta = normalizeGraphMeta(
1243
1419
  data && data.meta ? data.meta : null,
1244
1420
  state.graphData.nodes.length,
@@ -1 +1 @@
1
- {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/server/ui.ts"],"names":[],"mappings":";;AAEA,oCAi2CC;AAn2CD,2DAAmE;AAEnE,SAAgB,YAAY;IAC1B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAmjBkB,gDAA4B,CAAC,aAAa;2BAC1C,gDAA4B,CAAC,aAAa;0BAC3C,gDAA4B,CAAC,YAAY;0BACzC,gDAA4B,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAyyB3D,CAAC;AACT,CAAC"}
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/server/ui.ts"],"names":[],"mappings":";;AAEA,oCAihDC;AAnhDD,2DAAmE;AAEnE,SAAgB,YAAY;IAC1B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAmjBkB,gDAA4B,CAAC,aAAa;2BAC1C,gDAA4B,CAAC,aAAa;0BAC3C,gDAA4B,CAAC,YAAY;0BACzC,gDAA4B,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAy9B3D,CAAC;AACT,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-kg",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Local code knowledge graph CLI with interactive visualization and deterministic analysis APIs",
5
5
  "license": "MIT",
6
6
  "keywords": [