@dyyz1993/pi-coding-agent 0.74.46 → 0.74.48

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.
Files changed (49) hide show
  1. package/dist/core/agent-session.d.ts.map +1 -1
  2. package/dist/core/agent-session.js +16 -0
  3. package/dist/core/agent-session.js.map +1 -1
  4. package/dist/core/session-manager.d.ts +28 -1
  5. package/dist/core/session-manager.d.ts.map +1 -1
  6. package/dist/core/session-manager.js +89 -10
  7. package/dist/core/session-manager.js.map +1 -1
  8. package/dist/extensions/ask-tools/index.ts +45 -0
  9. package/dist/extensions/auto-memory/__tests__/extract-result.test.ts +42 -0
  10. package/dist/extensions/auto-memory/__tests__/prefetch-history.test.ts +136 -0
  11. package/dist/extensions/auto-memory/__tests__/prompts.test.ts +29 -0
  12. package/dist/extensions/auto-memory/__tests__/skip-rules.test.ts +366 -0
  13. package/dist/extensions/auto-memory/contract.d.ts +16 -0
  14. package/dist/extensions/auto-memory/contract.d.ts.map +1 -1
  15. package/dist/extensions/auto-memory/contract.js.map +1 -1
  16. package/dist/extensions/auto-memory/contract.ts +16 -0
  17. package/dist/extensions/auto-memory/index.ts +134 -13
  18. package/dist/extensions/auto-memory/prompts.ts +10 -0
  19. package/dist/extensions/auto-memory/skip-rules.ts +2 -0
  20. package/dist/extensions/auto-session-title/index.ts +2 -0
  21. package/dist/extensions/bash-ext/index.ts +855 -845
  22. package/dist/extensions/claude-hooks-compat/index.ts +12 -7
  23. package/dist/extensions/compaction-manager/index.ts +68 -7
  24. package/dist/extensions/coordinator/handler.test.ts +388 -123
  25. package/dist/extensions/coordinator/handler.ts +78 -12
  26. package/dist/extensions/coordinator/index.ts +306 -198
  27. package/dist/extensions/coordinator/types.d.ts +16 -0
  28. package/dist/extensions/coordinator/types.d.ts.map +1 -1
  29. package/dist/extensions/coordinator/types.js.map +1 -1
  30. package/dist/extensions/coordinator/types.ts +57 -49
  31. package/dist/extensions/hooks-engine/index.ts +3 -0
  32. package/dist/extensions/lsp/lsp/client/smart-file-tracker.ts +302 -0
  33. package/dist/extensions/lsp/lsp/index.ts +15 -9
  34. package/dist/extensions/lsp/lsp/lsp-clangd-e2e.test.ts +229 -0
  35. package/dist/extensions/lsp/lsp/utils/project-scanner.ts +101 -12
  36. package/dist/extensions/message-bridge/index.ts +14 -11
  37. package/dist/extensions/output-guard/index.ts +39 -0
  38. package/dist/extensions/preview/index.ts +23 -0
  39. package/dist/extensions/session-supervisor/index.ts +14 -8
  40. package/dist/extensions/subagent-v2/extract-parent-todos.test.ts +146 -0
  41. package/dist/extensions/subagent-v2/index.ts +430 -57
  42. package/dist/extensions/todo-ext/index.ts +62 -3
  43. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  44. package/dist/modes/interactive/interactive-mode.js +6 -0
  45. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  46. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  47. package/dist/modes/rpc/rpc-mode.js +10 -0
  48. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  49. package/package.json +1 -1
@@ -1,158 +1,188 @@
1
1
  import {
2
- createTypedChannel,
3
- type ExtensionAPI,
2
+ createTypedChannel,
3
+ type ExtensionAPI,
4
4
  } from "@dyyz1993/pi-coding-agent";
5
5
  import { Type } from "typebox";
6
6
  import { COORDINATOR_CHANNEL_NAME, type CoordinatorChannelContract, type SessionStatus } from "./types.js";
7
7
  import { createCoordinatorHandler, TaskStore, type ProcessManagerApi } from "./handler.js";
8
8
 
9
9
  const DelegateParams = Type.Object({
10
- task: Type.String({ description: "Task description to delegate to the background session" }),
11
- title: Type.Optional(Type.String({ description: "Short title for this delegated task" })),
10
+ task: Type.String({ description: "Task description to delegate to the background session" }),
11
+ title: Type.Optional(Type.String({ description: "Short title for this delegated task" })),
12
+ projectPath: Type.Optional(Type.String({ description: "Project directory to run the delegated session in. Defaults to the current working directory." })),
12
13
  });
13
14
 
14
15
  const DelegateSendParams = Type.Object({
15
- targetSessionId: Type.String({ description: "Session ID to send the message to" }),
16
- message: Type.String({ description: "Message content to send" }),
16
+ targetSessionId: Type.String({ description: "Session ID to send the message to" }),
17
+ message: Type.String({ description: "Message content to send" }),
17
18
  });
18
19
 
19
20
  const DelegateStatusParams = Type.Object({
20
- sessionId: Type.String({ description: "Session ID to check status for" }),
21
+ sessionId: Type.String({ description: "Session ID to check status for" }),
21
22
  });
22
23
 
23
24
  const DelegateStopParams = Type.Object({
24
- sessionId: Type.String({ description: "Session ID to stop" }),
25
+ sessionId: Type.String({ description: "Session ID to stop" }),
25
26
  });
26
27
 
27
28
  const DelegateForkParams = Type.Object({
28
- sessionId: Type.String({ description: "Source session ID to fork from" }),
29
- task: Type.String({ description: "Task description for the forked session" }),
30
- title: Type.Optional(Type.String({ description: "Short title for the forked task" })),
29
+ sessionId: Type.String({ description: "Source session ID to fork from" }),
30
+ task: Type.String({ description: "Task description for the forked session" }),
31
+ title: Type.Optional(Type.String({ description: "Short title for the forked task" })),
32
+ projectPath: Type.Optional(Type.String({ description: "Project directory to run the forked session in. Defaults to the current working directory." })),
31
33
  });
32
34
 
33
35
  export default function coordinatorExtension(pi: ExtensionAPI) {
34
- const rawChannel = pi.registerChannel(COORDINATOR_CHANNEL_NAME);
35
-
36
- const { server: serverChannel, client } = createTypedChannel<CoordinatorChannelContract>(rawChannel);
37
-
38
- let currentSessionId = "";
39
- let store: TaskStore | null = null;
40
-
41
- pi.on("session_start", (_event, ctx) => {
42
- currentSessionId = ctx.sessionManager.getSessionId();
43
- store = new TaskStore(ctx.sessionManager.getSessionDir());
44
- });
45
-
46
- const serverProxy: ProcessManagerApi = {
47
- async delegate(task, _projectPath) {
48
- return client.call("session_delegate", { task }) as Promise<{ sessionId: string; status: "started" | "already_running" }>;
49
- },
50
-
51
- async delegate_send(fromSessionId, toSessionId, message) {
52
- return client.call("session_delegate_send", {
53
- targetSessionId: toSessionId,
54
- message,
55
- }) as Promise<{ delivered: boolean; targetStatus: "active" | "started" | "not_found" }>;
56
- },
57
-
58
- async delegate_status(sessionId) {
59
- try {
60
- const result = await client.call("session_delegate_status", { sessionId }) as { task: { status: string } | null };
61
- return result.task ? { status: result.task.status as SessionStatus } : { status: "stopped" as const };
62
- } catch (err) {
63
- console.debug("[coordinator] delegate_status failed:", err instanceof Error ? err.message : err);
64
- return { status: "stopped" as const };
65
- }
66
- },
67
-
68
- async delegate_list() {
69
- try {
70
- const result = await client.call("session_delegate_list", {}) as { tasks: Array<{ sessionId: string; status: SessionStatus; projectPath: string }> };
71
- return result.tasks;
72
- } catch (err) {
73
- console.debug("[coordinator] delegate_list failed:", err instanceof Error ? err.message : err);
74
- return [];
75
- }
76
- },
77
-
78
- async delegate_stop(sessionId) {
79
- try {
80
- const result = await client.call("session_delegate_stop", { sessionId }) as { ok: boolean };
81
- return result.ok;
82
- } catch (err) {
83
- console.debug("[coordinator] delegate_stop failed:", err instanceof Error ? err.message : err);
84
- return false;
85
- }
86
- },
87
-
88
- async delegate_fork(sessionId, task, title) {
89
- return client.call("session_delegate_fork", { sessionId, task, title }) as Promise<{ sessionId: string; status: "started" | "already_running" }>;
90
- },
91
-
92
- async delegate_compact_status(sessionId: string) {
93
- try {
94
- const result = await client.call("session_delegate_status", { sessionId }) as { isCompacting?: boolean; contextUsage?: { tokens: number | null; contextWindow: number; percent: number | null } };
95
- return {
96
- isCompacting: result.isCompacting ?? false,
97
- contextUsage: result.contextUsage ?? { tokens: null as number | null, contextWindow: 0, percent: null as number | null },
98
- };
99
- } catch (err) {
100
- console.debug("[coordinator] delegate_compact_status failed:", err instanceof Error ? err.message : err);
101
- return { isCompacting: false, contextUsage: { tokens: null as number | null, contextWindow: 0, percent: null as number | null } };
102
- }
103
- },
104
- };
105
-
106
- createCoordinatorHandler(
107
- serverChannel,
108
- serverProxy,
109
- () => currentSessionId,
110
- () => store ?? new TaskStore("/tmp/coordinator-fallback"),
111
- );
112
-
113
- pi.on("context", (event, _ctx) => {
114
- if (!store) return;
115
- const prompt = store.buildPrompt();
116
- if (prompt) {
117
- event.messages.push({
118
- role: "user",
119
- content: [{ type: "text", text: prompt }],
120
- timestamp: Date.now(),
121
- });
122
- }
123
- });
36
+ const rawChannel = pi.registerChannel(COORDINATOR_CHANNEL_NAME);
37
+
38
+ const { server: serverChannel, client } = createTypedChannel<CoordinatorChannelContract>(rawChannel);
39
+
40
+ let currentSessionId = "";
41
+ let store: TaskStore | null = null;
42
+
43
+ pi.on("session_start", (_event, ctx) => {
44
+ currentSessionId = ctx.sessionManager.getSessionId();
45
+ store = new TaskStore(ctx.sessionManager.getSessionDir());
46
+ });
47
+
48
+ const serverProxy: ProcessManagerApi = {
49
+ async delegate(task, projectPath) {
50
+ return client.call("session_delegate", { task, projectPath }) as Promise<{ sessionId: string; status: "started" | "already_running" }>;
51
+ },
52
+
53
+ async delegate_send(fromSessionId, toSessionId, message) {
54
+ return client.call("session_delegate_send", {
55
+ targetSessionId: toSessionId,
56
+ message,
57
+ }) as Promise<{ delivered: boolean; targetStatus: "active" | "started" | "not_found" }>;
58
+ },
59
+
60
+ async delegate_status(sessionId) {
61
+ try {
62
+ const result = await client.call("session_delegate_status", { sessionId }) as { task: { status: string } | null };
63
+ return result.task ? { status: result.task.status as SessionStatus } : { status: "stopped" as const };
64
+ } catch (err) {
65
+ console.debug("[coordinator] delegate_status failed:", err instanceof Error ? err.message : err);
66
+ return { status: "stopped" as const };
67
+ }
68
+ },
69
+
70
+ async delegate_list() {
71
+ try {
72
+ const result = await client.call("session_delegate_list", {}) as { tasks: Array<{ sessionId: string; status: SessionStatus; projectPath: string }> };
73
+ return result.tasks;
74
+ } catch (err) {
75
+ console.debug("[coordinator] delegate_list failed:", err instanceof Error ? err.message : err);
76
+ return [];
77
+ }
78
+ },
79
+
80
+ async delegate_stop(sessionId) {
81
+ try {
82
+ const result = await client.call("session_delegate_stop", { sessionId }) as { ok: boolean };
83
+ return result.ok;
84
+ } catch (err) {
85
+ console.debug("[coordinator] delegate_stop failed:", err instanceof Error ? err.message : err);
86
+ return false;
87
+ }
88
+ },
89
+
90
+ async delegate_fork(sessionId, task, title, projectPath) {
91
+ return client.call("session_delegate_fork", { sessionId, task, title, projectPath }) as Promise<{ sessionId: string; status: "started" | "already_running" }>;
92
+ },
93
+
94
+ async delegate_compact_status(sessionId: string) {
95
+ try {
96
+ const result = await client.call("session_delegate_status", { sessionId }) as { isCompacting?: boolean; contextUsage?: { tokens: number | null; contextWindow: number; percent: number | null } };
97
+ return {
98
+ isCompacting: result.isCompacting ?? false,
99
+ contextUsage: result.contextUsage ?? { tokens: null as number | null, contextWindow: 0, percent: null as number | null },
100
+ };
101
+ } catch (err) {
102
+ console.debug("[coordinator] delegate_compact_status failed:", err instanceof Error ? err.message : err);
103
+ return { isCompacting: false, contextUsage: { tokens: null as number | null, contextWindow: 0, percent: null as number | null } };
104
+ }
105
+ },
106
+
107
+ async delegate_remove(sessionId: string) {
108
+ try {
109
+ const result = await client.call("session_delegate_remove", { sessionId }) as { ok: boolean };
110
+ return result.ok;
111
+ } catch (err) {
112
+ console.debug("[coordinator] delegate_remove failed:", err instanceof Error ? err.message : err);
113
+ return false;
114
+ }
115
+ },
116
+
117
+ async delegate_clear_stopped() {
118
+ try {
119
+ const result = await client.call("session_delegate_clear_stopped", {}) as { removed: number };
120
+ return result.removed;
121
+ } catch (err) {
122
+ console.debug("[coordinator] delegate_clear_stopped failed:", err instanceof Error ? err.message : err);
123
+ return 0;
124
+ }
125
+ },
126
+ };
127
+
128
+ createCoordinatorHandler(
129
+ serverChannel,
130
+ serverProxy,
131
+ () => currentSessionId,
132
+ () => store ?? new TaskStore("/tmp/coordinator-fallback"),
133
+ );
134
+
135
+ pi.on("context", (event, _ctx) => {
136
+ if (!store) return;
137
+ const prompt = store.buildPrompt();
138
+ if (prompt) {
139
+ event.messages.push({
140
+ role: "user",
141
+ content: [{ type: "text", text: prompt }],
142
+ timestamp: Date.now(),
143
+ });
144
+ }
145
+ });
124
146
 
125
147
  pi.registerTool({
126
148
  name: "session_delegate",
127
149
  label: "Session Delegate",
128
150
  description: [
129
151
  "Delegate a task to a background pi session.",
152
+ "Optionally specify a projectPath to run the session in a specific project directory.",
130
153
  "Returns a sessionId for communication via session_delegate_send.",
131
154
  "The delegated session can message back using its own coordinator channel.",
132
155
  "The delegate session is automatically restarted if inactive when receiving messages.",
133
156
  ].join(" "),
134
- parameters: DelegateParams,
135
- async execute(toolCallId, params, _signal, _onUpdate, ctx) {
136
- const sid = currentSessionId || ctx.sessionManager.getSessionId();
137
- const result = await serverProxy.delegate(params.task, ctx.cwd);
138
-
139
- if (store) {
140
- store.add({
141
- sessionId: result.sessionId,
142
- title: params.title || params.task.slice(0, 60),
143
- task: params.task,
144
- projectPath: ctx.cwd,
145
- dispatchedAt: Date.now(),
146
- status: "idle",
147
- });
148
- }
149
-
150
- return {
151
- content: [{ type: "text" as const, text: `Delegated task to session ${result.sessionId} (status: ${result.status}). Use session_delegate_send to communicate.` }],
152
- details: { ...result, dispatchedBy: sid },
153
- };
154
- },
155
- });
157
+ parameters: DelegateParams,
158
+ async execute(toolCallId, params, _signal, _onUpdate, ctx) {
159
+ const sid = currentSessionId || ctx.sessionManager.getSessionId();
160
+ const projectPath = params.projectPath || ctx.cwd;
161
+ const result = await serverProxy.delegate(params.task, projectPath);
162
+
163
+ if (!result.sessionId) {
164
+ console.debug("[coordinator] delegate failed: no sessionId returned");
165
+ pi.appendEntry("coordinator_delegate_failed", { task: params.task, projectPath });
166
+ return {
167
+ content: [{ type: "text" as const, text: `Failed to delegate task: no sessionId returned.` }],
168
+ details: { error: "no sessionId" },
169
+ };
170
+ }
171
+
172
+ pi.appendEntry("coordinator_delegate", {
173
+ sessionId: result.sessionId,
174
+ status: result.status,
175
+ task: params.task,
176
+ title: params.title,
177
+ projectPath,
178
+ dispatchedBy: sid,
179
+ });
180
+ return {
181
+ content: [{ type: "text" as const, text: `Delegated task to session ${result.sessionId} (status: ${result.status}, cwd: ${projectPath}). Use session_delegate_send to communicate.` }],
182
+ details: { ...result, dispatchedBy: sid, projectPath },
183
+ };
184
+ },
185
+ });
156
186
 
157
187
  pi.registerTool({
158
188
  name: "session_delegate_send",
@@ -170,12 +200,14 @@ export default function coordinatorExtension(pi: ExtensionAPI) {
170
200
  const result = await serverProxy.delegate_send(sid, params.targetSessionId, params.message);
171
201
 
172
202
  if (!result.delivered) {
203
+ pi.appendEntry("coordinator_send_failed", { fromSessionId: sid, toSessionId: params.targetSessionId });
173
204
  return {
174
205
  content: [{ type: "text" as const, text: `Could not deliver message to ${params.targetSessionId}: session not found (the session file may have been deleted from disk)` }],
175
206
  details: { delivered: false, targetSessionId: params.targetSessionId },
176
207
  };
177
208
  }
178
209
 
210
+ pi.appendEntry("coordinator_send", { fromSessionId: sid, toSessionId: params.targetSessionId, status: result.targetStatus });
179
211
  return {
180
212
  content: [{ type: "text" as const, text: `Message delivered to ${params.targetSessionId} (status: ${result.targetStatus})` }],
181
213
  details: result,
@@ -183,79 +215,155 @@ export default function coordinatorExtension(pi: ExtensionAPI) {
183
215
  },
184
216
  });
185
217
 
186
- pi.registerTool({
187
- name: "session_delegate_status",
188
- label: "Session Delegate Status",
189
- description: "Check the status of a delegated task session.",
190
- parameters: DelegateStatusParams,
191
- async execute(toolCallId, params, _signal, _onUpdate, _ctx) {
192
- const task = store?.get(params.sessionId);
193
- if (task) {
194
- const status = task.status === "completed" ? "DONE" : task.status.toUpperCase();
195
- return {
196
- content: [{ type: "text" as const, text: `Task "${task.title}" (${params.sessionId}): ${status}` }],
197
- details: { task },
198
- };
199
- }
200
- const remote = await serverProxy.delegate_status(params.sessionId);
201
- return {
202
- content: [{ type: "text" as const, text: `Session ${params.sessionId} status: ${remote.status}` }],
203
- details: { task: null },
204
- };
205
- },
206
- });
207
-
208
- pi.registerTool({
209
- name: "session_delegate_stop",
210
- label: "Session Delegate Stop",
211
- description: "Stop a delegated task session.",
212
- parameters: DelegateStopParams,
213
- async execute(toolCallId, params, _signal, _onUpdate, _ctx) {
214
- const ok = await serverProxy.delegate_stop(params.sessionId);
215
- if (ok && store) {
216
- store.update(params.sessionId, { status: "stopped" });
217
- }
218
- return {
219
- content: [{ type: "text" as const, text: ok ? `Session ${params.sessionId} stopped.` : `Session ${params.sessionId} not found or already stopped.` }],
220
- details: { ok },
221
- };
222
- },
223
- });
224
-
225
- pi.registerTool({
226
- name: "session_delegate_fork",
227
- label: "Session Delegate Fork",
228
- description: [
229
- "Fork an existing session and delegate a new task to the forked session.",
230
- "The forked session starts with a copy of the source session's conversation history.",
231
- "The original session continues running unchanged.",
232
- ].join(" "),
233
- parameters: DelegateForkParams,
234
- async execute(toolCallId, params, _signal, _onUpdate, ctx) {
235
- const sid = currentSessionId || ctx.sessionManager.getSessionId();
236
- const result = await serverProxy.delegate_fork(params.sessionId, params.task, params.title);
237
- if (store) {
238
- store.add({
239
- sessionId: result.sessionId,
240
- title: params.title || params.task.slice(0, 60),
241
- task: params.task,
242
- projectPath: ctx.cwd,
243
- dispatchedAt: Date.now(),
244
- status: "idle",
245
- });
246
- }
247
- return {
248
- content: [{ type: "text" as const, text: `Forked session ${params.sessionId} → ${result.sessionId} (status: ${result.status}). Task: ${params.task}` }],
249
- details: { ...result, forkedFrom: params.sessionId, dispatchedBy: sid },
250
- };
251
- },
252
- });
253
-
254
- client.on("message_received", (data: unknown) => {
255
- const d = data as { fromSessionId: string; message: string };
256
- pi.sendUserMessage(
257
- `[Coordinator] Message from session ${d.fromSessionId}:\n${d.message}`,
258
- { deliverAs: "followUp" },
259
- );
260
- });
218
+ pi.registerTool({
219
+ name: "session_delegate_status",
220
+ label: "Session Delegate Status",
221
+ description: "Check the status of a delegated task session.",
222
+ parameters: DelegateStatusParams,
223
+ async execute(toolCallId, params, _signal, _onUpdate, _ctx) {
224
+ const task = store?.get(params.sessionId);
225
+ if (task) {
226
+ const status = task.status === "completed" ? "DONE" : task.status.toUpperCase();
227
+ return {
228
+ content: [{ type: "text" as const, text: `Task "${task.title}" (${params.sessionId}): ${status}` }],
229
+ details: { task },
230
+ };
231
+ }
232
+ const remote = await serverProxy.delegate_status(params.sessionId);
233
+ return {
234
+ content: [{ type: "text" as const, text: `Session ${params.sessionId} status: ${remote.status}` }],
235
+ details: { task: null },
236
+ };
237
+ },
238
+ });
239
+
240
+ pi.registerTool({
241
+ name: "session_delegate_stop",
242
+ label: "Session Delegate Stop",
243
+ description: "Stop a delegated task session.",
244
+ parameters: DelegateStopParams,
245
+ async execute(toolCallId, params, _signal, _onUpdate, _ctx) {
246
+ const ok = await serverProxy.delegate_stop(params.sessionId);
247
+ return {
248
+ content: [{ type: "text" as const, text: ok ? `Session ${params.sessionId} stopped.` : `Session ${params.sessionId} not found or already stopped.` }],
249
+ details: { ok },
250
+ };
251
+ },
252
+ });
253
+
254
+ pi.registerTool({
255
+ name: "session_delegate_fork",
256
+ label: "Session Delegate Fork",
257
+ description: [
258
+ "Fork an existing session and delegate a new task to the forked session.",
259
+ "The forked session starts with a copy of the source session's conversation history.",
260
+ "Optionally specify a projectPath to run the forked session in a specific project directory.",
261
+ "The original session continues running unchanged.",
262
+ ].join(" "),
263
+ parameters: DelegateForkParams,
264
+ async execute(toolCallId, params, _signal, _onUpdate, ctx) {
265
+ const sid = currentSessionId || ctx.sessionManager.getSessionId();
266
+ const projectPath = params.projectPath || ctx.cwd;
267
+ const result = await serverProxy.delegate_fork(params.sessionId, params.task, params.title, projectPath);
268
+ pi.appendEntry("coordinator_fork", {
269
+ sessionId: result.sessionId,
270
+ forkedFrom: params.sessionId,
271
+ status: result.status,
272
+ task: params.task,
273
+ title: params.title,
274
+ projectPath,
275
+ dispatchedBy: sid,
276
+ });
277
+ return {
278
+ content: [{ type: "text" as const, text: `Forked session ${params.sessionId} → ${result.sessionId} (status: ${result.status}, cwd: ${projectPath}). Task: ${params.task}` }],
279
+ details: { ...result, forkedFrom: params.sessionId, dispatchedBy: sid, projectPath },
280
+ };
281
+ },
282
+ });
283
+
284
+ pi.registerTool({
285
+ name: "session_delegate_stop",
286
+ label: "Session Delegate Stop",
287
+ description: "Stop a delegated task session.",
288
+ parameters: DelegateStopParams,
289
+ async execute(toolCallId, params, _signal, _onUpdate, _ctx) {
290
+ const ok = await serverProxy.delegate_stop(params.sessionId);
291
+ pi.appendEntry("coordinator_stop", { sessionId: params.sessionId, ok });
292
+ return {
293
+ content: [{ type: "text" as const, text: ok ? `Session ${params.sessionId} stopped.` : `Session ${params.sessionId} not found or already stopped.` }],
294
+ details: { ok },
295
+ };
296
+ },
297
+ });
298
+
299
+ pi.registerTool({
300
+ name: "session_delegate_remove",
301
+ label: "Session Delegate Remove",
302
+ description: [
303
+ "Remove a delegated task from the task list.",
304
+ "Stops the session if still running, then removes the task entry.",
305
+ "Use this to clean up completed, stopped, or zombie tasks.",
306
+ ].join(" "),
307
+ parameters: DelegateStatusParams,
308
+ async execute(toolCallId, params, _signal, _onUpdate, _ctx) {
309
+ const ok = await serverProxy.delegate_remove(params.sessionId);
310
+ pi.appendEntry("coordinator_remove", { sessionId: params.sessionId, ok });
311
+ return {
312
+ content: [{ type: "text" as const, text: ok ? `Task ${params.sessionId} removed.` : `Task ${params.sessionId} not found.` }],
313
+ details: { ok },
314
+ };
315
+ },
316
+ });
317
+
318
+ pi.registerTool({
319
+ name: "session_delegate_clear_stopped",
320
+ label: "Session Delegate Clear Stopped",
321
+ description: [
322
+ "Remove all stopped and completed tasks from the task list.",
323
+ "Use this to clean up accumulated zombie tasks.",
324
+ ].join(" "),
325
+ parameters: Type.Object({}),
326
+ async execute(toolCallId, _params, _signal, _onUpdate, _ctx) {
327
+ const removed = await serverProxy.delegate_clear_stopped();
328
+ pi.appendEntry("coordinator_clear_stopped", { removed });
329
+ return {
330
+ content: [{ type: "text" as const, text: `Cleared ${removed} stopped/completed task(s).` }],
331
+ details: { removed },
332
+ };
333
+ },
334
+ });
335
+
336
+ client.on("message_received", (data: unknown) => {
337
+ const d = data as { fromSessionId: string; message: string };
338
+ // Skip messages from sessions that have been stopped
339
+ const task = store?.get(d.fromSessionId);
340
+ if (task?.status === "stopped") return;
341
+
342
+ // Detect completion signals from delegated sessions
343
+ if (store && task) {
344
+ const lowerMsg = d.message.toLowerCase();
345
+ const isCompletion = lowerMsg.includes("[completed]") || lowerMsg.includes("[done]") || lowerMsg.includes("task completed");
346
+ if (isCompletion) {
347
+ store.update(d.fromSessionId, { status: "completed", completedAt: Date.now(), result: d.message });
348
+ pi.appendEntry("coordinator_task_completed", { sessionId: d.fromSessionId, task: task.title, result: d.message.slice(0, 200) });
349
+ } else if (task.status !== "completed") {
350
+ store.update(d.fromSessionId, { status: "streaming" });
351
+ }
352
+ }
353
+
354
+ try {
355
+ pi.sendUserMessage(
356
+ `[Coordinator] Message from session ${d.fromSessionId}:\n${d.message}`,
357
+ { deliverAs: "followUp" },
358
+ );
359
+ } catch (err) {
360
+ // Silently ignore stale-ctx errors: the extension runtime may have been
361
+ // invalidated by a concurrent session replacement or reload. The new
362
+ // runtime's handler will take over.
363
+ if (err instanceof Error && err.message.includes("stale")) {
364
+ return;
365
+ }
366
+ throw err;
367
+ }
368
+ });
261
369
  }
@@ -37,6 +37,7 @@ export interface CoordinatorChannelContract extends ChannelContract {
37
37
  params: {
38
38
  task: string;
39
39
  title?: string;
40
+ projectPath?: string;
40
41
  };
41
42
  return: DelegateCreateResult;
42
43
  };
@@ -65,11 +66,26 @@ export interface CoordinatorChannelContract extends ChannelContract {
65
66
  ok: boolean;
66
67
  };
67
68
  };
69
+ session_delegate_remove: {
70
+ params: {
71
+ sessionId: string;
72
+ };
73
+ return: {
74
+ ok: boolean;
75
+ };
76
+ };
77
+ session_delegate_clear_stopped: {
78
+ params: Record<string, never>;
79
+ return: {
80
+ removed: number;
81
+ };
82
+ };
68
83
  session_delegate_fork: {
69
84
  params: {
70
85
  sessionId: string;
71
86
  task: string;
72
87
  title?: string;
88
+ projectPath?: string;
73
89
  };
74
90
  return: DelegateCreateResult;
75
91
  };
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ChannelContract } from \"@dyyz1993/pi-coding-agent\";\n\nexport const COORDINATOR_CHANNEL_NAME = \"coordinator\";\n\nexport type SessionStatus = \"idle\" | \"streaming\" | \"stopped\" | \"completed\";\n\nexport interface DelegatedTask {\n\tsessionId: string;\n\ttitle: string;\n\ttask: string;\n\tprojectPath: string;\n\tdispatchedAt: number;\n\tstatus: SessionStatus;\n\tcompletedAt?: number;\n\tresult?: string;\n}\n\nexport interface DelegateCreateResult {\n\tsessionId: string;\n\tstatus: \"started\" | \"already_running\";\n}\n\nexport interface DelegateSendResult {\n\tdelivered: boolean;\n\ttargetStatus: \"active\" | \"started\" | \"not_found\";\n}\n\nexport interface DelegateListResult {\n\ttasks: DelegatedTask[];\n}\n\nexport interface DelegateStatusExt {\n\ttask: DelegatedTask | null;\n\tisCompacting?: boolean;\n\tcontextUsage?: { tokens: number | null; contextWindow: number; percent: number | null };\n}\n\nexport interface CoordinatorChannelContract extends ChannelContract {\n\tmethods: {\n\t\tsession_delegate: {\n\t\t\tparams: { task: string; title?: string };\n\t\t\treturn: DelegateCreateResult;\n\t\t};\n\t\tsession_delegate_send: {\n\t\t\tparams: { targetSessionId: string; message: string };\n\t\t\treturn: DelegateSendResult;\n\t\t};\n\t\tsession_delegate_status: {\n\t\t\tparams: { sessionId: string };\n\t\t\treturn: DelegateStatusExt;\n\t\t};\n\t\tsession_delegate_list: {\n\t\t\tparams: Record<string, never>;\n\t\t\treturn: DelegateListResult;\n\t\t};\n\t\tsession_delegate_stop: {\n\t\t\tparams: { sessionId: string };\n\t\t\treturn: { ok: boolean };\n\t\t};\n\t\tsession_delegate_fork: {\n\t\t\tparams: { sessionId: string; task: string; title?: string };\n\t\t\treturn: DelegateCreateResult;\n\t\t};\n\t};\n\tevents: {\n\t\tmessage_received: { fromSessionId: string; message: string };\n\t\ttask_started: { sessionId: string; title: string; task: string };\n\t\ttask_stopped: { sessionId: string };\n\t\ttask_completed: { sessionId: string; result?: string };\n\t\ttask_error: { sessionId: string; error: string };\n\t};\n}\n"]}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ChannelContract } from \"@dyyz1993/pi-coding-agent\";\n\nexport const COORDINATOR_CHANNEL_NAME = \"coordinator\";\n\nexport type SessionStatus = \"idle\" | \"streaming\" | \"stopped\" | \"completed\";\n\nexport interface DelegatedTask {\n sessionId: string;\n title: string;\n task: string;\n projectPath: string;\n dispatchedAt: number;\n status: SessionStatus;\n completedAt?: number;\n result?: string;\n}\n\nexport interface DelegateCreateResult {\n sessionId: string;\n status: \"started\" | \"already_running\";\n}\n\nexport interface DelegateSendResult {\n delivered: boolean;\n targetStatus: \"active\" | \"started\" | \"not_found\";\n}\n\nexport interface DelegateListResult {\n tasks: DelegatedTask[];\n}\n\nexport interface DelegateStatusExt {\n task: DelegatedTask | null;\n isCompacting?: boolean;\n contextUsage?: { tokens: number | null; contextWindow: number; percent: number | null };\n}\n\nexport interface CoordinatorChannelContract extends ChannelContract {\n methods: {\n session_delegate: {\n params: { task: string; title?: string; projectPath?: string };\n return: DelegateCreateResult;\n };\n session_delegate_send: {\n params: { targetSessionId: string; message: string };\n return: DelegateSendResult;\n };\n session_delegate_status: {\n params: { sessionId: string };\n return: DelegateStatusExt;\n };\n session_delegate_list: {\n params: Record<string, never>;\n return: DelegateListResult;\n };\n session_delegate_stop: {\n params: { sessionId: string };\n return: { ok: boolean };\n };\n session_delegate_remove: {\n params: { sessionId: string };\n return: { ok: boolean };\n };\n session_delegate_clear_stopped: {\n params: Record<string, never>;\n return: { removed: number };\n };\n session_delegate_fork: {\n params: { sessionId: string; task: string; title?: string; projectPath?: string };\n return: DelegateCreateResult;\n };\n };\n events: {\n message_received: { fromSessionId: string; message: string };\n task_started: { sessionId: string; title: string; task: string };\n task_stopped: { sessionId: string };\n task_completed: { sessionId: string; result?: string };\n task_error: { sessionId: string; error: string };\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,wBAAwB,GAAG,aAAa,CAAC","sourcesContent":["import type { ChannelContract } from \"@dyyz1993/pi-coding-agent\";\n\nexport const COORDINATOR_CHANNEL_NAME = \"coordinator\";\n\nexport type SessionStatus = \"idle\" | \"streaming\" | \"stopped\" | \"completed\";\n\nexport interface DelegatedTask {\n\tsessionId: string;\n\ttitle: string;\n\ttask: string;\n\tprojectPath: string;\n\tdispatchedAt: number;\n\tstatus: SessionStatus;\n\tcompletedAt?: number;\n\tresult?: string;\n}\n\nexport interface DelegateCreateResult {\n\tsessionId: string;\n\tstatus: \"started\" | \"already_running\";\n}\n\nexport interface DelegateSendResult {\n\tdelivered: boolean;\n\ttargetStatus: \"active\" | \"started\" | \"not_found\";\n}\n\nexport interface DelegateListResult {\n\ttasks: DelegatedTask[];\n}\n\nexport interface DelegateStatusExt {\n\ttask: DelegatedTask | null;\n\tisCompacting?: boolean;\n\tcontextUsage?: { tokens: number | null; contextWindow: number; percent: number | null };\n}\n\nexport interface CoordinatorChannelContract extends ChannelContract {\n\tmethods: {\n\t\tsession_delegate: {\n\t\t\tparams: { task: string; title?: string };\n\t\t\treturn: DelegateCreateResult;\n\t\t};\n\t\tsession_delegate_send: {\n\t\t\tparams: { targetSessionId: string; message: string };\n\t\t\treturn: DelegateSendResult;\n\t\t};\n\t\tsession_delegate_status: {\n\t\t\tparams: { sessionId: string };\n\t\t\treturn: DelegateStatusExt;\n\t\t};\n\t\tsession_delegate_list: {\n\t\t\tparams: Record<string, never>;\n\t\t\treturn: DelegateListResult;\n\t\t};\n\t\tsession_delegate_stop: {\n\t\t\tparams: { sessionId: string };\n\t\t\treturn: { ok: boolean };\n\t\t};\n\t\tsession_delegate_fork: {\n\t\t\tparams: { sessionId: string; task: string; title?: string };\n\t\t\treturn: DelegateCreateResult;\n\t\t};\n\t};\n\tevents: {\n\t\tmessage_received: { fromSessionId: string; message: string };\n\t\ttask_started: { sessionId: string; title: string; task: string };\n\t\ttask_stopped: { sessionId: string };\n\t\ttask_completed: { sessionId: string; result?: string };\n\t\ttask_error: { sessionId: string; error: string };\n\t};\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,wBAAwB,GAAG,aAAa,CAAC","sourcesContent":["import type { ChannelContract } from \"@dyyz1993/pi-coding-agent\";\n\nexport const COORDINATOR_CHANNEL_NAME = \"coordinator\";\n\nexport type SessionStatus = \"idle\" | \"streaming\" | \"stopped\" | \"completed\";\n\nexport interface DelegatedTask {\n sessionId: string;\n title: string;\n task: string;\n projectPath: string;\n dispatchedAt: number;\n status: SessionStatus;\n completedAt?: number;\n result?: string;\n}\n\nexport interface DelegateCreateResult {\n sessionId: string;\n status: \"started\" | \"already_running\";\n}\n\nexport interface DelegateSendResult {\n delivered: boolean;\n targetStatus: \"active\" | \"started\" | \"not_found\";\n}\n\nexport interface DelegateListResult {\n tasks: DelegatedTask[];\n}\n\nexport interface DelegateStatusExt {\n task: DelegatedTask | null;\n isCompacting?: boolean;\n contextUsage?: { tokens: number | null; contextWindow: number; percent: number | null };\n}\n\nexport interface CoordinatorChannelContract extends ChannelContract {\n methods: {\n session_delegate: {\n params: { task: string; title?: string; projectPath?: string };\n return: DelegateCreateResult;\n };\n session_delegate_send: {\n params: { targetSessionId: string; message: string };\n return: DelegateSendResult;\n };\n session_delegate_status: {\n params: { sessionId: string };\n return: DelegateStatusExt;\n };\n session_delegate_list: {\n params: Record<string, never>;\n return: DelegateListResult;\n };\n session_delegate_stop: {\n params: { sessionId: string };\n return: { ok: boolean };\n };\n session_delegate_remove: {\n params: { sessionId: string };\n return: { ok: boolean };\n };\n session_delegate_clear_stopped: {\n params: Record<string, never>;\n return: { removed: number };\n };\n session_delegate_fork: {\n params: { sessionId: string; task: string; title?: string; projectPath?: string };\n return: DelegateCreateResult;\n };\n };\n events: {\n message_received: { fromSessionId: string; message: string };\n task_started: { sessionId: string; title: string; task: string };\n task_stopped: { sessionId: string };\n task_completed: { sessionId: string; result?: string };\n task_error: { sessionId: string; error: string };\n };\n}\n"]}