@henryqw/pi-codegraph 0.1.0 → 0.2.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/README.md +22 -30
- package/extensions/codegraph.ts +21 -9
- package/package.json +29 -8
package/README.md
CHANGED
|
@@ -1,57 +1,49 @@
|
|
|
1
|
-
# pi-codegraph
|
|
1
|
+
# @henryqw/pi-codegraph
|
|
2
2
|
|
|
3
|
-
Get a separate CodeGraph index when you start Pi in a new Git worktree.
|
|
3
|
+
Get a separate [CodeGraph](https://github.com/colbymchenry/codegraph) index when you start Pi in a new Git worktree. Use CodeGraph's explore tool through pi-mcp-adapter from Pi.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
```sh
|
|
7
|
+
```bash
|
|
10
8
|
npm install -g @colbymchenry/codegraph
|
|
11
9
|
pi install npm:pi-mcp-adapter
|
|
12
10
|
pi install npm:@henryqw/pi-codegraph
|
|
13
11
|
```
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
Requires `codegraph` CLI on `PATH`, and [pi-mcp-adapter](https://github.com/nicobailon/pi-mcp-adapter).
|
|
14
|
+
|
|
15
|
+
## Use
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
From the primary checkout, initialize CodeGraph once:
|
|
18
18
|
|
|
19
|
-
```
|
|
20
|
-
cd /path/to/primary-checkout
|
|
19
|
+
```bash
|
|
21
20
|
codegraph init --yes
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
Then launch `pi` in a linked worktree. The adapter server is `henryqw_pi-codegraph__codegraph`. It discovers tools lazily; other CodeGraph tools remain available through `mcp`.
|
|
25
24
|
|
|
26
|
-
##
|
|
25
|
+
## Flow
|
|
27
26
|
|
|
28
27
|
- A missing worktree index is built only when the primary checkout already has `.codegraph/codegraph.db`.
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
- Non-Git directories and repositories without a primary index are not initialized.
|
|
32
|
-
-
|
|
33
|
-
- The adapter server is `henryqw_pi-codegraph__codegraph`. It discovers tools lazily and exposes `codegraph_explore` directly without an extra package prefix. Other CodeGraph tools remain available through `mcp`. On a cold connection, CodeGraph may require an explicit `projectPath`; pass the worktree root when its tool schema requests it.
|
|
34
|
-
|
|
35
|
-
The MCP definition uses the adapter's native `pi.mcp` package discovery. Install this **package**, not just its extension `.ts` file. Loading a single file with `pi -e` does not discover its MCP manifest. When using the whole local harness as a Pi package, its server is instead `henryqw_pi-harness__codegraph`; do not install both forms together.
|
|
36
|
-
|
|
37
|
-
## Failures and limits
|
|
28
|
+
- Initialization happens when Pi launches, not when Git creates the worktree.
|
|
29
|
+
- Each linked worktree keeps its own `.codegraph`; databases are never copied or shared between branches.
|
|
30
|
+
- Non-Git directories and repositories without a primary index are not initialized.
|
|
31
|
+
- When loaded, the extension reports whether the local index is `indexed`, `missing`, or `indexing…` through Pi's status channel. The `pi-footer` extension places a compact `CG` badge first on its third line and temporarily shows `● CG` during direct CodeGraph tool calls.
|
|
38
32
|
|
|
39
|
-
|
|
33
|
+
## State and storage
|
|
40
34
|
|
|
41
|
-
The
|
|
35
|
+
The extension relies on CodeGraph's own state — each worktree maintains its own `.codegraph/codegraph.db`. The extension never copies, shares, or modifies this database. Existing indexes are left alone; CodeGraph owns synchronization when its MCP server runs.
|
|
42
36
|
|
|
43
|
-
|
|
37
|
+
## Limits and recovery
|
|
44
38
|
|
|
45
|
-
|
|
46
|
-
2. Inspect the failed index and run `codegraph index` in that worktree.
|
|
47
|
-
3. Only after indexing succeeds, remove the reported empty lock directory with `rmdir`, then run `/reload`.
|
|
39
|
+
At startup, the extension checks for a loaded adapter and runs `codegraph --version`. If either prerequisite is unavailable, Pi warns, reports `prerequisites missing`, and skips setup. Restart Pi or run `/reload` after fixing prerequisites.
|
|
48
40
|
|
|
49
|
-
|
|
41
|
+
Initialization uses an exclusive `pi-codegraph-init.lock` in the worktree's Git metadata. Failed or interrupted initialization keeps the lock so a partial database is not accepted. To recover: remove the lock directory with `rmdir` only after `codegraph index` succeeds, then run `/reload`.
|
|
50
42
|
|
|
51
|
-
Only Git worktree-root indexes
|
|
43
|
+
The package never installs prerequisites automatically. The `codegraph` executable must be available to both Pi and its MCP child process. Only Git worktree-root indexes using the default `.codegraph` directory are supported; nested monorepo indexes are not initialized automatically. The primary checkout must remain indexed for automatic opt-in detection.
|
|
52
44
|
|
|
53
|
-
|
|
45
|
+
Do not remove an active lock. Existing indexes without an extension-owned lock are not health-checked. The lock coordinates this extension's sessions, not manual `codegraph init` commands; avoid running those during initialization.
|
|
54
46
|
|
|
55
|
-
|
|
47
|
+
The extension does not add ignore rules, delete indexes, or prune worktrees — add `.codegraph/` to your own ignore rules if needed. Pi Subagent conservatively treats ignored files as retained work: an indexed worker worktree may require manual cleanup.
|
|
56
48
|
|
|
57
49
|
If you already configured a `codegraph` server manually, remove that entry after confirming the package server works. Keeping both can expose duplicate servers/tools. The extension does not change your MCP configuration.
|
package/extensions/codegraph.ts
CHANGED
|
@@ -5,6 +5,8 @@ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-a
|
|
|
5
5
|
|
|
6
6
|
const LOCK_WAIT_MS = 5 * 60_000;
|
|
7
7
|
const INIT_TIMEOUT_MS = 10 * 60_000;
|
|
8
|
+
const WIDGET_KEY = "pi-codegraph";
|
|
9
|
+
const SUCCESS_TTL_MS = 5000;
|
|
8
10
|
|
|
9
11
|
async function hasIndex(root: string): Promise<boolean> {
|
|
10
12
|
try {
|
|
@@ -35,12 +37,12 @@ async function initialize(pi: ExtensionAPI, ctx: ExtensionContext): Promise<void
|
|
|
35
37
|
}
|
|
36
38
|
if (prerequisites.length) {
|
|
37
39
|
const message = `pi-codegraph: setup skipped.\n${prerequisites.join("\n")}\nThen restart Pi or /reload.`;
|
|
38
|
-
ctx.ui.setStatus("pi-codegraph", "
|
|
40
|
+
ctx.ui.setStatus("pi-codegraph", "pi-codegraph: prerequisites missing");
|
|
39
41
|
if (ctx.hasUI) ctx.ui.notify(message, "warning");
|
|
40
42
|
else console.warn(message);
|
|
41
43
|
return;
|
|
42
44
|
}
|
|
43
|
-
ctx.ui.setStatus("pi-codegraph",
|
|
45
|
+
ctx.ui.setStatus("pi-codegraph", "pi-codegraph: missing");
|
|
44
46
|
const rootResult = await pi.exec("git", ["rev-parse", "--show-toplevel"], { cwd: ctx.cwd, timeout: 10_000 });
|
|
45
47
|
if (rootResult.code !== 0 || rootResult.killed) {
|
|
46
48
|
if (!rootResult.killed && rootResult.stderr.includes("not a git repository")) return;
|
|
@@ -57,7 +59,8 @@ async function initialize(pi: ExtensionAPI, ctx: ExtensionContext): Promise<void
|
|
|
57
59
|
// Check the lock before the database: an in-progress/failed init can leave a partial DB.
|
|
58
60
|
const recovery = `Inspect CodeGraph in ${root}. If no initializer is running, run codegraph index in that directory, then remove ${lock} with rmdir and /reload.`;
|
|
59
61
|
const deadline = Date.now() + LOCK_WAIT_MS;
|
|
60
|
-
ctx.ui.setStatus("pi-codegraph", "
|
|
62
|
+
ctx.ui.setStatus("pi-codegraph", "pi-codegraph: checking index…");
|
|
63
|
+
let indexed = false;
|
|
61
64
|
try {
|
|
62
65
|
while (true) {
|
|
63
66
|
try {
|
|
@@ -66,27 +69,36 @@ async function initialize(pi: ExtensionAPI, ctx: ExtensionContext): Promise<void
|
|
|
66
69
|
} catch (error) {
|
|
67
70
|
if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
|
|
68
71
|
if (Date.now() >= deadline) throw new Error(`Timed out waiting for CodeGraph initialization. ${recovery}`);
|
|
69
|
-
ctx.ui.setStatus("pi-codegraph", "
|
|
72
|
+
ctx.ui.setStatus("pi-codegraph", "pi-codegraph: indexing…");
|
|
70
73
|
await delay(250);
|
|
71
74
|
}
|
|
72
75
|
}
|
|
73
76
|
let attempted = false;
|
|
74
77
|
let succeeded = false;
|
|
75
78
|
try {
|
|
76
|
-
if (await hasIndex(root))
|
|
79
|
+
if (await hasIndex(root)) {
|
|
80
|
+
indexed = true;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
77
83
|
const worktrees = await git(pi, root, ["worktree", "list", "--porcelain", "-z"]);
|
|
78
84
|
const first = worktrees.split("\0", 1)[0];
|
|
79
85
|
if (!first?.startsWith("worktree ")) throw new Error("Git returned an invalid primary worktree.");
|
|
80
86
|
const primary = first.slice("worktree ".length);
|
|
81
87
|
if (!primary || primary === root || !(await hasIndex(primary))) return;
|
|
82
|
-
ctx.ui.setStatus("pi-codegraph", "
|
|
88
|
+
ctx.ui.setStatus("pi-codegraph", "pi-codegraph: indexing…");
|
|
83
89
|
attempted = true;
|
|
84
90
|
const result = await pi.exec("codegraph", ["init", "--yes", root], { cwd: root, timeout: INIT_TIMEOUT_MS });
|
|
85
91
|
if (result.code !== 0 || result.killed || !(await hasIndex(root))) {
|
|
86
92
|
throw new Error(`CodeGraph init failed (${result.killed ? "timed out or killed" : `exit ${result.code}`}): ${(result.stderr || result.stdout).trim().slice(-2000)}`);
|
|
87
93
|
}
|
|
88
94
|
succeeded = true;
|
|
89
|
-
|
|
95
|
+
indexed = true;
|
|
96
|
+
if (ctx.hasUI) {
|
|
97
|
+
ctx.ui.setWidget(WIDGET_KEY, ["pi-codegraph: index ready"]);
|
|
98
|
+
setTimeout(() => ctx.ui.setWidget(WIDGET_KEY, undefined), SUCCESS_TTL_MS);
|
|
99
|
+
} else {
|
|
100
|
+
ctx.ui.notify("CodeGraph worktree index ready.", "info");
|
|
101
|
+
}
|
|
90
102
|
} catch (error) {
|
|
91
103
|
if (attempted) throw new Error(`${error instanceof Error ? error.message : String(error)}\n${recovery}`, { cause: error });
|
|
92
104
|
throw error;
|
|
@@ -95,7 +107,7 @@ async function initialize(pi: ExtensionAPI, ctx: ExtensionContext): Promise<void
|
|
|
95
107
|
if (!attempted || succeeded) await rmdir(lock);
|
|
96
108
|
}
|
|
97
109
|
} finally {
|
|
98
|
-
ctx.ui.setStatus("pi-codegraph",
|
|
110
|
+
ctx.ui.setStatus("pi-codegraph", indexed ? "pi-codegraph: indexed" : "pi-codegraph: missing");
|
|
99
111
|
}
|
|
100
112
|
}
|
|
101
113
|
|
|
@@ -105,7 +117,7 @@ export default function codegraphExtension(pi: ExtensionAPI): void {
|
|
|
105
117
|
await initialize(pi, ctx);
|
|
106
118
|
} catch (error) {
|
|
107
119
|
const message = `pi-codegraph: ${error instanceof Error ? error.message : String(error)}`;
|
|
108
|
-
ctx.ui.setStatus("pi-codegraph", "
|
|
120
|
+
ctx.ui.setStatus("pi-codegraph", "pi-codegraph: setup failed");
|
|
109
121
|
if (ctx.hasUI) ctx.ui.notify(message, "error");
|
|
110
122
|
else throw new Error(message, { cause: error });
|
|
111
123
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@henryqw/pi-codegraph",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Initialize CodeGraph indexes in opted-in Git worktrees and expose CodeGraph through pi-mcp-adapter.",
|
|
5
|
-
"keywords": [
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pi-package",
|
|
7
|
+
"pi",
|
|
8
|
+
"codegraph",
|
|
9
|
+
"mcp",
|
|
10
|
+
"worktree"
|
|
11
|
+
],
|
|
6
12
|
"type": "module",
|
|
7
|
-
"engines": {
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=22.19.0"
|
|
15
|
+
},
|
|
8
16
|
"license": "MIT",
|
|
9
|
-
"files": [
|
|
17
|
+
"files": [
|
|
18
|
+
"LICENSE",
|
|
19
|
+
"extensions",
|
|
20
|
+
"mcp.json",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
10
23
|
"scripts": {
|
|
11
24
|
"test": "node --test test/*.test.ts",
|
|
12
25
|
"typecheck": "tsc --noEmit --allowImportingTsExtensions --target ES2024 --module NodeNext --moduleResolution NodeNext --skipLibCheck extensions/codegraph.ts test/*.test.ts",
|
|
@@ -16,16 +29,24 @@
|
|
|
16
29
|
"@earendil-works/pi-coding-agent": ">=0.87.0 <0.88.0",
|
|
17
30
|
"pi-mcp-adapter": ">=2.36.0 <3.0.0"
|
|
18
31
|
},
|
|
19
|
-
"devDependencies": {
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@earendil-works/pi-coding-agent": "0.87.0"
|
|
34
|
+
},
|
|
20
35
|
"repository": {
|
|
21
36
|
"type": "git",
|
|
22
37
|
"url": "git+https://github.com/HenryQW/pi-harness.git",
|
|
23
38
|
"directory": "extensions/pi-codegraph"
|
|
24
39
|
},
|
|
25
|
-
"bugs": {
|
|
26
|
-
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/HenryQW/pi-harness/issues"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
27
46
|
"pi": {
|
|
28
|
-
"extensions": [
|
|
47
|
+
"extensions": [
|
|
48
|
+
"./extensions/codegraph.ts"
|
|
49
|
+
],
|
|
29
50
|
"mcp": "./mcp.json"
|
|
30
51
|
}
|
|
31
52
|
}
|