@melihmucuk/pi-crew 1.0.11 → 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-spawn.js +2 -0
- 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
|
}
|
|
@@ -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";
|
|
@@ -31,6 +32,7 @@ export function registerCrewSpawnTool({ pi, crew, extensionDir, notifyDiscoveryW
|
|
|
31
32
|
const id = crew.spawn(subagent, params.task, ctx.cwd, ownerSessionId, {
|
|
32
33
|
model: ctx.model,
|
|
33
34
|
modelRegistry: ctx.modelRegistry,
|
|
35
|
+
agentDir: getAgentDir(),
|
|
34
36
|
parentSessionFile: ctx.sessionManager.getSessionFile(),
|
|
35
37
|
onWarning: (msg) => ctx.ui.notify(msg, "warning"),
|
|
36
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"
|