jetbrains-pi-acp 0.1.7 → 0.1.8
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 +3 -3
- package/README.zh-CN.md +3 -3
- package/extensions/acp.ts +28 -5
- package/package.json +1 -1
- package/src/session-index.js +6 -6
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Requires **Node.js 22.19.0+** and a JetBrains IDE with ACP support, such as Inte
|
|
|
11
11
|
1. Sign in to your model provider from a terminal:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npx --yes jetbrains-pi-acp@0.1.
|
|
14
|
+
npx --yes jetbrains-pi-acp@0.1.8 --setup
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
In pi, run `/login`, complete sign-in, then exit pi and return to the IDE. Credentials are managed by pi.
|
|
@@ -23,7 +23,7 @@ Requires **Node.js 22.19.0+** and a JetBrains IDE with ACP support, such as Inte
|
|
|
23
23
|
"agent_servers": {
|
|
24
24
|
"pi": {
|
|
25
25
|
"command": "npx",
|
|
26
|
-
"args": ["--yes", "jetbrains-pi-acp@0.1.
|
|
26
|
+
"args": ["--yes", "jetbrains-pi-acp@0.1.8"],
|
|
27
27
|
"use_idea_mcp": true,
|
|
28
28
|
"use_custom_mcp": true
|
|
29
29
|
}
|
|
@@ -52,7 +52,7 @@ The IDE must be able to find `npx`; use its absolute path if needed. Menu locati
|
|
|
52
52
|
Append pi options after `--` in the agent's `args`, for example:
|
|
53
53
|
|
|
54
54
|
```json
|
|
55
|
-
["--yes", "jetbrains-pi-acp@0.1.
|
|
55
|
+
["--yes", "jetbrains-pi-acp@0.1.8", "--", "--model", "provider/model-id", "--thinking", "medium"]
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
Use configuration options here, not initial prompts, interactive mode, or session-selection arguments. The adapter manages RPC mode and sessions.
|
package/README.zh-CN.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
1. 在终端中登录模型提供商:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npx --yes jetbrains-pi-acp@0.1.
|
|
14
|
+
npx --yes jetbrains-pi-acp@0.1.8 --setup
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
在 pi 中运行 `/login`,完成登录后退出 pi 并返回 IDE。凭据由 pi 管理。
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"agent_servers": {
|
|
24
24
|
"pi": {
|
|
25
25
|
"command": "npx",
|
|
26
|
-
"args": ["--yes", "jetbrains-pi-acp@0.1.
|
|
26
|
+
"args": ["--yes", "jetbrains-pi-acp@0.1.8"],
|
|
27
27
|
"use_idea_mcp": true,
|
|
28
28
|
"use_custom_mcp": true
|
|
29
29
|
}
|
|
@@ -53,7 +53,7 @@ IDE 必须能找到 `npx`,必要时使用其绝对路径。菜单位置随 IDE
|
|
|
53
53
|
在 Agent 的 `args` 末尾添加 `--`,随后传递 pi 参数,例如:
|
|
54
54
|
|
|
55
55
|
```json
|
|
56
|
-
["--yes", "jetbrains-pi-acp@0.1.
|
|
56
|
+
["--yes", "jetbrains-pi-acp@0.1.8", "--", "--model", "provider/model-id", "--thinking", "medium"]
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
这里只传配置选项,不传初始提示、交互模式或会话选择参数。RPC 模式和会话由适配器管理。
|
package/extensions/acp.ts
CHANGED
|
@@ -185,7 +185,7 @@ export default function (pi: any) {
|
|
|
185
185
|
return { message: { ...event.message, acpMessageId: id } };
|
|
186
186
|
}
|
|
187
187
|
});
|
|
188
|
-
const archiveCache = new Map<string, { modified: number; archived: boolean }>();
|
|
188
|
+
const archiveCache = new Map<string, { modified: number; archived: boolean; children: string[]; records: string[] }>();
|
|
189
189
|
for (const [name, server] of Object.entries(config.mcpServers)) {
|
|
190
190
|
pi.registerMcpServer(name, server);
|
|
191
191
|
}
|
|
@@ -219,19 +219,42 @@ export default function (pi: any) {
|
|
|
219
219
|
const currentPaths = new Set(sessions.map(session => session.path));
|
|
220
220
|
const idsByPath = new Map(sessions.map(session => [session.path, session.id]));
|
|
221
221
|
for (const path of archiveCache.keys()) if (!currentPaths.has(path)) archiveCache.delete(path);
|
|
222
|
-
|
|
222
|
+
const infos = sessions.map(session => {
|
|
223
223
|
const modified = statSync(session.path).mtimeMs;
|
|
224
224
|
let cached = archiveCache.get(session.path);
|
|
225
225
|
if (!cached || cached.modified !== modified) {
|
|
226
|
-
const
|
|
226
|
+
const manager = SessionManager.open(session.path);
|
|
227
|
+
const archived = manager.getBranch().findLast((entry: any) =>
|
|
227
228
|
entry.type === 'custom' && entry.customType === 'acp_archive')?.data === true;
|
|
228
|
-
|
|
229
|
+
const entries = manager.getEntries() as any[];
|
|
230
|
+
const children = entries.flatMap(entry =>
|
|
231
|
+
entry.type === 'custom' && entry.customType === 'acp_task' && entry.data?.kind === 'agent' &&
|
|
232
|
+
entry.data.owner === session.id && typeof entry.data.sessionId === 'string' ? [entry.data.sessionId] : []);
|
|
233
|
+
const records = entries.flatMap(entry =>
|
|
234
|
+
entry.type === 'custom' && entry.customType === 'subagents:record' && typeof entry.data?.id === 'string' ? [entry.data.id] : []);
|
|
235
|
+
cached = { modified, archived, children, records };
|
|
229
236
|
archiveCache.set(session.path, cached);
|
|
230
237
|
}
|
|
231
238
|
return { sessionId: session.id, cwd: session.cwd, title: session.name || session.firstMessage,
|
|
232
239
|
updatedAt: session.modified.toISOString(), path: session.path, archived: cached.archived,
|
|
233
240
|
...(idsByPath.has(session.parentSessionPath) ? { forkedFrom: idsByPath.get(session.parentSessionPath) } : {}) };
|
|
234
|
-
})
|
|
241
|
+
});
|
|
242
|
+
// 子 agent 会话标记 subagent,由适配器从列表中过滤:
|
|
243
|
+
// 1) 适配器自己的子 agent:父会话的 acp_task 引用其 ID(自有格式,稳定);
|
|
244
|
+
// 2) 旧版 @tintinweb/pi-subagents 写在顶层目录的历史会话:名称为 `类型#8位hex`,
|
|
245
|
+
// 且父会话有 id 以该 hex 开头的 subagents:record。
|
|
246
|
+
// 当前 pi-subagents 的子会话在嵌套目录或临时目录,SessionManager.list 本就不返回。
|
|
247
|
+
// shortcut: 规则 2 只为旧包的历史数据,不再有此类会话后可整段删除。
|
|
248
|
+
const children = new Set(sessions.flatMap(session => archiveCache.get(session.path)?.children ?? []));
|
|
249
|
+
const recordsByPath = new Map(sessions.map(session => [session.path, archiveCache.get(session.path)?.records ?? []]));
|
|
250
|
+
const isSubagent = (session: any) => {
|
|
251
|
+
const hex = /#([0-9a-f]{8})$/.exec(session.name ?? '')?.[1];
|
|
252
|
+
return children.has(session.id) || (!!hex && !!session.parentSessionPath &&
|
|
253
|
+
!!recordsByPath.get(session.parentSessionPath)?.some(id => id.startsWith(hex)));
|
|
254
|
+
};
|
|
255
|
+
const subagents = new Set(sessions.filter(isSubagent).map(session => session.id));
|
|
256
|
+
ctx.ui.notify(`PI_ACP_SESSIONS:${JSON.stringify(infos.map(info =>
|
|
257
|
+
subagents.has(info.sessionId) ? { ...info, subagent: true } : info))}`, 'info');
|
|
235
258
|
},
|
|
236
259
|
});
|
|
237
260
|
pi.on('tool_call', async (event: any, ctx: any) => {
|
package/package.json
CHANGED
package/src/session-index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { t } from './i18n.js';
|
|
|
7
7
|
|
|
8
8
|
const executeFile = promisify(execFile);
|
|
9
9
|
|
|
10
|
-
//
|
|
10
|
+
// 历史会话索引:列表、查找、归档及列表变化订阅;列表默认不含子 agent 会话,仅内部查找时包含。
|
|
11
11
|
// 历史由临时启动的 discovery pi 进程通过 /__acp_list 读取。
|
|
12
12
|
export class SessionIndex {
|
|
13
13
|
constructor(agent) {
|
|
@@ -16,7 +16,7 @@ export class SessionIndex {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
async find(sessionId, cwd) {
|
|
19
|
-
const { sessions } = await this.list(cwd === undefined ? {} : { cwd }, { includeArchived: true });
|
|
19
|
+
const { sessions } = await this.list(cwd === undefined ? {} : { cwd }, { includeArchived: true, includeSubagents: true });
|
|
20
20
|
return sessions.find(info => info.sessionId === sessionId && (cwd === undefined || resolve(info.cwd) === resolve(cwd)));
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -31,7 +31,7 @@ export class SessionIndex {
|
|
|
31
31
|
}) };
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
async read(context, params) {
|
|
34
|
+
async read(context, params, { includeSubagents = false } = {}) {
|
|
35
35
|
let cwds = [context.cwd];
|
|
36
36
|
if (params._meta?.jetbrains?.air?.list?.includeWorktrees === true) {
|
|
37
37
|
try {
|
|
@@ -44,10 +44,10 @@ export class SessionIndex {
|
|
|
44
44
|
context.history = undefined;
|
|
45
45
|
await context.pi.request('prompt', { message: `/__acp_list ${JSON.stringify({ all: params.cwd === undefined, cwds })}` });
|
|
46
46
|
if (!context.history) throw new Error(t('piNoHistory'));
|
|
47
|
-
return context.history;
|
|
47
|
+
return includeSubagents ? context.history : context.history.filter(info => !info.subagent);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
async list(params, { includeArchived = false } = {}) {
|
|
50
|
+
async list(params, { includeArchived = false, includeSubagents = false } = {}) {
|
|
51
51
|
if (params.cursor !== undefined && (typeof params.cursor !== 'string' || !/^\d+$/.test(params.cursor))) {
|
|
52
52
|
throw invalid(t('listCursorInvalid'));
|
|
53
53
|
}
|
|
@@ -65,7 +65,7 @@ export class SessionIndex {
|
|
|
65
65
|
}
|
|
66
66
|
const created = await this.agent.newSession({ cwd: params.cwd ?? process.cwd(), mcpServers: [] }, { discovery: true });
|
|
67
67
|
try {
|
|
68
|
-
const history = (await this.read(created, params)).filter(info =>
|
|
68
|
+
const history = (await this.read(created, params, { includeSubagents })).filter(info =>
|
|
69
69
|
archived === 'all' || (info.archived === true) === (archived === 'archived'));
|
|
70
70
|
const sessions = history.slice(offset, offset + limit);
|
|
71
71
|
return { sessions, ...(offset + limit < history.length ? { nextCursor: String(offset + limit) } : {}) };
|