pi-lean-ctx 1.0.8 → 3.0.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/README.md +110 -8
- package/extensions/index.ts +45 -13
- package/extensions/mcp-bridge.ts +215 -0
- package/extensions/types.ts +13 -0
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# pi-lean-ctx
|
|
2
2
|
|
|
3
|
-
[Pi Coding Agent](https://github.com/badlogic/pi-mono) extension
|
|
3
|
+
[Pi Coding Agent](https://github.com/badlogic/pi-mono) extension with **first-class MCP support** — routes all tool output through [lean-ctx](https://leanctx.com) for **60–90% token savings** and exposes **34 MCP tools** natively in Pi.
|
|
4
4
|
|
|
5
5
|
## What it does
|
|
6
6
|
|
|
7
|
+
### Built-in Tool Overrides (CLI)
|
|
8
|
+
|
|
7
9
|
Overrides Pi's built-in tools to route them through `lean-ctx`:
|
|
8
10
|
|
|
9
11
|
| Tool | Compression |
|
|
@@ -14,6 +16,44 @@ Overrides Pi's built-in tools to route them through `lean-ctx`:
|
|
|
14
16
|
| `find` | File listings compressed and .gitignore-aware |
|
|
15
17
|
| `ls` | Directory output compressed |
|
|
16
18
|
|
|
19
|
+
### MCP Tools (Embedded Bridge)
|
|
20
|
+
|
|
21
|
+
Additionally, pi-lean-ctx spawns lean-ctx as an MCP server and registers all advanced tools directly in Pi:
|
|
22
|
+
|
|
23
|
+
| Tool | Purpose |
|
|
24
|
+
|------|---------|
|
|
25
|
+
| `ctx_session` | Session state management and persistence |
|
|
26
|
+
| `ctx_knowledge` | Project knowledge graph with temporal validity |
|
|
27
|
+
| `ctx_semantic_search` | Find code by meaning, not exact text |
|
|
28
|
+
| `ctx_overview` | Codebase overview and architecture analysis |
|
|
29
|
+
| `ctx_compress` | Manual compression control |
|
|
30
|
+
| `ctx_metrics` | Token savings dashboard |
|
|
31
|
+
| `ctx_agent` | Multi-agent coordination and handoffs |
|
|
32
|
+
| `ctx_graph` | Dependency graph analysis |
|
|
33
|
+
| `ctx_discover` | Smart code discovery |
|
|
34
|
+
| `ctx_context` | Context window management |
|
|
35
|
+
| `ctx_preload` | Predictive file preloading |
|
|
36
|
+
| `ctx_delta` | Changed-lines-only reads |
|
|
37
|
+
| `ctx_edit` | Read-modify-write in one call |
|
|
38
|
+
| `ctx_dedup` | Duplicate context elimination |
|
|
39
|
+
| `ctx_fill` | Budget-aware context filling |
|
|
40
|
+
| `ctx_intent` | Intent-based task routing |
|
|
41
|
+
| `ctx_response` | Response optimization |
|
|
42
|
+
| `ctx_wrapped` | Wrapped command execution |
|
|
43
|
+
| `ctx_benchmark` | Compression benchmarking |
|
|
44
|
+
| `ctx_analyze` | Code analysis |
|
|
45
|
+
| `ctx_cache` | Cache management |
|
|
46
|
+
| `ctx_execute` | Direct command execution |
|
|
47
|
+
| `ctx_impact` | Reverse dependency analysis |
|
|
48
|
+
| `ctx_architecture` | Project architecture map |
|
|
49
|
+
| `ctx_heatmap` | File access heatmap |
|
|
50
|
+
| `ctx_task` | Task management |
|
|
51
|
+
| `ctx_cost` | Cost attribution tracking |
|
|
52
|
+
| `ctx_share` | Cross-agent context sharing |
|
|
53
|
+
| `ctx_smart_read` | Adaptive mode selection |
|
|
54
|
+
|
|
55
|
+
These MCP tools are the same ones available in Cursor, Claude Code, VS Code, and all other supported editors — now first-class in Pi. Tools are auto-discovered via MCP, so new tools added to lean-ctx are automatically available without updating this package.
|
|
56
|
+
|
|
17
57
|
## Install
|
|
18
58
|
|
|
19
59
|
```bash
|
|
@@ -23,8 +63,57 @@ cargo install lean-ctx
|
|
|
23
63
|
|
|
24
64
|
# 2. Install the Pi package
|
|
25
65
|
pi install npm:pi-lean-ctx
|
|
66
|
+
|
|
67
|
+
# 3. Restart Pi
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or use the automated setup:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
lean-ctx init --agent pi
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## How it works
|
|
77
|
+
|
|
78
|
+
### CLI overrides (bash, read, grep, find, ls)
|
|
79
|
+
|
|
80
|
+
These tools invoke the `lean-ctx` binary via CLI with `LEAN_CTX_COMPRESS=1`. The output is parsed for compression stats and displayed with a token savings footer.
|
|
81
|
+
|
|
82
|
+
### MCP bridge (all other tools)
|
|
83
|
+
|
|
84
|
+
On startup, pi-lean-ctx spawns the `lean-ctx` binary as an MCP server (JSON-RPC over stdio). It discovers available tools via `list_tools`, filters out those already covered by CLI overrides, and registers the rest as native Pi tools.
|
|
85
|
+
|
|
86
|
+
If `lean-ctx` is already configured as an MCP server via [pi-mcp-adapter](https://github.com/nicobailon/pi-mcp-adapter) in `~/.pi/agent/mcp.json`, the embedded bridge is skipped to avoid duplicate tools.
|
|
87
|
+
|
|
88
|
+
### Automatic reconnection
|
|
89
|
+
|
|
90
|
+
If the MCP server process crashes, the bridge automatically reconnects (up to 3 attempts with exponential backoff). If reconnection fails, CLI-based tools continue working normally — only the advanced MCP tools become unavailable.
|
|
91
|
+
|
|
92
|
+
## pi-mcp-adapter compatibility
|
|
93
|
+
|
|
94
|
+
If you prefer using [pi-mcp-adapter](https://github.com/nicobailon/pi-mcp-adapter) to manage your MCP servers, lean-ctx integrates automatically:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Option A: lean-ctx writes the config for you
|
|
98
|
+
lean-ctx init --agent pi
|
|
99
|
+
|
|
100
|
+
# Option B: Manual configuration in ~/.pi/agent/mcp.json
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"mcpServers": {
|
|
106
|
+
"lean-ctx": {
|
|
107
|
+
"command": "/path/to/lean-ctx",
|
|
108
|
+
"lifecycle": "lazy",
|
|
109
|
+
"directTools": true
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
26
113
|
```
|
|
27
114
|
|
|
115
|
+
When pi-mcp-adapter manages the lean-ctx MCP server, pi-lean-ctx detects this and only registers its CLI-based tool overrides, leaving MCP tool management to the adapter.
|
|
116
|
+
|
|
28
117
|
## Binary Resolution
|
|
29
118
|
|
|
30
119
|
The extension locates the `lean-ctx` binary in this order:
|
|
@@ -42,19 +131,32 @@ The `read` tool automatically selects the optimal lean-ctx mode:
|
|
|
42
131
|
| File Type | Size | Mode |
|
|
43
132
|
|-----------|------|------|
|
|
44
133
|
| `.md`, `.json`, `.toml`, `.yaml`, etc. | Any | `full` |
|
|
45
|
-
| Code files (55+ extensions) | <
|
|
46
|
-
| Code files |
|
|
47
|
-
| Code files | >
|
|
134
|
+
| Code files (55+ extensions) | < 8 KB | `full` |
|
|
135
|
+
| Code files | 8–96 KB | `map` (deps + API signatures) |
|
|
136
|
+
| Code files | > 96 KB | `signatures` (AST extraction) |
|
|
48
137
|
| Other files | < 48 KB | `full` |
|
|
49
138
|
| Other files | > 48 KB | `map` |
|
|
50
139
|
|
|
51
|
-
|
|
140
|
+
## Slash Command
|
|
52
141
|
|
|
53
|
-
|
|
142
|
+
Use `/lean-ctx` in Pi to check:
|
|
143
|
+
- Which binary is being used
|
|
144
|
+
- MCP bridge status (embedded vs. adapter, connected/disconnected)
|
|
145
|
+
- Number and names of registered MCP tools
|
|
54
146
|
|
|
55
|
-
##
|
|
147
|
+
## Disabling specific tools
|
|
148
|
+
|
|
149
|
+
To disable specific MCP tools, configure `disabled_tools` in `~/.lean-ctx/config.toml`:
|
|
150
|
+
|
|
151
|
+
```toml
|
|
152
|
+
disabled_tools = ["ctx_graph", "ctx_benchmark"]
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Or via environment variable:
|
|
56
156
|
|
|
57
|
-
|
|
157
|
+
```bash
|
|
158
|
+
LEAN_CTX_DISABLED_TOOLS=ctx_graph,ctx_benchmark pi
|
|
159
|
+
```
|
|
58
160
|
|
|
59
161
|
## Links
|
|
60
162
|
|
package/extensions/index.ts
CHANGED
|
@@ -10,10 +10,12 @@ import {
|
|
|
10
10
|
} from "@mariozechner/pi-coding-agent";
|
|
11
11
|
import { Text } from "@mariozechner/pi-tui";
|
|
12
12
|
import { Type } from "@sinclair/typebox";
|
|
13
|
-
import { existsSync } from "node:fs";
|
|
13
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
14
14
|
import { readFile, stat } from "node:fs/promises";
|
|
15
|
-
import {
|
|
15
|
+
import { extname, resolve } from "node:path";
|
|
16
16
|
import { homedir, platform } from "node:os";
|
|
17
|
+
import { McpBridge } from "./mcp-bridge.js";
|
|
18
|
+
import type { CompressionStats } from "./types.js";
|
|
17
19
|
|
|
18
20
|
const CODE_EXTENSIONS = new Set([
|
|
19
21
|
".rs", ".ts", ".tsx", ".js", ".jsx", ".php", ".py", ".go",
|
|
@@ -121,12 +123,6 @@ async function readSlice(path: string, offset?: number, limit?: number) {
|
|
|
121
123
|
return { text: truncation.content, lines: lines.length, truncated: truncation.truncated };
|
|
122
124
|
}
|
|
123
125
|
|
|
124
|
-
type CompressionStats = {
|
|
125
|
-
originalTokens: number;
|
|
126
|
-
compressedTokens: number;
|
|
127
|
-
percentSaved: number;
|
|
128
|
-
};
|
|
129
|
-
|
|
130
126
|
function estimateTokens(text: string) {
|
|
131
127
|
return Math.ceil(text.length / 4);
|
|
132
128
|
}
|
|
@@ -232,6 +228,27 @@ function splitFooter(text: string) {
|
|
|
232
228
|
return { body: normalized.slice(0, -match[0].length), footer: match[1] };
|
|
233
229
|
}
|
|
234
230
|
|
|
231
|
+
function isMcpAdapterConfigured(): boolean {
|
|
232
|
+
const home = homedir();
|
|
233
|
+
const mcpConfigPaths = [
|
|
234
|
+
resolve(home, ".pi", "agent", "mcp.json"),
|
|
235
|
+
resolve(process.cwd(), ".pi", "mcp.json"),
|
|
236
|
+
];
|
|
237
|
+
|
|
238
|
+
for (const configPath of mcpConfigPaths) {
|
|
239
|
+
if (!existsSync(configPath)) continue;
|
|
240
|
+
try {
|
|
241
|
+
const content = readFileSync(configPath, "utf8");
|
|
242
|
+
const json = JSON.parse(content);
|
|
243
|
+
const servers = json?.mcpServers ?? {};
|
|
244
|
+
if ("lean-ctx" in servers) return true;
|
|
245
|
+
} catch {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
|
|
235
252
|
async function execLeanCtx(pi: ExtensionAPI, args: string[]) {
|
|
236
253
|
const bin = resolveBinary();
|
|
237
254
|
const result = await pi.exec(bin, args, { env: { LEAN_CTX_COMPRESS: "1" } });
|
|
@@ -455,15 +472,30 @@ export default function (pi: ExtensionAPI) {
|
|
|
455
472
|
},
|
|
456
473
|
});
|
|
457
474
|
|
|
475
|
+
const mcpBridge = new McpBridge(resolveBinary());
|
|
476
|
+
|
|
477
|
+
if (!isMcpAdapterConfigured()) {
|
|
478
|
+
mcpBridge.start(pi).catch((err) => {
|
|
479
|
+
console.error(`[pi-lean-ctx] MCP bridge startup failed: ${err}`);
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
458
483
|
pi.registerCommand("lean-ctx", {
|
|
459
|
-
description: "Show
|
|
484
|
+
description: "Show lean-ctx status: binary path, MCP bridge, and registered tools",
|
|
460
485
|
handler: async (_args, ctx) => {
|
|
461
486
|
const bin = resolveBinary();
|
|
462
487
|
const found = existsSync(bin);
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
);
|
|
488
|
+
const status = mcpBridge.getStatus();
|
|
489
|
+
|
|
490
|
+
const lines: string[] = [];
|
|
491
|
+
lines.push(found ? `Binary: ${bin}` : "Binary: NOT FOUND — install: cargo install lean-ctx");
|
|
492
|
+
lines.push(`MCP bridge: ${status.mode} (${status.connected ? "connected" : "disconnected"})`);
|
|
493
|
+
lines.push(`MCP tools: ${status.toolCount} registered`);
|
|
494
|
+
if (status.toolNames.length > 0) {
|
|
495
|
+
lines.push(` ${status.toolNames.join(", ")}`);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
ctx.ui.notify(lines.join("\n"), found && status.connected ? "info" : "warning");
|
|
467
499
|
},
|
|
468
500
|
});
|
|
469
501
|
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
4
|
+
import { Type } from "@sinclair/typebox";
|
|
5
|
+
import type { McpBridgeStatus } from "./types.js";
|
|
6
|
+
|
|
7
|
+
const CLI_OVERRIDE_TOOLS = new Set([
|
|
8
|
+
"ctx_read",
|
|
9
|
+
"ctx_multi_read",
|
|
10
|
+
"ctx_shell",
|
|
11
|
+
"ctx_search",
|
|
12
|
+
"ctx_tree",
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
const MAX_RECONNECT_ATTEMPTS = 3;
|
|
16
|
+
const RECONNECT_DELAY_MS = 2000;
|
|
17
|
+
|
|
18
|
+
type McpTool = {
|
|
19
|
+
name: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
inputSchema?: Record<string, unknown>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export class McpBridge {
|
|
25
|
+
private client: Client | null = null;
|
|
26
|
+
private transport: StdioClientTransport | null = null;
|
|
27
|
+
private registeredTools: string[] = [];
|
|
28
|
+
private connected = false;
|
|
29
|
+
private binary: string;
|
|
30
|
+
private reconnectAttempts = 0;
|
|
31
|
+
|
|
32
|
+
constructor(binary: string) {
|
|
33
|
+
this.binary = binary;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async start(pi: ExtensionAPI): Promise<void> {
|
|
37
|
+
try {
|
|
38
|
+
await this.connect();
|
|
39
|
+
await this.discoverAndRegisterTools(pi);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
42
|
+
console.error(`[lean-ctx MCP bridge] Failed to start: ${msg}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private async connect(): Promise<void> {
|
|
47
|
+
this.transport = new StdioClientTransport({
|
|
48
|
+
command: this.binary,
|
|
49
|
+
args: [],
|
|
50
|
+
stderr: "pipe",
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
this.client = new Client({
|
|
54
|
+
name: "pi-lean-ctx",
|
|
55
|
+
version: "3.0.0",
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
this.transport.onclose = () => {
|
|
59
|
+
this.connected = false;
|
|
60
|
+
this.scheduleReconnect();
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
this.transport.onerror = (err) => {
|
|
64
|
+
console.error(`[lean-ctx MCP bridge] Transport error: ${err.message}`);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
await this.client.connect(this.transport);
|
|
68
|
+
this.connected = true;
|
|
69
|
+
this.reconnectAttempts = 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private scheduleReconnect(): void {
|
|
73
|
+
if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
|
|
74
|
+
console.error(
|
|
75
|
+
`[lean-ctx MCP bridge] Max reconnect attempts (${MAX_RECONNECT_ATTEMPTS}) reached. MCP tools unavailable.`,
|
|
76
|
+
);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
this.reconnectAttempts++;
|
|
81
|
+
const delay = RECONNECT_DELAY_MS * this.reconnectAttempts;
|
|
82
|
+
|
|
83
|
+
setTimeout(async () => {
|
|
84
|
+
try {
|
|
85
|
+
await this.connect();
|
|
86
|
+
console.error("[lean-ctx MCP bridge] Reconnected successfully");
|
|
87
|
+
} catch {
|
|
88
|
+
this.scheduleReconnect();
|
|
89
|
+
}
|
|
90
|
+
}, delay);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private async discoverAndRegisterTools(pi: ExtensionAPI): Promise<void> {
|
|
94
|
+
if (!this.client) return;
|
|
95
|
+
|
|
96
|
+
const result = await this.client.listTools();
|
|
97
|
+
const tools = (result.tools ?? []) as McpTool[];
|
|
98
|
+
|
|
99
|
+
for (const tool of tools) {
|
|
100
|
+
if (CLI_OVERRIDE_TOOLS.has(tool.name)) continue;
|
|
101
|
+
this.registerMcpTool(pi, tool);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private registerMcpTool(pi: ExtensionAPI, tool: McpTool): void {
|
|
106
|
+
const bridge = this;
|
|
107
|
+
const schema = this.jsonSchemaToTypebox(tool.inputSchema);
|
|
108
|
+
|
|
109
|
+
pi.registerTool({
|
|
110
|
+
name: tool.name,
|
|
111
|
+
label: tool.name,
|
|
112
|
+
description: tool.description ?? `lean-ctx MCP tool: ${tool.name}`,
|
|
113
|
+
promptSnippet: tool.description ?? tool.name,
|
|
114
|
+
parameters: schema,
|
|
115
|
+
async execute(_toolCallId, params, _signal) {
|
|
116
|
+
return bridge.callTool(tool.name, params as Record<string, unknown>);
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
this.registeredTools.push(tool.name);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async callTool(
|
|
124
|
+
name: string,
|
|
125
|
+
args: Record<string, unknown>,
|
|
126
|
+
): Promise<{ content: Array<{ type: string; text: string }> }> {
|
|
127
|
+
if (!this.client || !this.connected) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
`lean-ctx MCP bridge not connected. Tool "${name}" unavailable.`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const result = await this.client.callTool({ name, arguments: args });
|
|
134
|
+
|
|
135
|
+
const content = (
|
|
136
|
+
result.content as Array<{ type: string; text?: string }>
|
|
137
|
+
).map((block) => ({
|
|
138
|
+
type: "text" as const,
|
|
139
|
+
text: block.text ?? "",
|
|
140
|
+
}));
|
|
141
|
+
|
|
142
|
+
return { content };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private jsonSchemaToTypebox(
|
|
146
|
+
schema?: Record<string, unknown>,
|
|
147
|
+
): ReturnType<typeof Type.Object> {
|
|
148
|
+
if (!schema || !schema.properties) {
|
|
149
|
+
return Type.Object({});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const properties = schema.properties as Record<
|
|
153
|
+
string,
|
|
154
|
+
Record<string, unknown>
|
|
155
|
+
>;
|
|
156
|
+
const required = new Set(
|
|
157
|
+
(schema.required as string[] | undefined) ?? [],
|
|
158
|
+
);
|
|
159
|
+
const fields: Record<string, ReturnType<typeof Type.String>> = {};
|
|
160
|
+
|
|
161
|
+
for (const [key, prop] of Object.entries(properties)) {
|
|
162
|
+
const desc = (prop.description as string) ?? undefined;
|
|
163
|
+
const jsonType = prop.type as string | undefined;
|
|
164
|
+
|
|
165
|
+
let field;
|
|
166
|
+
switch (jsonType) {
|
|
167
|
+
case "number":
|
|
168
|
+
case "integer":
|
|
169
|
+
field = Type.Number({ description: desc });
|
|
170
|
+
break;
|
|
171
|
+
case "boolean":
|
|
172
|
+
field = Type.Boolean({ description: desc });
|
|
173
|
+
break;
|
|
174
|
+
case "array":
|
|
175
|
+
field = Type.Array(Type.Unknown(), { description: desc });
|
|
176
|
+
break;
|
|
177
|
+
case "object":
|
|
178
|
+
field = Type.Record(Type.String(), Type.Unknown(), {
|
|
179
|
+
description: desc,
|
|
180
|
+
});
|
|
181
|
+
break;
|
|
182
|
+
default:
|
|
183
|
+
field = Type.String({ description: desc });
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
fields[key] = required.has(key)
|
|
188
|
+
? field
|
|
189
|
+
: Type.Optional(field);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return Type.Object(fields);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
getStatus(): McpBridgeStatus {
|
|
196
|
+
return {
|
|
197
|
+
mode: "embedded",
|
|
198
|
+
connected: this.connected,
|
|
199
|
+
toolCount: this.registeredTools.length,
|
|
200
|
+
toolNames: [...this.registeredTools],
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async shutdown(): Promise<void> {
|
|
205
|
+
this.reconnectAttempts = MAX_RECONNECT_ATTEMPTS;
|
|
206
|
+
try {
|
|
207
|
+
await this.client?.close();
|
|
208
|
+
} catch {
|
|
209
|
+
// best-effort cleanup
|
|
210
|
+
}
|
|
211
|
+
this.client = null;
|
|
212
|
+
this.transport = null;
|
|
213
|
+
this.connected = false;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type CompressionStats = {
|
|
2
|
+
originalTokens: number;
|
|
3
|
+
compressedTokens: number;
|
|
4
|
+
percentSaved: number;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export type McpBridgeStatus = {
|
|
8
|
+
mode: "embedded" | "adapter" | "disabled";
|
|
9
|
+
connected: boolean;
|
|
10
|
+
toolCount: number;
|
|
11
|
+
toolNames: string[];
|
|
12
|
+
error?: string;
|
|
13
|
+
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-lean-ctx",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Pi Coding Agent extension
|
|
5
|
-
"keywords": ["pi-package", "lean-ctx", "token-optimization", "compression"],
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Pi Coding Agent extension with first-class MCP support — routes bash, read, grep, find, and ls through lean-ctx CLI, and exposes all 34 lean-ctx MCP tools (ctx_session, ctx_knowledge, ctx_semantic_search, ctx_impact, ctx_architecture, etc.) natively in Pi",
|
|
5
|
+
"keywords": ["pi-package", "lean-ctx", "token-optimization", "compression", "mcp"],
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Yves Gugger",
|
|
8
8
|
"repository": {
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
"bugs": {
|
|
15
15
|
"url": "https://github.com/yvgude/lean-ctx/issues"
|
|
16
16
|
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@modelcontextprotocol/sdk": "^1.29.0"
|
|
19
|
+
},
|
|
17
20
|
"peerDependencies": {
|
|
18
21
|
"@mariozechner/pi-coding-agent": ">=0.50.0",
|
|
19
22
|
"@mariozechner/pi-tui": "*"
|