@melihmucuk/pi-crew 1.0.13 → 1.0.15
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 +19 -18
- package/agents/code-reviewer.md +52 -104
- package/agents/oracle.md +26 -52
- package/agents/planner.md +7 -7
- package/agents/quality-reviewer.md +90 -131
- package/agents/scout.md +3 -2
- package/agents/worker.md +8 -2
- package/extension/agent-discovery.ts +791 -0
- package/extension/bootstrap-session.ts +131 -0
- package/extension/index.ts +63 -0
- package/extension/integration/register-renderers.ts +77 -0
- package/extension/integration/register-tools.ts +39 -0
- package/extension/integration/tool-presentation.ts +50 -0
- package/extension/integration/tools/crew-abort.ts +126 -0
- package/extension/integration/tools/crew-done.ts +46 -0
- package/extension/integration/tools/crew-list.ts +92 -0
- package/extension/integration/tools/crew-respond.ts +59 -0
- package/extension/integration/tools/crew-spawn.ts +87 -0
- package/extension/integration/tools/tool-deps.ts +16 -0
- package/extension/integration.ts +13 -0
- package/extension/runtime/crew-runtime.ts +426 -0
- package/extension/runtime/delivery-coordinator.ts +131 -0
- package/extension/runtime/overflow-recovery.ts +211 -0
- package/extension/runtime/subagent-registry.ts +78 -0
- package/extension/runtime/subagent-state.ts +59 -0
- package/extension/status-widget.ts +107 -0
- package/extension/subagent-messages.ts +124 -0
- package/extension/tool-registry.ts +19 -0
- package/package.json +14 -14
- package/prompts/pi-crew-plan.md +46 -37
- package/prompts/pi-crew-review.md +3 -1
- package/skills/pi-crew/SKILL.md +129 -0
- package/dist/agent-discovery.d.ts +0 -29
- package/dist/agent-discovery.js +0 -527
- package/dist/bootstrap-session.d.ts +0 -21
- package/dist/bootstrap-session.js +0 -74
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -46
- package/dist/integration/register-command.d.ts +0 -3
- package/dist/integration/register-command.js +0 -51
- package/dist/integration/register-renderers.d.ts +0 -2
- package/dist/integration/register-renderers.js +0 -59
- package/dist/integration/register-tools.d.ts +0 -3
- package/dist/integration/register-tools.js +0 -25
- package/dist/integration/tool-presentation.d.ts +0 -27
- package/dist/integration/tool-presentation.js +0 -29
- package/dist/integration/tools/crew-abort.d.ts +0 -2
- package/dist/integration/tools/crew-abort.js +0 -79
- package/dist/integration/tools/crew-done.d.ts +0 -2
- package/dist/integration/tools/crew-done.js +0 -28
- package/dist/integration/tools/crew-list.d.ts +0 -2
- package/dist/integration/tools/crew-list.js +0 -74
- package/dist/integration/tools/crew-respond.d.ts +0 -2
- package/dist/integration/tools/crew-respond.js +0 -32
- package/dist/integration/tools/crew-spawn.d.ts +0 -2
- package/dist/integration/tools/crew-spawn.js +0 -48
- package/dist/integration/tools/tool-deps.d.ts +0 -9
- package/dist/integration/tools/tool-deps.js +0 -1
- package/dist/integration.d.ts +0 -3
- package/dist/integration.js +0 -8
- package/dist/runtime/crew-runtime.d.ts +0 -62
- package/dist/runtime/crew-runtime.js +0 -285
- package/dist/runtime/delivery-coordinator.d.ts +0 -26
- package/dist/runtime/delivery-coordinator.js +0 -86
- package/dist/runtime/overflow-recovery.d.ts +0 -3
- package/dist/runtime/overflow-recovery.js +0 -155
- package/dist/runtime/subagent-registry.d.ts +0 -14
- package/dist/runtime/subagent-registry.js +0 -58
- package/dist/runtime/subagent-state.d.ts +0 -35
- package/dist/runtime/subagent-state.js +0 -32
- package/dist/status-widget.d.ts +0 -3
- package/dist/status-widget.js +0 -84
- package/dist/subagent-messages.d.ts +0 -37
- package/dist/subagent-messages.js +0 -68
- package/dist/tool-registry.d.ts +0 -5
- package/dist/tool-registry.js +0 -13
- package/docs/architecture.md +0 -187
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
export function registerCrewCommand(pi, crew) {
|
|
2
|
-
pi.registerCommand("pi-crew-abort", {
|
|
3
|
-
description: "Abort an active subagent",
|
|
4
|
-
getArgumentCompletions(argumentPrefix) {
|
|
5
|
-
const activeAgents = crew.getAbortableAgents();
|
|
6
|
-
if (activeAgents.length === 0)
|
|
7
|
-
return null;
|
|
8
|
-
return activeAgents
|
|
9
|
-
.filter((agent) => agent.id.startsWith(argumentPrefix))
|
|
10
|
-
.map((agent) => ({
|
|
11
|
-
value: agent.id,
|
|
12
|
-
label: `${agent.id} (${agent.agentName})`,
|
|
13
|
-
}));
|
|
14
|
-
},
|
|
15
|
-
async handler(args, ctx) {
|
|
16
|
-
const trimmed = args.trim();
|
|
17
|
-
if (trimmed) {
|
|
18
|
-
const success = crew.abort(trimmed, { reason: "Aborted by user command" });
|
|
19
|
-
if (!success) {
|
|
20
|
-
ctx.ui.notify(`No active subagent with id "${trimmed}"`, "error");
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
ctx.ui.notify(`Subagent ${trimmed} aborted`, "info");
|
|
24
|
-
}
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
const activeAgents = crew.getAbortableAgents();
|
|
28
|
-
if (activeAgents.length === 0) {
|
|
29
|
-
ctx.ui.notify("No active subagents", "info");
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
const options = activeAgents.map((agent) => ({
|
|
33
|
-
id: agent.id,
|
|
34
|
-
label: `${agent.id} (${agent.agentName})`,
|
|
35
|
-
}));
|
|
36
|
-
const selected = await ctx.ui.select("Select subagent to abort", options.map((option) => option.label));
|
|
37
|
-
if (!selected)
|
|
38
|
-
return;
|
|
39
|
-
const selectedOption = options.find((option) => option.label === selected);
|
|
40
|
-
if (!selectedOption)
|
|
41
|
-
return;
|
|
42
|
-
const success = crew.abort(selectedOption.id, { reason: "Aborted by user command" });
|
|
43
|
-
if (success) {
|
|
44
|
-
ctx.ui.notify(`Subagent ${selectedOption.id} aborted`, "info");
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
ctx.ui.notify(`Subagent ${selectedOption.id} already finished`, "error");
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { getMarkdownTheme, } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
import { Box, Markdown, Text } from "@mariozechner/pi-tui";
|
|
3
|
-
import { STATUS_ICON, getCrewResultTitle, } from "../subagent-messages.js";
|
|
4
|
-
function getStatusColor(status) {
|
|
5
|
-
switch (status) {
|
|
6
|
-
case "done":
|
|
7
|
-
return "success";
|
|
8
|
-
case "error":
|
|
9
|
-
case "aborted":
|
|
10
|
-
return "error";
|
|
11
|
-
case "running":
|
|
12
|
-
case "waiting":
|
|
13
|
-
return "warning";
|
|
14
|
-
default:
|
|
15
|
-
return "muted";
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
function renderWarningMessage(content, theme) {
|
|
19
|
-
const box = new Box(1, 1, (text) => theme.bg("customMessageBg", text));
|
|
20
|
-
box.addChild(new Text(theme.fg("warning", String(content ?? "")), 0, 0));
|
|
21
|
-
return box;
|
|
22
|
-
}
|
|
23
|
-
export function registerCrewMessageRenderers(pi) {
|
|
24
|
-
pi.registerMessageRenderer("crew-result", (message, { expanded }, theme) => {
|
|
25
|
-
const details = message.details;
|
|
26
|
-
const title = details ? getCrewResultTitle(details) : "Subagent update";
|
|
27
|
-
const icon = details
|
|
28
|
-
? theme.fg(getStatusColor(details.status), STATUS_ICON[details.status])
|
|
29
|
-
: theme.fg("muted", "ℹ");
|
|
30
|
-
const header = `${icon} ${theme.fg("toolTitle", theme.bold(title))}`;
|
|
31
|
-
const body = details?.body ?? (!details && message.content ? String(message.content) : undefined);
|
|
32
|
-
const box = new Box(1, 1, (text) => theme.bg("customMessageBg", text));
|
|
33
|
-
box.addChild(new Text(header, 0, 0));
|
|
34
|
-
if (details?.sessionFile) {
|
|
35
|
-
box.addChild(new Text(theme.fg("muted", `📁 ${details.sessionFile}`), 0, 0));
|
|
36
|
-
}
|
|
37
|
-
if (body) {
|
|
38
|
-
if (expanded) {
|
|
39
|
-
box.addChild(new Text("", 0, 0));
|
|
40
|
-
box.addChild(new Markdown(body, 0, 0, getMarkdownTheme()));
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
const lines = body.split("\n");
|
|
44
|
-
const preview = lines.slice(0, 5).join("\n");
|
|
45
|
-
box.addChild(new Text(theme.fg("dim", preview), 0, 0));
|
|
46
|
-
if (lines.length > 5) {
|
|
47
|
-
box.addChild(new Text(theme.fg("muted", "(Ctrl+O to expand)"), 0, 0));
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return box;
|
|
52
|
-
});
|
|
53
|
-
pi.registerMessageRenderer("crew-remaining", (message, _options, theme) => {
|
|
54
|
-
return renderWarningMessage(message.content, theme);
|
|
55
|
-
});
|
|
56
|
-
pi.registerMessageRenderer("crew-list-warning", (message, _options, theme) => {
|
|
57
|
-
return renderWarningMessage(message.content, theme);
|
|
58
|
-
});
|
|
59
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { registerCrewAbortTool } from "./tools/crew-abort.js";
|
|
2
|
-
import { registerCrewDoneTool } from "./tools/crew-done.js";
|
|
3
|
-
import { registerCrewListTool } from "./tools/crew-list.js";
|
|
4
|
-
import { registerCrewRespondTool } from "./tools/crew-respond.js";
|
|
5
|
-
import { registerCrewSpawnTool } from "./tools/crew-spawn.js";
|
|
6
|
-
export function registerCrewTools(pi, crew, extensionDir) {
|
|
7
|
-
const shownDiscoveryWarnings = new Set();
|
|
8
|
-
const notifyDiscoveryWarnings = (ctx, warnings) => {
|
|
9
|
-
if (!ctx.hasUI)
|
|
10
|
-
return;
|
|
11
|
-
for (const warning of warnings) {
|
|
12
|
-
const key = `${warning.filePath}:${warning.message}`;
|
|
13
|
-
if (shownDiscoveryWarnings.has(key))
|
|
14
|
-
continue;
|
|
15
|
-
shownDiscoveryWarnings.add(key);
|
|
16
|
-
ctx.ui.notify(`${warning.message} (${warning.filePath})`, "error");
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
const deps = { pi, crew, extensionDir, notifyDiscoveryWarnings };
|
|
20
|
-
registerCrewListTool(deps);
|
|
21
|
-
registerCrewSpawnTool(deps);
|
|
22
|
-
registerCrewAbortTool(deps);
|
|
23
|
-
registerCrewRespondTool(deps);
|
|
24
|
-
registerCrewDoneTool(deps);
|
|
25
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
|
2
|
-
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
3
|
-
import { Box, Text } from "@mariozechner/pi-tui";
|
|
4
|
-
export type ToolTheme = Parameters<Exclude<Parameters<ExtensionAPI["registerTool"]>[0]["renderCall"], undefined>>[1];
|
|
5
|
-
export type ToolResult = AgentToolResult<unknown>;
|
|
6
|
-
export declare function toolError(text: string): {
|
|
7
|
-
content: {
|
|
8
|
-
type: "text";
|
|
9
|
-
text: string;
|
|
10
|
-
}[];
|
|
11
|
-
isError: boolean;
|
|
12
|
-
details: {
|
|
13
|
-
error: boolean;
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
|
-
export declare function toolSuccess(text: string, details?: Record<string, unknown>, options?: {
|
|
17
|
-
terminate?: boolean;
|
|
18
|
-
}): {
|
|
19
|
-
terminate?: boolean | undefined;
|
|
20
|
-
content: {
|
|
21
|
-
type: "text";
|
|
22
|
-
text: string;
|
|
23
|
-
}[];
|
|
24
|
-
details: Record<string, unknown>;
|
|
25
|
-
};
|
|
26
|
-
export declare function renderCrewCall(theme: ToolTheme, name: string, id: string, preview?: string): Box;
|
|
27
|
-
export declare function renderCrewResult(result: ToolResult, theme: ToolTheme): Text;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { Box, Text } from "@mariozechner/pi-tui";
|
|
2
|
-
export function toolError(text) {
|
|
3
|
-
return {
|
|
4
|
-
content: [{ type: "text", text }],
|
|
5
|
-
isError: true,
|
|
6
|
-
details: { error: true },
|
|
7
|
-
};
|
|
8
|
-
}
|
|
9
|
-
export function toolSuccess(text, details = {}, options = {}) {
|
|
10
|
-
return {
|
|
11
|
-
content: [{ type: "text", text }],
|
|
12
|
-
details,
|
|
13
|
-
...(options.terminate ? { terminate: true } : {}),
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
export function renderCrewCall(theme, name, id, preview) {
|
|
17
|
-
const box = new Box(1, 1);
|
|
18
|
-
box.addChild(new Text(theme.fg("toolTitle", theme.bold(`${name} `)) + theme.fg("accent", id), 0, 0));
|
|
19
|
-
if (preview) {
|
|
20
|
-
box.addChild(new Text(theme.fg("dim", preview), 0, 0));
|
|
21
|
-
}
|
|
22
|
-
return box;
|
|
23
|
-
}
|
|
24
|
-
export function renderCrewResult(result, theme) {
|
|
25
|
-
const text = result.content[0];
|
|
26
|
-
const details = result.details;
|
|
27
|
-
const content = text?.type === "text" && text.text ? text.text : "(no output)";
|
|
28
|
-
return new Text(details?.error ? theme.fg("error", content) : theme.fg("success", content), 0, 0);
|
|
29
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { Type } from "typebox";
|
|
2
|
-
import { renderCrewCall, renderCrewResult, toolError, toolSuccess, } from "../tool-presentation.js";
|
|
3
|
-
function formatAbortToolMessage(result) {
|
|
4
|
-
const parts = [];
|
|
5
|
-
if (result.abortedIds.length > 0) {
|
|
6
|
-
parts.push(`Aborted ${result.abortedIds.length} subagent(s): ${result.abortedIds.join(", ")}`);
|
|
7
|
-
}
|
|
8
|
-
if (result.missingIds.length > 0) {
|
|
9
|
-
parts.push(`Not found or already finished: ${result.missingIds.join(", ")}`);
|
|
10
|
-
}
|
|
11
|
-
if (result.foreignIds.length > 0) {
|
|
12
|
-
parts.push(`Belong to a different session: ${result.foreignIds.join(", ")}`);
|
|
13
|
-
}
|
|
14
|
-
return parts.join("\n");
|
|
15
|
-
}
|
|
16
|
-
export function registerCrewAbortTool({ pi, crew }) {
|
|
17
|
-
pi.registerTool({
|
|
18
|
-
name: "crew_abort",
|
|
19
|
-
label: "Abort Crew",
|
|
20
|
-
description: "Abort one, many, or all active subagents owned by the current session.",
|
|
21
|
-
parameters: Type.Object({
|
|
22
|
-
subagent_id: Type.Optional(Type.String({ description: "Single subagent ID to abort" })),
|
|
23
|
-
subagent_ids: Type.Optional(Type.Array(Type.String(), {
|
|
24
|
-
minItems: 1,
|
|
25
|
-
description: "Multiple subagent IDs to abort",
|
|
26
|
-
})),
|
|
27
|
-
all: Type.Optional(Type.Boolean({
|
|
28
|
-
description: "Abort all active subagents owned by the current session",
|
|
29
|
-
})),
|
|
30
|
-
}),
|
|
31
|
-
promptSnippet: "Abort one, many, or all active subagents from this session.",
|
|
32
|
-
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
33
|
-
const callerSessionId = ctx.sessionManager.getSessionId();
|
|
34
|
-
const modeCount = Number(Boolean(params.subagent_id))
|
|
35
|
-
+ Number(Boolean(params.subagent_ids?.length))
|
|
36
|
-
+ Number(params.all === true);
|
|
37
|
-
if (modeCount !== 1) {
|
|
38
|
-
return toolError("Provide exactly one of: subagent_id, subagent_ids, or all=true.");
|
|
39
|
-
}
|
|
40
|
-
if (params.all) {
|
|
41
|
-
const abortedIds = crew.abortAllOwned(callerSessionId, {
|
|
42
|
-
reason: "Aborted by tool request",
|
|
43
|
-
});
|
|
44
|
-
if (abortedIds.length === 0) {
|
|
45
|
-
return toolError("No active subagents in the current session.");
|
|
46
|
-
}
|
|
47
|
-
return toolSuccess(`Aborted ${abortedIds.length} subagent(s): ${abortedIds.join(", ")}`, { ids: abortedIds }, { terminate: true });
|
|
48
|
-
}
|
|
49
|
-
const ids = params.subagent_id
|
|
50
|
-
? [params.subagent_id]
|
|
51
|
-
: (params.subagent_ids ?? []);
|
|
52
|
-
const result = crew.abortOwned(ids, callerSessionId, {
|
|
53
|
-
reason: "Aborted by tool request",
|
|
54
|
-
});
|
|
55
|
-
const message = formatAbortToolMessage(result);
|
|
56
|
-
if (result.abortedIds.length === 0) {
|
|
57
|
-
return toolError(message || "No subagents were aborted.");
|
|
58
|
-
}
|
|
59
|
-
return toolSuccess(message, {
|
|
60
|
-
ids: result.abortedIds,
|
|
61
|
-
missing_ids: result.missingIds,
|
|
62
|
-
foreign_ids: result.foreignIds,
|
|
63
|
-
}, { terminate: true });
|
|
64
|
-
},
|
|
65
|
-
renderCall(args, theme, _context) {
|
|
66
|
-
if (args.all) {
|
|
67
|
-
return renderCrewCall(theme, "crew_abort", "all");
|
|
68
|
-
}
|
|
69
|
-
if (args.subagent_id) {
|
|
70
|
-
return renderCrewCall(theme, "crew_abort", args.subagent_id);
|
|
71
|
-
}
|
|
72
|
-
const count = Array.isArray(args.subagent_ids) ? args.subagent_ids.length : 0;
|
|
73
|
-
return renderCrewCall(theme, "crew_abort", `${count} ids`);
|
|
74
|
-
},
|
|
75
|
-
renderResult(result, _options, theme, _context) {
|
|
76
|
-
return renderCrewResult(result, theme);
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { Type } from "typebox";
|
|
2
|
-
import { renderCrewCall, renderCrewResult, toolError, toolSuccess, } from "../tool-presentation.js";
|
|
3
|
-
export function registerCrewDoneTool({ pi, crew }) {
|
|
4
|
-
pi.registerTool({
|
|
5
|
-
name: "crew_done",
|
|
6
|
-
label: "Done with Crew",
|
|
7
|
-
description: "Close an interactive subagent session. Use when you no longer need to interact with the subagent.",
|
|
8
|
-
parameters: Type.Object({
|
|
9
|
-
subagent_id: Type.String({ description: "ID of the subagent to close" }),
|
|
10
|
-
}),
|
|
11
|
-
promptSnippet: "Close an interactive subagent session when done.",
|
|
12
|
-
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
13
|
-
const callerSessionId = ctx.sessionManager.getSessionId();
|
|
14
|
-
const { error } = crew.done(params.subagent_id, callerSessionId);
|
|
15
|
-
if (error)
|
|
16
|
-
return toolError(error);
|
|
17
|
-
return toolSuccess(`Subagent ${params.subagent_id} closed.`, {
|
|
18
|
-
id: params.subagent_id,
|
|
19
|
-
});
|
|
20
|
-
},
|
|
21
|
-
renderCall(args, theme, _context) {
|
|
22
|
-
return renderCrewCall(theme, "crew_done", args.subagent_id || "...");
|
|
23
|
-
},
|
|
24
|
-
renderResult(result, _options, theme, _context) {
|
|
25
|
-
return renderCrewResult(result, theme);
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { Text } from "@mariozechner/pi-tui";
|
|
2
|
-
import { Type } from "typebox";
|
|
3
|
-
import { discoverAgents } from "../../agent-discovery.js";
|
|
4
|
-
import { STATUS_ICON, sendCrewListActiveWarning } from "../../subagent-messages.js";
|
|
5
|
-
export function registerCrewListTool({ pi, crew, notifyDiscoveryWarnings, }) {
|
|
6
|
-
pi.registerTool({
|
|
7
|
-
name: "crew_list",
|
|
8
|
-
label: "List Crew",
|
|
9
|
-
description: "List available subagent definitions and currently running subagents with their status. Use only to discover which subagents exist or to get a one-time status snapshot. Do NOT call this repeatedly to check if a subagent has finished — results are delivered automatically as steering messages.",
|
|
10
|
-
parameters: Type.Object({}),
|
|
11
|
-
promptSnippet: "List subagent definitions and active subagents",
|
|
12
|
-
promptGuidelines: [
|
|
13
|
-
"Use crew_list first to see available subagents before spawning.",
|
|
14
|
-
"crew_list: Call this only to discover available subagents before spawning, or when the user explicitly asks for a status report. Do not call it to check if a subagent finished — results arrive as steering messages automatically.",
|
|
15
|
-
],
|
|
16
|
-
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
17
|
-
const { agents, warnings } = discoverAgents(ctx.cwd);
|
|
18
|
-
notifyDiscoveryWarnings(ctx, warnings);
|
|
19
|
-
const callerSessionId = ctx.sessionManager.getSessionId();
|
|
20
|
-
const running = crew.getActiveSummariesForOwner(callerSessionId);
|
|
21
|
-
const lines = [];
|
|
22
|
-
lines.push("## Available Subagents");
|
|
23
|
-
if (agents.length === 0) {
|
|
24
|
-
lines.push("No valid subagent definitions found. Add `.md` files to `<cwd>/.pi/agents/` or `~/.pi/agent/agents/`.");
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
for (const agent of agents) {
|
|
28
|
-
lines.push("");
|
|
29
|
-
lines.push(`name: ${agent.name}`);
|
|
30
|
-
lines.push(`description: ${agent.description}`);
|
|
31
|
-
lines.push(`interactive: ${agent.interactive ? "true" : "false"}`);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
if (warnings.length > 0) {
|
|
35
|
-
lines.push("");
|
|
36
|
-
lines.push("## Ignored subagent definitions");
|
|
37
|
-
for (const warning of warnings) {
|
|
38
|
-
lines.push(`- ${warning.message} (${warning.filePath})`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
lines.push("");
|
|
42
|
-
lines.push("## Active Subagents");
|
|
43
|
-
if (running.length === 0) {
|
|
44
|
-
lines.push("No subagents currently active.");
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
for (const agent of running) {
|
|
48
|
-
const icon = STATUS_ICON[agent.status] ?? "❓";
|
|
49
|
-
lines.push("");
|
|
50
|
-
lines.push(`id: ${agent.id}`);
|
|
51
|
-
lines.push(`name: ${agent.agentName}`);
|
|
52
|
-
lines.push(`status: ${icon} ${agent.status}`);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
const text = lines.join("\n");
|
|
56
|
-
if (running.length > 0) {
|
|
57
|
-
Promise.resolve().then(() => {
|
|
58
|
-
sendCrewListActiveWarning(pi.sendMessage.bind(pi), {
|
|
59
|
-
isIdle: ctx.isIdle(),
|
|
60
|
-
triggerTurn: true,
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
return { content: [{ type: "text", text }], details: {} };
|
|
65
|
-
},
|
|
66
|
-
renderCall(_args, theme, _context) {
|
|
67
|
-
return new Text(theme.fg("toolTitle", theme.bold("crew_list")), 0, 0);
|
|
68
|
-
},
|
|
69
|
-
renderResult(result, _options, _theme, _context) {
|
|
70
|
-
const text = result.content[0];
|
|
71
|
-
return new Text(text?.type === "text" ? text.text : "(no output)", 0, 0);
|
|
72
|
-
},
|
|
73
|
-
});
|
|
74
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { Type } from "typebox";
|
|
2
|
-
import { renderCrewCall, renderCrewResult, toolError, toolSuccess, } from "../tool-presentation.js";
|
|
3
|
-
export function registerCrewRespondTool({ pi, crew }) {
|
|
4
|
-
pi.registerTool({
|
|
5
|
-
name: "crew_respond",
|
|
6
|
-
label: "Respond to Crew",
|
|
7
|
-
description: "Send a follow-up message to an interactive subagent that is waiting for a response.",
|
|
8
|
-
parameters: Type.Object({
|
|
9
|
-
subagent_id: Type.String({
|
|
10
|
-
description: "ID of the waiting subagent (from crew_list or crew_spawn result)",
|
|
11
|
-
}),
|
|
12
|
-
message: Type.String({ description: "Message to send to the subagent" }),
|
|
13
|
-
}),
|
|
14
|
-
promptSnippet: "Send a follow-up message to a waiting interactive subagent.",
|
|
15
|
-
promptGuidelines: [
|
|
16
|
-
"crew_respond: Response is delivered asynchronously as a steering message. Do not poll crew_list. Continue with unrelated work or end your turn and wait for the steering message.",
|
|
17
|
-
],
|
|
18
|
-
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
19
|
-
const callerSessionId = ctx.sessionManager.getSessionId();
|
|
20
|
-
const { error } = crew.respond(params.subagent_id, params.message, callerSessionId);
|
|
21
|
-
if (error)
|
|
22
|
-
return toolError(error);
|
|
23
|
-
return toolSuccess(`Message sent to subagent ${params.subagent_id}. Response will be delivered as a steering message.`, { id: params.subagent_id, message: params.message });
|
|
24
|
-
},
|
|
25
|
-
renderCall(args, theme, _context) {
|
|
26
|
-
return renderCrewCall(theme, "crew_respond", args.subagent_id || "...", args.message);
|
|
27
|
-
},
|
|
28
|
-
renderResult(result, _options, theme, _context) {
|
|
29
|
-
return renderCrewResult(result, theme);
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { getAgentDir } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
import { Type } from "typebox";
|
|
3
|
-
import { discoverAgents } from "../../agent-discovery.js";
|
|
4
|
-
import { renderCrewCall, renderCrewResult, toolError, toolSuccess, } from "../tool-presentation.js";
|
|
5
|
-
export function registerCrewSpawnTool({ pi, crew, extensionDir, notifyDiscoveryWarnings, }) {
|
|
6
|
-
pi.registerTool({
|
|
7
|
-
name: "crew_spawn",
|
|
8
|
-
label: "Spawn Crew",
|
|
9
|
-
description: "Spawn a non-blocking subagent that runs in an isolated session. The subagent works independently while your session stays interactive. Results are delivered back to your session as steering messages.",
|
|
10
|
-
parameters: Type.Object({
|
|
11
|
-
subagent: Type.String({ description: "Subagent name from crew_list" }),
|
|
12
|
-
task: Type.String({ description: "Task to delegate to the subagent" }),
|
|
13
|
-
}),
|
|
14
|
-
promptSnippet: "Spawn a non-blocking subagent. Use crew_list first to see available subagents.",
|
|
15
|
-
promptGuidelines: [
|
|
16
|
-
"crew_spawn: The subagent runs in isolation with no access to your session. Include file paths, requirements, and known locations directly in the task parameter.",
|
|
17
|
-
"crew_spawn: DELEGATE means OWNERSHIP TRANSFER. Once you spawn a subagent for a task, that task is exclusively theirs. If you also work on it, you waste the subagent's effort and create conflicting results. After spawning, work on an UNRELATED task or end your turn.",
|
|
18
|
-
"crew_spawn: To avoid duplication, gather only enough context to write a useful task (key files, entry points). Do not pre-investigate the full problem.",
|
|
19
|
-
"crew_spawn: Results arrive asynchronously as steering messages. Do not predict or fabricate results. Wait for all crew-result messages before acting on them.",
|
|
20
|
-
"crew_spawn: Never use crew_list as a completion polling loop. Results arrive as steering messages. Continue with unrelated work or end your turn and wait for the steering messages.",
|
|
21
|
-
"crew_spawn: Interactive subagents stay alive after responding. Use crew_respond to continue or crew_done to close when finished.",
|
|
22
|
-
],
|
|
23
|
-
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
24
|
-
const { agents, warnings } = discoverAgents(ctx.cwd);
|
|
25
|
-
notifyDiscoveryWarnings(ctx, warnings);
|
|
26
|
-
const subagent = agents.find((candidate) => candidate.name === params.subagent);
|
|
27
|
-
if (!subagent) {
|
|
28
|
-
const available = agents.map((candidate) => candidate.name).join(", ") || "none";
|
|
29
|
-
return toolError(`Unknown subagent: "${params.subagent}". Available: ${available}`);
|
|
30
|
-
}
|
|
31
|
-
const ownerSessionId = ctx.sessionManager.getSessionId();
|
|
32
|
-
const id = crew.spawn(subagent, params.task, ctx.cwd, ownerSessionId, {
|
|
33
|
-
model: ctx.model,
|
|
34
|
-
modelRegistry: ctx.modelRegistry,
|
|
35
|
-
agentDir: getAgentDir(),
|
|
36
|
-
parentSessionFile: ctx.sessionManager.getSessionFile(),
|
|
37
|
-
onWarning: (msg) => ctx.ui.notify(msg, "warning"),
|
|
38
|
-
}, extensionDir);
|
|
39
|
-
return toolSuccess(`Subagent '${subagent.name}' spawned as ${id}. Result will be delivered as a steering message when done.`, { id, agentName: subagent.name, task: params.task });
|
|
40
|
-
},
|
|
41
|
-
renderCall(args, theme, _context) {
|
|
42
|
-
return renderCrewCall(theme, "crew_spawn", args.subagent || "...", args.task);
|
|
43
|
-
},
|
|
44
|
-
renderResult(result, _options, theme, _context) {
|
|
45
|
-
return renderCrewResult(result, theme);
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
import type { AgentDiscoveryWarning } from "../../agent-discovery.js";
|
|
3
|
-
import type { CrewRuntime } from "../../runtime/crew-runtime.js";
|
|
4
|
-
export interface CrewToolDeps {
|
|
5
|
-
pi: ExtensionAPI;
|
|
6
|
-
crew: CrewRuntime;
|
|
7
|
-
extensionDir: string;
|
|
8
|
-
notifyDiscoveryWarnings: (ctx: ExtensionContext, warnings: AgentDiscoveryWarning[]) => void;
|
|
9
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/integration.d.ts
DELETED
package/dist/integration.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { registerCrewCommand } from "./integration/register-command.js";
|
|
2
|
-
import { registerCrewMessageRenderers } from "./integration/register-renderers.js";
|
|
3
|
-
import { registerCrewTools } from "./integration/register-tools.js";
|
|
4
|
-
export function registerCrewIntegration(pi, crew, extensionDir) {
|
|
5
|
-
registerCrewTools(pi, crew, extensionDir);
|
|
6
|
-
registerCrewCommand(pi, crew);
|
|
7
|
-
registerCrewMessageRenderers(pi);
|
|
8
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type { Api, Model } from "@mariozechner/pi-ai";
|
|
2
|
-
import type { ModelRegistry } from "@mariozechner/pi-coding-agent";
|
|
3
|
-
import type { AgentConfig } from "../agent-discovery.js";
|
|
4
|
-
import { type ActiveRuntimeBinding } from "./delivery-coordinator.js";
|
|
5
|
-
import { type AbortableAgentSummary, type ActiveAgentSummary } from "./subagent-state.js";
|
|
6
|
-
export type { AbortableAgentSummary, ActiveAgentSummary, } from "./subagent-state.js";
|
|
7
|
-
export interface AbortOwnedResult {
|
|
8
|
-
abortedIds: string[];
|
|
9
|
-
missingIds: string[];
|
|
10
|
-
foreignIds: string[];
|
|
11
|
-
}
|
|
12
|
-
interface AbortOptions {
|
|
13
|
-
reason: string;
|
|
14
|
-
}
|
|
15
|
-
export interface SpawnContext {
|
|
16
|
-
model: Model<Api> | undefined;
|
|
17
|
-
modelRegistry: ModelRegistry;
|
|
18
|
-
agentDir: string;
|
|
19
|
-
parentSessionFile?: string;
|
|
20
|
-
onWarning?: (message: string) => void;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Process-level singleton that owns all durable subagent state.
|
|
24
|
-
*
|
|
25
|
-
* This survives extension instance replacement caused by runtime
|
|
26
|
-
* teardown/recreation on /resume, /new, /fork (pi 0.65.0+).
|
|
27
|
-
* Each new extension instance rebinds delivery and widget hooks
|
|
28
|
-
* via activateSession/deactivateSession.
|
|
29
|
-
*/
|
|
30
|
-
declare class CrewRuntime {
|
|
31
|
-
private readonly registry;
|
|
32
|
-
private readonly delivery;
|
|
33
|
-
private readonly refreshCallbacks;
|
|
34
|
-
private refreshWidgetFor;
|
|
35
|
-
activateSession(binding: ActiveRuntimeBinding, refreshWidget?: () => void): void;
|
|
36
|
-
deactivateSession(sessionId: string): void;
|
|
37
|
-
spawn(agentConfig: AgentConfig, task: string, cwd: string, ownerSessionId: string, ctx: SpawnContext, extensionResolvedPath: string): string;
|
|
38
|
-
private attachSessionListeners;
|
|
39
|
-
private attachSpawnedSession;
|
|
40
|
-
private settleAgent;
|
|
41
|
-
private disposeAgent;
|
|
42
|
-
private runPromptCycle;
|
|
43
|
-
private spawnSession;
|
|
44
|
-
respond(id: string, message: string, callerSessionId: string): {
|
|
45
|
-
error?: string;
|
|
46
|
-
};
|
|
47
|
-
done(id: string, callerSessionId: string): {
|
|
48
|
-
error?: string;
|
|
49
|
-
};
|
|
50
|
-
abort(id: string, opts: AbortOptions): boolean;
|
|
51
|
-
abortOwned(ids: string[], callerSessionId: string, opts: AbortOptions): AbortOwnedResult;
|
|
52
|
-
abortAllOwned(callerSessionId: string, opts: AbortOptions): string[];
|
|
53
|
-
/**
|
|
54
|
-
* Abort all running subagents during shutdown cleanup.
|
|
55
|
-
* Called from SIGINT, session_shutdown(reason="quit"), and beforeExit fallback paths.
|
|
56
|
-
*/
|
|
57
|
-
abortAll(): void;
|
|
58
|
-
getAbortableAgents(): AbortableAgentSummary[];
|
|
59
|
-
getActiveSummariesForOwner(ownerSessionId: string): ActiveAgentSummary[];
|
|
60
|
-
}
|
|
61
|
-
export declare const crewRuntime: CrewRuntime;
|
|
62
|
-
export type { CrewRuntime };
|