@melihmucuk/pi-crew 1.0.10 → 1.0.12
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 -1
- package/dist/bootstrap-session.d.ts +1 -0
- package/dist/bootstrap-session.js +6 -4
- package/dist/index.js +7 -18
- package/dist/integration/tools/crew-list.js +9 -1
- package/dist/integration/tools/crew-respond.js +1 -1
- package/dist/integration/tools/crew-spawn.js +4 -3
- package/dist/runtime/crew-runtime.d.ts +3 -2
- package/dist/runtime/crew-runtime.js +4 -3
- package/dist/tool-registry.d.ts +2 -73
- package/dist/tool-registry.js +11 -15
- package/docs/architecture.md +4 -3
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -58,7 +58,7 @@ Supported modes:
|
|
|
58
58
|
"abort all active subagents"
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
Tool-triggered aborts are reported back as steering messages with the reason `Aborted by tool request`.
|
|
61
|
+
Tool-triggered aborts are reported back as steering messages with the reason `Aborted by tool request`. User-command aborts and shutdown-triggered aborts use distinct reasons.
|
|
62
62
|
|
|
63
63
|
### `crew_respond`
|
|
64
64
|
|
|
@@ -195,6 +195,8 @@ Override values replace the matching frontmatter fields for the named subagent a
|
|
|
195
195
|
|
|
196
196
|
When the current session owns active subagents, a live status widget appears in the TUI for that session, showing each subagent's ID, model, turn count, and context token usage.
|
|
197
197
|
|
|
198
|
+
On session replacement paths such as `/new`, `/resume`, `/fork`, and `/reload`, subagents keep running and reconnect to the owner session when it becomes active again. On real quit, pi-crew aborts running subagents during shutdown.
|
|
199
|
+
|
|
198
200
|
```
|
|
199
201
|
⠹ scout-a1b2 (claude-haiku-4-5) · turn 3 · 12.5k ctx
|
|
200
202
|
⠸ worker-c3d4 (claude-sonnet-4-6) · turn 7 · 45.2k ctx
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createAgentSession, DefaultResourceLoader, SessionManager, SettingsManager, } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
import {
|
|
3
|
-
function resolveTools(agentConfig
|
|
4
|
-
return
|
|
2
|
+
import { SUPPORTED_TOOL_NAMES } from "./tool-registry.js";
|
|
3
|
+
function resolveTools(agentConfig) {
|
|
4
|
+
return [...(agentConfig.tools ?? SUPPORTED_TOOL_NAMES)];
|
|
5
5
|
}
|
|
6
6
|
function resolveModel(agentConfig, ctx) {
|
|
7
7
|
const warnings = [];
|
|
@@ -33,9 +33,10 @@ export async function bootstrapSession(opts) {
|
|
|
33
33
|
const modelRegistry = ctx.modelRegistry;
|
|
34
34
|
const { model, warnings: modelWarnings } = resolveModel(agentConfig, ctx);
|
|
35
35
|
warnings.push(...modelWarnings);
|
|
36
|
-
const tools = resolveTools(agentConfig
|
|
36
|
+
const tools = resolveTools(agentConfig);
|
|
37
37
|
const resourceLoader = new DefaultResourceLoader({
|
|
38
38
|
cwd,
|
|
39
|
+
agentDir: ctx.agentDir,
|
|
39
40
|
extensionsOverride: (base) => ({
|
|
40
41
|
...base,
|
|
41
42
|
extensions: base.extensions.filter((ext) => !ext.resolvedPath.startsWith(extensionResolvedPath)),
|
|
@@ -59,6 +60,7 @@ export async function bootstrapSession(opts) {
|
|
|
59
60
|
sessionManager.newSession({ parentSession: ctx.parentSessionFile });
|
|
60
61
|
const result = await createAgentSession({
|
|
61
62
|
cwd,
|
|
63
|
+
agentDir: ctx.agentDir,
|
|
62
64
|
model,
|
|
63
65
|
thinkingLevel: agentConfig.thinking,
|
|
64
66
|
tools,
|
package/dist/index.js
CHANGED
|
@@ -10,13 +10,10 @@ function setupProcessHooks() {
|
|
|
10
10
|
if (processHooksSetup)
|
|
11
11
|
return;
|
|
12
12
|
processHooksSetup = true;
|
|
13
|
-
|
|
13
|
+
process.once('SIGINT', () => {
|
|
14
14
|
crewRuntime.abortAll();
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
};
|
|
18
|
-
process.once('SIGINT', () => abortAndExit('SIGINT'));
|
|
19
|
-
process.once('SIGTERM', () => abortAndExit('SIGTERM'));
|
|
15
|
+
process.exit(130);
|
|
16
|
+
});
|
|
20
17
|
process.on('beforeExit', () => crewRuntime.abortAll());
|
|
21
18
|
}
|
|
22
19
|
export default function (pi) {
|
|
@@ -38,20 +35,12 @@ export default function (pi) {
|
|
|
38
35
|
pi.on("session_start", (_event, ctx) => {
|
|
39
36
|
activateSession(ctx);
|
|
40
37
|
});
|
|
41
|
-
pi.on("
|
|
42
|
-
// Session is about to switch - no action needed here.
|
|
43
|
-
// Subagent cleanup is handled by process hooks, not session_shutdown.
|
|
44
|
-
});
|
|
45
|
-
pi.on("session_before_fork", () => {
|
|
46
|
-
// Session is about to fork - no action needed here.
|
|
47
|
-
// Subagent cleanup is handled by process hooks, not session_shutdown.
|
|
48
|
-
});
|
|
49
|
-
pi.on("session_shutdown", (_event, ctx) => {
|
|
38
|
+
pi.on("session_shutdown", (event, ctx) => {
|
|
50
39
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
51
|
-
// Deactivate delivery to this session, but don't abort subagents.
|
|
52
|
-
// Subagents continue running and will complete normally.
|
|
53
|
-
// Real cleanup happens in process exit hooks.
|
|
54
40
|
crewRuntime.deactivateSession(sessionId);
|
|
41
|
+
if (event.reason === "quit") {
|
|
42
|
+
crewRuntime.abortAll();
|
|
43
|
+
}
|
|
55
44
|
});
|
|
56
45
|
registerCrewIntegration(pi, crewRuntime, extensionDir);
|
|
57
46
|
}
|
|
@@ -6,15 +6,23 @@ export function registerCrewListTool({ pi, crew, notifyDiscoveryWarnings, }) {
|
|
|
6
6
|
pi.registerTool({
|
|
7
7
|
name: "crew_list",
|
|
8
8
|
label: "List Crew",
|
|
9
|
-
description: "List available subagent definitions and currently running subagents with their status.",
|
|
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
10
|
parameters: Type.Object({}),
|
|
11
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
|
+
],
|
|
12
16
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
13
17
|
const { agents, warnings } = discoverAgents(ctx.cwd);
|
|
14
18
|
notifyDiscoveryWarnings(ctx, warnings);
|
|
15
19
|
const callerSessionId = ctx.sessionManager.getSessionId();
|
|
16
20
|
const running = crew.getActiveSummariesForOwner(callerSessionId);
|
|
17
21
|
const lines = [];
|
|
22
|
+
if (running.length > 0) {
|
|
23
|
+
lines.push("⚠ Active subagents detected. Do not poll crew_list for completion — results arrive as steering messages. Continue with unrelated work or end your turn and wait for the steering messages.");
|
|
24
|
+
lines.push("");
|
|
25
|
+
}
|
|
18
26
|
lines.push("## Available Subagents");
|
|
19
27
|
if (agents.length === 0) {
|
|
20
28
|
lines.push("No valid subagent definitions found. Add `.md` files to `<cwd>/.pi/agents/` or `~/.pi/agent/agents/`.");
|
|
@@ -13,7 +13,7 @@ export function registerCrewRespondTool({ pi, crew }) {
|
|
|
13
13
|
}),
|
|
14
14
|
promptSnippet: "Send a follow-up message to a waiting interactive subagent.",
|
|
15
15
|
promptGuidelines: [
|
|
16
|
-
"crew_respond: Response is delivered asynchronously as a steering message. Do not poll crew_list.",
|
|
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
17
|
],
|
|
18
18
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
19
19
|
const callerSessionId = ctx.sessionManager.getSessionId();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getAgentDir } from "@mariozechner/pi-coding-agent";
|
|
1
2
|
import { Type } from "@sinclair/typebox";
|
|
2
3
|
import { discoverAgents } from "../../agent-discovery.js";
|
|
3
4
|
import { renderCrewCall, renderCrewResult, toolError, toolSuccess, } from "../tool-presentation.js";
|
|
@@ -12,13 +13,12 @@ export function registerCrewSpawnTool({ pi, crew, extensionDir, notifyDiscoveryW
|
|
|
12
13
|
}),
|
|
13
14
|
promptSnippet: "Spawn a non-blocking subagent. Use crew_list first to see available subagents.",
|
|
14
15
|
promptGuidelines: [
|
|
15
|
-
"Use crew_list first to see available subagents before spawning.",
|
|
16
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
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
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
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.
|
|
21
|
-
"crew_spawn: Interactive subagents stay alive after responding. Use crew_respond to continue
|
|
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
22
|
],
|
|
23
23
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
24
24
|
const { agents, warnings } = discoverAgents(ctx.cwd);
|
|
@@ -32,6 +32,7 @@ export function registerCrewSpawnTool({ pi, crew, extensionDir, notifyDiscoveryW
|
|
|
32
32
|
const id = crew.spawn(subagent, params.task, ctx.cwd, ownerSessionId, {
|
|
33
33
|
model: ctx.model,
|
|
34
34
|
modelRegistry: ctx.modelRegistry,
|
|
35
|
+
agentDir: getAgentDir(),
|
|
35
36
|
parentSessionFile: ctx.sessionManager.getSessionFile(),
|
|
36
37
|
onWarning: (msg) => ctx.ui.notify(msg, "warning"),
|
|
37
38
|
}, extensionDir);
|
|
@@ -15,6 +15,7 @@ interface AbortOptions {
|
|
|
15
15
|
export interface SpawnContext {
|
|
16
16
|
model: Model<Api> | undefined;
|
|
17
17
|
modelRegistry: ModelRegistry;
|
|
18
|
+
agentDir: string;
|
|
18
19
|
parentSessionFile?: string;
|
|
19
20
|
onWarning?: (message: string) => void;
|
|
20
21
|
}
|
|
@@ -50,8 +51,8 @@ declare class CrewRuntime {
|
|
|
50
51
|
abortOwned(ids: string[], callerSessionId: string, opts: AbortOptions): AbortOwnedResult;
|
|
51
52
|
abortAllOwned(callerSessionId: string, opts: AbortOptions): string[];
|
|
52
53
|
/**
|
|
53
|
-
* Abort all running subagents
|
|
54
|
-
* Called from
|
|
54
|
+
* Abort all running subagents during shutdown cleanup.
|
|
55
|
+
* Called from SIGINT, session_shutdown(reason="quit"), and beforeExit fallback paths.
|
|
55
56
|
*/
|
|
56
57
|
abortAll(): void;
|
|
57
58
|
getAbortableAgents(): AbortableAgentSummary[];
|
|
@@ -7,6 +7,7 @@ function toBootstrapContext(ctx) {
|
|
|
7
7
|
return {
|
|
8
8
|
model: ctx.model,
|
|
9
9
|
modelRegistry: ctx.modelRegistry,
|
|
10
|
+
agentDir: ctx.agentDir,
|
|
10
11
|
parentSessionFile: ctx.parentSessionFile,
|
|
11
12
|
};
|
|
12
13
|
}
|
|
@@ -265,13 +266,13 @@ class CrewRuntime {
|
|
|
265
266
|
return ids;
|
|
266
267
|
}
|
|
267
268
|
/**
|
|
268
|
-
* Abort all running subagents
|
|
269
|
-
* Called from
|
|
269
|
+
* Abort all running subagents during shutdown cleanup.
|
|
270
|
+
* Called from SIGINT, session_shutdown(reason="quit"), and beforeExit fallback paths.
|
|
270
271
|
*/
|
|
271
272
|
abortAll() {
|
|
272
273
|
const allAgents = this.registry.getAllRunning();
|
|
273
274
|
for (const state of allAgents) {
|
|
274
|
-
this.abort(state.id, { reason: "Aborted
|
|
275
|
+
this.abort(state.id, { reason: "Aborted during shutdown" });
|
|
275
276
|
}
|
|
276
277
|
}
|
|
277
278
|
getAbortableAgents() {
|
package/dist/tool-registry.d.ts
CHANGED
|
@@ -1,76 +1,5 @@
|
|
|
1
|
-
declare const
|
|
2
|
-
|
|
3
|
-
path: import("@sinclair/typebox").TString;
|
|
4
|
-
offset: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
5
|
-
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
6
|
-
}>, any>;
|
|
7
|
-
bash: (cwd: string) => import("@mariozechner/pi-agent-core").AgentTool<import("@sinclair/typebox").TObject<{
|
|
8
|
-
command: import("@sinclair/typebox").TString;
|
|
9
|
-
timeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
10
|
-
}>, any>;
|
|
11
|
-
edit: (cwd: string) => import("@mariozechner/pi-agent-core").AgentTool<import("@sinclair/typebox").TObject<{
|
|
12
|
-
path: import("@sinclair/typebox").TString;
|
|
13
|
-
edits: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
14
|
-
oldText: import("@sinclair/typebox").TString;
|
|
15
|
-
newText: import("@sinclair/typebox").TString;
|
|
16
|
-
}>>;
|
|
17
|
-
}>, any>;
|
|
18
|
-
write: (cwd: string) => import("@mariozechner/pi-agent-core").AgentTool<import("@sinclair/typebox").TObject<{
|
|
19
|
-
path: import("@sinclair/typebox").TString;
|
|
20
|
-
content: import("@sinclair/typebox").TString;
|
|
21
|
-
}>, any>;
|
|
22
|
-
grep: (cwd: string) => import("@mariozechner/pi-agent-core").AgentTool<import("@sinclair/typebox").TObject<{
|
|
23
|
-
pattern: import("@sinclair/typebox").TString;
|
|
24
|
-
path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
25
|
-
glob: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
26
|
-
ignoreCase: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
27
|
-
literal: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
28
|
-
context: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
29
|
-
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
30
|
-
}>, any>;
|
|
31
|
-
find: (cwd: string) => import("@mariozechner/pi-agent-core").AgentTool<import("@sinclair/typebox").TObject<{
|
|
32
|
-
pattern: import("@sinclair/typebox").TString;
|
|
33
|
-
path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
34
|
-
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
35
|
-
}>, any>;
|
|
36
|
-
ls: (cwd: string) => import("@mariozechner/pi-agent-core").AgentTool<import("@sinclair/typebox").TObject<{
|
|
37
|
-
path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
38
|
-
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
39
|
-
}>, any>;
|
|
40
|
-
};
|
|
41
|
-
export type SupportedToolName = keyof typeof TOOL_FACTORIES;
|
|
1
|
+
declare const SUPPORTED_TOOL_NAMES_LITERAL: readonly ["read", "bash", "edit", "write", "grep", "find", "ls"];
|
|
2
|
+
export type SupportedToolName = (typeof SUPPORTED_TOOL_NAMES_LITERAL)[number];
|
|
42
3
|
export declare const SUPPORTED_TOOL_NAMES: readonly ("read" | "bash" | "edit" | "write" | "grep" | "find" | "ls")[];
|
|
43
4
|
export declare function isSupportedToolName(name: string): name is SupportedToolName;
|
|
44
|
-
export declare function createSupportedTools(toolNames: readonly SupportedToolName[], cwd: string): (import("@mariozechner/pi-agent-core").AgentTool<import("@sinclair/typebox").TObject<{
|
|
45
|
-
path: import("@sinclair/typebox").TString;
|
|
46
|
-
offset: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
47
|
-
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
48
|
-
}>, any> | import("@mariozechner/pi-agent-core").AgentTool<import("@sinclair/typebox").TObject<{
|
|
49
|
-
command: import("@sinclair/typebox").TString;
|
|
50
|
-
timeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
51
|
-
}>, any> | import("@mariozechner/pi-agent-core").AgentTool<import("@sinclair/typebox").TObject<{
|
|
52
|
-
path: import("@sinclair/typebox").TString;
|
|
53
|
-
edits: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
54
|
-
oldText: import("@sinclair/typebox").TString;
|
|
55
|
-
newText: import("@sinclair/typebox").TString;
|
|
56
|
-
}>>;
|
|
57
|
-
}>, any> | import("@mariozechner/pi-agent-core").AgentTool<import("@sinclair/typebox").TObject<{
|
|
58
|
-
path: import("@sinclair/typebox").TString;
|
|
59
|
-
content: import("@sinclair/typebox").TString;
|
|
60
|
-
}>, any> | import("@mariozechner/pi-agent-core").AgentTool<import("@sinclair/typebox").TObject<{
|
|
61
|
-
pattern: import("@sinclair/typebox").TString;
|
|
62
|
-
path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
63
|
-
glob: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
64
|
-
ignoreCase: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
65
|
-
literal: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
66
|
-
context: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
67
|
-
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
68
|
-
}>, any> | import("@mariozechner/pi-agent-core").AgentTool<import("@sinclair/typebox").TObject<{
|
|
69
|
-
pattern: import("@sinclair/typebox").TString;
|
|
70
|
-
path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
71
|
-
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
72
|
-
}>, any> | import("@mariozechner/pi-agent-core").AgentTool<import("@sinclair/typebox").TObject<{
|
|
73
|
-
path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
74
|
-
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
75
|
-
}>, any>)[];
|
|
76
5
|
export {};
|
package/dist/tool-registry.js
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export const SUPPORTED_TOOL_NAMES = Object.freeze(Object.keys(TOOL_FACTORIES));
|
|
1
|
+
const SUPPORTED_TOOL_NAMES_LITERAL = [
|
|
2
|
+
"read",
|
|
3
|
+
"bash",
|
|
4
|
+
"edit",
|
|
5
|
+
"write",
|
|
6
|
+
"grep",
|
|
7
|
+
"find",
|
|
8
|
+
"ls",
|
|
9
|
+
];
|
|
10
|
+
export const SUPPORTED_TOOL_NAMES = Object.freeze([...SUPPORTED_TOOL_NAMES_LITERAL]);
|
|
12
11
|
export function isSupportedToolName(name) {
|
|
13
|
-
return name
|
|
14
|
-
}
|
|
15
|
-
export function createSupportedTools(toolNames, cwd) {
|
|
16
|
-
return toolNames.map((toolName) => TOOL_FACTORIES[toolName](cwd));
|
|
12
|
+
return SUPPORTED_TOOL_NAMES.includes(name);
|
|
17
13
|
}
|
package/docs/architecture.md
CHANGED
|
@@ -20,7 +20,7 @@ Primary components:
|
|
|
20
20
|
|
|
21
21
|
### 2.1 CrewRuntime singleton
|
|
22
22
|
|
|
23
|
-
`CrewRuntime` is a process-level singleton that survives pi runtime replacement (`/resume`, `/new`, `/fork`). When pi discards an old extension instance and creates a new one, the new instance reconnects to the same `crewRuntime` and picks up existing subagent state.
|
|
23
|
+
`CrewRuntime` is a process-level singleton that survives pi runtime replacement (`/resume`, `/new`, `/fork`, `/reload`). When pi discards an old extension instance and creates a new one, the new instance reconnects to the same `crewRuntime` and picks up existing subagent state.
|
|
24
24
|
|
|
25
25
|
Responsibilities:
|
|
26
26
|
|
|
@@ -35,7 +35,7 @@ Routes subagent results to the correct session at the correct time. Key behavior
|
|
|
35
35
|
|
|
36
36
|
- Tracks active session via `ActiveRuntimeBinding` (set on `session_start`, cleared on `session_shutdown`)
|
|
37
37
|
- Queues results when owner session is inactive
|
|
38
|
-
- Flushes queued results when owner session activates
|
|
38
|
+
- Flushes queued results when owner session activates on any `session_start`; resume/fork are the important replacement paths because subagents survive runtime replacement within the same process
|
|
39
39
|
- Uses `triggerTurn: false/true` split to preserve ordering between `crew-result` and `crew-remaining`
|
|
40
40
|
|
|
41
41
|
Underlying delivery: see pi's `sendMessage({ deliverAs, triggerTurn })` in extensions.md.
|
|
@@ -115,7 +115,7 @@ Invariants:
|
|
|
115
115
|
|
|
116
116
|
1. `crew_list`, `crew_abort`, `crew_respond`, `crew_done`, status widget: session-scoped. Only owner sees/controls.
|
|
117
117
|
2. `/pi-crew-abort`: cross-session emergency escape hatch.
|
|
118
|
-
3. `session_shutdown` deactivates delivery binding
|
|
118
|
+
3. `session_shutdown` always deactivates delivery binding. On replacement paths (`reload`, `new`, `resume`, `fork`), subagents continue running. On `quit`, the extension aborts all running subagents. `SIGINT` also aborts via a process hook, and `beforeExit` remains a fallback.
|
|
119
119
|
|
|
120
120
|
## 7. Subagent definition model
|
|
121
121
|
|
|
@@ -147,6 +147,7 @@ JSON overrides: `~/.pi/agent/pi-crew.json` (global), `<cwd>/.pi/pi-crew.json` (p
|
|
|
147
147
|
7. `crew-result` messages appear before `crew-remaining` notes (ordering via `triggerTurn` split).
|
|
148
148
|
8. Pending messages preserved for inactive sessions; TTL (24h) prevents memory leak.
|
|
149
149
|
9. Active subagent state survives runtime replacement within same process.
|
|
150
|
+
10. Graceful quit aborts subagents through `session_shutdown.reason === "quit"`; replacement paths do not.
|
|
150
151
|
|
|
151
152
|
## 9. Reading guide
|
|
152
153
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@melihmucuk/pi-crew",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Non-blocking subagent orchestration for pi coding agent",
|
|
6
6
|
"files": [
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
"@sinclair/typebox": "*"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@mariozechner/pi-agent-core": "^0.
|
|
46
|
-
"@mariozechner/pi-ai": "^0.
|
|
47
|
-
"@mariozechner/pi-coding-agent": "^0.
|
|
48
|
-
"@mariozechner/pi-tui": "^0.
|
|
45
|
+
"@mariozechner/pi-agent-core": "^0.68.0",
|
|
46
|
+
"@mariozechner/pi-ai": "^0.68.0",
|
|
47
|
+
"@mariozechner/pi-coding-agent": "^0.68.0",
|
|
48
|
+
"@mariozechner/pi-tui": "^0.68.0",
|
|
49
49
|
"@sinclair/typebox": "^0.34.49",
|
|
50
50
|
"@types/node": "^22.19.17",
|
|
51
51
|
"typescript": "^5.9.3"
|