pi-cc-extensions 0.1.2 → 0.1.5
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 +162 -162
- package/extensions/agent-autocomplete.ts +175 -0
- package/extensions/ccstyle-powerline/fixed-editor/terminal-split.ts +1318 -1317
- package/extensions/ccstyle-powerline/git-status.ts +9 -0
- package/extensions/ccstyle-powerline/powerline.ts +3150 -3150
- package/extensions/ccstyle-powerline/presets.ts +109 -109
- package/extensions/ccstyle-powerline/working-vibes.ts +1 -1
- package/extensions/claude-code-style.ts +7 -4
- package/extensions/session-reference/core.ts +0 -2
- package/extensions/session-reference/index.ts +411 -411
- package/package.json +12 -5
- package/extensions/session-reference/core.test.ts +0 -74
package/README.md
CHANGED
|
@@ -1,162 +1,162 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<img src="./assets/readme/hero.svg" width="100%" alt="pi-cc-extensions:为 Pi 提供 Claude Code 风格界面、上下文洞察和历史 Session 引用">
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
|
-
<p align="center">
|
|
6
|
-
<a href="#安装"><img alt="Pi package" src="https://img.shields.io/badge/Pi-package-58B7FF?style=flat-square"></a>
|
|
7
|
-
<a href="./package.json"><img alt="Version 0.1.
|
|
8
|
-
<a href="#兼容性"><img alt="Node.js 22.19 or newer" src="https://img.shields.io/badge/Node.js-%E2%89%A522.19-66E3C4?style=flat-square"></a>
|
|
9
|
-
<a href="./extensions"><img alt="TypeScript extensions" src="https://img.shields.io/badge/TypeScript-extensions-3178C6?style=flat-square"></a>
|
|
10
|
-
</p>
|
|
11
|
-
|
|
12
|
-
<p align="center">
|
|
13
|
-
为 Pi 补充一套更接近 Claude Code 的终端工作流 · 上下文洞察 · 历史 Session 引用
|
|
14
|
-
</p>
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## 截图
|
|
19
|
-
|
|
20
|
-
<table>
|
|
21
|
-
<tr>
|
|
22
|
-
<td colspan="2" align="center">
|
|
23
|
-
<img src="./assets/readme/welcome.webp" width="100%" alt="Pi 的 Welcome 界面,展示 Tips、已加载上下文、扩展和最近会话">
|
|
24
|
-
<br>
|
|
25
|
-
<sub><b>Welcome 界面</b><br>启动时查看已加载上下文、扩展与最近会话</sub>
|
|
26
|
-
</td>
|
|
27
|
-
</tr>
|
|
28
|
-
<tr>
|
|
29
|
-
<td width="50%" align="center">
|
|
30
|
-
<img src="./assets/readme/showcase.webp" width="100%" alt="Pi 终端中的 Claude Code 风格扩展界面,包含工具调用摘要、Diff 预览和 Powerline 状态栏">
|
|
31
|
-
<br>
|
|
32
|
-
<sub><b>Claude Code 风格界面</b><br>工具调用摘要、Diff 预览与 Powerline 状态栏</sub>
|
|
33
|
-
</td>
|
|
34
|
-
<td width="50%" align="center">
|
|
35
|
-
<img src="./assets/readme/session-reference.webp" width="100%" alt="在 Pi 中通过 @ 补全选择历史 Session">
|
|
36
|
-
<br>
|
|
37
|
-
<sub><b>历史 Session 引用</b><br>通过 @ 补全快速找到并引用历史会话</sub>
|
|
38
|
-
</td>
|
|
39
|
-
</tr>
|
|
40
|
-
<tr>
|
|
41
|
-
<td width="50%" align="center">
|
|
42
|
-
<img src="./assets/readme/context-usage.webp" width="100%" alt="Pi 上下文窗口用量查看器">
|
|
43
|
-
<br>
|
|
44
|
-
<sub><b>上下文用量</b><br>查看 System prompt、Tools、Skills 等占用分布</sub>
|
|
45
|
-
</td>
|
|
46
|
-
<td width="50%" align="center">
|
|
47
|
-
<img src="./assets/readme/context-preview.webp" width="100%" alt="Pi 中展开查看 System Prompt 内容">
|
|
48
|
-
<br>
|
|
49
|
-
<sub><b>上下文预览</b><br>按类别展开查看实际注入的上下文内容</sub>
|
|
50
|
-
</td>
|
|
51
|
-
</tr>
|
|
52
|
-
</table>
|
|
53
|
-
|
|
54
|
-
## 功能
|
|
55
|
-
|
|
56
|
-
### Claude Code 风格界面
|
|
57
|
-
|
|
58
|
-
`extensions/claude-code-style.ts` 提供:
|
|
59
|
-
|
|
60
|
-
- Claude Code 风格的工具调用行与结果摘要
|
|
61
|
-
- Powerline 状态栏和工作状态提示
|
|
62
|
-
- Edit / Write 的 Diff 预览
|
|
63
|
-
- 工具结果的折叠与展开
|
|
64
|
-
- `/ccstyle` 配置命令和 `Ctrl+Shift+O` 快捷键
|
|
65
|
-
|
|
66
|
-
常用命令:
|
|
67
|
-
|
|
68
|
-
```text
|
|
69
|
-
/ccstyle # 切换开关
|
|
70
|
-
/ccstyle status # 查看状态
|
|
71
|
-
/ccstyle compact # 紧凑摘要
|
|
72
|
-
/ccstyle minimal # 最小化输出
|
|
73
|
-
/ccstyle powerline # 查看 Powerline 预设
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
### 上下文窗口查看
|
|
77
|
-
|
|
78
|
-
`extensions/context.ts` 注册 `/context`,展示当前上下文窗口的使用分布,并可进一步预览:
|
|
79
|
-
|
|
80
|
-
- System prompt
|
|
81
|
-
- Tools
|
|
82
|
-
- Context files
|
|
83
|
-
- Skills
|
|
84
|
-
- User / assistant messages
|
|
85
|
-
- Tool results
|
|
86
|
-
- Compaction summaries
|
|
87
|
-
|
|
88
|
-
### 历史 Session 引用
|
|
89
|
-
|
|
90
|
-
`extensions/session-reference/index.ts` 将历史 Session 接入 `@` 补全:
|
|
91
|
-
|
|
92
|
-
1. 在提示词中输入 `@`。
|
|
93
|
-
2. 从 `[Session] ...` 或 `[SubAgent] ...` 补全项中选择要引用的上下文。
|
|
94
|
-
3. 提交时以 `@session:<session-id>` 引用其当前有效上下文。
|
|
95
|
-
|
|
96
|
-
Session 模糊查询默认显示 5 个候选;若已加载 `pi-subagents`,也可直接引用现有 SubAgent。一次提示词可以引用多个 Session;扩展会自动去重,并限制注入规模以避免上下文无限膨胀。更多细节见 [`extensions/session-reference/README.md`](./extensions/session-reference/README.md)。
|
|
97
|
-
|
|
98
|
-
## 安装
|
|
99
|
-
|
|
100
|
-
从
|
|
101
|
-
|
|
102
|
-
```bash
|
|
103
|
-
pi install
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
pi install git:github.com/minuque/pi-cc-extensions
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
安装后可以先运行:
|
|
113
|
-
|
|
114
|
-
```text
|
|
115
|
-
/context
|
|
116
|
-
/ccstyle status
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## 本地开发
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
npm test
|
|
123
|
-
pi -e .
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
也可以把当前仓库作为本地 Pi 包安装:
|
|
127
|
-
|
|
128
|
-
```bash
|
|
129
|
-
pi install /absolute/path/to/pi-cc-extensions
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
修改扩展后,在 Pi 中执行:
|
|
133
|
-
|
|
134
|
-
```text
|
|
135
|
-
/reload
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## 兼容性
|
|
139
|
-
|
|
140
|
-
- Node.js `>=22.19.0`
|
|
141
|
-
- 作为 Pi package 加载,入口由根目录 `package.json` 的 `pi.extensions` 显式声明
|
|
142
|
-
|
|
143
|
-
## 发布
|
|
144
|
-
|
|
145
|
-
发布前检查:
|
|
146
|
-
|
|
147
|
-
```bash
|
|
148
|
-
npm test
|
|
149
|
-
npm pack --dry-run
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
使用 npm 发布。未指定 tag 时使用 `latest`:
|
|
153
|
-
|
|
154
|
-
```bash
|
|
155
|
-
npm run release
|
|
156
|
-
npm run release -- --tag next
|
|
157
|
-
npm run release -- --tag beta
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
## 致谢
|
|
161
|
-
|
|
162
|
-
本项目中的 Powerline 状态栏、Welcome 界面、Working Vibes 等功能基于 [nicobailon/pi-powerline-footer](https://github.com/nicobailon/pi-powerline-footer) 二次开发,感谢原作者的开源贡献。
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./assets/readme/hero.svg" width="100%" alt="pi-cc-extensions:为 Pi 提供 Claude Code 风格界面、上下文洞察和历史 Session 引用">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="#安装"><img alt="Pi package" src="https://img.shields.io/badge/Pi-package-58B7FF?style=flat-square"></a>
|
|
7
|
+
<a href="./package.json"><img alt="Version 0.1.3" src="https://img.shields.io/badge/version-0.1.3-66E3C4?style=flat-square"></a>
|
|
8
|
+
<a href="#兼容性"><img alt="Node.js 22.19 or newer" src="https://img.shields.io/badge/Node.js-%E2%89%A522.19-66E3C4?style=flat-square"></a>
|
|
9
|
+
<a href="./extensions"><img alt="TypeScript extensions" src="https://img.shields.io/badge/TypeScript-extensions-3178C6?style=flat-square"></a>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
为 Pi 补充一套更接近 Claude Code 的终端工作流 · 上下文洞察 · 历史 Session 引用
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 截图
|
|
19
|
+
|
|
20
|
+
<table>
|
|
21
|
+
<tr>
|
|
22
|
+
<td colspan="2" align="center">
|
|
23
|
+
<img src="./assets/readme/welcome.webp" width="100%" alt="Pi 的 Welcome 界面,展示 Tips、已加载上下文、扩展和最近会话">
|
|
24
|
+
<br>
|
|
25
|
+
<sub><b>Welcome 界面</b><br>启动时查看已加载上下文、扩展与最近会话</sub>
|
|
26
|
+
</td>
|
|
27
|
+
</tr>
|
|
28
|
+
<tr>
|
|
29
|
+
<td width="50%" align="center">
|
|
30
|
+
<img src="./assets/readme/showcase.webp" width="100%" alt="Pi 终端中的 Claude Code 风格扩展界面,包含工具调用摘要、Diff 预览和 Powerline 状态栏">
|
|
31
|
+
<br>
|
|
32
|
+
<sub><b>Claude Code 风格界面</b><br>工具调用摘要、Diff 预览与 Powerline 状态栏</sub>
|
|
33
|
+
</td>
|
|
34
|
+
<td width="50%" align="center">
|
|
35
|
+
<img src="./assets/readme/session-reference.webp" width="100%" alt="在 Pi 中通过 @ 补全选择历史 Session">
|
|
36
|
+
<br>
|
|
37
|
+
<sub><b>历史 Session 引用</b><br>通过 @ 补全快速找到并引用历史会话</sub>
|
|
38
|
+
</td>
|
|
39
|
+
</tr>
|
|
40
|
+
<tr>
|
|
41
|
+
<td width="50%" align="center">
|
|
42
|
+
<img src="./assets/readme/context-usage.webp" width="100%" alt="Pi 上下文窗口用量查看器">
|
|
43
|
+
<br>
|
|
44
|
+
<sub><b>上下文用量</b><br>查看 System prompt、Tools、Skills 等占用分布</sub>
|
|
45
|
+
</td>
|
|
46
|
+
<td width="50%" align="center">
|
|
47
|
+
<img src="./assets/readme/context-preview.webp" width="100%" alt="Pi 中展开查看 System Prompt 内容">
|
|
48
|
+
<br>
|
|
49
|
+
<sub><b>上下文预览</b><br>按类别展开查看实际注入的上下文内容</sub>
|
|
50
|
+
</td>
|
|
51
|
+
</tr>
|
|
52
|
+
</table>
|
|
53
|
+
|
|
54
|
+
## 功能
|
|
55
|
+
|
|
56
|
+
### Claude Code 风格界面
|
|
57
|
+
|
|
58
|
+
`extensions/claude-code-style.ts` 提供:
|
|
59
|
+
|
|
60
|
+
- Claude Code 风格的工具调用行与结果摘要
|
|
61
|
+
- Powerline 状态栏和工作状态提示
|
|
62
|
+
- Edit / Write 的 Diff 预览
|
|
63
|
+
- 工具结果的折叠与展开
|
|
64
|
+
- `/ccstyle` 配置命令和 `Ctrl+Shift+O` 快捷键
|
|
65
|
+
|
|
66
|
+
常用命令:
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
/ccstyle # 切换开关
|
|
70
|
+
/ccstyle status # 查看状态
|
|
71
|
+
/ccstyle compact # 紧凑摘要
|
|
72
|
+
/ccstyle minimal # 最小化输出
|
|
73
|
+
/ccstyle powerline # 查看 Powerline 预设
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 上下文窗口查看
|
|
77
|
+
|
|
78
|
+
`extensions/context.ts` 注册 `/context`,展示当前上下文窗口的使用分布,并可进一步预览:
|
|
79
|
+
|
|
80
|
+
- System prompt
|
|
81
|
+
- Tools
|
|
82
|
+
- Context files
|
|
83
|
+
- Skills
|
|
84
|
+
- User / assistant messages
|
|
85
|
+
- Tool results
|
|
86
|
+
- Compaction summaries
|
|
87
|
+
|
|
88
|
+
### 历史 Session 引用
|
|
89
|
+
|
|
90
|
+
`extensions/session-reference/index.ts` 将历史 Session 接入 `@` 补全:
|
|
91
|
+
|
|
92
|
+
1. 在提示词中输入 `@`。
|
|
93
|
+
2. 从 `[Session] ...` 或 `[SubAgent] ...` 补全项中选择要引用的上下文。
|
|
94
|
+
3. 提交时以 `@session:<session-id>` 引用其当前有效上下文。
|
|
95
|
+
|
|
96
|
+
Session 模糊查询默认显示 5 个候选;若已加载 `pi-subagents`,也可直接引用现有 SubAgent。一次提示词可以引用多个 Session;扩展会自动去重,并限制注入规模以避免上下文无限膨胀。更多细节见 [`extensions/session-reference/README.md`](./extensions/session-reference/README.md)。
|
|
97
|
+
|
|
98
|
+
## 安装
|
|
99
|
+
|
|
100
|
+
从 npm 安装(推荐):
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
pi install npm:pi-cc-extensions
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
或从 Git 安装:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
pi install git:github.com/minuque/pi-cc-extensions
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
安装后可以先运行:
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
/context
|
|
116
|
+
/ccstyle status
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## 本地开发
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
npm test
|
|
123
|
+
pi -e .
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
也可以把当前仓库作为本地 Pi 包安装:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pi install /absolute/path/to/pi-cc-extensions
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
修改扩展后,在 Pi 中执行:
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
/reload
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## 兼容性
|
|
139
|
+
|
|
140
|
+
- Node.js `>=22.19.0`
|
|
141
|
+
- 作为 Pi package 加载,入口由根目录 `package.json` 的 `pi.extensions` 显式声明
|
|
142
|
+
|
|
143
|
+
## 发布
|
|
144
|
+
|
|
145
|
+
发布前检查:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
npm test
|
|
149
|
+
npm pack --dry-run
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
使用 npm 发布。未指定 tag 时使用 `latest`:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npm run release
|
|
156
|
+
npm run release -- --tag next
|
|
157
|
+
npm run release -- --tag beta
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## 致谢
|
|
161
|
+
|
|
162
|
+
本项目中的 Powerline 状态栏、Welcome 界面、Working Vibes 等功能基于 [nicobailon/pi-powerline-footer](https://github.com/nicobailon/pi-powerline-footer) 二次开发,感谢原作者的开源贡献。
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
5
|
+
import {
|
|
6
|
+
type AutocompleteItem,
|
|
7
|
+
type AutocompleteProvider,
|
|
8
|
+
type AutocompleteSuggestions,
|
|
9
|
+
fuzzyFilter,
|
|
10
|
+
} from "@earendil-works/pi-tui";
|
|
11
|
+
|
|
12
|
+
type AgentInfo = {
|
|
13
|
+
name: string;
|
|
14
|
+
displayName: string;
|
|
15
|
+
description: string;
|
|
16
|
+
model?: string;
|
|
17
|
+
filePath: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const MAX_SUGGESTIONS = 10;
|
|
21
|
+
// Match `@name` but NOT `@session:` (reserved by session-reference extension).
|
|
22
|
+
const AGENT_NAME_PATTERN = /(?:^|[\t ])@([^\s:@][^\s:]*)$/;
|
|
23
|
+
|
|
24
|
+
function getAgentDir(): string {
|
|
25
|
+
const override = process.env.PI_CODING_AGENT_DIR;
|
|
26
|
+
return join(override ? override : homedir(), ".pi", "agent", "agents");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function parseFrontmatter(content: string): Record<string, string> {
|
|
30
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
31
|
+
if (!match) return {};
|
|
32
|
+
const result: Record<string, string> = {};
|
|
33
|
+
for (const line of match[1]!.split("\n")) {
|
|
34
|
+
const kv = line.match(/^(\w+):\s*(.*)$/);
|
|
35
|
+
if (kv) result[kv[1]!] = kv[2]!.trim();
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function loadAgents(): AgentInfo[] {
|
|
41
|
+
const dir = getAgentDir();
|
|
42
|
+
if (!existsSync(dir)) return [];
|
|
43
|
+
|
|
44
|
+
return readdirSync(dir)
|
|
45
|
+
.filter((f) => f.endsWith(".md"))
|
|
46
|
+
.map((file) => {
|
|
47
|
+
const filePath = join(dir, file);
|
|
48
|
+
const content = readFileSync(filePath, "utf-8");
|
|
49
|
+
const fm = parseFrontmatter(content);
|
|
50
|
+
const name = file.replace(/\.md$/, "");
|
|
51
|
+
return {
|
|
52
|
+
name,
|
|
53
|
+
displayName: fm.display_name || name,
|
|
54
|
+
description: fm.description || "",
|
|
55
|
+
model: fm.model,
|
|
56
|
+
filePath,
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function createAgentAutocompleteProvider(
|
|
62
|
+
current: AutocompleteProvider,
|
|
63
|
+
getAgents: () => AgentInfo[],
|
|
64
|
+
): AutocompleteProvider {
|
|
65
|
+
return {
|
|
66
|
+
async getSuggestions(
|
|
67
|
+
lines: string[],
|
|
68
|
+
cursorLine: number,
|
|
69
|
+
cursorCol: number,
|
|
70
|
+
options: { signal: AbortSignal; force?: boolean },
|
|
71
|
+
): Promise<AutocompleteSuggestions | null> {
|
|
72
|
+
const currentLine = lines[cursorLine] ?? "";
|
|
73
|
+
const textBeforeCursor = currentLine.slice(0, cursorCol);
|
|
74
|
+
const match = textBeforeCursor.match(AGENT_NAME_PATTERN);
|
|
75
|
+
|
|
76
|
+
if (!match) {
|
|
77
|
+
return current.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const query = match[1]!;
|
|
81
|
+
const agents = getAgents();
|
|
82
|
+
|
|
83
|
+
if (options.signal.aborted || agents.length === 0) {
|
|
84
|
+
return current.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const matches = query.trim()
|
|
88
|
+
? fuzzyFilter(agents, query, (a) => `${a.name} ${a.displayName} ${a.description}`)
|
|
89
|
+
: agents;
|
|
90
|
+
|
|
91
|
+
const items: AutocompleteItem[] = matches
|
|
92
|
+
.slice(0, MAX_SUGGESTIONS)
|
|
93
|
+
.map((agent) => ({
|
|
94
|
+
value: `@${agent.name}`,
|
|
95
|
+
label: `[SubAgent] ${agent.displayName}`,
|
|
96
|
+
description: agent.description
|
|
97
|
+
+ (agent.model ? ` · ${agent.model}` : ""),
|
|
98
|
+
}));
|
|
99
|
+
|
|
100
|
+
if (items.length === 0) {
|
|
101
|
+
return current.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return { items, prefix: `@${query}` };
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
applyCompletion(
|
|
108
|
+
lines: string[],
|
|
109
|
+
cursorLine: number,
|
|
110
|
+
cursorCol: number,
|
|
111
|
+
item: AutocompleteItem,
|
|
112
|
+
prefix: string,
|
|
113
|
+
) {
|
|
114
|
+
return current.applyCompletion(lines, cursorLine, cursorCol, item, prefix);
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
shouldTriggerFileCompletion(lines: string[], cursorLine: number, cursorCol: number) {
|
|
118
|
+
return current.shouldTriggerFileCompletion?.(lines, cursorLine, cursorCol) ?? true;
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export default function agentAutocompleteExtension(pi: ExtensionAPI): void {
|
|
124
|
+
let cachedAgents: AgentInfo[] | undefined;
|
|
125
|
+
|
|
126
|
+
const getAgents = (): AgentInfo[] => {
|
|
127
|
+
if (!cachedAgents) {
|
|
128
|
+
cachedAgents = loadAgents();
|
|
129
|
+
}
|
|
130
|
+
return cachedAgents;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// Reload agents on /reload
|
|
134
|
+
pi.on("resources_discover", () => {
|
|
135
|
+
cachedAgents = undefined;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
pi.on("session_start", (_event, ctx) => {
|
|
139
|
+
const agents = getAgents();
|
|
140
|
+
if (agents.length === 0 || ctx.mode !== "tui") return;
|
|
141
|
+
ctx.ui.addAutocompleteProvider((current) =>
|
|
142
|
+
createAgentAutocompleteProvider(current, getAgents),
|
|
143
|
+
);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Inject instruction when user types @agent-name (not @session:) in prompt.
|
|
147
|
+
// Supports multiple different subagents in a single prompt.
|
|
148
|
+
const AGENT_PROMPT_PATTERN = /(?:^|[\s])@([^\s:@][^\s:]*)/g;
|
|
149
|
+
pi.on("before_agent_start", async (event, _ctx) => {
|
|
150
|
+
const agents = getAgents();
|
|
151
|
+
if (agents.length === 0) return;
|
|
152
|
+
|
|
153
|
+
const mentions: string[] = [];
|
|
154
|
+
for (const m of event.prompt.matchAll(AGENT_PROMPT_PATTERN)) {
|
|
155
|
+
const name = m[1]!;
|
|
156
|
+
if (agents.some((a) => a.name === name) && !mentions.includes(name)) {
|
|
157
|
+
mentions.push(name);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (mentions.length === 0) return;
|
|
161
|
+
|
|
162
|
+
const agentMap = new Map(agents.map((a) => [a.name, a]));
|
|
163
|
+
const agentList = mentions.map((n) => `"${n}" (${agentMap.get(n)!.displayName})`).join(", ");
|
|
164
|
+
const agentTypes = mentions.map((n) => `"${n}"`).join(" | ");
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
systemPrompt:
|
|
168
|
+
event.systemPrompt
|
|
169
|
+
+ `\n\nThe user's prompt references these subagent types: ${agentList}. `
|
|
170
|
+
+ `You MUST use the Agent tool for EACH mentioned subagent to delegate the relevant parts of the request. `
|
|
171
|
+
+ `Handle different subagents separately — do NOT merge their tasks into a single Agent call. `
|
|
172
|
+
+ `For example, if the user mentions @coder and @explore, make two separate Agent tool calls, one with subagent_type="coder" and another with subagent_type="explore".`,
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
}
|