@wwjd/pi-graphify 0.3.0 → 0.4.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
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.0](https://github.com/WianVDM/pi-graphify/compare/pi-graphify-v0.3.0...pi-graphify-v0.4.0) (2026-07-12)
9
+
10
+
11
+ ### Features
12
+
13
+ * **commands:** add slash commands and unified /graphify menu ([7c7a566](https://github.com/WianVDM/pi-graphify/commit/7c7a566b4dcda3c7b2d166863a7704a98839669a))
14
+
8
15
  ## [0.3.0](https://github.com/WianVDM/pi-graphify/compare/pi-graphify-v0.2.0...pi-graphify-v0.3.0) (2026-07-12)
9
16
 
10
17
 
package/README.md CHANGED
@@ -8,12 +8,6 @@ A [Pi](https://pi.dev) extension that brings [Graphify](https://github.com/Graph
8
8
  pi install @wwjd/pi-graphify
9
9
  ```
10
10
 
11
- Or run locally during development:
12
-
13
- ```bash
14
- pi install .
15
- ```
16
-
17
11
  ## What it does
18
12
 
19
13
  `pi-graphify` detects the Graphify CLI and a project's `graphify-out/graph.json` graph, then exposes Graphify operations as Pi tools and slash commands. It routes requests through a backend abstraction so the agent can use Graphify without worrying about whether it's talking to the CLI or (in the future) an MCP server.
@@ -29,7 +23,14 @@ When a graph is present, the extension also injects a lightweight hint into the
29
23
 
30
24
  | Command | Description |
31
25
  |---|---|
26
+ | `/graphify` | Open the unified Graphify command menu. |
27
+ | `/graphify-build` | Build or incrementally update the Graphify knowledge graph. |
28
+ | `/graphify-query` | Ask a natural-language question against the graph. |
29
+ | `/graphify-path` | Find the shortest path between two graph nodes. |
30
+ | `/graphify-explain` | Explain a node and its connections in the graph. |
31
+ | `/graphify-affected` | Show the blast radius of changes to one or more files. |
32
32
  | `/graphify-status` | Check whether a graph exists and whether the Graphify CLI is compatible. |
33
+ | `/graphify-version` | Report the installed Graphify version and compatibility status. |
33
34
 
34
35
  ## Current tools
35
36
 
@@ -45,15 +46,6 @@ When a graph is present, the extension also injects a lightweight hint into the
45
46
 
46
47
  ## What's coming
47
48
 
48
- Slash commands for the tools above are planned in the next phase:
49
-
50
- - `/graphify-build`
51
- - `/graphify-query`
52
- - `/graphify-path`
53
- - `/graphify-explain`
54
- - `/graphify-affected`
55
- - `/graphify-version`
56
-
57
49
  Later phases will add background file watching, MCP backend support, ecosystem integrations, and release readiness work. See [plan/PLAN.md](plan/PLAN.md) for the full roadmap.
58
50
 
59
51
  ## How it works
@@ -75,13 +67,6 @@ This extension is in early development. The public API, tools, and commands will
75
67
  - [Release standards](RELEASE.md)
76
68
  - [Agent context](AGENTS.md)
77
69
 
78
- ## Development
79
-
80
- ```bash
81
- npm run typecheck
82
- npm run lint
83
- ```
84
-
85
70
  ## License
86
71
 
87
72
  MIT
package/docs/TESTING.md CHANGED
@@ -63,7 +63,7 @@ After installing, `graphify` should be available on your PATH. If it is not, add
63
63
 
64
64
  ## Build a graph for testing
65
65
 
66
- Phase 3 only adds the tools. The `/graphify-build` command is added in Phase 4, so for now build the graph directly with the Graphify CLI.
66
+ You can build the graph with the Graphify CLI directly, or use the `/graphify-build` slash command once the extension is loaded.
67
67
 
68
68
  The recommended approach for testing `pi-graphify` is a code-only graph. It skips semantic extraction, so it does not require an API key or extra Python dependencies:
69
69
 
@@ -85,14 +85,15 @@ Then run the full build:
85
85
  graphify .
86
86
  ```
87
87
 
88
- Once Phase 4 is complete, `/graphify-build` will be available as an alternative.
88
+ Inside Pi you can also run `/graphify` to open the command menu and select "Build graph", or type `/graphify-build` directly.
89
89
 
90
90
  ## Verify the extension with Graphify installed
91
91
 
92
92
  1. Start Pi in a project with a built graph.
93
93
  2. You should see a notification: `Graphify graph ready: ...`.
94
94
  3. The supported tools should be available to the LLM. You can verify by asking: "What graphify tools are available?" or by checking the system prompt tool list.
95
- 4. Test a tool by asking: "Use the graphify graph to explain how auth works in this codebase."
95
+ 4. Test a slash command: type `/graphify` to open the menu, or `/graphify-status` to check graph status.
96
+ 5. Test a tool by asking: "Use the graphify graph to explain how auth works in this codebase."
96
97
 
97
98
  ## Verify the extension without Graphify
98
99
 
@@ -9,6 +9,8 @@
9
9
  */
10
10
 
11
11
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
12
+ import { registerGraphifyCommands } from "../src/commands/index.js";
13
+ import { registerGraphifyMenuCommand } from "../src/commands/menu.js";
12
14
  import { GraphifyCoordinator } from "../src/coordinator.js";
13
15
  import { buildGraphifyHint, graphifyStatus } from "../src/graphify.js";
14
16
  import { registerGraphifyTools } from "../src/tools/index.js";
@@ -20,23 +22,8 @@ export default function (pi: ExtensionAPI) {
20
22
  const registeredToolNames = new Set<string>();
21
23
 
22
24
  // ── 1. Register slash commands synchronously ─────────────────────
23
- pi.registerCommand("graphify-status", {
24
- description: "Show Graphify graph status for the current project",
25
- handler: async (_args, ctx) => {
26
- const current = getCoordinator();
27
- if (!current) {
28
- ctx.ui.notify("Graphify is not initialized.", "warning");
29
- return;
30
- }
31
-
32
- const status = await current.status({ cwd: ctx.cwd });
33
- if (status.hasGraph && status.graphPath) {
34
- ctx.ui.notify(`Graphify graph ready: ${status.graphPath}`, "info");
35
- } else {
36
- ctx.ui.notify("No Graphify graph found. Build one with `graphify .`.", "warning");
37
- }
38
- },
39
- });
25
+ registerGraphifyCommands(pi, getCoordinator);
26
+ registerGraphifyMenuCommand(pi, getCoordinator);
40
27
 
41
28
  // ── 2. Initialize coordinator and register tools per session ───────
42
29
  // Tools are registered inside session_start so we can gate them by the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wwjd/pi-graphify",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Graphify knowledge graph integration for Pi coding agent",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "scripts": {
37
- "test": "node --test --import tsx src/tools/tools.test.ts src/extensions/extension-load.test.ts",
37
+ "test": "node --test --import tsx src/tools/tools.test.ts src/commands/commands.test.ts src/commands/menu.test.ts src/extensions/extension-load.test.ts",
38
38
  "lint": "biome check .",
39
39
  "lint:fix": "biome check --write .",
40
40
  "format": "biome format --write .",
@@ -0,0 +1,63 @@
1
+ /**
2
+ * /graphify-affected — show files and nodes affected by changes to given files.
3
+ */
4
+
5
+ import { resolve } from "node:path";
6
+ import type { GraphifyCapabilities } from "../backends/types.js";
7
+ import { formatResultForCommand } from "./format.js";
8
+ import { notifyCommandError, requireCoordinatorWithCapability } from "./helpers.js";
9
+ import { splitArgs, usageError } from "./parse.js";
10
+ import type { CommandDefinition, CommandExecutor } from "./types.js";
11
+
12
+ const FEATURE: keyof GraphifyCapabilities = "affected";
13
+ const AFFECTED_USAGE = "<file> [file...]";
14
+
15
+ const executeAffected: CommandExecutor = async (ctx, getCoordinator, args) => {
16
+ if (!ctx.hasUI) return;
17
+
18
+ const coordinator = requireCoordinatorWithCapability(
19
+ ctx,
20
+ getCoordinator,
21
+ FEATURE,
22
+ "The installed Graphify version does not support affected analysis.",
23
+ );
24
+ if (!coordinator) return;
25
+
26
+ try {
27
+ const files = parseAffectedArgs(ctx.cwd, args);
28
+ const result = await coordinator.affected({ cwd: ctx.cwd, files });
29
+ ctx.ui.notify(formatResultForCommand(result), "info");
30
+ } catch (error) {
31
+ notifyCommandError(ctx, error);
32
+ }
33
+ };
34
+
35
+ export const affectedCommand: CommandDefinition = {
36
+ name: "graphify-affected",
37
+ label: "Show affected",
38
+ description: "Show files and nodes affected by changes to given files",
39
+ feature: FEATURE,
40
+ usage: AFFECTED_USAGE,
41
+ argMode: "input",
42
+ prompt: "Files to analyze",
43
+ placeholder: "src/index.ts src/utils.ts",
44
+ execute: executeAffected,
45
+ };
46
+
47
+ function parseAffectedArgs(cwd: string, args: string): string[] {
48
+ const tokens = splitArgs(args);
49
+ if (tokens.length === 0) {
50
+ throw usageError("graphify-affected", AFFECTED_USAGE);
51
+ }
52
+
53
+ return tokens.map((file) => resolveFile(cwd, file));
54
+ }
55
+
56
+ function resolveFile(cwd: string, file: string): string {
57
+ const absolute = resolve(cwd, file);
58
+ const normalizedCwd = resolve(cwd);
59
+ if (!absolute.startsWith(normalizedCwd)) {
60
+ throw new Error(`Invalid file path: ${file} is outside the project directory.`);
61
+ }
62
+ return absolute;
63
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * /graphify-build — build or update the Graphify knowledge graph.
3
+ */
4
+
5
+ import type { GraphifyCapabilities } from "../backends/types.js";
6
+ import { formatResultForCommand } from "./format.js";
7
+ import { notifyCommandError, requireCoordinatorWithCapability } from "./helpers.js";
8
+ import { parseBooleanFlag, splitArgs, usageError } from "./parse.js";
9
+ import type { CommandDefinition, CommandExecutor } from "./types.js";
10
+
11
+ const FEATURE: keyof GraphifyCapabilities = "build";
12
+ const BUILD_USAGE = "[--code-only] [--update] [--directed]";
13
+
14
+ const executeBuild: CommandExecutor = async (ctx, getCoordinator, args) => {
15
+ if (!ctx.hasUI) return;
16
+
17
+ const coordinator = requireCoordinatorWithCapability(
18
+ ctx,
19
+ getCoordinator,
20
+ FEATURE,
21
+ "The installed Graphify version does not support graph builds.",
22
+ );
23
+ if (!coordinator) return;
24
+
25
+ if (!ctx.isProjectTrusted()) {
26
+ ctx.ui.notify("Project trust is required to build the Graphify graph.", "warning");
27
+ return;
28
+ }
29
+
30
+ try {
31
+ const { codeOnly, update, directed } = parseBuildArgs(args);
32
+ const result = await coordinator.build({
33
+ cwd: ctx.cwd,
34
+ codeOnly,
35
+ update,
36
+ directed,
37
+ });
38
+ ctx.ui.notify(formatResultForCommand(result), "info");
39
+ } catch (error) {
40
+ notifyCommandError(ctx, error);
41
+ }
42
+ };
43
+
44
+ export const buildCommand: CommandDefinition = {
45
+ name: "graphify-build",
46
+ label: "Build graph",
47
+ description: "Build or incrementally update the Graphify knowledge graph",
48
+ feature: FEATURE,
49
+ usage: BUILD_USAGE,
50
+ argMode: "flags",
51
+ prompt: "Build graph (optional flags)",
52
+ placeholder: "--code-only --update --directed",
53
+ execute: executeBuild,
54
+ };
55
+
56
+ interface ParsedBuildArgs {
57
+ codeOnly: boolean | undefined;
58
+ update: boolean | undefined;
59
+ directed: boolean | undefined;
60
+ }
61
+
62
+ function parseBuildArgs(args: string): ParsedBuildArgs {
63
+ const tokens = splitArgs(args);
64
+ let result = parseBooleanFlag(tokens, "code-only", true);
65
+ const codeOnly = result.value;
66
+ result = parseBooleanFlag(result.rest, "update", true);
67
+ const update = result.value;
68
+ result = parseBooleanFlag(result.rest, "directed", true);
69
+ const directed = result.value;
70
+
71
+ const unknown = result.rest.find((t) => t.startsWith("--"));
72
+ if (unknown || result.rest.length > 0) {
73
+ throw usageError("graphify-build", BUILD_USAGE);
74
+ }
75
+
76
+ return { codeOnly, update, directed };
77
+ }