@shog-lab/pi-toolkit 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/LICENSE +21 -0
- package/README.md +75 -0
- package/bin/init.js +100 -0
- package/dist/extensions/jimeng/index.d.ts +11 -0
- package/dist/extensions/jimeng/index.d.ts.map +1 -0
- package/dist/extensions/jimeng/index.js +130 -0
- package/dist/extensions/jimeng/index.js.map +1 -0
- package/dist/extensions/jimeng/package.json +12 -0
- package/dist/extensions/mcp-bridge/index.d.ts +29 -0
- package/dist/extensions/mcp-bridge/index.d.ts.map +1 -0
- package/dist/extensions/mcp-bridge/index.js +142 -0
- package/dist/extensions/mcp-bridge/index.js.map +1 -0
- package/dist/extensions/mcp-bridge/mcp-client.d.ts +49 -0
- package/dist/extensions/mcp-bridge/mcp-client.d.ts.map +1 -0
- package/dist/extensions/mcp-bridge/mcp-client.js +145 -0
- package/dist/extensions/mcp-bridge/mcp-client.js.map +1 -0
- package/dist/extensions/mcp-bridge/package.json +8 -0
- package/dist/extensions/subagent/index.d.ts +20 -0
- package/dist/extensions/subagent/index.d.ts.map +1 -0
- package/dist/extensions/subagent/index.js +118 -0
- package/dist/extensions/subagent/index.js.map +1 -0
- package/dist/extensions/subagent/package.json +8 -0
- package/dist/extensions/understand_image/index.d.ts +10 -0
- package/dist/extensions/understand_image/index.d.ts.map +1 -0
- package/dist/extensions/understand_image/index.js +159 -0
- package/dist/extensions/understand_image/index.js.map +1 -0
- package/dist/extensions/understand_image/package.json +9 -0
- package/dist/extensions/web_search/index.d.ts +8 -0
- package/dist/extensions/web_search/index.d.ts.map +1 -0
- package/dist/extensions/web_search/index.js +100 -0
- package/dist/extensions/web_search/index.js.map +1 -0
- package/dist/extensions/web_search/package.json +9 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 shog-lab
|
|
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,75 @@
|
|
|
1
|
+
# @shog-lab/pi-toolkit
|
|
2
|
+
|
|
3
|
+
**Common [pi-coding-agent](https://github.com/earendil-works/pi-coding-agent) extensions and CLI tools — plus an MCP server bridge.**
|
|
4
|
+
|
|
5
|
+
A drop-in package adding several commonly-used external tool integrations to any pi setup. Composes naturally with [`pi-mind`](https://github.com/shog-lab/pi-mind/tree/main/packages/memory) (memory).
|
|
6
|
+
|
|
7
|
+
## Extensions
|
|
8
|
+
|
|
9
|
+
| Extension | Tool name(s) | Backend | Required env |
|
|
10
|
+
|---|---|---|---|
|
|
11
|
+
| `jimeng` | `jimeng_generate` | Volcengine Jimeng T2I API | `JIMENG_ACCESS_KEY`, `JIMENG_SECRET_KEY` |
|
|
12
|
+
| `web_search` | `web_search` | mmx CLI | (mmx config) |
|
|
13
|
+
| `understand_image` | `understand_image` | mmx vision CLI | (mmx config) |
|
|
14
|
+
| `mcp-bridge` | `<server>_<tool>` per MCP server | Any MCP server | `mcp-servers.json` config |
|
|
15
|
+
| `subagent` | `spawn_subagent` | child pi process | (none) |
|
|
16
|
+
|
|
17
|
+
Each extension silently skips registration if its required env / config is missing — install pi-toolkit even if you only use some.
|
|
18
|
+
|
|
19
|
+
Plus `agent-browser` CLI is shipped as a dependency. Its SKILL.md is symlinked from upstream so the agent knows how to use it via Bash.
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm i -D @shog-lab/pi-toolkit
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`postinstall` symlinks `extensions/*/` into the host repo's `.pi/extensions/`, so pi auto-discovers them on next launch.
|
|
28
|
+
|
|
29
|
+
## Configure
|
|
30
|
+
|
|
31
|
+
### Jimeng (image generation)
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
export JIMENG_ACCESS_KEY="AKLT..."
|
|
35
|
+
export JIMENG_SECRET_KEY="..."
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### MCP servers (figma, filesystem, etc.)
|
|
39
|
+
|
|
40
|
+
Create `mcp-servers.json` (or `.pi/mcp-servers.json`) at the host repo root:
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"figma": {
|
|
45
|
+
"command": "npx",
|
|
46
|
+
"args": ["-y", "figma-developer-mcp", "--stdio"],
|
|
47
|
+
"env": { "FIGMA_API_KEY": "your-key" }
|
|
48
|
+
},
|
|
49
|
+
"filesystem": {
|
|
50
|
+
"command": "npx",
|
|
51
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/expose"]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
On next `pi` launch, `mcp-bridge`:
|
|
57
|
+
1. Spawns each declared server as a child process
|
|
58
|
+
2. Runs the MCP `initialize` handshake
|
|
59
|
+
3. Calls `tools/list` to discover tools
|
|
60
|
+
4. Registers each as a pi tool, prefixed with the server name: `figma_get_node`, `filesystem_read_file`, etc.
|
|
61
|
+
|
|
62
|
+
Failures (server not installed, bad config, missing env) log a warning and skip that server — they don't crash pi or other tools.
|
|
63
|
+
|
|
64
|
+
Find more MCP servers at <https://github.com/modelcontextprotocol/servers>.
|
|
65
|
+
|
|
66
|
+
## Use
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cd ~/my-repo
|
|
70
|
+
pi # all configured extensions/tools auto-loaded
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
MIT
|
package/bin/init.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* pi-toolkit postinstall: symlink extensions into the host repo's .pi/.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors pi-mind's init.js — uses $INIT_CWD to locate host root (works for
|
|
6
|
+
* symlinked / file: / workspace installs), then creates symlinks for each
|
|
7
|
+
* subdirectory under extensions/.
|
|
8
|
+
*
|
|
9
|
+
* Disable with PI_TOOLKIT_SKIP_INIT=1.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { existsSync, mkdirSync, readdirSync, readlinkSync, symlinkSync, unlinkSync, statSync } from "node:fs";
|
|
13
|
+
import { dirname, join, relative, resolve } from "node:path";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
import { createRequire } from "node:module";
|
|
16
|
+
|
|
17
|
+
const require = createRequire(import.meta.url);
|
|
18
|
+
|
|
19
|
+
if (process.env.PI_TOOLKIT_SKIP_INIT === "1") {
|
|
20
|
+
console.log("[pi-toolkit] init skipped (PI_TOOLKIT_SKIP_INIT=1)");
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
25
|
+
const PKG_ROOT = resolve(dirname(__filename), "..");
|
|
26
|
+
|
|
27
|
+
function findHostRoot() {
|
|
28
|
+
const initCwd = process.env.INIT_CWD;
|
|
29
|
+
if (initCwd && resolve(initCwd) !== PKG_ROOT) {
|
|
30
|
+
return resolve(initCwd);
|
|
31
|
+
}
|
|
32
|
+
let dir = resolve(PKG_ROOT);
|
|
33
|
+
while (dir !== "/" && dir !== ".") {
|
|
34
|
+
const parent = dirname(dir);
|
|
35
|
+
if (parent === dir) break;
|
|
36
|
+
if (parent.endsWith("/node_modules")) {
|
|
37
|
+
return dirname(parent);
|
|
38
|
+
}
|
|
39
|
+
dir = parent;
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const HOST_ROOT = findHostRoot();
|
|
45
|
+
if (!HOST_ROOT) {
|
|
46
|
+
console.log("[pi-toolkit] not installed in a host project (dev mode), skipping init");
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log(`[pi-toolkit] initializing in ${HOST_ROOT}`);
|
|
51
|
+
|
|
52
|
+
function ensureDir(p) {
|
|
53
|
+
if (!existsSync(p)) {
|
|
54
|
+
mkdirSync(p, { recursive: true });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function linkInto(srcDir, destDir) {
|
|
59
|
+
if (!existsSync(srcDir)) return;
|
|
60
|
+
ensureDir(destDir);
|
|
61
|
+
for (const name of readdirSync(srcDir)) {
|
|
62
|
+
const src = join(srcDir, name);
|
|
63
|
+
if (!statSync(src).isDirectory()) continue;
|
|
64
|
+
const dest = join(destDir, name);
|
|
65
|
+
const relSrc = relative(destDir, src);
|
|
66
|
+
|
|
67
|
+
if (existsSync(dest)) {
|
|
68
|
+
try {
|
|
69
|
+
const current = readlinkSync(dest);
|
|
70
|
+
if (current === relSrc) continue;
|
|
71
|
+
unlinkSync(dest);
|
|
72
|
+
} catch {
|
|
73
|
+
console.log(`[pi-toolkit] skip ${relative(HOST_ROOT, dest)} (already exists, not managed by pi-toolkit)`);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
symlinkSync(relSrc, dest);
|
|
78
|
+
console.log(`[pi-toolkit] linked ${relative(HOST_ROOT, dest)} → ${relSrc}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Extensions are TypeScript-compiled — symlink to dist/extensions where pi
|
|
83
|
+
// loads from .js (no .ts source siblings to confuse it).
|
|
84
|
+
linkInto(join(PKG_ROOT, "dist", "extensions"), join(HOST_ROOT, ".pi", "extensions"));
|
|
85
|
+
|
|
86
|
+
// agent-browser ships its own SKILL.md describing the CLI to the agent.
|
|
87
|
+
// Symlink upstream (so `npm update agent-browser` auto-refreshes the skill)
|
|
88
|
+
// instead of vendoring our own copy.
|
|
89
|
+
try {
|
|
90
|
+
const abPkg = require.resolve("agent-browser/package.json");
|
|
91
|
+
const abSkillsDir = join(dirname(abPkg), "skills");
|
|
92
|
+
if (existsSync(abSkillsDir)) {
|
|
93
|
+
linkInto(abSkillsDir, join(HOST_ROOT, ".pi", "skills"));
|
|
94
|
+
}
|
|
95
|
+
} catch {
|
|
96
|
+
// agent-browser isn't installed — shouldn't happen since it's a dependency,
|
|
97
|
+
// but don't break postinstall over it.
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log(`[pi-toolkit] ready.`);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jimeng (即梦) Image Generation Extension for pi-coding-agent
|
|
3
|
+
*
|
|
4
|
+
* Registers a `jimeng_generate` tool that generates images via
|
|
5
|
+
* Volcengine's Jimeng T2I API (text-to-image).
|
|
6
|
+
*
|
|
7
|
+
* Requires JIMENG_ACCESS_KEY and JIMENG_SECRET_KEY environment variables.
|
|
8
|
+
*/
|
|
9
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
10
|
+
export default function jimengExtension(pi: ExtensionAPI): void;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../extensions/jimeng/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAwDpE,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EAAE,EAAE,YAAY,QA6GvD"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jimeng (即梦) Image Generation Extension for pi-coding-agent
|
|
3
|
+
*
|
|
4
|
+
* Registers a `jimeng_generate` tool that generates images via
|
|
5
|
+
* Volcengine's Jimeng T2I API (text-to-image).
|
|
6
|
+
*
|
|
7
|
+
* Requires JIMENG_ACCESS_KEY and JIMENG_SECRET_KEY environment variables.
|
|
8
|
+
*/
|
|
9
|
+
import { Type } from "@sinclair/typebox";
|
|
10
|
+
import { Signer } from "@volcengine/openapi";
|
|
11
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { dirname, join } from "node:path";
|
|
13
|
+
const API_HOST = "visual.volcengineapi.com";
|
|
14
|
+
const API_VERSION = "2022-08-31";
|
|
15
|
+
const MODEL_KEY = "jimeng_t2i_v40";
|
|
16
|
+
const MAX_POLL_ATTEMPTS = 60;
|
|
17
|
+
const POLL_INTERVAL_MS = 2000;
|
|
18
|
+
function signRequest(accessKey, secretKey, action, body) {
|
|
19
|
+
const requestData = {
|
|
20
|
+
method: "POST",
|
|
21
|
+
region: "cn-north-1",
|
|
22
|
+
params: { Action: action, Version: API_VERSION },
|
|
23
|
+
headers: {
|
|
24
|
+
"Content-Type": "application/json",
|
|
25
|
+
Host: API_HOST,
|
|
26
|
+
},
|
|
27
|
+
body,
|
|
28
|
+
};
|
|
29
|
+
const signer = new Signer(requestData, "cv");
|
|
30
|
+
signer.addAuthorization({ accessKeyId: accessKey, secretKey });
|
|
31
|
+
return requestData.headers;
|
|
32
|
+
}
|
|
33
|
+
async function apiCall(accessKey, secretKey, action, body) {
|
|
34
|
+
const headers = signRequest(accessKey, secretKey, action, body);
|
|
35
|
+
const url = `https://${API_HOST}/?Action=${action}&Version=${API_VERSION}`;
|
|
36
|
+
const res = await fetch(url, { method: "POST", headers, body });
|
|
37
|
+
if (!res.ok)
|
|
38
|
+
throw new Error(`Jimeng API error: ${res.status}`);
|
|
39
|
+
return (await res.json());
|
|
40
|
+
}
|
|
41
|
+
export default function jimengExtension(pi) {
|
|
42
|
+
const accessKey = process.env.JIMENG_ACCESS_KEY;
|
|
43
|
+
const secretKey = process.env.JIMENG_SECRET_KEY;
|
|
44
|
+
if (!accessKey || !secretKey) {
|
|
45
|
+
// Silently skip if not configured
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
pi.registerTool({
|
|
49
|
+
name: "jimeng_generate",
|
|
50
|
+
label: "Jimeng Image",
|
|
51
|
+
description: "Generate an image from a text prompt using Jimeng (即梦) AI. Returns the file path of the generated image.",
|
|
52
|
+
promptSnippet: "Generate AI images from text descriptions (Chinese prompts work best)",
|
|
53
|
+
parameters: Type.Object({
|
|
54
|
+
prompt: Type.String({ description: "Image description (Chinese recommended for best results)" }),
|
|
55
|
+
width: Type.Optional(Type.Number({ description: "Image width in pixels (default: 1024)" })),
|
|
56
|
+
height: Type.Optional(Type.Number({ description: "Image height in pixels (default: 1024)" })),
|
|
57
|
+
filename: Type.Optional(Type.String({ description: "Output filename (default: jimeng-{timestamp}.png)" })),
|
|
58
|
+
}),
|
|
59
|
+
async execute(_toolCallId, params, signal, onUpdate) {
|
|
60
|
+
const width = params.width || 1024;
|
|
61
|
+
const height = params.height || 1024;
|
|
62
|
+
const filename = params.filename || `jimeng-${Date.now()}.png`;
|
|
63
|
+
const outputPath = join(process.env.PI_MIND_DIR || (process.cwd() + "/.pi-mind"), filename);
|
|
64
|
+
// Step 1: Submit task
|
|
65
|
+
onUpdate?.({ content: [{ type: "text", text: "提交生成任务..." }] });
|
|
66
|
+
const submitBody = JSON.stringify({
|
|
67
|
+
req_key: MODEL_KEY,
|
|
68
|
+
prompt: params.prompt,
|
|
69
|
+
width,
|
|
70
|
+
height,
|
|
71
|
+
scale: 0.5,
|
|
72
|
+
force_single: true,
|
|
73
|
+
});
|
|
74
|
+
const submitResult = await apiCall(accessKey, secretKey, "CVSync2AsyncSubmitTask", submitBody);
|
|
75
|
+
if (submitResult.code !== 10000) {
|
|
76
|
+
return { content: [{ type: "text", text: `生成失败: ${submitResult.message || "Unknown error"}` }] };
|
|
77
|
+
}
|
|
78
|
+
const taskId = submitResult.data?.task_id;
|
|
79
|
+
if (!taskId) {
|
|
80
|
+
return { content: [{ type: "text", text: "生成失败: 未返回 task_id" }] };
|
|
81
|
+
}
|
|
82
|
+
// Step 2: Poll for result
|
|
83
|
+
for (let attempt = 0; attempt < MAX_POLL_ATTEMPTS; attempt++) {
|
|
84
|
+
if (signal?.aborted) {
|
|
85
|
+
return { content: [{ type: "text", text: "已取消" }] };
|
|
86
|
+
}
|
|
87
|
+
const queryBody = JSON.stringify({
|
|
88
|
+
req_key: MODEL_KEY,
|
|
89
|
+
task_id: taskId,
|
|
90
|
+
req_json: JSON.stringify({ return_url: true, logo_info: { add_logo: false } }),
|
|
91
|
+
});
|
|
92
|
+
const result = await apiCall(accessKey, secretKey, "CVSync2AsyncGetResult", queryBody);
|
|
93
|
+
if (result.code === 10000) {
|
|
94
|
+
const status = result.data?.status;
|
|
95
|
+
if (status === "done") {
|
|
96
|
+
const urls = result.data?.image_urls;
|
|
97
|
+
if (!urls?.length) {
|
|
98
|
+
return { content: [{ type: "text", text: "生成完成但未返回图片 URL" }] };
|
|
99
|
+
}
|
|
100
|
+
// Step 3: Download image
|
|
101
|
+
onUpdate?.({ content: [{ type: "text", text: "下载图片..." }] });
|
|
102
|
+
const imgRes = await fetch(urls[0]);
|
|
103
|
+
if (!imgRes.ok) {
|
|
104
|
+
return { content: [{ type: "text", text: `图片下载失败: ${imgRes.status}` }] };
|
|
105
|
+
}
|
|
106
|
+
const buffer = Buffer.from(await imgRes.arrayBuffer());
|
|
107
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
108
|
+
writeFileSync(outputPath, buffer);
|
|
109
|
+
return {
|
|
110
|
+
content: [{ type: "text", text: `图片已生成并保存到 ${outputPath} (${width}x${height}, ${buffer.length} bytes)。\n图片URL: ${urls[0]}\n请使用 send_image 工具将图片发送给用户。` }],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (status === "not_found" || status === "expired") {
|
|
114
|
+
return { content: [{ type: "text", text: `生成失败: 任务 ${status}` }] };
|
|
115
|
+
}
|
|
116
|
+
// Still generating
|
|
117
|
+
if (attempt % 5 === 0) {
|
|
118
|
+
onUpdate?.({ content: [{ type: "text", text: `生成中... (${attempt * 2}s)` }] });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
return { content: [{ type: "text", text: `查询失败: ${result.message || "Unknown error"}` }] };
|
|
123
|
+
}
|
|
124
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
125
|
+
}
|
|
126
|
+
return { content: [{ type: "text", text: "生成超时(120s)" }] };
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../extensions/jimeng/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shog-lab/pi-toolkit-jimeng",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "Jimeng (即梦) image generation via Volcengine API.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "index.js",
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"@volcengine/openapi": "^1.0.0",
|
|
10
|
+
"@sinclair/typebox": "^0.34.0"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-toolkit MCP Bridge — connect pi to any MCP server.
|
|
3
|
+
*
|
|
4
|
+
* Reads `mcp-servers.json` from the host repo (or `.pi/mcp-servers.json`),
|
|
5
|
+
* spawns each declared server, discovers its tools via the MCP protocol,
|
|
6
|
+
* and re-registers each as a pi tool prefixed with the server name to
|
|
7
|
+
* avoid collisions.
|
|
8
|
+
*
|
|
9
|
+
* Config example:
|
|
10
|
+
*
|
|
11
|
+
* {
|
|
12
|
+
* "figma": {
|
|
13
|
+
* "command": "npx",
|
|
14
|
+
* "args": ["-y", "figma-developer-mcp", "--stdio"],
|
|
15
|
+
* "env": { "FIGMA_API_KEY": "..." }
|
|
16
|
+
* },
|
|
17
|
+
* "filesystem": {
|
|
18
|
+
* "command": "npx",
|
|
19
|
+
* "args": ["-y", "@modelcontextprotocol/server-filesystem", "/some/dir"]
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* Pi sees tools like `figma_get_file`, `figma_get_node`, etc.
|
|
24
|
+
*
|
|
25
|
+
* No config file → silent no-op. Bridge is opt-in per repo.
|
|
26
|
+
*/
|
|
27
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
28
|
+
export default function mcpBridgeExtension(pi: ExtensionAPI): void;
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../extensions/mcp-bridge/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAmGpE,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAoBjE"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-toolkit MCP Bridge — connect pi to any MCP server.
|
|
3
|
+
*
|
|
4
|
+
* Reads `mcp-servers.json` from the host repo (or `.pi/mcp-servers.json`),
|
|
5
|
+
* spawns each declared server, discovers its tools via the MCP protocol,
|
|
6
|
+
* and re-registers each as a pi tool prefixed with the server name to
|
|
7
|
+
* avoid collisions.
|
|
8
|
+
*
|
|
9
|
+
* Config example:
|
|
10
|
+
*
|
|
11
|
+
* {
|
|
12
|
+
* "figma": {
|
|
13
|
+
* "command": "npx",
|
|
14
|
+
* "args": ["-y", "figma-developer-mcp", "--stdio"],
|
|
15
|
+
* "env": { "FIGMA_API_KEY": "..." }
|
|
16
|
+
* },
|
|
17
|
+
* "filesystem": {
|
|
18
|
+
* "command": "npx",
|
|
19
|
+
* "args": ["-y", "@modelcontextprotocol/server-filesystem", "/some/dir"]
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* Pi sees tools like `figma_get_file`, `figma_get_node`, etc.
|
|
24
|
+
*
|
|
25
|
+
* No config file → silent no-op. Bridge is opt-in per repo.
|
|
26
|
+
*/
|
|
27
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
28
|
+
import { join } from "node:path";
|
|
29
|
+
import { McpClient } from "./mcp-client.js";
|
|
30
|
+
const CONFIG_FILENAMES = [
|
|
31
|
+
".pi/mcp-servers.json",
|
|
32
|
+
"mcp-servers.json",
|
|
33
|
+
];
|
|
34
|
+
function loadConfig() {
|
|
35
|
+
for (const filename of CONFIG_FILENAMES) {
|
|
36
|
+
const path = join(process.cwd(), filename);
|
|
37
|
+
if (!existsSync(path))
|
|
38
|
+
continue;
|
|
39
|
+
try {
|
|
40
|
+
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
41
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
42
|
+
return parsed;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
console.warn(`[mcp-bridge] failed to parse ${path}: ${e instanceof Error ? e.message : e}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
function registerMcpTool(pi, client, tool) {
|
|
52
|
+
const piToolName = `${client.serverName}_${tool.name}`;
|
|
53
|
+
pi.registerTool({
|
|
54
|
+
name: piToolName,
|
|
55
|
+
label: `${client.serverName}: ${tool.name}`,
|
|
56
|
+
description: tool.description || `MCP tool ${tool.name} from ${client.serverName}`,
|
|
57
|
+
parameters: tool.inputSchema,
|
|
58
|
+
async execute(_id, args) {
|
|
59
|
+
try {
|
|
60
|
+
const result = await client.callTool(tool.name, args ?? {});
|
|
61
|
+
const text = (result.content ?? [])
|
|
62
|
+
.map((c) => {
|
|
63
|
+
if (c.type === "text")
|
|
64
|
+
return c.text ?? "";
|
|
65
|
+
if (c.type === "image")
|
|
66
|
+
return `[image ${c.mimeType ?? ""}]`;
|
|
67
|
+
if (c.type === "resource")
|
|
68
|
+
return `[resource]`;
|
|
69
|
+
return `[${c.type}]`;
|
|
70
|
+
})
|
|
71
|
+
.filter(Boolean)
|
|
72
|
+
.join("\n");
|
|
73
|
+
return {
|
|
74
|
+
content: [{ type: "text", text: text || "(empty result)" }],
|
|
75
|
+
details: {},
|
|
76
|
+
isError: result.isError ?? false,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
81
|
+
return {
|
|
82
|
+
content: [{ type: "text", text: `MCP call failed: ${msg}` }],
|
|
83
|
+
details: {},
|
|
84
|
+
isError: true,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
async function connectAndRegister(pi, serverName, serverConfig) {
|
|
91
|
+
const client = new McpClient(serverName, serverConfig);
|
|
92
|
+
try {
|
|
93
|
+
const tools = await client.listTools();
|
|
94
|
+
for (const tool of tools) {
|
|
95
|
+
registerMcpTool(pi, client, tool);
|
|
96
|
+
}
|
|
97
|
+
console.log(`[mcp-bridge] connected to "${serverName}" — registered ${tools.length} tool(s)`);
|
|
98
|
+
return client;
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
102
|
+
console.warn(`[mcp-bridge] failed to connect to "${serverName}": ${msg}`);
|
|
103
|
+
client.close();
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const activeClients = [];
|
|
108
|
+
function attachCleanupHandlers() {
|
|
109
|
+
const cleanup = () => {
|
|
110
|
+
for (const client of activeClients) {
|
|
111
|
+
try {
|
|
112
|
+
client.close();
|
|
113
|
+
}
|
|
114
|
+
catch { /* ignore */ }
|
|
115
|
+
}
|
|
116
|
+
activeClients.length = 0;
|
|
117
|
+
};
|
|
118
|
+
process.once("exit", cleanup);
|
|
119
|
+
process.once("SIGINT", () => { cleanup(); process.exit(130); });
|
|
120
|
+
process.once("SIGTERM", () => { cleanup(); process.exit(143); });
|
|
121
|
+
}
|
|
122
|
+
export default function mcpBridgeExtension(pi) {
|
|
123
|
+
const config = loadConfig();
|
|
124
|
+
if (!config || Object.keys(config).length === 0) {
|
|
125
|
+
// No config or empty config — bridge does nothing
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
attachCleanupHandlers();
|
|
129
|
+
// Fire-and-forget connect each server. Tools register asynchronously as each handshake completes.
|
|
130
|
+
// Pi's tool registry is mutable at runtime, so late additions are fine — they appear on the next agent turn.
|
|
131
|
+
for (const [serverName, serverConfig] of Object.entries(config)) {
|
|
132
|
+
connectAndRegister(pi, serverName, serverConfig)
|
|
133
|
+
.then((client) => {
|
|
134
|
+
if (client)
|
|
135
|
+
activeClients.push(client);
|
|
136
|
+
})
|
|
137
|
+
.catch((e) => {
|
|
138
|
+
console.warn(`[mcp-bridge] unexpected error for "${serverName}":`, e);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../extensions/mcp-bridge/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal MCP (Model Context Protocol) stdio JSON-RPC client.
|
|
3
|
+
*
|
|
4
|
+
* Spawns an MCP server as a child process, performs the initialize handshake,
|
|
5
|
+
* and exposes tools/list + tools/call.
|
|
6
|
+
*
|
|
7
|
+
* MCP spec: https://spec.modelcontextprotocol.io/
|
|
8
|
+
*/
|
|
9
|
+
export interface McpServerConfig {
|
|
10
|
+
command: string;
|
|
11
|
+
args?: string[];
|
|
12
|
+
env?: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
export interface McpTool {
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
inputSchema: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export interface McpContent {
|
|
20
|
+
type: "text" | "image" | "resource";
|
|
21
|
+
text?: string;
|
|
22
|
+
data?: string;
|
|
23
|
+
mimeType?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface McpToolResult {
|
|
26
|
+
content: McpContent[];
|
|
27
|
+
isError?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare class McpClient {
|
|
30
|
+
private proc;
|
|
31
|
+
private nextId;
|
|
32
|
+
private pending;
|
|
33
|
+
private stdoutBuffer;
|
|
34
|
+
private initialized;
|
|
35
|
+
private closed;
|
|
36
|
+
private initializePromise;
|
|
37
|
+
readonly serverName: string;
|
|
38
|
+
constructor(serverName: string, config: McpServerConfig);
|
|
39
|
+
/** Run the MCP initialize handshake. Idempotent — multiple callers share one in-flight promise. */
|
|
40
|
+
initialize(): Promise<void>;
|
|
41
|
+
listTools(): Promise<McpTool[]>;
|
|
42
|
+
callTool(name: string, args: Record<string, unknown>): Promise<McpToolResult>;
|
|
43
|
+
close(): void;
|
|
44
|
+
private send;
|
|
45
|
+
private notify;
|
|
46
|
+
private onStdout;
|
|
47
|
+
private failAll;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=mcp-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-client.d.ts","sourceRoot":"","sources":["../../../extensions/mcp-bridge/mcp-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAkBH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAMD,qBAAa,SAAS;IACpB,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAIV;IACL,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,iBAAiB,CAA8B;IACvD,SAAgB,UAAU,EAAE,MAAM,CAAC;gBAEvB,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe;IAsBvD,mGAAmG;IACnG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAerB,SAAS,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAM/B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC;IAMnF,KAAK,IAAI,IAAI;IAWb,OAAO,CAAC,IAAI;IAmBZ,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,QAAQ;IA6BhB,OAAO,CAAC,OAAO;CAOhB"}
|