decorated-pi 0.5.5 → 0.7.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 +69 -71
- package/commands/dp-model.ts +23 -0
- package/commands/dp-settings.ts +28 -0
- package/commands/mcp-status.ts +62 -0
- package/commands/retry.ts +19 -0
- package/commands/usage.ts +544 -0
- package/hooks/compaction.ts +204 -0
- package/hooks/externalize.ts +70 -0
- package/hooks/image-vision.ts +132 -0
- package/hooks/inject-agents-md.ts +164 -0
- package/hooks/mcp.ts +392 -0
- package/hooks/normalize-codeblocks.ts +88 -0
- package/hooks/pi-tool-filter.ts +28 -0
- package/{extensions/safety → hooks/redact}/types.ts +1 -8
- package/hooks/redact.ts +104 -0
- package/{extensions → hooks}/rtk.ts +92 -115
- package/hooks/session-title.ts +78 -0
- package/hooks/skeleton.ts +212 -0
- package/hooks/smart-at.ts +318 -0
- package/{extensions/file-times.ts → hooks/track-mtime.ts} +40 -38
- package/{extensions → hooks}/wakatime.ts +120 -122
- package/index.ts +166 -1
- package/package.json +8 -6
- package/settings.ts +341 -0
- package/tools/ask/index.ts +93 -0
- package/{extensions → tools}/lsp/client.ts +0 -25
- package/{extensions → tools}/lsp/format.ts +2 -99
- package/{extensions → tools}/lsp/index.ts +1 -1
- package/{extensions → tools}/lsp/servers.ts +1 -1
- package/{extensions → tools}/lsp/tools.ts +1 -66
- package/{extensions → tools}/lsp/types.ts +0 -11
- package/tools/mcp/builtin/codegraph.ts +21 -0
- package/tools/mcp/builtin/context7.ts +10 -0
- package/tools/mcp/builtin/exa.ts +10 -0
- package/tools/mcp/builtin/index.ts +19 -0
- package/tools/mcp/cache.ts +124 -0
- package/{extensions → tools}/mcp/client.ts +2 -2
- package/tools/mcp/config.ts +288 -0
- package/tools/mcp/index.ts +44 -0
- package/tools/mcp/tool-definition.ts +112 -0
- package/{extensions/patch.ts → tools/patch/core.ts} +135 -43
- package/{extensions/io.ts → tools/patch/index.ts} +24 -206
- package/tsconfig.json +10 -1
- package/ui/ask.ts +443 -0
- package/ui/mcp-status.ts +202 -0
- package/ui/model-picker.ts +162 -0
- package/ui/module-settings.ts +188 -0
- package/ui/usage.ts +396 -0
- package/extensions/index.ts +0 -154
- package/extensions/io-tool-output.ts +0 -33
- package/extensions/mcp/builtin.ts +0 -376
- package/extensions/mcp/index.ts +0 -435
- package/extensions/model-integration.ts +0 -531
- package/extensions/providers/ark-coding.ts +0 -75
- package/extensions/providers/index.ts +0 -9
- package/extensions/providers/ollama-cloud.ts +0 -101
- package/extensions/providers/qianfan-coding.ts +0 -71
- package/extensions/safety/index.ts +0 -102
- package/extensions/session-title.ts +0 -65
- package/extensions/settings.ts +0 -170
- package/extensions/slash.ts +0 -458
- package/extensions/smart-at.ts +0 -481
- package/extensions/subdir-agents.ts +0 -151
- /package/{extensions/safety → hooks/redact}/detect.ts +0 -0
- /package/{extensions/safety → hooks/redact}/entropy.ts +0 -0
- /package/{extensions/safety → hooks/redact}/patterns.ts +0 -0
- /package/{extensions → tools}/lsp/env.ts +0 -0
- /package/{extensions → tools}/lsp/manager.ts +0 -0
- /package/{extensions → tools}/lsp/prompt.ts +0 -0
- /package/{extensions → tools}/lsp/protocol.ts +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# decorated-pi
|
|
2
2
|
|
|
3
|
-
`decorated-pi` is a practical enhancement pack for [Pi](https://github.com/earendil-works/pi) —
|
|
3
|
+
`decorated-pi` is a practical enhancement pack for [Pi](https://github.com/earendil-works/pi) — token-efficient workflow, cache-friendly design, and smarter tools.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -12,21 +12,41 @@ pi install /path/to/decorated-pi
|
|
|
12
12
|
|
|
13
13
|
## Features
|
|
14
14
|
|
|
15
|
-
### 1.
|
|
15
|
+
### 1. Token Efficiency
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Multiple layers of token savings that compound across every session. **All integrated CLI tools only require installing their respective CLIs — zero config**.
|
|
18
|
+
|
|
19
|
+
**RTK** — integrates [RTK](https://github.com/rtk-ai/rtk) to compress bash output into structured summaries, so the LLM never sees raw noise.
|
|
20
|
+
|
|
21
|
+
**codegraph** — integrates [codegraph](https://github.com/colbymchenry/codegraph) to offer a code map of your project, so the LLM can navigate symbols and call graphs without chaining `ls` → `grep` → `read`.
|
|
22
|
+
|
|
23
|
+
**Auxiliary Models** — offloads heavy-but-dumb tasks to cheaper models so your primary model only pays for the hard work:
|
|
24
|
+
|
|
25
|
+
- **Image read fallback** — detects image type via magic bytes, calls a configured vision-capable model, and injects the analysis text, so your main model never touches image tokens
|
|
26
|
+
- **Compact model** — handles context compaction with a smaller model instead of burning main-model capacity
|
|
27
|
+
|
|
28
|
+
Configured via `/dp-model`.
|
|
29
|
+
|
|
30
|
+
**Cache‑friendly design** — stable system prompt prefix:
|
|
31
|
+
|
|
32
|
+
- tool definitions, guidelines, and skills are sorted alphabetically so the system prompt is identical across sessions
|
|
33
|
+
- volatile elements like `Current date: …` are stripped before prompt assembly
|
|
34
|
+
- MCP tool schemas are persisted to a local cache, so the tool list stays stable regardless of network conditions or server availability
|
|
35
|
+
|
|
36
|
+
### 2. Smarter Tools
|
|
37
|
+
|
|
38
|
+
Drop‑in replacements for Pi's built‑in tools, with better UX and fewer wasted turns.
|
|
39
|
+
|
|
40
|
+
#### Patch Tool
|
|
18
41
|
|
|
19
42
|
| Capability | Pi native `edit` | `patch` |
|
|
20
43
|
| ------ | :---: | :---: |
|
|
21
|
-
| Syntax‑highlighted overwrite | ✅ streaming | ✅ incremental |
|
|
22
44
|
| **Anchor‑based search** | ❌ extending `oldText` for uniqueness | ✅ `anchor` bounds scope for precise matching |
|
|
23
45
|
| **Fuzzy whitespace match** | ❌ only reports "not found" | ✅ auto‑corrects tab↔space / trailing whitespace mismatches |
|
|
24
46
|
| **Edit fault diagnostics** | ❌ only reports "not found" | ✅ pinpoint faults for LLM comprehension |
|
|
25
47
|
| **Stale‑read protection** | ❌ Blind to external changes | ✅ `read` captures mtime, `patch` rejects stale targets |
|
|
26
48
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Replaces Pi's built-in `@` file completion with smarter matching and noise filtering:
|
|
49
|
+
#### Smarter `@` File Search
|
|
30
50
|
|
|
31
51
|
| Aspect | Pi native `@` | `decorated-pi` |
|
|
32
52
|
| ------ | :---: | :---: |
|
|
@@ -35,48 +55,15 @@ Replaces Pi's built-in `@` file completion with smarter matching and noise filte
|
|
|
35
55
|
| **Default suggestions** | ❌ all files visible on empty query | ✅ only visible project files |
|
|
36
56
|
| **Match precision** | ❌ case‑insensitive simple scoring | ✅ multi‑level case‑sensitive scoring |
|
|
37
57
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
Three-layer detection: high-confidence known-format patterns (AWS, GitHub, OpenAI, etc.), config-key regex matching, and adjusted Shannon entropy heuristics for unknown secret-like values.
|
|
41
|
-
|
|
42
|
-
Example redaction on a `read` / `bash` output:
|
|
43
|
-
|
|
44
|
-
```json
|
|
45
|
-
{
|
|
46
|
-
"aws_access_key_id": "AKI**************PLE",
|
|
47
|
-
"github_token": "ghp***************def",
|
|
48
|
-
"database_password": "Sup#######t99",
|
|
49
|
-
"api_key": "sk_**************f5a",
|
|
50
|
-
"random_secret": "a1b??????5f5"
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
> `*` = known pattern, `#` = config key regex, `?` = entropy heuristic.
|
|
58
|
+
#### LSP support
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
Offloads auxiliary ops to cheaper models, reducing cost on every session. Configured via `/dp-model`:
|
|
59
|
-
|
|
60
|
-
- **Image read fallback** — when the model reads an image file, detects type via magic bytes, calls a configured vision-capable model, and replaces the read result with image analysis text (jpeg, png, gif, webp)
|
|
61
|
-
- **Compact model** — uses a configured model for context compaction (instead of the main model).
|
|
62
|
-
|
|
63
|
-
### 5. Progressive Context from `AGENTS.md` / `CLAUDE.md`
|
|
64
|
-
|
|
65
|
-
Extension capability: context is disclosed progressively as the agent works across different parts of the project.
|
|
66
|
-
|
|
67
|
-
- When reading or editing a file, discovers `AGENTS.md` / `CLAUDE.md` in that file's directory and ancestor directories
|
|
68
|
-
- Newly discovered guidance is injected into tool results, scoped to the current context
|
|
69
|
-
|
|
70
|
-
### 6. LSP Tool Suite
|
|
71
|
-
|
|
72
|
-
A cleaned-up, minimal LSP toolset. The extension keeps only the two LSP tools that cover the most practical coding workflows: checking diagnostics after edits and inspecting file structure before focused changes.
|
|
60
|
+
Covers what codegraph can't: real-time compiler and lint errors.
|
|
73
61
|
|
|
74
62
|
- **`lsp_diagnostics`** — file diagnostics with severity filtering
|
|
75
|
-
- **`lsp_document_symbols`** — file symbol outline
|
|
76
63
|
|
|
77
64
|
Supported languages: c/cpp, go, java, lua, json, python, ruby, rust, svelte, typescript
|
|
78
65
|
|
|
79
|
-
###
|
|
66
|
+
### 3. MCP Ecosystem
|
|
80
67
|
|
|
81
68
|
Zero-config MCP client with built-in servers:
|
|
82
69
|
|
|
@@ -84,9 +71,9 @@ Zero-config MCP client with built-in servers:
|
|
|
84
71
|
| --- | --- | --- |
|
|
85
72
|
| Context7 | `context7_*` | `https://mcp.context7.com/mcp` |
|
|
86
73
|
| Exa | `exa_*` | `https://mcp.exa.ai/mcp` |
|
|
74
|
+
| codegraph | `codegraph_*` | bundled binary |
|
|
87
75
|
|
|
88
|
-
**Custom servers** in `.pi/agent/mcp.json` (project) or `~/.pi/agent/
|
|
89
|
-
Tool prompts and schemas are cached locally so MCP tools are available immediately on startup, even before servers connect.
|
|
76
|
+
**Custom servers** in `.pi/agent/mcp.json` (project) or `~/.pi/agent/mcp.json` (global). Project overrides global. Tool prompts and schemas are cached locally so MCP tools are available immediately on startup.
|
|
90
77
|
|
|
91
78
|
```json
|
|
92
79
|
{
|
|
@@ -108,45 +95,56 @@ Tool prompts and schemas are cached locally so MCP tools are available immediate
|
|
|
108
95
|
}
|
|
109
96
|
```
|
|
110
97
|
|
|
111
|
-
Use `/mcp` to view connection status and
|
|
98
|
+
Use `/mcp` to view connection status and toggle servers.
|
|
112
99
|
|
|
113
|
-
###
|
|
100
|
+
### 4. Secret Redaction
|
|
114
101
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
| Provider | Base URL |
|
|
118
|
-
| ---------- | ----------- |
|
|
119
|
-
| Ollama Cloud | `ollama.com/v1` |
|
|
120
|
-
| Baidu Qianfan | `qianfan.baidubce.com/v2/coding` |
|
|
121
|
-
| ARK Coding | `ark.cn-beijing.volces.com/api/coding/v3` |
|
|
102
|
+
Three-layer detection: high-confidence known-format patterns (AWS, GitHub, OpenAI, etc.), config-key regex matching, and adjusted Shannon entropy heuristics for unknown secret-like values.
|
|
122
103
|
|
|
123
|
-
|
|
104
|
+
Example redaction on a `read` / `bash` output:
|
|
124
105
|
|
|
125
|
-
|
|
126
|
-
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"aws_access_key_id": "AKI**************PLE",
|
|
109
|
+
"github_token": "ghp***************def",
|
|
110
|
+
"database_password": "Sup#######t99",
|
|
111
|
+
"api_key": "sk_**************f5a",
|
|
112
|
+
"random_secret": "a1b??????5f5"
|
|
113
|
+
}
|
|
114
|
+
```
|
|
127
115
|
|
|
128
|
-
|
|
116
|
+
> `*` = known pattern, `#` = config key regex, `?` = entropy heuristic.
|
|
129
117
|
|
|
130
|
-
|
|
118
|
+
### 5. Other
|
|
131
119
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
120
|
+
- `/usage` — token stats with cache‑hit rate, per‑model breakdown (Session / Today / This Week / This Month / All Time)
|
|
121
|
+
- `/retry` — continue after interruption
|
|
122
|
+
- Progressive context — supports subdirectory `AGENTS.md` / `CLAUDE.md` discovery and injection
|
|
123
|
+
- **WakaTime** — coding activity tracking via [WakaTime](https://wakatime.com)
|
|
135
124
|
|
|
136
|
-
|
|
125
|
+
## Configuration
|
|
137
126
|
|
|
138
|
-
Modules can be toggled
|
|
127
|
+
Runtime settings in `~/.pi/agent/decorated-pi.json`. Modules can be toggled via `/dp-settings` (changes take effect after `/reload`).
|
|
139
128
|
|
|
140
129
|
```json
|
|
141
130
|
{
|
|
142
131
|
"modules": {
|
|
143
|
-
"
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
"
|
|
132
|
+
"tools": {
|
|
133
|
+
"patchOverrideEdit": true,
|
|
134
|
+
"ask": true,
|
|
135
|
+
"lsp": true,
|
|
136
|
+
"mcp": true
|
|
137
|
+
},
|
|
138
|
+
"hooks": {
|
|
139
|
+
"secretRedaction": true,
|
|
140
|
+
"rtk": true,
|
|
141
|
+
"wakatime": true
|
|
142
|
+
},
|
|
143
|
+
"commands": {
|
|
144
|
+
"atOverride": true,
|
|
145
|
+
"retry": true,
|
|
146
|
+
"usage": true
|
|
147
|
+
}
|
|
150
148
|
}
|
|
151
149
|
}
|
|
152
150
|
```
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /dp-model — pick image / compact model.
|
|
3
|
+
* UI lives in extensions/ui/model-picker.ts (shared with /mcp status etc).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
7
|
+
import { ModelPickerComponent } from "../ui/model-picker.js";
|
|
8
|
+
|
|
9
|
+
export function registerDpModelCommand(pi: ExtensionAPI): void {
|
|
10
|
+
pi.registerCommand("dp-model", {
|
|
11
|
+
description: "Configure image and compact models",
|
|
12
|
+
handler: async (_args, ctx) => {
|
|
13
|
+
if (ctx.hasUI) {
|
|
14
|
+
await ctx.ui.custom<void>(
|
|
15
|
+
(tui, theme, _kb, done) =>
|
|
16
|
+
new ModelPickerComponent(tui, theme, ctx.modelRegistry, () => done(undefined))
|
|
17
|
+
);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
ctx.ui.notify("dp-model requires interactive mode.", "warning");
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /dp-settings — toggle module on/off.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
6
|
+
import { moduleSnapshotChanged } from "../settings.js";
|
|
7
|
+
import { ModuleSettingsComponent } from "../ui/module-settings.js";
|
|
8
|
+
|
|
9
|
+
export function registerDpSettingsCommand(pi: ExtensionAPI): void {
|
|
10
|
+
pi.registerCommand("dp-settings", {
|
|
11
|
+
description: "Toggle decorated-pi modules on/off",
|
|
12
|
+
handler: async (_args, ctx) => {
|
|
13
|
+
if (ctx.hasUI) {
|
|
14
|
+
await ctx.ui.custom<void>(
|
|
15
|
+
(tui, theme, _kb, done) =>
|
|
16
|
+
new ModuleSettingsComponent(tui, theme, () => done(undefined))
|
|
17
|
+
);
|
|
18
|
+
// Only prompt for reload when the effective settings differ from
|
|
19
|
+
// the snapshot taken when pi loaded the extension.
|
|
20
|
+
if (moduleSnapshotChanged()) {
|
|
21
|
+
ctx.ui.notify("Module settings updated. /reload to apply.", "warning");
|
|
22
|
+
}
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
ctx.ui.notify("dp-settings requires interactive mode.", "warning");
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /mcp — show MCP servers, toggle, refresh.
|
|
3
|
+
*
|
|
4
|
+
* Wires the pure UI component (ui/mcp-status.ts) to the hook layer
|
|
5
|
+
* (hooks/mcp.ts) by injecting callbacks. The UI itself knows nothing
|
|
6
|
+
* about hooks/config persistence.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
10
|
+
import { McpStatusComponent, type McpServerView } from "../ui/mcp-status.js";
|
|
11
|
+
import { getMcpStatus, refreshServerCache, updateConfigEnabled } from "../hooks/mcp.js";
|
|
12
|
+
import { toggleMcpServerEnabled } from "../tools/mcp/config.js";
|
|
13
|
+
|
|
14
|
+
export function registerMcpStatusCommand(pi: ExtensionAPI): void {
|
|
15
|
+
pi.registerCommand("mcp", {
|
|
16
|
+
description: "Show active MCP servers and their tools",
|
|
17
|
+
handler: async (_args, ctx) => {
|
|
18
|
+
if (ctx.hasUI) {
|
|
19
|
+
await ctx.ui.custom<void>(
|
|
20
|
+
(tui, theme, _kb, done) =>
|
|
21
|
+
new McpStatusComponent(tui, theme, {
|
|
22
|
+
read: () => getMcpStatus() as McpServerView[],
|
|
23
|
+
toggle: async (name, enabled) => {
|
|
24
|
+
const scope: "global" | "project" = "global";
|
|
25
|
+
const ok = toggleMcpServerEnabled(name, enabled, scope, ctx.cwd || undefined);
|
|
26
|
+
if (ok) {
|
|
27
|
+
// Await so the connection (if disabling) is fully torn down
|
|
28
|
+
// before /reload. Otherwise teardownMcp() may hang on a
|
|
29
|
+
// zombie conn and stall session_shutdown.
|
|
30
|
+
await updateConfigEnabled(name, enabled);
|
|
31
|
+
}
|
|
32
|
+
return ok;
|
|
33
|
+
},
|
|
34
|
+
refresh: (name) => refreshServerCache(name, ctx.modelRegistry),
|
|
35
|
+
}, done)
|
|
36
|
+
);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const servers = getMcpStatus();
|
|
40
|
+
if (servers.length === 0) {
|
|
41
|
+
ctx.ui.notify("No MCP servers configured.", "info");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const lines: string[] = [`MCP servers (${servers.length}):`, ""];
|
|
45
|
+
for (const s of servers) {
|
|
46
|
+
lines.push(`• ${s.name} (${s.source})`);
|
|
47
|
+
lines.push(` URL: ${s.url}`);
|
|
48
|
+
if (s.state === "connecting") lines.push(` Status: connecting...`);
|
|
49
|
+
else if (s.state === "failed") lines.push(` Status: failed — ${s.error ?? "unknown error"}`);
|
|
50
|
+
else {
|
|
51
|
+
lines.push(` Tools: ${s.toolCount}`);
|
|
52
|
+
for (const tool of s.tools) {
|
|
53
|
+
const desc = tool.description ? ` — ${tool.description.slice(0, 60)}` : "";
|
|
54
|
+
lines.push(` - ${tool.name}${desc}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
lines.push("");
|
|
58
|
+
}
|
|
59
|
+
pi.sendMessage({ customType: "mcp-status", content: lines.join("\n"), display: true }, { triggerTurn: false });
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /retry — continue after interruption.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
6
|
+
|
|
7
|
+
export function registerRetryCommand(pi: ExtensionAPI): void {
|
|
8
|
+
let retryInProgress = false;
|
|
9
|
+
pi.registerCommand("retry", {
|
|
10
|
+
description: "Continue after interruption",
|
|
11
|
+
handler: async (_args, ctx) => {
|
|
12
|
+
if (retryInProgress) { ctx.ui.notify("Retry is already in progress", "warning"); return; }
|
|
13
|
+
if (!ctx.isIdle()) ctx.abort();
|
|
14
|
+
retryInProgress = true;
|
|
15
|
+
pi.sendMessage({ customType: "retry-trigger", content: "Continue.", display: false }, { triggerTurn: true });
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
pi.on("agent_start", () => { retryInProgress = false; });
|
|
19
|
+
}
|