@dex-ai/pi-compat 0.1.2
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/.changeset/config.json +11 -0
- package/.github/workflows/release.yml +42 -0
- package/README.md +142 -0
- package/bun.lock +38 -0
- package/package.json +32 -0
- package/src/adapter.ts +618 -0
- package/src/event-map.ts +64 -0
- package/src/index.ts +40 -0
- package/src/loader.ts +314 -0
- package/src/schema-convert.ts +214 -0
- package/src/shim-api.ts +263 -0
- package/tests/integration.test.ts +102 -0
- package/tests/loader.test.ts +55 -0
- package/tests/schema-convert.test.ts +177 -0
- package/tests/shim-api.test.ts +104 -0
- package/tests/status-bar.test.ts +63 -0
- package/tsconfig.json +22 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
|
|
3
|
+
"changelog": "@changesets/cli/changelog",
|
|
4
|
+
"commit": false,
|
|
5
|
+
"fixed": [],
|
|
6
|
+
"linked": [],
|
|
7
|
+
"access": "public",
|
|
8
|
+
"baseBranch": "main",
|
|
9
|
+
"updateInternalDependencies": "patch",
|
|
10
|
+
"ignore": []
|
|
11
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
release:
|
|
12
|
+
name: Release
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
permissions:
|
|
15
|
+
contents: write
|
|
16
|
+
pull-requests: write
|
|
17
|
+
id-token: write
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- uses: oven-sh/setup-bun@v2
|
|
22
|
+
with:
|
|
23
|
+
bun-version: latest
|
|
24
|
+
|
|
25
|
+
- uses: actions/setup-node@v4
|
|
26
|
+
with:
|
|
27
|
+
node-version: "22.x"
|
|
28
|
+
registry-url: "https://registry.npmjs.org"
|
|
29
|
+
|
|
30
|
+
- run: bun install
|
|
31
|
+
|
|
32
|
+
- name: Create Release Pull Request or Publish
|
|
33
|
+
id: changesets
|
|
34
|
+
uses: changesets/action@v1
|
|
35
|
+
with:
|
|
36
|
+
publish: bun run release
|
|
37
|
+
version: bun run version
|
|
38
|
+
env:
|
|
39
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
40
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
41
|
+
NPM_CONFIG_PROVENANCE: true
|
|
42
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# @dex-ai/pi-compat
|
|
2
|
+
|
|
3
|
+
Pi extension compatibility layer — load and run [pi-coding-agent](https://github.com/nicobailon/pi-coding-agent) extensions inside Dex.
|
|
4
|
+
|
|
5
|
+
## What This Does
|
|
6
|
+
|
|
7
|
+
Pi has a mature extension ecosystem with powerful tools like:
|
|
8
|
+
- **pi-lens** — LSP + AST-grep code intelligence
|
|
9
|
+
- **pi-subagents** — Multi-agent delegation
|
|
10
|
+
- **pi-mcp-adapter** — MCP server integration
|
|
11
|
+
- **pi-intercom** — Inter-session communication
|
|
12
|
+
- **@samfp/pi-memory** — Persistent memory with consolidation
|
|
13
|
+
|
|
14
|
+
This package lets you use those extensions in Dex without rewriting them. It creates a shim `ExtensionAPI` that captures Pi's imperative registrations (tools, event handlers, skills) and maps them to Dex's declarative Extension interface.
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { piCompatExtension } from '@dex-ai/pi-compat';
|
|
20
|
+
import { Agent } from '@dex-ai/sdk';
|
|
21
|
+
|
|
22
|
+
const agent = await Agent.create({
|
|
23
|
+
extensions: [
|
|
24
|
+
// Load pi-lens (globally installed)
|
|
25
|
+
await piCompatExtension({ packages: ['pi-lens'] }),
|
|
26
|
+
|
|
27
|
+
// Load multiple Pi extensions at once
|
|
28
|
+
await piCompatExtension({
|
|
29
|
+
packages: ['pi-lens', '@samfp/pi-memory'],
|
|
30
|
+
flags: { 'lens-lsp': true },
|
|
31
|
+
}),
|
|
32
|
+
|
|
33
|
+
// Load from a path
|
|
34
|
+
await piCompatExtension({
|
|
35
|
+
paths: ['~/.pi/agent/extensions/my-extension'],
|
|
36
|
+
}),
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## How It Works
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
┌─────────────────────┐ ┌─────────────────────┐ ┌──────────────────┐
|
|
45
|
+
│ Pi Extension │ │ pi-compat shim │ │ Dex Extension │
|
|
46
|
+
│ │ │ │ │ │
|
|
47
|
+
│ pi.registerTool() │────▶│ captures → converts │────▶│ ext.tools[] │
|
|
48
|
+
│ pi.on("event") │────▶│ maps event names │────▶│ ext.on.{event} │
|
|
49
|
+
│ pi.exec() │────▶│ child_process.spawn │ │ (functional) │
|
|
50
|
+
│ pi.registerFlag() │────▶│ flag → env/config │────▶│ ext.config │
|
|
51
|
+
│ skills/ directory │────▶│ loads SKILL.md files │────▶│ ext.skills[] │
|
|
52
|
+
│ │ │ │ │ │
|
|
53
|
+
│ pi.registerShortcut │────▶│ (no-op) │ │ │
|
|
54
|
+
│ ctx.ui.* │────▶│ (no-op stubs) │ │ │
|
|
55
|
+
│ pi.registerProvider │────▶│ (no-op) │ │ │
|
|
56
|
+
└─────────────────────┘ └─────────────────────┘ └──────────────────┘
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Architecture Translation
|
|
60
|
+
|
|
61
|
+
| Pi Concept | Dex Equivalent | Status |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `pi.registerTool({ name, parameters: Type.Object(...), execute })` | `ext.tools: [{ name, parameters: z.object(...), execute }]` | ✅ Mapped (TypeBox → Zod) |
|
|
64
|
+
| `pi.on("session_start", handler)` | `ext.on: { 'session-start': handler }` | ✅ Mapped |
|
|
65
|
+
| `pi.on("tool_call", handler)` | `ext.on: { 'tool-start': handler }` | ✅ Mapped |
|
|
66
|
+
| `pi.on("tool_result", handler)` | `ext.on: { 'tool-stop': handler }` | ✅ Mapped |
|
|
67
|
+
| `pi.on("agent_end", handler)` | `ext.on: { 'generate-stop': handler }` | ✅ Mapped |
|
|
68
|
+
| `pi.on("turn_start/end")` | `ext.on: { 'model-start/stop' }` | ✅ Mapped |
|
|
69
|
+
| `pi.exec(cmd, args)` | `child_process.spawn()` | ✅ Functional |
|
|
70
|
+
| `pi.registerFlag(name, opts)` | `opts.flags` on piCompatExtension | ✅ Via options |
|
|
71
|
+
| Skills (`package.json "pi".skills`) | `ext.skills[]` (loaded from SKILL.md) | ✅ Loaded |
|
|
72
|
+
| `pi.registerCommand()` | (captured, not exposed) | ⚠️ Captured only |
|
|
73
|
+
| `pi.registerShortcut()` | — | ❌ No-op |
|
|
74
|
+
| `pi.registerProvider()` | — | ❌ No-op |
|
|
75
|
+
| `pi.sendMessage()` | — | ❌ No-op |
|
|
76
|
+
| `ctx.ui.*` | — | ❌ No-op stubs |
|
|
77
|
+
|
|
78
|
+
## Event Mapping
|
|
79
|
+
|
|
80
|
+
| Pi Event | Dex Event | Notes |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| `session_start` | `session-start` | Fires on agent init |
|
|
83
|
+
| `session_shutdown` | `session-stop` | Fires on agent dispose |
|
|
84
|
+
| `before_agent_start` | `generate-start` | Before each generate() |
|
|
85
|
+
| `agent_end` | `generate-stop` | After each generate() |
|
|
86
|
+
| `turn_start` | `model-start` | Before each LLM call |
|
|
87
|
+
| `turn_end` | `model-stop` | After each LLM call |
|
|
88
|
+
| `tool_call` | `tool-start` | Before tool execution (can block) |
|
|
89
|
+
| `tool_result` | `tool-stop` | After tool execution (can modify) |
|
|
90
|
+
| `context` | `generate-input` | Context injection |
|
|
91
|
+
|
|
92
|
+
## Prerequisites
|
|
93
|
+
|
|
94
|
+
Pi extensions must be installed globally (or locally) with their dependencies:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Install pi extensions
|
|
98
|
+
npm install -g pi-lens @samfp/pi-memory pi-subagents
|
|
99
|
+
|
|
100
|
+
# The pi-coding-agent core package must also be installed
|
|
101
|
+
# (pi extensions peer-depend on it for types)
|
|
102
|
+
npm install -g @earendil-works/pi-coding-agent
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Configuration via Flags
|
|
106
|
+
|
|
107
|
+
Pi extensions use `registerFlag()` / `getFlag()` for configuration. Pass flag values via the `flags` option:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
await piCompatExtension({
|
|
111
|
+
packages: ['pi-lens'],
|
|
112
|
+
flags: {
|
|
113
|
+
'lens-lsp': true, // Enable LSP features
|
|
114
|
+
'lens-guard': true, // Enable git guard
|
|
115
|
+
'lens-verbose': false, // Disable verbose logging
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Limitations
|
|
121
|
+
|
|
122
|
+
1. **No UI** — Pi's rich TUI features (overlays, widgets, custom footer) are no-ops. Extensions that are purely UI-focused (pi-powerline-footer) won't provide value.
|
|
123
|
+
|
|
124
|
+
2. **Event fidelity** — Some Pi events have no direct Dex equivalent. Extensions relying heavily on `message_start/update/end`, `before_provider_request`, or `input` events will have those handlers silently ignored.
|
|
125
|
+
|
|
126
|
+
3. **TypeBox → Zod** — Schema conversion is best-effort. Complex TypeBox features (discriminated unions with `$ref`, conditional schemas) may fall back to `z.any()`.
|
|
127
|
+
|
|
128
|
+
4. **No message injection** — Pi's `sendMessage()` / `sendUserMessage()` for steering mid-generation isn't mapped. Extensions that inject messages won't function for that capability.
|
|
129
|
+
|
|
130
|
+
5. **Single provider** — Pi's `registerProvider()` is a no-op. Extensions that add custom providers won't contribute models.
|
|
131
|
+
|
|
132
|
+
## Development
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
bun install
|
|
136
|
+
bun run typecheck
|
|
137
|
+
bun test
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## License
|
|
141
|
+
|
|
142
|
+
MIT
|
package/bun.lock
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"configVersion": 1,
|
|
4
|
+
"workspaces": {
|
|
5
|
+
"": {
|
|
6
|
+
"name": "@dex-ai/pi-compat",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"jiti": "^2.7.0",
|
|
9
|
+
"typebox": "^1.1.24",
|
|
10
|
+
"zod": "^3.24.4",
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@dex-ai/sdk": "file:../dex-ai-sdk",
|
|
14
|
+
"@types/bun": "^1.0.0",
|
|
15
|
+
"typescript": "^5.6.3",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
"packages": {
|
|
20
|
+
"@dex-ai/sdk": ["@dex-ai/sdk@file:../dex-ai-sdk", { "devDependencies": { "@types/bun": "latest", "bun-types": "^1.3.14", "typescript": "^5.6.3" } }],
|
|
21
|
+
|
|
22
|
+
"@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
|
|
23
|
+
|
|
24
|
+
"@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="],
|
|
25
|
+
|
|
26
|
+
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
|
|
27
|
+
|
|
28
|
+
"jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="],
|
|
29
|
+
|
|
30
|
+
"typebox": ["typebox@1.1.38", "", {}, "sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA=="],
|
|
31
|
+
|
|
32
|
+
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
|
33
|
+
|
|
34
|
+
"undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="],
|
|
35
|
+
|
|
36
|
+
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
|
37
|
+
}
|
|
38
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dex-ai/pi-compat",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Pi extension compatibility layer — load and run pi-coding-agent extensions inside Dex",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.ts"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"typecheck": "tsc --noEmit",
|
|
12
|
+
"test": "bun test",
|
|
13
|
+
"changeset": "changeset",
|
|
14
|
+
"version": "changeset version",
|
|
15
|
+
"release": "changeset publish"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"jiti": "^2.7.0",
|
|
19
|
+
"typebox": "^1.1.24",
|
|
20
|
+
"zod": "^3.24.4"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@dex-ai/sdk": "^0.1.2",
|
|
24
|
+
"typescript": "^5.6.3",
|
|
25
|
+
"@types/bun": "^1.0.0",
|
|
26
|
+
"@changesets/cli": "^2.29.0"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public",
|
|
30
|
+
"registry": "https://registry.npmjs.org/"
|
|
31
|
+
}
|
|
32
|
+
}
|