@wwjd/pi-graphify 0.1.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/AGENTS.md +23 -0
- package/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/README.md +94 -0
- package/RELEASE.md +149 -0
- package/docs/ARCHITECTURE.md +388 -0
- package/docs/DESIGN.md +288 -0
- package/docs/ECOSYSTEM.md +130 -0
- package/docs/STANDARDS.md +155 -0
- package/docs/VERSIONING.md +241 -0
- package/extensions/index.ts +54 -0
- package/package.json +66 -0
- package/src/config.ts +26 -0
- package/src/graphify.ts +98 -0
- package/src/tools/index.ts +11 -0
- package/src/tools/status.ts +43 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pi-graphify
|
|
3
|
+
description: Agent context for working on pi-graphify
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# pi-graphify
|
|
7
|
+
|
|
8
|
+
A Pi extension that integrates [Graphify](https://github.com/Graphify-Labs/graphify) into Pi sessions.
|
|
9
|
+
|
|
10
|
+
## Key references
|
|
11
|
+
|
|
12
|
+
- Project standards: [docs/STANDARDS.md](docs/STANDARDS.md)
|
|
13
|
+
- Design: [docs/DESIGN.md](docs/DESIGN.md)
|
|
14
|
+
- Architecture: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
|
15
|
+
- Ecosystem: [docs/ECOSYSTEM.md](docs/ECOSYSTEM.md)
|
|
16
|
+
- Versioning: [docs/VERSIONING.md](docs/VERSIONING.md)
|
|
17
|
+
- Release: [RELEASE.md](RELEASE.md)
|
|
18
|
+
|
|
19
|
+
## Quick verification
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm run typecheck && npm run lint
|
|
23
|
+
```
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## 0.1.0 (2026-07-11)
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Initial project setup from the official pi package template.
|
|
15
|
+
- Scaffolded extension, skill, prompt template, and theme for graphify.
|
|
16
|
+
- add graphify_status tool and /graphify-status command
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# pi-graphify
|
|
2
|
+
|
|
3
|
+
A production-quality [pi](https://pi.dev) extension for [Graphify](https://github.com/Graphify-Labs/graphify).
|
|
4
|
+
|
|
5
|
+
This extension brings Graphify knowledge graph capabilities into your Pi sessions, making it easy to query, explore, and update codebase graphs without leaving the agent.
|
|
6
|
+
|
|
7
|
+
> ⚠️ **Work in progress** — this package is in early development. The public API, tools, and commands will evolve as the extension matures toward a stable 1.0 release.
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Install from a local path (during development)
|
|
13
|
+
pi install .
|
|
14
|
+
|
|
15
|
+
# Or run ephemerally without installing
|
|
16
|
+
pi -e .
|
|
17
|
+
|
|
18
|
+
# Type check
|
|
19
|
+
npm run typecheck
|
|
20
|
+
|
|
21
|
+
# Lint
|
|
22
|
+
npm run lint
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## What's Included
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
pi-graphify/
|
|
29
|
+
├── extensions/
|
|
30
|
+
│ └── index.ts # Extension entry point (tools, commands, events)
|
|
31
|
+
├── src/ # Core implementation
|
|
32
|
+
├── package.json # Pi manifest + npm config
|
|
33
|
+
├── tsconfig.json # TypeScript config (type checking only)
|
|
34
|
+
├── biome.json # Linter/formatter config
|
|
35
|
+
├── .gitignore
|
|
36
|
+
├── LICENSE
|
|
37
|
+
├── CHANGELOG.md
|
|
38
|
+
├── RELEASE.md # Versioning and release standards
|
|
39
|
+
├── AGENTS.md # Agent context / development conventions
|
|
40
|
+
└── README.md
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Package Structure
|
|
44
|
+
|
|
45
|
+
### Extensions (`extensions/`)
|
|
46
|
+
|
|
47
|
+
TypeScript modules that extend pi's behavior with custom tools, slash commands, and event handlers.
|
|
48
|
+
|
|
49
|
+
### Source (`src/`)
|
|
50
|
+
|
|
51
|
+
Pi-agnostic implementation logic. The `extensions/` layer imports from here and registers everything with Pi.
|
|
52
|
+
|
|
53
|
+
## Development
|
|
54
|
+
|
|
55
|
+
### Requirements
|
|
56
|
+
|
|
57
|
+
- Node.js 22+
|
|
58
|
+
- npm 10+
|
|
59
|
+
- pi CLI
|
|
60
|
+
|
|
61
|
+
### Scripts
|
|
62
|
+
|
|
63
|
+
| Command | Description |
|
|
64
|
+
|---------|-------------|
|
|
65
|
+
| `npm run typecheck` | TypeScript type checking (`tsc --noEmit`) |
|
|
66
|
+
| `npm run lint` | Check lint + formatting (`biome check`) |
|
|
67
|
+
| `npm run lint:fix` | Auto-fix lint + formatting issues |
|
|
68
|
+
| `npm run format` | Format code only |
|
|
69
|
+
|
|
70
|
+
### Testing the package
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Run ephemerally with no other extensions loaded
|
|
74
|
+
pi -ne -e . --no-session
|
|
75
|
+
|
|
76
|
+
# Test a specific tool in print mode
|
|
77
|
+
pi -ne -e . --no-session -p "List the available tools."
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Publishing
|
|
81
|
+
|
|
82
|
+
This package is intended for publication to npm so it can be listed on [pi.dev/packages](https://pi.dev/packages). CI/CD workflows for release automation are included under `.github/workflows/`.
|
|
83
|
+
|
|
84
|
+
See `RELEASE.md` for versioning and release standards.
|
|
85
|
+
|
|
86
|
+
Before publishing, update:
|
|
87
|
+
|
|
88
|
+
- `package.json` author and repository fields
|
|
89
|
+
- `README.md` with final usage instructions
|
|
90
|
+
- `CHANGELOG.md` with release notes
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT
|
package/RELEASE.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Release Standards
|
|
2
|
+
|
|
3
|
+
This document defines how `pi-graphify` is versioned and released.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Versioning
|
|
8
|
+
|
|
9
|
+
`pi-graphify` follows [Semantic Versioning 2.0.0](https://semver.org/):
|
|
10
|
+
|
|
11
|
+
| Position | Name | Bumped when |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `MAJOR` | Breaking release | A public tool, command, config option, or behavior changes in a way that could break existing users. |
|
|
14
|
+
| `MINOR` | Feature release | New tools, commands, or backward-compatible features are added. |
|
|
15
|
+
| `PATCH` | Fix release | Bugs are fixed, docs are corrected, or internal behavior improves without affecting the public API. |
|
|
16
|
+
|
|
17
|
+
Pre-1.0 policy: while the package is at `0.x`, the API is considered unstable. Minor releases may introduce substantial changes. Patch releases are safe to apply.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## What triggers each version bump
|
|
22
|
+
|
|
23
|
+
### MAJOR (`x.0.0`)
|
|
24
|
+
|
|
25
|
+
- Removing a registered tool or command.
|
|
26
|
+
- Renaming a tool, command, or parameter.
|
|
27
|
+
- Changing the default behavior of a tool or command in a way that breaks existing workflows.
|
|
28
|
+
- Changing the required config schema or environment variables.
|
|
29
|
+
|
|
30
|
+
### MINOR (`0.x.0`)
|
|
31
|
+
|
|
32
|
+
- Adding a new tool (e.g., `graphify_query`).
|
|
33
|
+
- Adding a new slash command (e.g., `/graphify-watch`).
|
|
34
|
+
- Adding new optional parameters to existing tools/commands.
|
|
35
|
+
- Adding new config options with safe defaults.
|
|
36
|
+
- Adding support for new Graphify CLI features.
|
|
37
|
+
|
|
38
|
+
### PATCH (`0.0.x`)
|
|
39
|
+
|
|
40
|
+
- Fixing a bug in a tool or command.
|
|
41
|
+
- Improving error messages or output formatting.
|
|
42
|
+
- Updating documentation.
|
|
43
|
+
- Updating dependencies that do not change public behavior.
|
|
44
|
+
- Internal refactoring with no user-visible change.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Commit conventions
|
|
49
|
+
|
|
50
|
+
All commits must use [Conventional Commits](https://www.conventionalcommits.org/).
|
|
51
|
+
|
|
52
|
+
Allowed prefixes:
|
|
53
|
+
|
|
54
|
+
| Prefix | Use for |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `feat:` | New user-facing feature or tool |
|
|
57
|
+
| `fix:` | Bug fix |
|
|
58
|
+
| `docs:` | Documentation-only changes |
|
|
59
|
+
| `refactor:` | Code change that neither fixes a bug nor adds a feature |
|
|
60
|
+
| `test:` | Adding or correcting tests |
|
|
61
|
+
| `chore:` | Maintenance, dependency updates, cleanup |
|
|
62
|
+
| `ci:` | Changes to CI/CD configuration |
|
|
63
|
+
|
|
64
|
+
For breaking changes, add `BREAKING CHANGE:` in the commit body or use `!` after the prefix:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
feat!: remove graphify_status tool in favor of graphify_info
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Release workflow
|
|
73
|
+
|
|
74
|
+
Releases are automated with [release-please](https://github.com/googleapis/release-please) via `.github/workflows/release.yml`.
|
|
75
|
+
|
|
76
|
+
### How it works
|
|
77
|
+
|
|
78
|
+
1. **You commit to `main`** using conventional commits.
|
|
79
|
+
2. **release-please scans the commit history** and opens a Release PR titled something like `chore(main): release 0.2.0`.
|
|
80
|
+
3. **The Release PR contains:**
|
|
81
|
+
- An updated `CHANGELOG.md`.
|
|
82
|
+
- A version bump in `package.json` and `package-lock.json`.
|
|
83
|
+
4. **You review and merge the Release PR.**
|
|
84
|
+
5. **release-please creates:**
|
|
85
|
+
- A Git tag (e.g., `v0.2.0`).
|
|
86
|
+
- A GitHub Release with auto-generated notes.
|
|
87
|
+
6. **The `publish` job runs** and publishes the package to npm with provenance.
|
|
88
|
+
|
|
89
|
+
### Manual steps required
|
|
90
|
+
|
|
91
|
+
- Ensure `NPM_TOKEN` is configured as a repository secret in GitHub.
|
|
92
|
+
- Ensure GitHub Actions has permission to create pull requests.
|
|
93
|
+
- Review the Release PR before merging.
|
|
94
|
+
|
|
95
|
+
### No manual version bumps
|
|
96
|
+
|
|
97
|
+
Do not manually edit `version` in `package.json`. release-please handles this. The only exception is the very first `0.1.0`, which is already set.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Branching strategy
|
|
102
|
+
|
|
103
|
+
Because this is a solo project, keep the branching model minimal:
|
|
104
|
+
|
|
105
|
+
- **`main`** is the only long-lived branch.
|
|
106
|
+
- Commit directly to `main` for small changes.
|
|
107
|
+
- Optional: use short-lived feature branches (e.g., `feat/query-tool`) if you want cleaner history, but they are not required.
|
|
108
|
+
- No release branches, no sub-branches, no cherry-pick branches.
|
|
109
|
+
- Hotfixes are committed to `main` and release-please cuts a new patch release.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Git tags
|
|
114
|
+
|
|
115
|
+
Git tags are created automatically by release-please in the format `v0.2.0`. Do not create tags manually.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## npm provenance
|
|
120
|
+
|
|
121
|
+
The publish workflow uses `npm publish --provenance`, which attaches a signed attestation to the package on npm. This requires:
|
|
122
|
+
|
|
123
|
+
- The `publish` job runs in GitHub Actions.
|
|
124
|
+
- The workflow has `id-token: write` permission.
|
|
125
|
+
- The package is published with `--access public`.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Pre-release checklist
|
|
130
|
+
|
|
131
|
+
Before merging a Release PR, verify:
|
|
132
|
+
|
|
133
|
+
- [ ] `CHANGELOG.md` accurately describes the release.
|
|
134
|
+
- [ ] The version bump is correct (patch/minor/major).
|
|
135
|
+
- [ ] `npm run typecheck` passes on `main`.
|
|
136
|
+
- [ ] `npm run lint` passes on `main`.
|
|
137
|
+
- [ ] `NPM_TOKEN` is available.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Emergency fixes
|
|
142
|
+
|
|
143
|
+
If a release is broken and needs an immediate fix:
|
|
144
|
+
|
|
145
|
+
1. Commit the fix to `main` with `fix: <description>`.
|
|
146
|
+
2. release-please will open a new Release PR with a patch bump.
|
|
147
|
+
3. Merge it to publish the fix.
|
|
148
|
+
|
|
149
|
+
Do not unpublish npm versions. Prefer publishing a patch release over unpublishing.
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# Architecture Document: pi-graphify
|
|
2
|
+
|
|
3
|
+
This document describes the internal architecture of `pi-graphify`. It is intended for developers who want to understand or contribute to the extension.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Component overview
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
11
|
+
│ Pi Agent │
|
|
12
|
+
└─────────────────────────────────────────────────────────────┘
|
|
13
|
+
│
|
|
14
|
+
▼
|
|
15
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
16
|
+
│ Extension Entry Point │
|
|
17
|
+
│ (extensions/index.ts) │
|
|
18
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
|
|
19
|
+
│ │ Tool │ │ Command │ │ Event handlers │ │
|
|
20
|
+
│ │ registration │ │ registration │ │ (session, model) │ │
|
|
21
|
+
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
|
|
22
|
+
└─────────────────────────────────────────────────────────────┘
|
|
23
|
+
│
|
|
24
|
+
▼
|
|
25
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
26
|
+
│ Coordinator │
|
|
27
|
+
│ (src/coordinator.ts) │
|
|
28
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
|
|
29
|
+
│ │ Backend │ │ Version │ │ State manager │ │
|
|
30
|
+
│ │ selector │ │ manager │ │ │ │
|
|
31
|
+
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
|
|
32
|
+
└─────────────────────────────────────────────────────────────┘
|
|
33
|
+
│
|
|
34
|
+
┌───────────────┴───────────────┐
|
|
35
|
+
▼ ▼
|
|
36
|
+
┌────────────────────────────┐ ┌────────────────────────────┐
|
|
37
|
+
│ CliBackend │ │ McpBackend │
|
|
38
|
+
│ (src/backends/cli.ts) │ │ (src/backends/mcp.ts) │
|
|
39
|
+
│ Shells out to `graphify` │ │ Spawns `graphify --mcp` │
|
|
40
|
+
│ via execFile │ │ and speaks JSON-RPC │
|
|
41
|
+
└────────────────────────────┘ └────────────────────────────┘
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Backend abstraction
|
|
47
|
+
|
|
48
|
+
All Graphify operations are abstracted behind a `GraphifyBackend` interface. This allows the rest of the extension to be backend-agnostic.
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
export interface GraphifyBackend {
|
|
52
|
+
readonly type: 'cli' | 'mcp';
|
|
53
|
+
readonly version: string | null;
|
|
54
|
+
readonly capabilities: GraphifyCapabilities;
|
|
55
|
+
|
|
56
|
+
status(cwd: string): Promise<GraphStatusResult>;
|
|
57
|
+
build(options: BuildOptions): Promise<GraphifyResult>;
|
|
58
|
+
query(options: QueryOptions): Promise<GraphifyResult>;
|
|
59
|
+
path(options: PathOptions): Promise<GraphifyResult>;
|
|
60
|
+
explain(options: ExplainOptions): Promise<GraphifyResult>;
|
|
61
|
+
affected(options: AffectedOptions): Promise<GraphifyResult>;
|
|
62
|
+
add(options: AddOptions): Promise<GraphifyResult>;
|
|
63
|
+
watch(options: WatchOptions): Promise<GraphifyResult>;
|
|
64
|
+
reflect(options: ReflectOptions): Promise<GraphifyResult>;
|
|
65
|
+
|
|
66
|
+
close?(): Promise<void>;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Capabilities
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
export interface GraphifyCapabilities {
|
|
74
|
+
query: boolean;
|
|
75
|
+
path: boolean;
|
|
76
|
+
explain: boolean;
|
|
77
|
+
affected: boolean;
|
|
78
|
+
add: boolean;
|
|
79
|
+
watch: boolean;
|
|
80
|
+
reflect: boolean;
|
|
81
|
+
mcp: boolean;
|
|
82
|
+
directedGraph: boolean;
|
|
83
|
+
incrementalUpdate: boolean;
|
|
84
|
+
semanticExtraction: boolean;
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Capabilities are determined by:
|
|
89
|
+
1. Detected Graphify version.
|
|
90
|
+
2. Whether the backend is CLI or MCP.
|
|
91
|
+
3. A feature map that maps version ranges to supported features.
|
|
92
|
+
|
|
93
|
+
### Backend selector
|
|
94
|
+
|
|
95
|
+
The coordinator chooses the backend in this order:
|
|
96
|
+
|
|
97
|
+
1. **MCP if explicitly enabled** (`backend: 'mcp'` in config) and available.
|
|
98
|
+
2. **MCP if auto-detected** (`backend: 'auto'`) and the MCP server starts successfully.
|
|
99
|
+
3. **CLI** as the universal fallback.
|
|
100
|
+
|
|
101
|
+
The CLI backend is always safe to attempt because Graphify is required to be installed. The MCP backend is preferred when it works because it provides typed, structured responses and avoids spawning a process per call.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Backend implementations
|
|
106
|
+
|
|
107
|
+
### CliBackend
|
|
108
|
+
|
|
109
|
+
Responsibilities:
|
|
110
|
+
- Resolve the Graphify executable path.
|
|
111
|
+
- Execute `graphify <command>` with argument arrays via `execFile`.
|
|
112
|
+
- Parse stdout/stderr into a normalized `GraphifyResult`.
|
|
113
|
+
- Enforce timeouts.
|
|
114
|
+
- Handle version detection via `graphify --version`.
|
|
115
|
+
|
|
116
|
+
Security:
|
|
117
|
+
- Never construct shell strings.
|
|
118
|
+
- Validate all paths before passing them.
|
|
119
|
+
- Respect `timeout` to prevent hung processes.
|
|
120
|
+
|
|
121
|
+
### McpBackend
|
|
122
|
+
|
|
123
|
+
Responsibilities:
|
|
124
|
+
- Spawn `graphify --mcp` as a long-lived stdio process per session.
|
|
125
|
+
- Maintain a JSON-RPC client over stdin/stdout.
|
|
126
|
+
- Map Pi tool calls to MCP tool invocations.
|
|
127
|
+
- Cache the graph context so the MCP server does not reload the graph on every call.
|
|
128
|
+
- Close the process on `session_shutdown`.
|
|
129
|
+
|
|
130
|
+
Fallback:
|
|
131
|
+
- If the MCP process fails to start or crashes, the coordinator falls back to `CliBackend` and logs the reason.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Coordinator
|
|
136
|
+
|
|
137
|
+
The coordinator is the single entry point for all Graphify operations. It:
|
|
138
|
+
|
|
139
|
+
1. Loads configuration.
|
|
140
|
+
2. Detects or selects the backend.
|
|
141
|
+
3. Checks the installed Graphify version against the supported range.
|
|
142
|
+
4. Builds a capability map.
|
|
143
|
+
5. Routes tool/command requests to the backend.
|
|
144
|
+
6. Normalizes backend results into a common format.
|
|
145
|
+
7. Handles errors and converts them into user-friendly messages.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
export class GraphifyCoordinator {
|
|
149
|
+
constructor(config: GraphifyConfig, backend: GraphifyBackend);
|
|
150
|
+
|
|
151
|
+
initialize(): Promise<void>;
|
|
152
|
+
getStatus(): Promise<SystemStatus>;
|
|
153
|
+
runOperation(name: string, options: unknown): Promise<GraphifyResult>;
|
|
154
|
+
supports(feature: keyof GraphifyCapabilities): boolean;
|
|
155
|
+
close(): Promise<void>;
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Version manager
|
|
162
|
+
|
|
163
|
+
The version manager is responsible for detecting the installed Graphify version and determining what features are available.
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
export interface GraphifyVersionInfo {
|
|
167
|
+
version: string | null;
|
|
168
|
+
installationMethod: 'uv' | 'pipx' | 'pip' | 'system' | 'unknown';
|
|
169
|
+
isSupported: boolean;
|
|
170
|
+
isRecommended: boolean;
|
|
171
|
+
minSupported: string;
|
|
172
|
+
recommended: string;
|
|
173
|
+
warnings: string[];
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
It is used by:
|
|
178
|
+
- The coordinator to disable unsupported features.
|
|
179
|
+
- The `graphify_version` tool to report compatibility.
|
|
180
|
+
- The `session_start` handler to notify the user of issues.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## State manager
|
|
185
|
+
|
|
186
|
+
The state manager holds per-session runtime state. It does not persist across sessions; it is rebuilt on `session_start`.
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
export interface GraphifyState {
|
|
190
|
+
cwd: string;
|
|
191
|
+
graphPath: string | null;
|
|
192
|
+
graphExists: boolean;
|
|
193
|
+
graphMtime: number | null;
|
|
194
|
+
backendType: 'cli' | 'mcp';
|
|
195
|
+
graphifyVersion: string | null;
|
|
196
|
+
capabilities: GraphifyCapabilities;
|
|
197
|
+
watcherActive: boolean;
|
|
198
|
+
lastError: string | null;
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
This state is used by:
|
|
203
|
+
- Event handlers to decide whether to inject hints.
|
|
204
|
+
- Tools to check prerequisites quickly.
|
|
205
|
+
- Commands to report status.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Watcher manager
|
|
210
|
+
|
|
211
|
+
The watcher manager watches source files and triggers incremental rebuilds.
|
|
212
|
+
|
|
213
|
+
Responsibilities:
|
|
214
|
+
- Use `chokidar` to watch the project root.
|
|
215
|
+
- Ignore `node_modules/`, `.git/`, `graphify-out/`, and other non-source directories.
|
|
216
|
+
- Debounce change events.
|
|
217
|
+
- Run `graphify --update` with `codeOnly: true` by default.
|
|
218
|
+
- Never run full semantic rebuilds automatically.
|
|
219
|
+
- Stop cleanly on `session_shutdown`.
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
export interface WatcherOptions {
|
|
223
|
+
root: string;
|
|
224
|
+
debounceMs: number;
|
|
225
|
+
ignored: string[];
|
|
226
|
+
codeOnly: boolean;
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Tool/command mapping
|
|
233
|
+
|
|
234
|
+
Each tool has a corresponding command, but the implementation is shared.
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
// src/tools/query.ts
|
|
238
|
+
export function registerQueryTool(pi: ExtensionAPI, coordinator: GraphifyCoordinator) {
|
|
239
|
+
pi.registerTool({
|
|
240
|
+
name: 'graphify_query',
|
|
241
|
+
// ...
|
|
242
|
+
execute: async (_id, params, _signal, _onUpdate, ctx) => {
|
|
243
|
+
return coordinator.runOperation('query', { ...params, cwd: ctx.cwd });
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// src/commands/query.ts
|
|
249
|
+
export function registerQueryCommand(pi: ExtensionAPI, coordinator: GraphifyCoordinator) {
|
|
250
|
+
pi.registerCommand('graphify-query', {
|
|
251
|
+
handler: async (args, ctx) => {
|
|
252
|
+
const result = await coordinator.runOperation('query', { question: args, cwd: ctx.cwd });
|
|
253
|
+
ctx.ui.notify(result.stdout.slice(0, 200), 'info');
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
This ensures tools and commands behave identically and reduces duplication.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Error normalization
|
|
264
|
+
|
|
265
|
+
All backends return a `GraphifyResult`:
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
export interface GraphifyResult {
|
|
269
|
+
stdout: string;
|
|
270
|
+
stderr: string;
|
|
271
|
+
exitCode: number;
|
|
272
|
+
durationMs: number;
|
|
273
|
+
backend: 'cli' | 'mcp';
|
|
274
|
+
feature: string;
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
The coordinator converts backend errors into extension-level errors:
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
export class GraphifyError extends Error {
|
|
282
|
+
readonly code: 'MISSING' | 'VERSION' | 'BUILD' | 'QUERY' | 'TIMEOUT' | 'MCP' | 'UNKNOWN';
|
|
283
|
+
readonly details: Record<string, unknown>;
|
|
284
|
+
readonly userMessage: string;
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
This allows tools and UI to present consistent messages without knowing backend specifics.
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Configuration loading
|
|
293
|
+
|
|
294
|
+
Configuration is loaded in this order (later overrides earlier):
|
|
295
|
+
|
|
296
|
+
1. Default config (`src/config.ts`).
|
|
297
|
+
2. Global config (`~/.pi/agent/pi-graphify/config.json`).
|
|
298
|
+
3. Project-local config (`.pi/pi-graphify.json`) if project is trusted.
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
export interface GraphifyConfig {
|
|
302
|
+
backend: 'auto' | 'cli' | 'mcp';
|
|
303
|
+
autoHint: boolean;
|
|
304
|
+
autoWatch: boolean;
|
|
305
|
+
watchDebounceMs: number;
|
|
306
|
+
buildTimeoutMs: number;
|
|
307
|
+
queryTimeoutMs: number;
|
|
308
|
+
shortTimeoutMs: number;
|
|
309
|
+
staleThresholdHours: number;
|
|
310
|
+
codeOnlyUpdates: boolean;
|
|
311
|
+
interceptReads: boolean;
|
|
312
|
+
graphifyPath?: string;
|
|
313
|
+
mcpTimeoutMs: number;
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Integration hooks
|
|
320
|
+
|
|
321
|
+
`pi-graphify` is designed so that third-party integrations are optional, easy to add, and easy to build. The core extension works without any integrations. When another extension is available, `pi-graphify` can detect it and wire itself in through well-defined hooks.
|
|
322
|
+
|
|
323
|
+
### Hook interface
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
export interface GraphifyIntegration {
|
|
327
|
+
readonly name: string;
|
|
328
|
+
readonly priority: number;
|
|
329
|
+
isAvailable(pi: ExtensionAPI): boolean | Promise<boolean>;
|
|
330
|
+
onGraphBuilt?(result: GraphifyResult): void | Promise<void>;
|
|
331
|
+
onQueryResult?(result: GraphifyResult, question: string): void | Promise<void>;
|
|
332
|
+
onLesson?(lesson: GraphifyLesson): void | Promise<void>;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export interface GraphifyLesson {
|
|
336
|
+
kind: 'insight' | 'correction' | 'dead_end' | 'preference';
|
|
337
|
+
summary: string;
|
|
338
|
+
sourceNodes: string[];
|
|
339
|
+
query?: string;
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### How integrations are registered
|
|
344
|
+
|
|
345
|
+
Third-party Pi extensions register themselves by importing a small registration helper from `pi-graphify`:
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
import { registerGraphifyIntegration } from 'pi-graphify/integrations';
|
|
349
|
+
|
|
350
|
+
registerGraphifyIntegration({
|
|
351
|
+
name: 'pi-hermes-memory',
|
|
352
|
+
priority: 100,
|
|
353
|
+
isAvailable: (pi) => pi.getAllTools().some((t) => t.name === 'memory'),
|
|
354
|
+
onLesson: async (lesson) => {
|
|
355
|
+
// Save a durable memory entry
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
If no integrations are registered, the extension functions normally. This keeps the core lean and avoids hard dependencies.
|
|
361
|
+
|
|
362
|
+
### Built-in integration stubs
|
|
363
|
+
|
|
364
|
+
The extension ships with no built-in third-party integrations. It may include example adapters in a separate `examples/integrations/` directory to show how to build them.
|
|
365
|
+
|
|
366
|
+
### Future integration candidates
|
|
367
|
+
|
|
368
|
+
- `pi-hermes-memory`: save graph-derived lessons as memory entries.
|
|
369
|
+
- `pi-fallow`: cross-reference dead-code findings with graph communities.
|
|
370
|
+
- Custom provider extensions: route semantic extraction through the user’s configured provider.
|
|
371
|
+
|
|
372
|
+
These are explicitly out of scope for the initial implementation but are supported by the hook design.
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Module boundaries
|
|
377
|
+
|
|
378
|
+
- `extensions/` — Only Pi registration code. No business logic.
|
|
379
|
+
- `src/coordinator.ts` — The only place backend selection happens.
|
|
380
|
+
- `src/backends/` — Backend-specific code. No Pi imports.
|
|
381
|
+
- `src/tools/` — Tool definitions. Each tool calls the coordinator.
|
|
382
|
+
- `src/commands/` — Command definitions. Each command calls the coordinator.
|
|
383
|
+
- `src/config.ts` — Pure config loading. No Pi imports.
|
|
384
|
+
- `src/state.ts` — Session state.
|
|
385
|
+
- `src/watcher.ts` — File watcher.
|
|
386
|
+
- `src/version.ts` — Version detection and compatibility.
|
|
387
|
+
|
|
388
|
+
This separation makes the core logic testable without loading Pi.
|