gitnexus 1.2.7 → 1.2.8

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.
@@ -5,98 +5,98 @@
5
5
  * Templates use {{PLACEHOLDER}} substitution.
6
6
  */
7
7
  // ─── Grouping Prompt ──────────────────────────────────────────────────
8
- export const GROUPING_SYSTEM_PROMPT = `You are a documentation architect. Given a list of source files with their exported symbols, group them into logical documentation modules.
9
-
10
- Rules:
11
- - Each module should represent a cohesive feature, layer, or domain
12
- - Every file must appear in exactly one module
13
- - Module names should be human-readable (e.g. "Authentication", "Database Layer", "API Routes")
14
- - Aim for 5-15 modules for a typical project. Fewer for small projects, more for large ones
15
- - Group by functionality, not by file type or directory structure alone
8
+ export const GROUPING_SYSTEM_PROMPT = `You are a documentation architect. Given a list of source files with their exported symbols, group them into logical documentation modules.
9
+
10
+ Rules:
11
+ - Each module should represent a cohesive feature, layer, or domain
12
+ - Every file must appear in exactly one module
13
+ - Module names should be human-readable (e.g. "Authentication", "Database Layer", "API Routes")
14
+ - Aim for 5-15 modules for a typical project. Fewer for small projects, more for large ones
15
+ - Group by functionality, not by file type or directory structure alone
16
16
  - Do NOT create modules for tests, configs, or non-source files`;
17
- export const GROUPING_USER_PROMPT = `Group these source files into documentation modules.
18
-
19
- **Files and their exports:**
20
- {{FILE_LIST}}
21
-
22
- **Directory structure:**
23
- {{DIRECTORY_TREE}}
24
-
25
- Respond with ONLY a JSON object mapping module names to file path arrays. No markdown, no explanation.
26
- Example format:
27
- {
28
- "Authentication": ["src/auth/login.ts", "src/auth/session.ts"],
29
- "Database": ["src/db/connection.ts", "src/db/models.ts"]
17
+ export const GROUPING_USER_PROMPT = `Group these source files into documentation modules.
18
+
19
+ **Files and their exports:**
20
+ {{FILE_LIST}}
21
+
22
+ **Directory structure:**
23
+ {{DIRECTORY_TREE}}
24
+
25
+ Respond with ONLY a JSON object mapping module names to file path arrays. No markdown, no explanation.
26
+ Example format:
27
+ {
28
+ "Authentication": ["src/auth/login.ts", "src/auth/session.ts"],
29
+ "Database": ["src/db/connection.ts", "src/db/models.ts"]
30
30
  }`;
31
31
  // ─── Leaf Module Prompt ───────────────────────────────────────────────
32
- export const MODULE_SYSTEM_PROMPT = `You are a technical documentation writer. Write clear, developer-focused documentation for a code module.
33
-
34
- Rules:
35
- - Reference actual function names, class names, and code patterns — do NOT invent APIs
36
- - Use the call graph and execution flow data for accuracy, but do NOT mechanically list every edge
37
- - Include Mermaid diagrams only when they genuinely help understanding. Keep them small (5-10 nodes max)
38
- - Structure the document however makes sense for this module — there is no mandatory format
32
+ export const MODULE_SYSTEM_PROMPT = `You are a technical documentation writer. Write clear, developer-focused documentation for a code module.
33
+
34
+ Rules:
35
+ - Reference actual function names, class names, and code patterns — do NOT invent APIs
36
+ - Use the call graph and execution flow data for accuracy, but do NOT mechanically list every edge
37
+ - Include Mermaid diagrams only when they genuinely help understanding. Keep them small (5-10 nodes max)
38
+ - Structure the document however makes sense for this module — there is no mandatory format
39
39
  - Write for a developer who needs to understand and contribute to this code`;
40
- export const MODULE_USER_PROMPT = `Write documentation for the **{{MODULE_NAME}}** module.
41
-
42
- ## Source Code
43
-
44
- {{SOURCE_CODE}}
45
-
46
- ## Call Graph & Execution Flows (reference for accuracy)
47
-
48
- Internal calls: {{INTRA_CALLS}}
49
- Outgoing calls: {{OUTGOING_CALLS}}
50
- Incoming calls: {{INCOMING_CALLS}}
51
- Execution flows: {{PROCESSES}}
52
-
53
- ---
54
-
40
+ export const MODULE_USER_PROMPT = `Write documentation for the **{{MODULE_NAME}}** module.
41
+
42
+ ## Source Code
43
+
44
+ {{SOURCE_CODE}}
45
+
46
+ ## Call Graph & Execution Flows (reference for accuracy)
47
+
48
+ Internal calls: {{INTRA_CALLS}}
49
+ Outgoing calls: {{OUTGOING_CALLS}}
50
+ Incoming calls: {{INCOMING_CALLS}}
51
+ Execution flows: {{PROCESSES}}
52
+
53
+ ---
54
+
55
55
  Write comprehensive documentation for this module. Cover its purpose, how it works, its key components, and how it connects to the rest of the codebase. Use whatever structure best fits this module — you decide the sections and headings. Include a Mermaid diagram only if it genuinely clarifies the architecture.`;
56
56
  // ─── Parent Module Prompt ─────────────────────────────────────────────
57
- export const PARENT_SYSTEM_PROMPT = `You are a technical documentation writer. Write a summary page for a module that contains sub-modules. Synthesize the children's documentation — do not re-read source code.
58
-
59
- Rules:
60
- - Reference actual components from the child modules
61
- - Focus on how the sub-modules work together, not repeating their individual docs
62
- - Keep it concise — the reader can click through to child pages for detail
57
+ export const PARENT_SYSTEM_PROMPT = `You are a technical documentation writer. Write a summary page for a module that contains sub-modules. Synthesize the children's documentation — do not re-read source code.
58
+
59
+ Rules:
60
+ - Reference actual components from the child modules
61
+ - Focus on how the sub-modules work together, not repeating their individual docs
62
+ - Keep it concise — the reader can click through to child pages for detail
63
63
  - Include a Mermaid diagram only if it genuinely clarifies how the sub-modules relate`;
64
- export const PARENT_USER_PROMPT = `Write documentation for the **{{MODULE_NAME}}** module, which contains these sub-modules:
65
-
66
- {{CHILDREN_DOCS}}
67
-
68
- Cross-module calls: {{CROSS_MODULE_CALLS}}
69
- Shared execution flows: {{CROSS_PROCESSES}}
70
-
71
- ---
72
-
64
+ export const PARENT_USER_PROMPT = `Write documentation for the **{{MODULE_NAME}}** module, which contains these sub-modules:
65
+
66
+ {{CHILDREN_DOCS}}
67
+
68
+ Cross-module calls: {{CROSS_MODULE_CALLS}}
69
+ Shared execution flows: {{CROSS_PROCESSES}}
70
+
71
+ ---
72
+
73
73
  Write a concise overview of this module group. Explain its purpose, how the sub-modules fit together, and the key workflows that span them. Link to sub-module pages (e.g. \`[Sub-module Name](sub-module-slug.md)\`) rather than repeating their content. Use whatever structure fits best.`;
74
74
  // ─── Overview Prompt ──────────────────────────────────────────────────
75
- export const OVERVIEW_SYSTEM_PROMPT = `You are a technical documentation writer. Write the top-level overview page for a repository wiki. This is the first page a new developer sees.
76
-
77
- Rules:
78
- - Be clear and welcoming — this is the entry point to the entire codebase
79
- - Reference actual module names so readers can navigate to their docs
80
- - Include a high-level Mermaid architecture diagram showing only the most important modules and their relationships (max 10 nodes). A new dev should grasp it in 10 seconds
81
- - Do NOT create module index tables or list every module with descriptions — just link to module pages naturally within the text
75
+ export const OVERVIEW_SYSTEM_PROMPT = `You are a technical documentation writer. Write the top-level overview page for a repository wiki. This is the first page a new developer sees.
76
+
77
+ Rules:
78
+ - Be clear and welcoming — this is the entry point to the entire codebase
79
+ - Reference actual module names so readers can navigate to their docs
80
+ - Include a high-level Mermaid architecture diagram showing only the most important modules and their relationships (max 10 nodes). A new dev should grasp it in 10 seconds
81
+ - Do NOT create module index tables or list every module with descriptions — just link to module pages naturally within the text
82
82
  - Use the inter-module edges and execution flow data for accuracy, but do NOT dump them raw`;
83
- export const OVERVIEW_USER_PROMPT = `Write the overview page for this repository's wiki.
84
-
85
- ## Project Info
86
-
87
- {{PROJECT_INFO}}
88
-
89
- ## Module Summaries
90
-
91
- {{MODULE_SUMMARIES}}
92
-
93
- ## Reference Data (for accuracy — do not reproduce verbatim)
94
-
95
- Inter-module call edges: {{MODULE_EDGES}}
96
- Key system flows: {{TOP_PROCESSES}}
97
-
98
- ---
99
-
83
+ export const OVERVIEW_USER_PROMPT = `Write the overview page for this repository's wiki.
84
+
85
+ ## Project Info
86
+
87
+ {{PROJECT_INFO}}
88
+
89
+ ## Module Summaries
90
+
91
+ {{MODULE_SUMMARIES}}
92
+
93
+ ## Reference Data (for accuracy — do not reproduce verbatim)
94
+
95
+ Inter-module call edges: {{MODULE_EDGES}}
96
+ Key system flows: {{TOP_PROCESSES}}
97
+
98
+ ---
99
+
100
100
  Write a clear overview of this project: what it does, how it's architected, and the key end-to-end flows. Include a simple Mermaid architecture diagram (max 10 nodes, big-picture only). Link to module pages (e.g. \`[Module Name](module-slug.md)\`) naturally in the text rather than listing them in a table. If project config was provided, include brief setup instructions. Structure the page however reads best.`;
101
101
  // ─── Template Substitution Helper ─────────────────────────────────────
102
102
  /**
@@ -320,19 +320,19 @@ export class LocalBackend {
320
320
  // Find processes this symbol participates in
321
321
  let processRows = [];
322
322
  try {
323
- processRows = await executeQuery(repo.id, `
324
- MATCH (n {id: '${escaped}'})-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process)
325
- RETURN p.id AS pid, p.label AS label, p.heuristicLabel AS heuristicLabel, p.processType AS processType, p.stepCount AS stepCount, r.step AS step
323
+ processRows = await executeQuery(repo.id, `
324
+ MATCH (n {id: '${escaped}'})-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process)
325
+ RETURN p.id AS pid, p.label AS label, p.heuristicLabel AS heuristicLabel, p.processType AS processType, p.stepCount AS stepCount, r.step AS step
326
326
  `);
327
327
  }
328
328
  catch { /* symbol might not be in any process */ }
329
329
  // Get cluster cohesion as internal ranking signal (never exposed)
330
330
  let cohesion = 0;
331
331
  try {
332
- const cohesionRows = await executeQuery(repo.id, `
333
- MATCH (n {id: '${escaped}'})-[:CodeRelation {type: 'MEMBER_OF'}]->(c:Community)
334
- RETURN c.cohesion AS cohesion
335
- LIMIT 1
332
+ const cohesionRows = await executeQuery(repo.id, `
333
+ MATCH (n {id: '${escaped}'})-[:CodeRelation {type: 'MEMBER_OF'}]->(c:Community)
334
+ RETURN c.cohesion AS cohesion
335
+ LIMIT 1
336
336
  `);
337
337
  if (cohesionRows.length > 0) {
338
338
  cohesion = (cohesionRows[0].cohesion ?? cohesionRows[0][0]) || 0;
@@ -343,9 +343,9 @@ export class LocalBackend {
343
343
  let content;
344
344
  if (includeContent) {
345
345
  try {
346
- const contentRows = await executeQuery(repo.id, `
347
- MATCH (n {id: '${escaped}'})
348
- RETURN n.content AS content
346
+ const contentRows = await executeQuery(repo.id, `
347
+ MATCH (n {id: '${escaped}'})
348
+ RETURN n.content AS content
349
349
  `);
350
350
  if (contentRows.length > 0) {
351
351
  content = contentRows[0].content ?? contentRows[0][0];
@@ -450,11 +450,11 @@ export class LocalBackend {
450
450
  for (const bm25Result of bm25Results) {
451
451
  const fullPath = bm25Result.filePath;
452
452
  try {
453
- const symbolQuery = `
454
- MATCH (n)
455
- WHERE n.filePath = '${fullPath.replace(/'/g, "''")}'
456
- RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine
457
- LIMIT 3
453
+ const symbolQuery = `
454
+ MATCH (n)
455
+ WHERE n.filePath = '${fullPath.replace(/'/g, "''")}'
456
+ RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine
457
+ LIMIT 3
458
458
  `;
459
459
  const symbols = await executeQuery(repo.id, symbolQuery);
460
460
  if (symbols.length > 0) {
@@ -500,14 +500,14 @@ export class LocalBackend {
500
500
  const queryVec = await embedQuery(query);
501
501
  const dims = getEmbeddingDims();
502
502
  const queryVecStr = `[${queryVec.join(',')}]`;
503
- const vectorQuery = `
504
- CALL QUERY_VECTOR_INDEX('CodeEmbedding', 'code_embedding_idx',
505
- CAST(${queryVecStr} AS FLOAT[${dims}]), ${limit})
506
- YIELD node AS emb, distance
507
- WITH emb, distance
508
- WHERE distance < 0.6
509
- RETURN emb.nodeId AS nodeId, distance
510
- ORDER BY distance
503
+ const vectorQuery = `
504
+ CALL QUERY_VECTOR_INDEX('CodeEmbedding', 'code_embedding_idx',
505
+ CAST(${queryVecStr} AS FLOAT[${dims}]), ${limit})
506
+ YIELD node AS emb, distance
507
+ WITH emb, distance
508
+ WHERE distance < 0.6
509
+ RETURN emb.nodeId AS nodeId, distance
510
+ ORDER BY distance
511
511
  `;
512
512
  const embResults = await executeQuery(repo.id, vectorQuery);
513
513
  if (embResults.length === 0)
@@ -612,11 +612,11 @@ export class LocalBackend {
612
612
  try {
613
613
  // Fetch more raw communities than the display limit so aggregation has enough data
614
614
  const rawLimit = Math.max(limit * 5, 200);
615
- const clusters = await executeQuery(repo.id, `
616
- MATCH (c:Community)
617
- RETURN c.id AS id, c.label AS label, c.heuristicLabel AS heuristicLabel, c.cohesion AS cohesion, c.symbolCount AS symbolCount
618
- ORDER BY c.symbolCount DESC
619
- LIMIT ${rawLimit}
615
+ const clusters = await executeQuery(repo.id, `
616
+ MATCH (c:Community)
617
+ RETURN c.id AS id, c.label AS label, c.heuristicLabel AS heuristicLabel, c.cohesion AS cohesion, c.symbolCount AS symbolCount
618
+ ORDER BY c.symbolCount DESC
619
+ LIMIT ${rawLimit}
620
620
  `);
621
621
  const rawClusters = clusters.map((c) => ({
622
622
  id: c.id || c[0],
@@ -633,11 +633,11 @@ export class LocalBackend {
633
633
  }
634
634
  if (params.showProcesses !== false) {
635
635
  try {
636
- const processes = await executeQuery(repo.id, `
637
- MATCH (p:Process)
638
- RETURN p.id AS id, p.label AS label, p.heuristicLabel AS heuristicLabel, p.processType AS processType, p.stepCount AS stepCount
639
- ORDER BY p.stepCount DESC
640
- LIMIT ${limit}
636
+ const processes = await executeQuery(repo.id, `
637
+ MATCH (p:Process)
638
+ RETURN p.id AS id, p.label AS label, p.heuristicLabel AS heuristicLabel, p.processType AS processType, p.stepCount AS stepCount
639
+ ORDER BY p.stepCount DESC
640
+ LIMIT ${limit}
641
641
  `);
642
642
  result.processes = processes.map((p) => ({
643
643
  id: p.id || p[0],
@@ -668,10 +668,10 @@ export class LocalBackend {
668
668
  let symbols;
669
669
  if (uid) {
670
670
  const escaped = uid.replace(/'/g, "''");
671
- symbols = await executeQuery(repo.id, `
672
- MATCH (n {id: '${escaped}'})
673
- RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine${include_content ? ', n.content AS content' : ''}
674
- LIMIT 1
671
+ symbols = await executeQuery(repo.id, `
672
+ MATCH (n {id: '${escaped}'})
673
+ RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine${include_content ? ', n.content AS content' : ''}
674
+ LIMIT 1
675
675
  `);
676
676
  }
677
677
  else {
@@ -688,10 +688,10 @@ export class LocalBackend {
688
688
  else {
689
689
  whereClause = `WHERE n.name = '${escaped}'`;
690
690
  }
691
- symbols = await executeQuery(repo.id, `
692
- MATCH (n) ${whereClause}
693
- RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine${include_content ? ', n.content AS content' : ''}
694
- LIMIT 10
691
+ symbols = await executeQuery(repo.id, `
692
+ MATCH (n) ${whereClause}
693
+ RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine${include_content ? ', n.content AS content' : ''}
694
+ LIMIT 10
695
695
  `);
696
696
  }
697
697
  if (symbols.length === 0) {
@@ -715,25 +715,25 @@ export class LocalBackend {
715
715
  const sym = symbols[0];
716
716
  const symId = (sym.id || sym[0]).replace(/'/g, "''");
717
717
  // Categorized incoming refs
718
- const incomingRows = await executeQuery(repo.id, `
719
- MATCH (caller)-[r:CodeRelation]->(n {id: '${symId}'})
720
- WHERE r.type IN ['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS']
721
- RETURN r.type AS relType, caller.id AS uid, caller.name AS name, caller.filePath AS filePath, labels(caller)[0] AS kind
722
- LIMIT 30
718
+ const incomingRows = await executeQuery(repo.id, `
719
+ MATCH (caller)-[r:CodeRelation]->(n {id: '${symId}'})
720
+ WHERE r.type IN ['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS']
721
+ RETURN r.type AS relType, caller.id AS uid, caller.name AS name, caller.filePath AS filePath, labels(caller)[0] AS kind
722
+ LIMIT 30
723
723
  `);
724
724
  // Categorized outgoing refs
725
- const outgoingRows = await executeQuery(repo.id, `
726
- MATCH (n {id: '${symId}'})-[r:CodeRelation]->(target)
727
- WHERE r.type IN ['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS']
728
- RETURN r.type AS relType, target.id AS uid, target.name AS name, target.filePath AS filePath, labels(target)[0] AS kind
729
- LIMIT 30
725
+ const outgoingRows = await executeQuery(repo.id, `
726
+ MATCH (n {id: '${symId}'})-[r:CodeRelation]->(target)
727
+ WHERE r.type IN ['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS']
728
+ RETURN r.type AS relType, target.id AS uid, target.name AS name, target.filePath AS filePath, labels(target)[0] AS kind
729
+ LIMIT 30
730
730
  `);
731
731
  // Process participation
732
732
  let processRows = [];
733
733
  try {
734
- processRows = await executeQuery(repo.id, `
735
- MATCH (n {id: '${symId}'})-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process)
736
- RETURN p.id AS pid, p.heuristicLabel AS label, r.step AS step, p.stepCount AS stepCount
734
+ processRows = await executeQuery(repo.id, `
735
+ MATCH (n {id: '${symId}'})-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process)
736
+ RETURN p.id AS pid, p.heuristicLabel AS label, r.step AS step, p.stepCount AS stepCount
737
737
  `);
738
738
  }
739
739
  catch { /* no process info */ }
@@ -787,10 +787,10 @@ export class LocalBackend {
787
787
  }
788
788
  if (type === 'cluster') {
789
789
  const escaped = name.replace(/'/g, "''");
790
- const clusterQuery = `
791
- MATCH (c:Community)
792
- WHERE c.label = '${escaped}' OR c.heuristicLabel = '${escaped}'
793
- RETURN c.id AS id, c.label AS label, c.heuristicLabel AS heuristicLabel, c.cohesion AS cohesion, c.symbolCount AS symbolCount
790
+ const clusterQuery = `
791
+ MATCH (c:Community)
792
+ WHERE c.label = '${escaped}' OR c.heuristicLabel = '${escaped}'
793
+ RETURN c.id AS id, c.label AS label, c.heuristicLabel AS heuristicLabel, c.cohesion AS cohesion, c.symbolCount AS symbolCount
794
794
  `;
795
795
  const clusters = await executeQuery(repo.id, clusterQuery);
796
796
  if (clusters.length === 0)
@@ -805,11 +805,11 @@ export class LocalBackend {
805
805
  totalSymbols += s;
806
806
  weightedCohesion += (c.cohesion || 0) * s;
807
807
  }
808
- const members = await executeQuery(repo.id, `
809
- MATCH (n)-[:CodeRelation {type: 'MEMBER_OF'}]->(c:Community)
810
- WHERE c.label = '${escaped}' OR c.heuristicLabel = '${escaped}'
811
- RETURN DISTINCT n.name AS name, labels(n)[0] AS type, n.filePath AS filePath
812
- LIMIT 30
808
+ const members = await executeQuery(repo.id, `
809
+ MATCH (n)-[:CodeRelation {type: 'MEMBER_OF'}]->(c:Community)
810
+ WHERE c.label = '${escaped}' OR c.heuristicLabel = '${escaped}'
811
+ RETURN DISTINCT n.name AS name, labels(n)[0] AS type, n.filePath AS filePath
812
+ LIMIT 30
813
813
  `);
814
814
  return {
815
815
  cluster: {
@@ -826,20 +826,20 @@ export class LocalBackend {
826
826
  };
827
827
  }
828
828
  if (type === 'process') {
829
- const processes = await executeQuery(repo.id, `
830
- MATCH (p:Process)
831
- WHERE p.label = '${name.replace(/'/g, "''")}' OR p.heuristicLabel = '${name.replace(/'/g, "''")}'
832
- RETURN p.id AS id, p.label AS label, p.heuristicLabel AS heuristicLabel, p.processType AS processType, p.stepCount AS stepCount
833
- LIMIT 1
829
+ const processes = await executeQuery(repo.id, `
830
+ MATCH (p:Process)
831
+ WHERE p.label = '${name.replace(/'/g, "''")}' OR p.heuristicLabel = '${name.replace(/'/g, "''")}'
832
+ RETURN p.id AS id, p.label AS label, p.heuristicLabel AS heuristicLabel, p.processType AS processType, p.stepCount AS stepCount
833
+ LIMIT 1
834
834
  `);
835
835
  if (processes.length === 0)
836
836
  return { error: `Process '${name}' not found` };
837
837
  const proc = processes[0];
838
838
  const procId = proc.id || proc[0];
839
- const steps = await executeQuery(repo.id, `
840
- MATCH (n)-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p {id: '${procId}'})
841
- RETURN n.name AS name, labels(n)[0] AS type, n.filePath AS filePath, r.step AS step
842
- ORDER BY r.step
839
+ const steps = await executeQuery(repo.id, `
840
+ MATCH (n)-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p {id: '${procId}'})
841
+ RETURN n.name AS name, labels(n)[0] AS type, n.filePath AS filePath, r.step AS step
842
+ ORDER BY r.step
843
843
  `);
844
844
  return {
845
845
  process: {
@@ -900,10 +900,10 @@ export class LocalBackend {
900
900
  for (const file of changedFiles) {
901
901
  const escaped = file.replace(/\\/g, '/').replace(/'/g, "''");
902
902
  try {
903
- const symbols = await executeQuery(repo.id, `
904
- MATCH (n) WHERE n.filePath CONTAINS '${escaped}'
905
- RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath
906
- LIMIT 20
903
+ const symbols = await executeQuery(repo.id, `
904
+ MATCH (n) WHERE n.filePath CONTAINS '${escaped}'
905
+ RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath
906
+ LIMIT 20
907
907
  `);
908
908
  for (const sym of symbols) {
909
909
  changedSymbols.push({
@@ -922,9 +922,9 @@ export class LocalBackend {
922
922
  for (const sym of changedSymbols) {
923
923
  const escaped = sym.id.replace(/'/g, "''");
924
924
  try {
925
- const procs = await executeQuery(repo.id, `
926
- MATCH (n {id: '${escaped}'})-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process)
927
- RETURN p.id AS pid, p.heuristicLabel AS label, p.processType AS processType, p.stepCount AS stepCount, r.step AS step
925
+ const procs = await executeQuery(repo.id, `
926
+ MATCH (n {id: '${escaped}'})-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process)
927
+ RETURN p.id AS pid, p.heuristicLabel AS label, p.processType AS processType, p.stepCount AS stepCount, r.step AS step
928
928
  `);
929
929
  for (const proc of procs) {
930
930
  const pid = proc.pid || proc[0];
@@ -1099,11 +1099,11 @@ export class LocalBackend {
1099
1099
  const minConfidence = params.minConfidence ?? 0;
1100
1100
  const relTypeFilter = relationTypes.map(t => `'${t}'`).join(', ');
1101
1101
  const confidenceFilter = minConfidence > 0 ? ` AND r.confidence >= ${minConfidence}` : '';
1102
- const targetQuery = `
1103
- MATCH (n)
1104
- WHERE n.name = '${target.replace(/'/g, "''")}'
1105
- RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath
1106
- LIMIT 1
1102
+ const targetQuery = `
1103
+ MATCH (n)
1104
+ WHERE n.name = '${target.replace(/'/g, "''")}'
1105
+ RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath
1106
+ LIMIT 1
1107
1107
  `;
1108
1108
  const targets = await executeQuery(repo.id, targetQuery);
1109
1109
  if (targets.length === 0)
@@ -1173,11 +1173,11 @@ export class LocalBackend {
1173
1173
  await this.ensureInitialized(repo.id);
1174
1174
  try {
1175
1175
  const rawLimit = Math.max(limit * 5, 200);
1176
- const clusters = await executeQuery(repo.id, `
1177
- MATCH (c:Community)
1178
- RETURN c.id AS id, c.label AS label, c.heuristicLabel AS heuristicLabel, c.cohesion AS cohesion, c.symbolCount AS symbolCount
1179
- ORDER BY c.symbolCount DESC
1180
- LIMIT ${rawLimit}
1176
+ const clusters = await executeQuery(repo.id, `
1177
+ MATCH (c:Community)
1178
+ RETURN c.id AS id, c.label AS label, c.heuristicLabel AS heuristicLabel, c.cohesion AS cohesion, c.symbolCount AS symbolCount
1179
+ ORDER BY c.symbolCount DESC
1180
+ LIMIT ${rawLimit}
1181
1181
  `);
1182
1182
  const rawClusters = clusters.map((c) => ({
1183
1183
  id: c.id || c[0],
@@ -1200,11 +1200,11 @@ export class LocalBackend {
1200
1200
  const repo = await this.resolveRepo(repoName);
1201
1201
  await this.ensureInitialized(repo.id);
1202
1202
  try {
1203
- const processes = await executeQuery(repo.id, `
1204
- MATCH (p:Process)
1205
- RETURN p.id AS id, p.label AS label, p.heuristicLabel AS heuristicLabel, p.processType AS processType, p.stepCount AS stepCount
1206
- ORDER BY p.stepCount DESC
1207
- LIMIT ${limit}
1203
+ const processes = await executeQuery(repo.id, `
1204
+ MATCH (p:Process)
1205
+ RETURN p.id AS id, p.label AS label, p.heuristicLabel AS heuristicLabel, p.processType AS processType, p.stepCount AS stepCount
1206
+ ORDER BY p.stepCount DESC
1207
+ LIMIT ${limit}
1208
1208
  `);
1209
1209
  return {
1210
1210
  processes: processes.map((p) => ({
@@ -1228,10 +1228,10 @@ export class LocalBackend {
1228
1228
  const repo = await this.resolveRepo(repoName);
1229
1229
  await this.ensureInitialized(repo.id);
1230
1230
  const escaped = name.replace(/'/g, "''");
1231
- const clusterQuery = `
1232
- MATCH (c:Community)
1233
- WHERE c.label = '${escaped}' OR c.heuristicLabel = '${escaped}'
1234
- RETURN c.id AS id, c.label AS label, c.heuristicLabel AS heuristicLabel, c.cohesion AS cohesion, c.symbolCount AS symbolCount
1231
+ const clusterQuery = `
1232
+ MATCH (c:Community)
1233
+ WHERE c.label = '${escaped}' OR c.heuristicLabel = '${escaped}'
1234
+ RETURN c.id AS id, c.label AS label, c.heuristicLabel AS heuristicLabel, c.cohesion AS cohesion, c.symbolCount AS symbolCount
1235
1235
  `;
1236
1236
  const clusters = await executeQuery(repo.id, clusterQuery);
1237
1237
  if (clusters.length === 0)
@@ -1246,11 +1246,11 @@ export class LocalBackend {
1246
1246
  totalSymbols += s;
1247
1247
  weightedCohesion += (c.cohesion || 0) * s;
1248
1248
  }
1249
- const members = await executeQuery(repo.id, `
1250
- MATCH (n)-[:CodeRelation {type: 'MEMBER_OF'}]->(c:Community)
1251
- WHERE c.label = '${escaped}' OR c.heuristicLabel = '${escaped}'
1252
- RETURN DISTINCT n.name AS name, labels(n)[0] AS type, n.filePath AS filePath
1253
- LIMIT 30
1249
+ const members = await executeQuery(repo.id, `
1250
+ MATCH (n)-[:CodeRelation {type: 'MEMBER_OF'}]->(c:Community)
1251
+ WHERE c.label = '${escaped}' OR c.heuristicLabel = '${escaped}'
1252
+ RETURN DISTINCT n.name AS name, labels(n)[0] AS type, n.filePath AS filePath
1253
+ LIMIT 30
1254
1254
  `);
1255
1255
  return {
1256
1256
  cluster: {
@@ -1274,20 +1274,20 @@ export class LocalBackend {
1274
1274
  const repo = await this.resolveRepo(repoName);
1275
1275
  await this.ensureInitialized(repo.id);
1276
1276
  const escaped = name.replace(/'/g, "''");
1277
- const processes = await executeQuery(repo.id, `
1278
- MATCH (p:Process)
1279
- WHERE p.label = '${escaped}' OR p.heuristicLabel = '${escaped}'
1280
- RETURN p.id AS id, p.label AS label, p.heuristicLabel AS heuristicLabel, p.processType AS processType, p.stepCount AS stepCount
1281
- LIMIT 1
1277
+ const processes = await executeQuery(repo.id, `
1278
+ MATCH (p:Process)
1279
+ WHERE p.label = '${escaped}' OR p.heuristicLabel = '${escaped}'
1280
+ RETURN p.id AS id, p.label AS label, p.heuristicLabel AS heuristicLabel, p.processType AS processType, p.stepCount AS stepCount
1281
+ LIMIT 1
1282
1282
  `);
1283
1283
  if (processes.length === 0)
1284
1284
  return { error: `Process '${name}' not found` };
1285
1285
  const proc = processes[0];
1286
1286
  const procId = proc.id || proc[0];
1287
- const steps = await executeQuery(repo.id, `
1288
- MATCH (n)-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p {id: '${procId}'})
1289
- RETURN n.name AS name, labels(n)[0] AS type, n.filePath AS filePath, r.step AS step
1290
- ORDER BY r.step
1287
+ const steps = await executeQuery(repo.id, `
1288
+ MATCH (n)-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p {id: '${procId}'})
1289
+ RETURN n.name AS name, labels(n)[0] AS type, n.filePath AS filePath, r.step AS step
1290
+ ORDER BY r.step
1291
1291
  `);
1292
1292
  return {
1293
1293
  process: {
@@ -256,48 +256,48 @@ async function getProcessesResource(backend, repoName) {
256
256
  * Schema resource — graph structure for Cypher queries
257
257
  */
258
258
  function getSchemaResource() {
259
- return `# GitNexus Graph Schema
260
-
261
- nodes:
262
- - File: Source code files
263
- - Folder: Directory containers
264
- - Function: Functions and arrow functions
265
- - Class: Class definitions
266
- - Interface: Interface/type definitions
267
- - Method: Class methods
268
- - CodeElement: Catch-all for other code elements
269
- - Community: Auto-detected functional area (Leiden algorithm)
270
- - Process: Execution flow trace
271
-
272
- additional_node_types: "Multi-language: Struct, Enum, Macro, Typedef, Union, Namespace, Trait, Impl, TypeAlias, Const, Static, Property, Record, Delegate, Annotation, Constructor, Template, Module (use backticks in queries: \`Struct\`, \`Enum\`, etc.)"
273
-
274
- relationships:
275
- - CONTAINS: File/Folder contains child
276
- - DEFINES: File defines a symbol
277
- - CALLS: Function/method invocation
278
- - IMPORTS: Module imports
279
- - EXTENDS: Class inheritance
280
- - IMPLEMENTS: Interface implementation
281
- - MEMBER_OF: Symbol belongs to community
282
- - STEP_IN_PROCESS: Symbol is step N in process
283
-
284
- relationship_table: "All relationships use a single CodeRelation table with a 'type' property. Properties: type (STRING), confidence (DOUBLE), reason (STRING), step (INT32)"
285
-
286
- example_queries:
287
- find_callers: |
288
- MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"})
289
- RETURN caller.name, caller.filePath
290
-
291
- find_community_members: |
292
- MATCH (s)-[:CodeRelation {type: 'MEMBER_OF'}]->(c:Community)
293
- WHERE c.heuristicLabel = "Auth"
294
- RETURN s.name, labels(s)[0] AS type
295
-
296
- trace_process: |
297
- MATCH (s)-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process)
298
- WHERE p.heuristicLabel = "LoginFlow"
299
- RETURN s.name, r.step
300
- ORDER BY r.step
259
+ return `# GitNexus Graph Schema
260
+
261
+ nodes:
262
+ - File: Source code files
263
+ - Folder: Directory containers
264
+ - Function: Functions and arrow functions
265
+ - Class: Class definitions
266
+ - Interface: Interface/type definitions
267
+ - Method: Class methods
268
+ - CodeElement: Catch-all for other code elements
269
+ - Community: Auto-detected functional area (Leiden algorithm)
270
+ - Process: Execution flow trace
271
+
272
+ additional_node_types: "Multi-language: Struct, Enum, Macro, Typedef, Union, Namespace, Trait, Impl, TypeAlias, Const, Static, Property, Record, Delegate, Annotation, Constructor, Template, Module (use backticks in queries: \`Struct\`, \`Enum\`, etc.)"
273
+
274
+ relationships:
275
+ - CONTAINS: File/Folder contains child
276
+ - DEFINES: File defines a symbol
277
+ - CALLS: Function/method invocation
278
+ - IMPORTS: Module imports
279
+ - EXTENDS: Class inheritance
280
+ - IMPLEMENTS: Interface implementation
281
+ - MEMBER_OF: Symbol belongs to community
282
+ - STEP_IN_PROCESS: Symbol is step N in process
283
+
284
+ relationship_table: "All relationships use a single CodeRelation table with a 'type' property. Properties: type (STRING), confidence (DOUBLE), reason (STRING), step (INT32)"
285
+
286
+ example_queries:
287
+ find_callers: |
288
+ MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"})
289
+ RETURN caller.name, caller.filePath
290
+
291
+ find_community_members: |
292
+ MATCH (s)-[:CodeRelation {type: 'MEMBER_OF'}]->(c:Community)
293
+ WHERE c.heuristicLabel = "Auth"
294
+ RETURN s.name, labels(s)[0] AS type
295
+
296
+ trace_process: |
297
+ MATCH (s)-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process)
298
+ WHERE p.heuristicLabel = "LoginFlow"
299
+ RETURN s.name, r.step
300
+ ORDER BY r.step
301
301
  `;
302
302
  }
303
303
  /**