gitnexus 1.4.5 → 1.4.7

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.
Files changed (49) hide show
  1. package/dist/cli/eval-server.js +13 -5
  2. package/dist/cli/index.js +0 -0
  3. package/dist/cli/tool.d.ts +3 -2
  4. package/dist/cli/tool.js +48 -13
  5. package/dist/core/graph/types.d.ts +2 -2
  6. package/dist/core/ingestion/call-processor.d.ts +7 -2
  7. package/dist/core/ingestion/call-processor.js +308 -235
  8. package/dist/core/ingestion/call-routing.d.ts +17 -2
  9. package/dist/core/ingestion/call-routing.js +21 -0
  10. package/dist/core/ingestion/parsing-processor.d.ts +2 -1
  11. package/dist/core/ingestion/parsing-processor.js +37 -8
  12. package/dist/core/ingestion/pipeline.js +5 -1
  13. package/dist/core/ingestion/symbol-table.d.ts +19 -3
  14. package/dist/core/ingestion/symbol-table.js +41 -2
  15. package/dist/core/ingestion/tree-sitter-queries.d.ts +12 -12
  16. package/dist/core/ingestion/tree-sitter-queries.js +200 -0
  17. package/dist/core/ingestion/type-env.js +126 -18
  18. package/dist/core/ingestion/type-extractors/c-cpp.js +28 -3
  19. package/dist/core/ingestion/type-extractors/csharp.js +61 -7
  20. package/dist/core/ingestion/type-extractors/go.js +86 -10
  21. package/dist/core/ingestion/type-extractors/jvm.js +122 -23
  22. package/dist/core/ingestion/type-extractors/php.js +172 -7
  23. package/dist/core/ingestion/type-extractors/python.js +107 -21
  24. package/dist/core/ingestion/type-extractors/ruby.js +18 -3
  25. package/dist/core/ingestion/type-extractors/rust.js +61 -14
  26. package/dist/core/ingestion/type-extractors/shared.d.ts +13 -0
  27. package/dist/core/ingestion/type-extractors/shared.js +243 -4
  28. package/dist/core/ingestion/type-extractors/types.d.ts +57 -12
  29. package/dist/core/ingestion/type-extractors/typescript.js +52 -8
  30. package/dist/core/ingestion/utils.d.ts +25 -0
  31. package/dist/core/ingestion/utils.js +160 -1
  32. package/dist/core/ingestion/workers/parse-worker.d.ts +23 -7
  33. package/dist/core/ingestion/workers/parse-worker.js +73 -28
  34. package/dist/core/lbug/lbug-adapter.d.ts +2 -0
  35. package/dist/core/lbug/lbug-adapter.js +2 -0
  36. package/dist/core/lbug/schema.d.ts +1 -1
  37. package/dist/core/lbug/schema.js +1 -1
  38. package/dist/mcp/core/lbug-adapter.d.ts +22 -0
  39. package/dist/mcp/core/lbug-adapter.js +167 -23
  40. package/dist/mcp/local/local-backend.d.ts +1 -0
  41. package/dist/mcp/local/local-backend.js +25 -3
  42. package/dist/mcp/resources.js +11 -0
  43. package/dist/mcp/server.js +26 -4
  44. package/dist/mcp/tools.js +15 -5
  45. package/hooks/claude/gitnexus-hook.cjs +0 -0
  46. package/hooks/claude/pre-tool-use.sh +0 -0
  47. package/hooks/claude/session-start.sh +0 -0
  48. package/package.json +6 -5
  49. package/scripts/patch-tree-sitter-swift.cjs +0 -0
@@ -24,6 +24,7 @@
24
24
  * POST /shutdown — Graceful shutdown.
25
25
  */
26
26
  import http from 'http';
27
+ import { writeSync } from 'node:fs';
27
28
  import { LocalBackend } from '../mcp/local/local-backend.js';
28
29
  // ─── Text Formatters ──────────────────────────────────────────────────
29
30
  // Convert structured JSON results into compact, LLM-friendly text.
@@ -121,8 +122,10 @@ export function formatContextResult(result) {
121
122
  return lines.join('\n').trim();
122
123
  }
123
124
  export function formatImpactResult(result) {
124
- if (result.error)
125
- return `Error: ${result.error}`;
125
+ if (result.error) {
126
+ const suggestion = result.suggestion ? `\nSuggestion: ${result.suggestion}` : '';
127
+ return `Error: ${result.error}${suggestion}`;
128
+ }
126
129
  const target = result.target;
127
130
  const direction = result.direction;
128
131
  const byDepth = result.byDepth || {};
@@ -132,7 +135,11 @@ export function formatImpactResult(result) {
132
135
  }
133
136
  const lines = [];
134
137
  const dirLabel = direction === 'upstream' ? 'depends on this (will break if changed)' : 'this depends on';
135
- lines.push(`Blast radius for ${target?.kind || ''} ${target?.name} (${direction}): ${total} symbol(s) ${dirLabel}\n`);
138
+ lines.push(`Blast radius for ${target?.kind || ''} ${target?.name} (${direction}): ${total} symbol(s) ${dirLabel}`);
139
+ if (result.partial) {
140
+ lines.push('⚠️ Partial results — graph traversal was interrupted. Deeper impacts may exist.');
141
+ }
142
+ lines.push('');
136
143
  const depthLabels = {
137
144
  1: 'WILL BREAK (direct)',
138
145
  2: 'LIKELY AFFECTED (indirect)',
@@ -346,10 +353,11 @@ export async function evalServerCommand(options) {
346
353
  console.error(` Auto-shutdown after ${idleTimeoutSec}s idle`);
347
354
  }
348
355
  try {
349
- process.stdout.write(`GITNEXUS_EVAL_SERVER_READY:${port}\n`);
356
+ // Use fd 1 directly — LadybugDB captures process.stdout (#324)
357
+ writeSync(1, `GITNEXUS_EVAL_SERVER_READY:${port}\n`);
350
358
  }
351
359
  catch {
352
- // stdout may not be available
360
+ // stdout may not be available (e.g., broken pipe)
353
361
  }
354
362
  });
355
363
  resetIdleTimer();
package/dist/cli/index.js CHANGED
File without changes
@@ -10,8 +10,9 @@
10
10
  * gitnexus impact --target "AuthService" --direction upstream
11
11
  * gitnexus cypher "MATCH (n:Function) RETURN n.name LIMIT 10"
12
12
  *
13
- * Note: Output goes to stderr because LadybugDB's native module captures stdout
14
- * at the OS level during init. This is consistent with augment.ts.
13
+ * Note: Output goes to stdout via fs.writeSync(fd 1), bypassing LadybugDB's
14
+ * native module which captures the Node.js process.stdout stream during init.
15
+ * See the output() function for details (#324).
15
16
  */
16
17
  export declare function queryCommand(queryText: string, options?: {
17
18
  repo?: string;
package/dist/cli/tool.js CHANGED
@@ -10,9 +10,11 @@
10
10
  * gitnexus impact --target "AuthService" --direction upstream
11
11
  * gitnexus cypher "MATCH (n:Function) RETURN n.name LIMIT 10"
12
12
  *
13
- * Note: Output goes to stderr because LadybugDB's native module captures stdout
14
- * at the OS level during init. This is consistent with augment.ts.
13
+ * Note: Output goes to stdout via fs.writeSync(fd 1), bypassing LadybugDB's
14
+ * native module which captures the Node.js process.stdout stream during init.
15
+ * See the output() function for details (#324).
15
16
  */
17
+ import { writeSync } from 'node:fs';
16
18
  import { LocalBackend } from '../mcp/local/local-backend.js';
17
19
  let _backend = null;
18
20
  async function getBackend() {
@@ -26,10 +28,30 @@ async function getBackend() {
26
28
  }
27
29
  return _backend;
28
30
  }
31
+ /**
32
+ * Write tool output to stdout using low-level fd write.
33
+ *
34
+ * LadybugDB's native module captures Node.js process.stdout during init,
35
+ * but the underlying OS file descriptor 1 (stdout) remains intact.
36
+ * By using fs.writeSync(1, ...) we bypass the Node.js stream layer
37
+ * and write directly to the real stdout fd (#324).
38
+ *
39
+ * Falls back to stderr if the fd write fails (e.g., broken pipe).
40
+ */
29
41
  function output(data) {
30
42
  const text = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
31
- // stderr because LadybugDB captures stdout at OS level
32
- process.stderr.write(text + '\n');
43
+ try {
44
+ writeSync(1, text + '\n');
45
+ }
46
+ catch (err) {
47
+ if (err?.code === 'EPIPE') {
48
+ // Consumer closed the pipe (e.g., `gitnexus cypher ... | head -1`)
49
+ // Exit cleanly per Unix convention
50
+ process.exit(0);
51
+ }
52
+ // Fallback: stderr (previous behavior, works on all platforms)
53
+ process.stderr.write(text + '\n');
54
+ }
33
55
  }
34
56
  export async function queryCommand(queryText, options) {
35
57
  if (!queryText?.trim()) {
@@ -67,15 +89,28 @@ export async function impactCommand(target, options) {
67
89
  console.error('Usage: gitnexus impact <symbol_name> [--direction upstream|downstream]');
68
90
  process.exit(1);
69
91
  }
70
- const backend = await getBackend();
71
- const result = await backend.callTool('impact', {
72
- target,
73
- direction: options?.direction || 'upstream',
74
- maxDepth: options?.depth ? parseInt(options.depth) : undefined,
75
- includeTests: options?.includeTests ?? false,
76
- repo: options?.repo,
77
- });
78
- output(result);
92
+ try {
93
+ const backend = await getBackend();
94
+ const result = await backend.callTool('impact', {
95
+ target,
96
+ direction: options?.direction || 'upstream',
97
+ maxDepth: options?.depth ? parseInt(options.depth, 10) : undefined,
98
+ includeTests: options?.includeTests ?? false,
99
+ repo: options?.repo,
100
+ });
101
+ output(result);
102
+ }
103
+ catch (err) {
104
+ // Belt-and-suspenders: catch infrastructure failures (getBackend, callTool transport)
105
+ // The backend's impact() already returns structured errors for graph query failures
106
+ output({
107
+ error: (err instanceof Error ? err.message : String(err)) || 'Impact analysis failed unexpectedly',
108
+ target: { name: target },
109
+ direction: options?.direction || 'upstream',
110
+ suggestion: 'Try reducing --depth or using gitnexus context <symbol> as a fallback',
111
+ });
112
+ process.exit(1);
113
+ }
79
114
  }
80
115
  export async function cypherCommand(query, options) {
81
116
  if (!query?.trim()) {
@@ -25,7 +25,7 @@ export type NodeProperties = {
25
25
  parameterCount?: number;
26
26
  returnType?: string;
27
27
  };
28
- export type RelationshipType = 'CONTAINS' | 'CALLS' | 'INHERITS' | 'OVERRIDES' | 'IMPORTS' | 'USES' | 'DEFINES' | 'DECORATES' | 'IMPLEMENTS' | 'EXTENDS' | 'HAS_METHOD' | 'MEMBER_OF' | 'STEP_IN_PROCESS';
28
+ export type RelationshipType = 'CONTAINS' | 'CALLS' | 'INHERITS' | 'OVERRIDES' | 'IMPORTS' | 'USES' | 'DEFINES' | 'DECORATES' | 'IMPLEMENTS' | 'EXTENDS' | 'HAS_METHOD' | 'HAS_PROPERTY' | 'ACCESSES' | 'MEMBER_OF' | 'STEP_IN_PROCESS';
29
29
  export interface GraphNode {
30
30
  id: string;
31
31
  label: NodeLabel;
@@ -38,7 +38,7 @@ export interface GraphRelationship {
38
38
  type: RelationshipType;
39
39
  /** Confidence score 0-1 (1.0 = certain, lower = uncertain resolution) */
40
40
  confidence: number;
41
- /** Resolution reason: 'import-resolved', 'same-file', 'fuzzy-global', or empty for non-CALLS */
41
+ /** Semantics are edge-type-dependent: CALLS uses resolution tier, ACCESSES uses 'read'/'write', OVERRIDES uses MRO reason */
42
42
  reason: string;
43
43
  /** Step number for STEP_IN_PROCESS relationships (1-indexed) */
44
44
  step?: number;
@@ -1,17 +1,22 @@
1
1
  import { KnowledgeGraph } from '../graph/types.js';
2
2
  import { ASTCache } from './ast-cache.js';
3
3
  import type { ResolutionContext } from './resolution-context.js';
4
- import type { ExtractedCall, ExtractedHeritage, ExtractedRoute, FileConstructorBindings } from './workers/parse-worker.js';
4
+ import type { ExtractedCall, ExtractedAssignment, ExtractedHeritage, ExtractedRoute, FileConstructorBindings } from './workers/parse-worker.js';
5
5
  export declare const processCalls: (graph: KnowledgeGraph, files: {
6
6
  path: string;
7
7
  content: string;
8
8
  }[], astCache: ASTCache, ctx: ResolutionContext, onProgress?: (current: number, total: number) => void) => Promise<ExtractedHeritage[]>;
9
- export declare const extractReturnTypeName: (raw: string, depth?: number) => string | undefined;
10
9
  /**
11
10
  * Fast path: resolve pre-extracted call sites from workers.
12
11
  * No AST parsing — workers already extracted calledName + sourceId.
13
12
  */
14
13
  export declare const processCallsFromExtracted: (graph: KnowledgeGraph, extractedCalls: ExtractedCall[], ctx: ResolutionContext, onProgress?: (current: number, total: number) => void, constructorBindings?: FileConstructorBindings[]) => Promise<void>;
14
+ /**
15
+ * Resolve pre-extracted field write assignments to ACCESSES {reason: 'write'} edges.
16
+ * Accepts optional constructorBindings for return-type-aware receiver inference,
17
+ * mirroring processCallsFromExtracted's verified binding lookup.
18
+ */
19
+ export declare const processAssignmentsFromExtracted: (graph: KnowledgeGraph, assignments: ExtractedAssignment[], ctx: ResolutionContext, constructorBindings?: FileConstructorBindings[]) => void;
15
20
  /**
16
21
  * Resolve pre-extracted Laravel routes to CALLS edges from route files to controller methods.
17
22
  */