pi-cc-extensions 0.7.2 → 0.7.3
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
CHANGED
|
@@ -95,7 +95,7 @@ Session 模糊查询默认显示 5 个候选;若已加载 `pi-subagents`,也
|
|
|
95
95
|
2. 从补全列表中选择 SubAgent。
|
|
96
96
|
3. 提交后自动注入委托指令;提示词中提到的每个 SubAgent 都会分别交由 Agent 工具处理。
|
|
97
97
|
|
|
98
|
-
该补全不会占用 `@session:` 的历史 Session
|
|
98
|
+
该补全不会占用 `@session:` 的历史 Session 引用语法;与 `@bacnh85/pi-fff` 同时启用时,SubAgent、Session 和 FFF 文件候选会合并显示。修改 SubAgent 定义后执行 `/reload` 即可重新加载。
|
|
99
99
|
|
|
100
100
|
## 安装
|
|
101
101
|
|
|
@@ -19,7 +19,7 @@ type AgentInfo = {
|
|
|
19
19
|
|
|
20
20
|
const MAX_SUGGESTIONS = 10;
|
|
21
21
|
// Match `@name` but NOT `@session:` (reserved by session-reference extension).
|
|
22
|
-
const AGENT_NAME_PATTERN = /(?:^|[\t ])@([^\s:@][^\s:]*)$/;
|
|
22
|
+
const AGENT_NAME_PATTERN = /(?:^|[\t ])@((?:[^\s:@][^\s:]*)?)$/;
|
|
23
23
|
|
|
24
24
|
function getAgentDir(): string {
|
|
25
25
|
const override = process.env.PI_CODING_AGENT_DIR;
|
|
@@ -58,11 +58,12 @@ function loadAgents(): AgentInfo[] {
|
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
function createAgentAutocompleteProvider(
|
|
61
|
+
export function createAgentAutocompleteProvider(
|
|
62
62
|
current: AutocompleteProvider,
|
|
63
63
|
getAgents: () => AgentInfo[],
|
|
64
64
|
): AutocompleteProvider {
|
|
65
65
|
return {
|
|
66
|
+
triggerCharacters: ["@"],
|
|
66
67
|
async getSuggestions(
|
|
67
68
|
lines: string[],
|
|
68
69
|
cursorLine: number,
|
|
@@ -84,11 +85,15 @@ function createAgentAutocompleteProvider(
|
|
|
84
85
|
return current.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
const matches =
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
const [baseSuggestions, matches] = await Promise.all([
|
|
89
|
+
current.getSuggestions(lines, cursorLine, cursorCol, options),
|
|
90
|
+
Promise.resolve(query.trim()
|
|
91
|
+
? fuzzyFilter(agents, query, (a) => `${a.name} ${a.displayName} ${a.description}`)
|
|
92
|
+
: agents),
|
|
93
|
+
]);
|
|
94
|
+
if (options.signal.aborted) return null;
|
|
90
95
|
|
|
91
|
-
const
|
|
96
|
+
const agentItems: AutocompleteItem[] = matches
|
|
92
97
|
.slice(0, MAX_SUGGESTIONS)
|
|
93
98
|
.map((agent) => ({
|
|
94
99
|
value: `@${agent.name}`,
|
|
@@ -96,11 +101,18 @@ function createAgentAutocompleteProvider(
|
|
|
96
101
|
description: agent.description
|
|
97
102
|
+ (agent.model ? ` · ${agent.model}` : ""),
|
|
98
103
|
}));
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
const baseItems = baseSuggestions?.prefix === `@${query}`
|
|
105
|
+
? baseSuggestions.items
|
|
106
|
+
: [];
|
|
107
|
+
const seen = new Set<string>();
|
|
108
|
+
const items = [...agentItems, ...baseItems].filter((item) => {
|
|
109
|
+
const key = `${item.value}\0${item.label}`;
|
|
110
|
+
if (seen.has(key)) return false;
|
|
111
|
+
seen.add(key);
|
|
112
|
+
return true;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (items.length === 0) return baseSuggestions;
|
|
104
116
|
return { items, prefix: `@${query}` };
|
|
105
117
|
},
|
|
106
118
|
|
|
@@ -122,6 +134,7 @@ function createAgentAutocompleteProvider(
|
|
|
122
134
|
|
|
123
135
|
export default function agentAutocompleteExtension(pi: ExtensionAPI): void {
|
|
124
136
|
let cachedAgents: AgentInfo[] | undefined;
|
|
137
|
+
let sessionGeneration = 0;
|
|
125
138
|
|
|
126
139
|
const getAgents = (): AgentInfo[] => {
|
|
127
140
|
if (!cachedAgents) {
|
|
@@ -136,11 +149,22 @@ export default function agentAutocompleteExtension(pi: ExtensionAPI): void {
|
|
|
136
149
|
});
|
|
137
150
|
|
|
138
151
|
pi.on("session_start", (_event, ctx) => {
|
|
152
|
+
const generation = ++sessionGeneration;
|
|
139
153
|
const agents = getAgents();
|
|
140
154
|
if (agents.length === 0 || ctx.mode !== "tui") return;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
155
|
+
|
|
156
|
+
// Register after other session_start handlers have installed their wrappers.
|
|
157
|
+
// pi-fff handles every @ prefix and otherwise shadows providers loaded before it.
|
|
158
|
+
setTimeout(() => {
|
|
159
|
+
if (generation !== sessionGeneration) return;
|
|
160
|
+
ctx.ui.addAutocompleteProvider((current) =>
|
|
161
|
+
createAgentAutocompleteProvider(current, getAgents),
|
|
162
|
+
);
|
|
163
|
+
}, 0);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
pi.on("session_shutdown", () => {
|
|
167
|
+
sessionGeneration++;
|
|
144
168
|
});
|
|
145
169
|
|
|
146
170
|
// Inject instruction when user types @agent-name (not @session:) in prompt.
|
|
@@ -215,7 +215,7 @@ function mergeReferences(sessions: SessionInfo[], subagents: SessionReference[])
|
|
|
215
215
|
return [...bySessionId.values()];
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
function createAutocompleteProvider(
|
|
218
|
+
export function createAutocompleteProvider(
|
|
219
219
|
current: AutocompleteProvider,
|
|
220
220
|
getReferences: () => Promise<SessionReference[]>,
|
|
221
221
|
currentCwd: string,
|
|
@@ -263,6 +263,7 @@ function samePath(left: string | undefined, right: string): boolean {
|
|
|
263
263
|
|
|
264
264
|
export default function sessionReferenceExtension(pi: ExtensionAPI): void {
|
|
265
265
|
let getAvailableReferences: (() => Promise<SessionReference[]>) | undefined;
|
|
266
|
+
let sessionGeneration = 0;
|
|
266
267
|
const subagentIds = new Set<string>();
|
|
267
268
|
// pi-subagents emits "subagent:async-started" and "subagent:async-complete" events.
|
|
268
269
|
// We track records locally so @[SubAgent] suggestions work even without a global manager.
|
|
@@ -290,6 +291,7 @@ export default function sessionReferenceExtension(pi: ExtensionAPI): void {
|
|
|
290
291
|
});
|
|
291
292
|
|
|
292
293
|
pi.on("session_start", (_event, ctx) => {
|
|
294
|
+
const generation = ++sessionGeneration;
|
|
293
295
|
subagentIds.clear();
|
|
294
296
|
let loadErrorShown = false;
|
|
295
297
|
const currentSessionId = ctx.sessionManager.getSessionId();
|
|
@@ -320,7 +322,14 @@ export default function sessionReferenceExtension(pi: ExtensionAPI): void {
|
|
|
320
322
|
getAvailableReferences = getReferences;
|
|
321
323
|
if (ctx.mode === "tui") {
|
|
322
324
|
void getReferences();
|
|
323
|
-
|
|
325
|
+
// Register after other session_start handlers. pi-fff claims every @
|
|
326
|
+
// prefix, so a provider installed before it would never see session mentions.
|
|
327
|
+
setTimeout(() => {
|
|
328
|
+
if (generation !== sessionGeneration) return;
|
|
329
|
+
ctx.ui.addAutocompleteProvider((current) =>
|
|
330
|
+
createAutocompleteProvider(current, getReferences, ctx.cwd),
|
|
331
|
+
);
|
|
332
|
+
}, 0);
|
|
324
333
|
}
|
|
325
334
|
});
|
|
326
335
|
|
|
@@ -404,6 +413,7 @@ export default function sessionReferenceExtension(pi: ExtensionAPI): void {
|
|
|
404
413
|
});
|
|
405
414
|
|
|
406
415
|
pi.on("session_shutdown", () => {
|
|
416
|
+
sessionGeneration++;
|
|
407
417
|
for (const unsubscribe of unsubscribeSubagentEvents) unsubscribe();
|
|
408
418
|
subagentIds.clear();
|
|
409
419
|
getAvailableReferences = undefined;
|