pi-graphnav 0.2.2 → 0.3.1
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 +2 -1
- package/extensions/command/parse.ts +17 -3
- package/extensions/core/config.ts +15 -4
- package/extensions/core/tools.ts +1 -1
- package/extensions/graphnav.ts +17 -3
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -83,6 +83,7 @@ pi install npm:pi-graphnav
|
|
|
83
83
|
| `/codegraph` or `/codegraph status` | project, index state, mode, blocked/nudged counts |
|
|
84
84
|
| `/codegraph [on\|off]` | switch it all (remembered across sessions) |
|
|
85
85
|
| `/codegraph mode <mode>` | symbol searches: `enforce` (default), `nudge` or `off` |
|
|
86
|
+
| `/codegraph statusline <when>` | status line: `always` (default), `problems` or `never`; CodeGraph keeps working |
|
|
86
87
|
| `/codegraph sync` | sync the index with changed files |
|
|
87
88
|
| `/codegraph reindex` | rebuild the index from scratch |
|
|
88
89
|
| `/codegraph init` | create the index (for a directory that is not a git repo) |
|
|
@@ -92,7 +93,7 @@ Settings live in `<pi agent dir>/codegraph.json` (`PI_CODING_AGENT_DIR`, else `~
|
|
|
92
93
|
| Key | Default | |
|
|
93
94
|
|---|---|---|
|
|
94
95
|
| `enabled` | `true` | master switch |
|
|
95
|
-
| `showStatus` | `
|
|
96
|
+
| `showStatus` | `"always"` | status line entry: `"always"`, `"problems"` (only while indexing, or when the index is missing, failing or unavailable) or `"never"`; `true`/`false` still work |
|
|
96
97
|
| `mode` | `"enforce"` | `enforce`, `nudge` or `off` |
|
|
97
98
|
| `autoInit` | `true` | init a git repo that has no index |
|
|
98
99
|
| `autoSync` | `true` | sync or rebuild a stale index at session start |
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
/** `/codegraph ...`: parsing and argument completion. Pure: the handler in graphnav.ts acts on the result. */
|
|
2
|
-
import { MODES, type Mode } from "../core/config.ts";
|
|
2
|
+
import { MODES, type Mode, STATUS_SHOWS, type StatusShow } from "../core/config.ts";
|
|
3
3
|
|
|
4
4
|
export type Command =
|
|
5
5
|
| { kind: "status" }
|
|
6
6
|
| { kind: "on" }
|
|
7
7
|
| { kind: "off" }
|
|
8
8
|
| { kind: "mode"; mode: Mode }
|
|
9
|
+
| { kind: "statusline"; show: StatusShow }
|
|
9
10
|
| { kind: "sync" }
|
|
10
11
|
| { kind: "reindex" }
|
|
11
12
|
| { kind: "init" }
|
|
12
13
|
| { kind: "invalid"; message: string };
|
|
13
14
|
|
|
14
|
-
export const USAGE = "Usage: /codegraph [status] · on · off · mode <enforce|nudge|off> · sync · reindex · init";
|
|
15
|
+
export const USAGE = "Usage: /codegraph [status] · on · off · mode <enforce|nudge|off> · statusline <always|problems|never> · sync · reindex · init";
|
|
15
16
|
|
|
16
17
|
export function parseCommand(args: string | undefined): Command {
|
|
17
18
|
const [cmd, ...rest] = (args ?? "").trim().split(/\s+/).filter(Boolean);
|
|
@@ -31,6 +32,12 @@ export function parseCommand(args: string | undefined): Command {
|
|
|
31
32
|
? { kind: "mode", mode: m as Mode }
|
|
32
33
|
: { kind: "invalid", message: "Usage: /codegraph mode <enforce|nudge|off>" };
|
|
33
34
|
}
|
|
35
|
+
case "statusline": {
|
|
36
|
+
const v = rest[0]?.toLowerCase();
|
|
37
|
+
return STATUS_SHOWS.includes(v as StatusShow) && rest.length === 1
|
|
38
|
+
? { kind: "statusline", show: v as StatusShow }
|
|
39
|
+
: { kind: "invalid", message: "Usage: /codegraph statusline <always|problems|never>" };
|
|
40
|
+
}
|
|
34
41
|
case "sync":
|
|
35
42
|
return { kind: "sync" };
|
|
36
43
|
case "reindex":
|
|
@@ -55,6 +62,7 @@ const TOP_LEVEL: CompletionItem[] = [
|
|
|
55
62
|
{ value: "on", label: "on", description: "Turn CodeGraph-first on" },
|
|
56
63
|
{ value: "off", label: "off", description: "Turn CodeGraph-first off" },
|
|
57
64
|
{ value: "mode ", label: "mode", description: "Symbol searches: enforce, nudge or off" },
|
|
65
|
+
{ value: "statusline ", label: "statusline", description: "Status line: always, only problems, or never" },
|
|
58
66
|
{ value: "sync", label: "sync", description: "Sync the index with changed files" },
|
|
59
67
|
{ value: "reindex", label: "reindex", description: "Rebuild the index from scratch" },
|
|
60
68
|
{ value: "init", label: "init", description: "Create the index for this project" },
|
|
@@ -66,10 +74,16 @@ const MODE_ITEMS: CompletionItem[] = [
|
|
|
66
74
|
{ value: "mode off", label: "off", description: "Leave text searches alone" },
|
|
67
75
|
];
|
|
68
76
|
|
|
77
|
+
const STATUSLINE_ITEMS: CompletionItem[] = [
|
|
78
|
+
{ value: "statusline always", label: "always", description: "Always show the CodeGraph status" },
|
|
79
|
+
{ value: "statusline problems", label: "problems", description: "Only while indexing, or when the index is missing, failing or unavailable" },
|
|
80
|
+
{ value: "statusline never", label: "never", description: "Never show it (CodeGraph keeps working)" },
|
|
81
|
+
];
|
|
82
|
+
|
|
69
83
|
/** `prefix` is the whole argument text typed so far (pi replaces it with `value`). */
|
|
70
84
|
export function completions(prefix: string): CompletionItem[] | null {
|
|
71
85
|
const text = (prefix ?? "").toLowerCase().replace(/^\s+/, "");
|
|
72
|
-
const pool = text.startsWith("mode ") ? MODE_ITEMS : TOP_LEVEL;
|
|
86
|
+
const pool = text.startsWith("mode ") ? MODE_ITEMS : text.startsWith("statusline ") ? STATUSLINE_ITEMS : TOP_LEVEL;
|
|
73
87
|
const out = pool.filter((i) => i.value.startsWith(text));
|
|
74
88
|
return out.length > 0 ? out : null;
|
|
75
89
|
}
|
|
@@ -11,11 +11,22 @@ import { join } from "node:path";
|
|
|
11
11
|
export type Mode = "enforce" | "nudge" | "off";
|
|
12
12
|
export const MODES: readonly Mode[] = ["enforce", "nudge", "off"];
|
|
13
13
|
|
|
14
|
+
/** Status line: always, only when something needs attention (indexing, missing, error, unavailable), or never. */
|
|
15
|
+
export type StatusShow = "always" | "problems" | "never";
|
|
16
|
+
export const STATUS_SHOWS: readonly StatusShow[] = ["always", "problems", "never"];
|
|
17
|
+
|
|
18
|
+
/** `showStatus` from a config file: one of STATUS_SHOWS, or the 0.2 booleans (true = always, false = never). */
|
|
19
|
+
export function parseStatusShow(v: unknown): StatusShow | undefined {
|
|
20
|
+
if (v === true) return "always";
|
|
21
|
+
if (v === false) return "never";
|
|
22
|
+
return STATUS_SHOWS.includes(v as StatusShow) ? (v as StatusShow) : undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
14
25
|
export interface Config {
|
|
15
26
|
/** Master switch: when false the extension adds no guidance, gates nothing and indexes nothing. */
|
|
16
27
|
enabled: boolean;
|
|
17
|
-
/**
|
|
18
|
-
showStatus:
|
|
28
|
+
/** When to show the status line entry. */
|
|
29
|
+
showStatus: StatusShow;
|
|
19
30
|
/** Symbol searches with rg/grep: block once (`enforce`), only add a hint (`nudge`) or leave alone (`off`). */
|
|
20
31
|
mode: Mode;
|
|
21
32
|
/** Create the index (`codegraph init`) for a git repo that has none. */
|
|
@@ -32,7 +43,7 @@ export interface Config {
|
|
|
32
43
|
|
|
33
44
|
export const DEFAULT_CONFIG: Config = {
|
|
34
45
|
enabled: true,
|
|
35
|
-
showStatus:
|
|
46
|
+
showStatus: "always",
|
|
36
47
|
mode: "enforce",
|
|
37
48
|
autoInit: true,
|
|
38
49
|
autoSync: true,
|
|
@@ -49,7 +60,7 @@ export function sanitizeConfig(raw: unknown): Config {
|
|
|
49
60
|
const d = DEFAULT_CONFIG;
|
|
50
61
|
return {
|
|
51
62
|
enabled: typeof r.enabled === "boolean" ? r.enabled : d.enabled,
|
|
52
|
-
showStatus:
|
|
63
|
+
showStatus: parseStatusShow(r.showStatus) ?? d.showStatus,
|
|
53
64
|
mode: MODES.includes(r.mode as Mode) ? (r.mode as Mode) : d.mode,
|
|
54
65
|
autoInit: typeof r.autoInit === "boolean" ? r.autoInit : d.autoInit,
|
|
55
66
|
autoSync: typeof r.autoSync === "boolean" ? r.autoSync : d.autoSync,
|
package/extensions/core/tools.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The names match the CodeGraph MCP server's tools, so calls pass straight through.
|
|
5
5
|
*/
|
|
6
|
-
import { Type } from "
|
|
6
|
+
import { Type } from "typebox";
|
|
7
7
|
|
|
8
8
|
const projectPath = Type.Optional(
|
|
9
9
|
Type.String({ description: "Absolute path of another indexed project. Defaults to the current project." }),
|
package/extensions/graphnav.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { homedir } from "node:os";
|
|
|
14
14
|
import { resolve } from "node:path";
|
|
15
15
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
16
16
|
import { completions, parseCommand } from "./command/parse.ts";
|
|
17
|
-
import { type Config, DEFAULT_CONFIG, type ProjectOverrides, readConfig, readProjectConfig, saveConfig } from "./core/config.ts";
|
|
17
|
+
import { type Config, DEFAULT_CONFIG, type ProjectOverrides, readConfig, readProjectConfig, saveConfig, type StatusShow } from "./core/config.ts";
|
|
18
18
|
import {
|
|
19
19
|
codemodeSearches,
|
|
20
20
|
candidateSymbols,
|
|
@@ -54,6 +54,13 @@ export interface Status {
|
|
|
54
54
|
error?: string;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/** Does the status line show for this setting? `problems`: only when the user may need to act or wait. */
|
|
58
|
+
export function showsStatus(show: StatusShow, s: Status): boolean {
|
|
59
|
+
if (show === "never") return false;
|
|
60
|
+
if (show === "always") return true;
|
|
61
|
+
return !!s.unavailable || s.state === "indexing" || s.state === "missing" || s.state === "error";
|
|
62
|
+
}
|
|
63
|
+
|
|
57
64
|
export function statusText(s: Status): string {
|
|
58
65
|
if (!s.config.enabled) return "codegraph: off";
|
|
59
66
|
if (s.unavailable) return `codegraph: unavailable · ${s.config.mode}`;
|
|
@@ -132,6 +139,8 @@ export interface Deps {
|
|
|
132
139
|
run?: Runner;
|
|
133
140
|
spawn?: Spawner;
|
|
134
141
|
breaker?: { threshold: number; resetMs: number };
|
|
142
|
+
/** How long the gate waits for its index probe before failing open (default 2000 ms). */
|
|
143
|
+
probeTimeoutMs?: number;
|
|
135
144
|
}
|
|
136
145
|
|
|
137
146
|
const withTimeout = <T>(p: Promise<T>, ms: number): Promise<T> =>
|
|
@@ -170,7 +179,7 @@ export function createExtension(deps: Deps = {}) {
|
|
|
170
179
|
const guardNow = new Map<string, Guard>();
|
|
171
180
|
const unavailable = (root = project?.root) => (root ? (guardNow.get(root)?.open ?? false) : false);
|
|
172
181
|
const snapshot = (): Status => ({ config, project, state, index, error: lastError, ...counts, unavailable: unavailable(), overrides });
|
|
173
|
-
const refresh = () => ui?.setStatus("codegraph", config.enabled && config.showStatus ? statusText(snapshot()) : "");
|
|
182
|
+
const refresh = () => ui?.setStatus("codegraph", config.enabled && showsStatus(config.showStatus, snapshot()) ? statusText(snapshot()) : "");
|
|
174
183
|
|
|
175
184
|
const server = (root: string) => {
|
|
176
185
|
let s = servers.get(root);
|
|
@@ -322,7 +331,7 @@ export function createExtension(deps: Deps = {}) {
|
|
|
322
331
|
await Promise.all(
|
|
323
332
|
unknown.map(async (sym) => {
|
|
324
333
|
try {
|
|
325
|
-
const res = await withTimeout(server(root).call("codegraph_search", { query: leafOf(sym), limit: 25, projectPath: root }), 2000);
|
|
334
|
+
const res = await withTimeout(server(root).call("codegraph_search", { query: leafOf(sym), limit: 25, projectPath: root }), deps.probeTimeoutMs ?? 2000);
|
|
326
335
|
if (res.isError) return;
|
|
327
336
|
const at = definitionsIn(resultText(res), sym);
|
|
328
337
|
if (at.length === 0) mem.unindexed.add(leafOf(sym));
|
|
@@ -421,6 +430,11 @@ export function createExtension(deps: Deps = {}) {
|
|
|
421
430
|
await persist();
|
|
422
431
|
ctx.ui.notify(`codegraph: mode ${cmd.mode}`, "info");
|
|
423
432
|
return;
|
|
433
|
+
case "statusline":
|
|
434
|
+
config.showStatus = base.showStatus = cmd.show;
|
|
435
|
+
await persist();
|
|
436
|
+
ctx.ui.notify(`codegraph: status line ${cmd.show}`, "info");
|
|
437
|
+
return;
|
|
424
438
|
case "sync":
|
|
425
439
|
case "reindex":
|
|
426
440
|
case "init": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-graphnav",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "CodeGraph-first code navigation for pi: persistent index, auto init/sync, and a gate that steers structural searches to codegraph_* tools.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -42,12 +42,13 @@
|
|
|
42
42
|
"minimatch": "11.0.3"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@earendil-works/pi-
|
|
45
|
+
"@earendil-works/pi-ai": "^1.5.0",
|
|
46
|
+
"@earendil-works/pi-coding-agent": "^1.5.0",
|
|
46
47
|
"@types/bun": "^1.4.4",
|
|
47
|
-
"
|
|
48
|
-
"
|
|
48
|
+
"typebox": "^1.4.6",
|
|
49
|
+
"typescript": "^7.0.2"
|
|
49
50
|
},
|
|
50
51
|
"dependencies": {
|
|
51
|
-
"arrow-resilience-kit": "^0.10.
|
|
52
|
+
"arrow-resilience-kit": "^0.10.5"
|
|
52
53
|
}
|
|
53
54
|
}
|