gitnexus 1.6.4-rc.11 → 1.6.4-rc.13

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/cli/setup.js CHANGED
@@ -512,13 +512,13 @@ async function installCursorSkills(result) {
512
512
  }
513
513
  }
514
514
  /**
515
- * Install global OpenCode skills to ~/.config/opencode/skill/gitnexus/
515
+ * Install global OpenCode skills to ~/.config/opencode/skills/gitnexus/
516
516
  */
517
517
  async function installOpenCodeSkills(result) {
518
518
  const opencodeDir = path.join(os.homedir(), '.config', 'opencode');
519
519
  if (!(await dirExists(opencodeDir)))
520
520
  return;
521
- const skillsDir = path.join(opencodeDir, 'skill');
521
+ const skillsDir = path.join(opencodeDir, 'skills');
522
522
  try {
523
523
  const installed = await installSkillsTo(skillsDir);
524
524
  if (installed.length > 0) {
@@ -58,6 +58,31 @@ const BUILT_INS = new Set([
58
58
  'sum',
59
59
  'abs',
60
60
  ]);
61
+ function pythonDescriptionExtractor(nodeLabel, _nodeName, captureMap) {
62
+ if (nodeLabel !== 'Function' && nodeLabel !== 'Method')
63
+ return undefined;
64
+ const functionNode = captureMap['definition.function'] ?? captureMap['definition.method'];
65
+ if (functionNode === undefined)
66
+ return undefined;
67
+ return extractPythonDocstring(functionNode);
68
+ }
69
+ function extractPythonDocstring(functionNode) {
70
+ const body = functionNode.childForFieldName('body');
71
+ const firstStatement = body?.namedChild(0);
72
+ if (firstStatement?.type !== 'expression_statement')
73
+ return undefined;
74
+ const literal = firstStatement.namedChild(0);
75
+ if (literal?.type !== 'string')
76
+ return undefined;
77
+ return normalizePythonStringLiteral(literal.text);
78
+ }
79
+ function normalizePythonStringLiteral(text) {
80
+ const match = text.match(/^[rRuUbBfF]*("""|'''|"|')([\s\S]*)\1$/);
81
+ const raw = match?.[2]?.trim();
82
+ if (!raw)
83
+ return undefined;
84
+ return raw.replace(/\s+/g, ' ');
85
+ }
61
86
  export const pythonProvider = defineLanguage({
62
87
  id: SupportedLanguages.Python,
63
88
  extensions: ['.py'],
@@ -74,6 +99,7 @@ export const pythonProvider = defineLanguage({
74
99
  variableExtractor: createVariableExtractor(pythonVariableConfig),
75
100
  classExtractor: createClassExtractor(pythonClassConfig),
76
101
  heritageExtractor: createHeritageExtractor(SupportedLanguages.Python),
102
+ descriptionExtractor: pythonDescriptionExtractor,
77
103
  builtInNames: BUILT_INS,
78
104
  labelOverride: pythonFunctionDefinitionLabel,
79
105
  // ── RFC #909 Ring 3: scope-based resolution hooks (RFC §5) ──────────
@@ -84,12 +84,15 @@ export const processesPhase = {
84
84
  }
85
85
  list.push(url);
86
86
  }
87
- const toolsByFile = new Map();
87
+ const toolsByHandlerId = new Map();
88
+ const toolsWithoutHandlerByFile = new Map();
88
89
  for (const td of toolDefs) {
89
- let list = toolsByFile.get(td.filePath);
90
+ const key = td.handlerNodeId ?? td.filePath;
91
+ const targetMap = td.handlerNodeId ? toolsByHandlerId : toolsWithoutHandlerByFile;
92
+ let list = targetMap.get(key);
90
93
  if (!list) {
91
94
  list = [];
92
- toolsByFile.set(td.filePath, list);
95
+ targetMap.set(key, list);
93
96
  }
94
97
  list.push(td.name);
95
98
  }
@@ -118,7 +121,9 @@ export const processesPhase = {
118
121
  linked++;
119
122
  }
120
123
  }
121
- const toolNames = toolsByFile.get(entryFile);
124
+ const exactToolNames = toolsByHandlerId.get(proc.entryPointId);
125
+ const fallbackToolNames = toolsWithoutHandlerByFile.get(entryFile);
126
+ const toolNames = exactToolNames ?? fallbackToolNames;
122
127
  if (toolNames) {
123
128
  for (const toolName of toolNames) {
124
129
  const toolNodeId = generateId('Tool', toolName);
@@ -13,6 +13,7 @@ export interface ToolDef {
13
13
  name: string;
14
14
  filePath: string;
15
15
  description: string;
16
+ handlerNodeId?: string;
16
17
  }
17
18
  export interface ToolsOutput {
18
19
  toolDefs: ToolDef[];
@@ -23,7 +23,13 @@ export const toolsPhase = {
23
23
  if (seenToolNames.has(td.toolName))
24
24
  continue;
25
25
  seenToolNames.add(td.toolName);
26
- toolDefs.push({ name: td.toolName, filePath: td.filePath, description: td.description });
26
+ const handlerNodeId = td.handlerNodeId && ctx.graph.getNode(td.handlerNodeId) ? td.handlerNodeId : undefined;
27
+ toolDefs.push({
28
+ name: td.toolName,
29
+ filePath: td.filePath,
30
+ description: td.description,
31
+ ...(handlerNodeId !== undefined ? { handlerNodeId } : {}),
32
+ });
27
33
  }
28
34
  // TS tool definition arrays — require inputSchema nearby
29
35
  const toolCandidatePaths = allPaths.filter((p) => (p.endsWith('.ts') || p.endsWith('.js')) &&
@@ -60,10 +66,10 @@ export const toolsPhase = {
60
66
  label: 'Tool',
61
67
  properties: { name: td.name, filePath: td.filePath, description: td.description },
62
68
  });
63
- const handlerFileId = generateId('File', td.filePath);
69
+ const handlerId = td.handlerNodeId ?? generateId('File', td.filePath);
64
70
  ctx.graph.addRelationship({
65
- id: generateId('HANDLES_TOOL', `${handlerFileId}->${toolNodeId}`),
66
- sourceId: handlerFileId,
71
+ id: generateId('HANDLES_TOOL', `${handlerId}->${toolNodeId}`),
72
+ sourceId: handlerId,
67
73
  targetId: toolNodeId,
68
74
  type: 'HANDLES_TOOL',
69
75
  confidence: 1.0,
@@ -117,6 +117,7 @@ export interface ExtractedToolDef {
117
117
  toolName: string;
118
118
  description: string;
119
119
  lineNumber: number;
120
+ handlerNodeId?: string;
120
121
  }
121
122
  export interface ExtractedORMQuery {
122
123
  filePath: string;
@@ -1668,8 +1668,9 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
1668
1668
  result.toolDefs.push({
1669
1669
  filePath: file.path,
1670
1670
  toolName: nodeName,
1671
- description: dec.arg || '',
1671
+ description: (dec.arg || description || '').slice(0, 200),
1672
1672
  lineNumber: definitionNode.startPosition.row + lineOffset,
1673
+ handlerNodeId: nodeId,
1673
1674
  });
1674
1675
  }
1675
1676
  fileDecorators.delete(checkLine);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.4-rc.11",
3
+ "version": "1.6.4-rc.13",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",