pi-gitnexus 0.2.1 → 0.3.0

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/CHANGELOG.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  ## 0.3.0
4
4
 
5
+ - **Configurable command** — the gitnexus binary invocation is now configurable. Default is `gitnexus` on PATH. Use `/gitnexus config` to set a custom command (e.g. `npx gitnexus@latest`) via an input dialog; the value is persisted to `~/.pi/pi-gitnexus.json`. The `--gitnexus-cmd` CLI flag overrides the saved config for one-off runs. Nothing is ever installed automatically.
5
6
  - **TypeScript compatibility** — `tool_result` handler now uses inferred event types from the API overload instead of a manual annotation, fixing a compile error with `@mariozechner/pi-coding-agent` 0.54.x.
6
7
  - **Dependency updates** — `@mariozechner/pi-coding-agent` to 0.54.2, `@types/node` to 25.x.
7
8
 
package/README.md CHANGED
@@ -28,15 +28,18 @@ Five tools are also registered directly in pi — the agent can use them explici
28
28
 
29
29
  ## Requirements
30
30
 
31
- - [gitnexus](https://github.com/abhigyanpatwari/GitNexus) installed globally: `npm i -g gitnexus`
31
+ - [gitnexus](https://github.com/abhigyanpatwari/GitNexus) available as `gitnexus` on PATH (e.g. `npm i -g gitnexus`)
32
32
  - A GitNexus index in your project: run `/gitnexus analyze`
33
33
 
34
+ The extension never installs anything automatically. It assumes `gitnexus` is on PATH. If your setup differs, use `/gitnexus config` to set a custom command (e.g. `npx gitnexus@latest`).
35
+
34
36
  ## Getting started
35
37
 
36
- 1. Install gitnexus: `npm i -g gitnexus`
37
- 2. Open your project in pi
38
- 3. Run `/gitnexus analyze` to build the knowledge graph
39
- 4. Done file reads and searches are now enriched automatically
38
+ 1. Install the extension: `pi install npm:pi-gitnexus`
39
+ 2. Install gitnexus: `npm i -g gitnexus`
40
+ 3. Open your project in pi
41
+ 4. Run `/gitnexus analyze` to build the knowledge graph
42
+ 5. Done — file reads and searches are now enriched automatically
40
43
 
41
44
  ## What triggers augmentation
42
45
 
@@ -59,6 +62,7 @@ Each tool result augments up to 3 patterns in parallel. Patterns already augment
59
62
  | `/gitnexus` | Show index status and session enrichment count |
60
63
  | `/gitnexus analyze` | Build or rebuild the knowledge graph |
61
64
  | `/gitnexus on` / `/gitnexus off` | Enable/disable auto-augment (tools unaffected) |
65
+ | `/gitnexus config` | Set the gitnexus command (saved to `~/.pi/pi-gitnexus.json`) |
62
66
  | `/gitnexus <pattern>` | Manual graph lookup for a symbol or pattern |
63
67
  | `/gitnexus query <text>` | Search execution flows |
64
68
  | `/gitnexus context <name>` | 360° view of a symbol: callers, callees, processes |
@@ -97,6 +101,7 @@ This extension (pi-gitnexus) is MIT licensed. [GitNexus](https://github.com/abhi
97
101
 
98
102
  ## Notes
99
103
 
104
+ - The extension never runs `gitnexus analyze` automatically — indexing is always user-initiated via `/gitnexus analyze`.
100
105
  - The index is a static snapshot. Re-run `/gitnexus analyze` after significant code changes. The agent will suggest this when the index appears stale.
101
106
  - `gitnexus_detect_changes` is a lightweight alternative: pass `git diff HEAD` output to see affected flows without a full reindex.
102
107
  - `gitnexus_cypher` and `gitnexus_rename` are intentionally not exposed (raw graph access and automated multi-file rename).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gitnexus",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "GitNexus knowledge graph integration for pi — enriches searches with call chains, execution flows, and blast radius",
5
5
  "author": "tintinweb",
6
6
  "license": "MIT",
package/src/gitnexus.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { spawn } from 'child_process';
2
- import { resolve, sep, basename, extname } from 'path';
3
- import { existsSync } from 'fs';
2
+ import { resolve, sep, basename, extname, join } from 'path';
3
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
4
+ import { homedir } from 'os';
4
5
 
5
6
  /** Max output chars returned to the LLM. Prevents context flooding. JS strings are UTF-16 chars, not bytes. */
6
7
  export const MAX_OUTPUT_CHARS = 8 * 1024;
@@ -13,6 +14,35 @@ export const MAX_OUTPUT_CHARS = 8 * 1024;
13
14
  export let spawnEnv: NodeJS.ProcessEnv = process.env;
14
15
  export function updateSpawnEnv(env: NodeJS.ProcessEnv): void { spawnEnv = env; }
15
16
 
17
+ /**
18
+ * Resolved command prefix for invoking gitnexus.
19
+ * Set to ['gitnexus'] when the binary is on PATH, otherwise ['npx', '-y', 'gitnexus@latest'].
20
+ * Updated by setGitnexusCmd() during session_start probe.
21
+ */
22
+ export let gitnexusCmd: string[] = ['gitnexus'];
23
+ export function setGitnexusCmd(cmd: string[]): void { gitnexusCmd = cmd; }
24
+
25
+ const CONFIG_PATH = join(homedir(), '.pi', 'pi-gitnexus.json');
26
+
27
+ interface GitNexusConfig {
28
+ cmd?: string;
29
+ }
30
+
31
+ export function loadSavedConfig(): GitNexusConfig {
32
+ try {
33
+ return JSON.parse(readFileSync(CONFIG_PATH, 'utf8')) as GitNexusConfig;
34
+ } catch {
35
+ return {};
36
+ }
37
+ }
38
+
39
+ export function saveConfig(config: GitNexusConfig): void {
40
+ try {
41
+ mkdirSync(join(homedir(), '.pi'), { recursive: true });
42
+ writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n');
43
+ } catch { /* ignore write errors */ }
44
+ }
45
+
16
46
  /** Augment subprocess timeout in ms. Applied via setTimeout + proc.kill('SIGTERM') — spawn has no built-in timeout. */
17
47
  const AUGMENT_TIMEOUT = 8_000;
18
48
 
@@ -174,7 +204,8 @@ export async function runAugment(pattern: string, cwd: string): Promise<string>
174
204
  let output = '';
175
205
  let done = false;
176
206
 
177
- const proc = spawn('gitnexus', ['augment', pattern], {
207
+ const [bin, ...baseArgs] = gitnexusCmd;
208
+ const proc = spawn(bin, [...baseArgs, 'augment', pattern], {
178
209
  cwd,
179
210
  stdio: ['ignore', 'ignore', 'pipe'],
180
211
  env: spawnEnv,
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { spawn } from 'child_process';
2
2
  import type { ExtensionAPI, ExtensionContext } from '@mariozechner/pi-coding-agent';
3
- import { findGitNexusIndex, clearIndexCache, extractPattern, extractFilePatternsFromContent, runAugment, spawnEnv, updateSpawnEnv } from './gitnexus';
3
+ import { findGitNexusIndex, clearIndexCache, extractPattern, extractFilePatternsFromContent, runAugment, spawnEnv, updateSpawnEnv, gitnexusCmd, setGitnexusCmd, loadSavedConfig, saveConfig } from './gitnexus';
4
4
  import { mcpClient } from './mcp-client';
5
5
  import { registerTools } from './tools';
6
6
 
@@ -19,14 +19,20 @@ async function resolveShellPath(): Promise<void> {
19
19
  updateSpawnEnv({ ...process.env, PATH: path });
20
20
  }
21
21
 
22
- function probeGitNexusBinary(): Promise<boolean> {
22
+ function trySpawn(bin: string, args: string[]): Promise<boolean> {
23
23
  return new Promise((resolve_) => {
24
- const proc = spawn('gitnexus', ['--version'], { stdio: 'ignore', env: spawnEnv });
24
+ const proc = spawn(bin, args, { stdio: 'ignore', env: spawnEnv });
25
25
  proc.on('close', (code: number | null) => resolve_(code === 0));
26
26
  proc.on('error', () => resolve_(false));
27
27
  });
28
28
  }
29
29
 
30
+ /** Probe for gitnexus using the configured command. */
31
+ async function probeGitNexusBinary(): Promise<boolean> {
32
+ const [bin, ...args] = gitnexusCmd;
33
+ return trySpawn(bin, [...args, '--version']);
34
+ }
35
+
30
36
  /** Cached from session_start/session_switch — avoids re-probing on every /gitnexus status. */
31
37
  let binaryAvailable = false;
32
38
 
@@ -51,6 +57,12 @@ const augmentedCache = new Set<string>();
51
57
  export default function(pi: ExtensionAPI) {
52
58
  registerTools(pi);
53
59
 
60
+ pi.registerFlag('gitnexus-cmd', {
61
+ type: 'string',
62
+ default: 'gitnexus',
63
+ description: 'Command used to invoke gitnexus, e.g. "npx gitnexus@latest"',
64
+ });
65
+
54
66
  // Append a one-liner so the agent understands graph context in search results.
55
67
  pi.on('before_agent_start', async (event: { systemPrompt?: string }, ctx: ExtensionContext) => {
56
68
  if (!findGitNexusIndex(ctx.cwd)) return;
@@ -111,6 +123,12 @@ export default function(pi: ExtensionAPI) {
111
123
  sessionCwd = ctx.cwd;
112
124
  await resolveShellPath();
113
125
 
126
+ // Resolve command: default → saved config → CLI flag (highest precedence)
127
+ const saved = loadSavedConfig().cmd;
128
+ const flag = pi.getFlag('gitnexus-cmd') as string | undefined;
129
+ const cmdStr = flag ?? saved ?? 'gitnexus';
130
+ setGitnexusCmd(cmdStr.trim().split(/\s+/));
131
+
114
132
  binaryAvailable = await probeGitNexusBinary();
115
133
  if (!findGitNexusIndex(ctx.cwd)) return;
116
134
 
@@ -149,7 +167,8 @@ export default function(pi: ExtensionAPI) {
149
167
  }
150
168
  const out = await new Promise<string>((resolve_) => {
151
169
  let stdout = '';
152
- const proc = spawn('gitnexus', ['status'], {
170
+ const [bin, ...baseArgs] = gitnexusCmd;
171
+ const proc = spawn(bin, [...baseArgs, 'status'], {
153
172
  cwd: ctx.cwd,
154
173
  stdio: ['ignore', 'pipe', 'ignore'],
155
174
  env: spawnEnv,
@@ -174,6 +193,7 @@ export default function(pi: ExtensionAPI) {
174
193
  ' /gitnexus — show status\n' +
175
194
  ' /gitnexus analyze — index the codebase\n' +
176
195
  ' /gitnexus on|off — enable/disable auto-augment on searches\n' +
196
+ ' /gitnexus config — set the gitnexus command (saved to ~/.pi/pi-gitnexus.json)\n' +
177
197
  ' /gitnexus <pattern> — manual graph lookup\n' +
178
198
  ' /gitnexus query <q> — search execution flows\n' +
179
199
  ' /gitnexus context <n> — callers/callees of a symbol\n' +
@@ -194,6 +214,19 @@ export default function(pi: ExtensionAPI) {
194
214
  return;
195
215
  }
196
216
 
217
+ // /gitnexus config
218
+ if (sub === 'config') {
219
+ const current = gitnexusCmd.join(' ');
220
+ const input = await ctx.ui.input('gitnexus command', current);
221
+ if (input === undefined) return; // cancelled
222
+ const trimmed = input.trim();
223
+ if (!trimmed) return;
224
+ setGitnexusCmd(trimmed.split(/\s+/));
225
+ saveConfig({ cmd: trimmed });
226
+ ctx.ui.notify(`GitNexus command set to: ${trimmed}`, 'info');
227
+ return;
228
+ }
229
+
197
230
  // /gitnexus analyze
198
231
  if (sub === 'analyze') {
199
232
  if (!binaryAvailable) {
@@ -203,7 +236,8 @@ export default function(pi: ExtensionAPI) {
203
236
  augmentEnabled = false;
204
237
  ctx.ui.notify('GitNexus: analyzing codebase, this may take a while…', 'info');
205
238
  const exitCode = await new Promise<number | null>((resolve_) => {
206
- const proc = spawn('gitnexus', ['analyze'], {
239
+ const [bin, ...baseArgs] = gitnexusCmd;
240
+ const proc = spawn(bin, [...baseArgs, 'analyze'], {
207
241
  cwd: ctx.cwd,
208
242
  stdio: 'ignore',
209
243
  env: spawnEnv,
package/src/mcp-client.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { spawn, ChildProcess } from 'child_process';
2
- import { MAX_OUTPUT_CHARS, spawnEnv } from './gitnexus';
2
+ import { MAX_OUTPUT_CHARS, spawnEnv, gitnexusCmd } from './gitnexus';
3
3
 
4
4
  interface JsonRpcResponse {
5
5
  jsonrpc: '2.0';
@@ -45,7 +45,8 @@ class GitNexusMcpClient {
45
45
  if (this.startPromise) return this.startPromise;
46
46
 
47
47
  this.startPromise = new Promise<void>((resolve_, reject) => {
48
- const proc = spawn('gitnexus', ['mcp'], {
48
+ const [bin, ...baseArgs] = gitnexusCmd;
49
+ const proc = spawn(bin, [...baseArgs, 'mcp'], {
49
50
  cwd,
50
51
  stdio: ['pipe', 'pipe', 'ignore'],
51
52
  env: spawnEnv,