@melihmucuk/pi-crew 1.0.7 → 1.0.9
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/agents/code-reviewer.md +18 -6
- package/agents/planner.md +9 -1
- package/agents/quality-reviewer.md +20 -13
- package/agents/scout.md +33 -26
- package/dist/agent-discovery.d.ts +0 -5
- package/dist/agent-discovery.js +1 -1
- package/dist/bootstrap-session.d.ts +13 -4
- package/dist/bootstrap-session.js +25 -16
- package/dist/index.js +37 -7
- package/dist/integration/register-command.d.ts +2 -2
- package/dist/integration/register-command.js +5 -5
- package/dist/integration/register-renderers.js +3 -0
- package/dist/integration/register-tools.d.ts +2 -2
- package/dist/integration/register-tools.js +2 -2
- package/dist/integration/tool-presentation.d.ts +2 -3
- package/dist/integration/tool-presentation.js +7 -8
- package/dist/integration/tools/crew-abort.d.ts +1 -1
- package/dist/integration/tools/crew-abort.js +3 -3
- package/dist/integration/tools/crew-done.d.ts +1 -1
- package/dist/integration/tools/crew-done.js +2 -2
- package/dist/integration/tools/crew-list.d.ts +1 -1
- package/dist/integration/tools/crew-list.js +3 -3
- package/dist/integration/tools/crew-respond.d.ts +1 -1
- package/dist/integration/tools/crew-respond.js +6 -7
- package/dist/integration/tools/crew-spawn.d.ts +1 -1
- package/dist/integration/tools/crew-spawn.js +17 -14
- package/dist/integration/tools/tool-deps.d.ts +3 -2
- package/dist/integration.d.ts +2 -2
- package/dist/integration.js +3 -3
- package/dist/runtime/crew-runtime.d.ts +61 -0
- package/dist/{crew-manager.js → runtime/crew-runtime.js} +84 -58
- package/dist/runtime/delivery-coordinator.d.ts +16 -7
- package/dist/runtime/delivery-coordinator.js +46 -20
- package/dist/runtime/subagent-registry.d.ts +1 -0
- package/dist/runtime/subagent-registry.js +3 -0
- package/dist/runtime/subagent-state.d.ts +2 -0
- package/dist/status-widget.d.ts +2 -2
- package/dist/status-widget.js +3 -3
- package/dist/subagent-messages.d.ts +5 -2
- package/dist/subagent-messages.js +5 -4
- package/docs/architecture.md +106 -843
- package/package.json +1 -1
- package/prompts/pi-crew-plan.md +82 -123
- package/prompts/pi-crew-review.md +64 -115
- package/dist/crew-manager.d.ts +0 -44
package/agents/code-reviewer.md
CHANGED
|
@@ -34,7 +34,10 @@ Use best judgement when processing input.
|
|
|
34
34
|
|
|
35
35
|
- Use the diff to identify which files changed
|
|
36
36
|
- Read the full file to understand existing patterns, control flow, and error handling
|
|
37
|
+
- Trace the relevant entry point, call chain, and affected callers before deciding something is a bug
|
|
38
|
+
- Look for similar existing implementations to confirm whether the change follows established patterns
|
|
37
39
|
- Check for existing style guide or conventions files (CONVENTIONS.md, AGENTS.md, .editorconfig, etc.)
|
|
40
|
+
- When useful, validate with available evidence such as tests, typecheck output, call-site search, git history/blame, or existing nearby code
|
|
38
41
|
|
|
39
42
|
---
|
|
40
43
|
|
|
@@ -69,6 +72,13 @@ Use best judgement when processing input.
|
|
|
69
72
|
- Don't invent hypothetical problems - if an edge case matters, explain the realistic scenario where it breaks
|
|
70
73
|
- Ask yourself: "Am I flagging this because it's genuinely wrong, or because I feel I should find something?" If you cannot articulate a concrete scenario where the code fails, do not flag it.
|
|
71
74
|
- If you need more context to be sure, use your available tools to get it
|
|
75
|
+
- Before reporting any bug, validate these points:
|
|
76
|
+
1. Which invariant, assumption, or contract is violated?
|
|
77
|
+
2. Which concrete input, state, or environment triggers it?
|
|
78
|
+
3. Which code path reaches the failure?
|
|
79
|
+
4. What evidence supports it (existing code, caller usage, tests, typecheck, history, or direct inspection)?
|
|
80
|
+
|
|
81
|
+
If you cannot answer those questions with concrete evidence, do not report the issue.
|
|
72
82
|
|
|
73
83
|
**Don't be a zealot about style.** When checking code against conventions:
|
|
74
84
|
|
|
@@ -77,7 +87,7 @@ Use best judgement when processing input.
|
|
|
77
87
|
- Excessive nesting is a legitimate concern regardless of other style choices.
|
|
78
88
|
- Don't flag style preferences as issues unless they clearly violate established project conventions.
|
|
79
89
|
|
|
80
|
-
**Confidence Gate**: For every issue you report, internally rate your confidence (high/medium/low). Only report issues where your confidence is **high**. If medium, investigate further using available tools
|
|
90
|
+
**Confidence Gate**: For every issue you report, internally rate your confidence (high/medium/low). Only report issues where your confidence is **high**. If confidence is medium or low, investigate further using available tools. If it still is not high confidence after investigation, do not report it as an issue.
|
|
81
91
|
|
|
82
92
|
---
|
|
83
93
|
|
|
@@ -131,15 +141,17 @@ For each issue found:
|
|
|
131
141
|
**[SEVERITY] Category: Brief title**
|
|
132
142
|
File: `path/to/file.ts:123`
|
|
133
143
|
Issue: Clear description of what's wrong
|
|
134
|
-
|
|
144
|
+
Invariant: Which assumption, contract, or expected behavior is violated
|
|
145
|
+
Context: Which concrete input/state/environment triggers it, and how the code reaches failure
|
|
146
|
+
Evidence: What you validated (call path, caller usage, tests, typecheck, similar code, or file context)
|
|
135
147
|
Suggestion: How to fix (if not obvious)
|
|
136
148
|
|
|
137
|
-
At the end of your review, include a summary
|
|
149
|
+
At the end of your review, include a summary:
|
|
138
150
|
|
|
139
151
|
**Code Review Summary**
|
|
140
152
|
Files reviewed: [count]
|
|
141
|
-
|
|
142
|
-
|
|
153
|
+
Issues found: [count by severity]
|
|
154
|
+
Confidence: [overall confidence in findings: high/medium]
|
|
143
155
|
Highest-risk area: [which file/module needs attention most and why]
|
|
144
156
|
|
|
145
|
-
If
|
|
157
|
+
If confidence is medium, state what additional context would increase it.
|
package/agents/planner.md
CHANGED
|
@@ -12,7 +12,7 @@ You are an autonomous planning agent that converts messy requests into a **deter
|
|
|
12
12
|
- Do **not** implement.
|
|
13
13
|
- Do **not** modify files.
|
|
14
14
|
- Gather only the **minimum** project context needed to plan correctly.
|
|
15
|
-
- Output exactly one mode: **Blocking Questions** OR **Implementation Plan** (no mixing, no extras).
|
|
15
|
+
- Output exactly one mode: **Blocking Questions** OR **Implementation Plan** OR **No plan needed** (no mixing, no extras).
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -140,3 +140,11 @@ Output a Markdown document (no code fences), using exactly these sections and or
|
|
|
140
140
|
- Expected end state.
|
|
141
141
|
- Functional criteria (what works and how).
|
|
142
142
|
- Important non-functional criteria if relevant (error handling, performance, UX).
|
|
143
|
+
|
|
144
|
+
### 3) No plan needed
|
|
145
|
+
|
|
146
|
+
Use this only when the task is trivial enough that a competent coding agent can implement it directly without meaningful planning value.
|
|
147
|
+
|
|
148
|
+
Output exactly:
|
|
149
|
+
|
|
150
|
+
`No plan needed: <one-sentence reason>`
|
|
@@ -38,7 +38,9 @@ Before reviewing, understand the project's standards:
|
|
|
38
38
|
|
|
39
39
|
- Read AGENTS.md (both global and project-level) for conventions
|
|
40
40
|
- Look at the overall project structure to understand patterns
|
|
41
|
+
- Trace the relevant entry point, call chain, and affected callers so you understand whether the structure fits the surrounding code
|
|
41
42
|
- Identify up to 2-3 representative, clean files in the same area/module as the code under review and use them as baseline. Compare against these, not against an abstract ideal.
|
|
43
|
+
- When useful, validate with available evidence such as call-site search, import usage, typecheck output, git history/blame, or existing nearby code
|
|
42
44
|
|
|
43
45
|
This is critical: quality is relative to THIS project's standards, not to some platonic ideal of clean code.
|
|
44
46
|
|
|
@@ -118,8 +120,15 @@ Apply the **6-month test**: Will this actually cause a problem when someone (hum
|
|
|
118
120
|
- Don't recommend abstractions for code that isn't duplicated yet. "Extract this to a util" is only valid if there are already 2+ copies or a very obvious reuse case.
|
|
119
121
|
- Don't flag complexity in code that is inherently complex. Some business logic IS complicated. The question is whether the code makes it more complicated than it needs to be.
|
|
120
122
|
- Ask yourself: "Am I suggesting this because it genuinely helps maintainability, or because I'd write it differently?" If the latter, skip it.
|
|
123
|
+
- Before reporting any finding, validate these points:
|
|
124
|
+
1. Which maintainability invariant or project convention is being violated?
|
|
125
|
+
2. Which concrete future change, extension, or debugging task becomes harder because of it?
|
|
126
|
+
3. Which code path, dependency relationship, or file boundary demonstrates the problem?
|
|
127
|
+
4. What evidence supports it (similar code, caller/import usage, typecheck, history, or direct inspection)?
|
|
121
128
|
|
|
122
|
-
|
|
129
|
+
If you cannot answer those questions with concrete evidence, do not report the finding.
|
|
130
|
+
|
|
131
|
+
**Confidence Gate**: For every finding, internally rate your confidence (high/medium/low). Only report findings where your confidence is **high**. If confidence is medium or low, investigate further using available tools. If it still is not high confidence after investigation, do not report it.
|
|
123
132
|
|
|
124
133
|
---
|
|
125
134
|
|
|
@@ -128,10 +137,11 @@ Apply the **6-month test**: Will this actually cause a problem when someone (hum
|
|
|
128
137
|
For each finding:
|
|
129
138
|
|
|
130
139
|
**[SEVERITY] Category: Brief title**
|
|
131
|
-
File: `path/to/file.ts:123` (or
|
|
140
|
+
File: `path/to/file.ts:123` (functionName or section, line range if identifiable)
|
|
132
141
|
Issue: What the structural problem is
|
|
133
|
-
|
|
134
|
-
Impact:
|
|
142
|
+
Invariant: Which maintainability rule, convention, or boundary is violated
|
|
143
|
+
Impact: Which concrete future change, extension, or debugging task becomes harder
|
|
144
|
+
Evidence: What you validated (call path, import/caller usage, similar code, typecheck, history, or file context)
|
|
135
145
|
Suggestion: Specific refactoring approach (not vague "clean this up")
|
|
136
146
|
|
|
137
147
|
## Severity Levels
|
|
@@ -142,23 +152,20 @@ Suggestion: Specific refactoring approach (not vague "clean this up")
|
|
|
142
152
|
|
|
143
153
|
---
|
|
144
154
|
|
|
145
|
-
## Output
|
|
155
|
+
## Output Summary
|
|
146
156
|
|
|
147
|
-
At the end of your review, include a summary
|
|
157
|
+
At the end of your review, include a summary:
|
|
148
158
|
|
|
149
159
|
**Quality Review Summary**
|
|
150
160
|
Files reviewed: [count]
|
|
151
161
|
Findings: [count by severity]
|
|
152
|
-
Overall confidence: [high/medium]
|
|
153
|
-
Highest-risk area: [which file/module needs attention most and why]
|
|
154
162
|
Overall health: [one sentence assessment]
|
|
163
|
+
Highest-risk area: [which file/module needs attention most and why]
|
|
155
164
|
|
|
156
|
-
If
|
|
157
|
-
|
|
158
|
-
If no issues found, output exactly:
|
|
165
|
+
If no issues found:
|
|
159
166
|
|
|
160
167
|
**No issues found.**
|
|
161
|
-
Reviewed: [list of files
|
|
162
|
-
Overall
|
|
168
|
+
Reviewed: [list of files]
|
|
169
|
+
Overall health: [brief assessment]
|
|
163
170
|
|
|
164
171
|
Do not pad this with compliments or hedging language.
|
package/agents/scout.md
CHANGED
|
@@ -6,53 +6,60 @@ thinking: minimal
|
|
|
6
6
|
tools: read, grep, find, ls, bash
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
You are a scout. Quickly investigate a codebase and return structured findings that another agent can use without
|
|
9
|
+
You are a scout. Quickly investigate a codebase and return structured findings that another agent can use without repeating your exploration. Deliver your output in the same language as the user's request.
|
|
10
10
|
|
|
11
11
|
Do NOT modify any files. Bash is for read-only commands only. Do not run builds, tests, or any command that mutates state.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## Goal
|
|
14
|
+
|
|
15
|
+
Find only the context needed for the assigned question or area. Stop as soon as you can hand off clear, actionable findings.
|
|
16
|
+
|
|
17
|
+
Do not implement.
|
|
18
|
+
Do not propose a plan unless explicitly asked.
|
|
19
|
+
Do not dump large code snippets.
|
|
14
20
|
|
|
15
21
|
## Gathering Context
|
|
16
22
|
|
|
17
23
|
Before diving into the task:
|
|
18
24
|
|
|
19
|
-
- Check
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
---
|
|
25
|
+
- Check project convention files (`AGENTS.md`, `CONVENTIONS.md`, `.editorconfig`, etc.) if relevant
|
|
26
|
+
- Identify the language, framework, and main structure only if it helps the assigned investigation
|
|
27
|
+
- Prefer narrow search first; widen only if needed
|
|
24
28
|
|
|
25
29
|
## Strategy
|
|
26
30
|
|
|
27
|
-
1.
|
|
28
|
-
2. Read the files
|
|
29
|
-
3.
|
|
30
|
-
4.
|
|
31
|
-
5. Stop
|
|
32
|
-
|
|
33
|
-
---
|
|
31
|
+
1. Locate the relevant files, symbols, and ownership area
|
|
32
|
+
2. Read only the files and sections needed to answer the assigned question
|
|
33
|
+
3. Trace only the necessary relationships: callers, callees, imports, types, config, or data flow
|
|
34
|
+
4. Extract concrete findings another agent can act on
|
|
35
|
+
5. Stop once the task is answerable
|
|
34
36
|
|
|
35
37
|
## Output Format
|
|
36
38
|
|
|
37
|
-
##
|
|
39
|
+
## Scope Investigated
|
|
40
|
+
|
|
41
|
+
- What you investigated
|
|
42
|
+
- What you did not investigate
|
|
38
43
|
|
|
39
|
-
|
|
44
|
+
## Findings
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
2. `path/to/other` (lines 100-150) - Description
|
|
46
|
+
For each finding, use this format:
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
- `path/to/file.ts#L10-L40` or ``symbolName` in `path/to/file.ts``
|
|
49
|
+
- Finding: what exists here
|
|
50
|
+
- Relevance: why this matters for the assigned task
|
|
45
51
|
|
|
46
|
-
|
|
52
|
+
## Relationships
|
|
47
53
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
```
|
|
54
|
+
- Key file-to-file, type, or call relationships that matter
|
|
55
|
+
- Keep this concrete and brief
|
|
51
56
|
|
|
52
|
-
##
|
|
57
|
+
## Open Questions / Gaps
|
|
53
58
|
|
|
54
|
-
|
|
59
|
+
- Missing context, ambiguity, or areas not fully verified
|
|
60
|
+
- Only include if they materially affect planning or implementation
|
|
55
61
|
|
|
56
62
|
## Start Here
|
|
57
63
|
|
|
58
|
-
|
|
64
|
+
- First file or symbol to inspect next
|
|
65
|
+
- Second file or symbol if needed
|
|
@@ -25,10 +25,5 @@ interface AgentDiscoveryResult {
|
|
|
25
25
|
agents: AgentConfig[];
|
|
26
26
|
warnings: AgentDiscoveryWarning[];
|
|
27
27
|
}
|
|
28
|
-
interface ParseResult {
|
|
29
|
-
agent: AgentConfig | null;
|
|
30
|
-
warnings: AgentDiscoveryWarning[];
|
|
31
|
-
}
|
|
32
|
-
export declare function parseAgentDefinition(content: string, filePath: string): ParseResult;
|
|
33
28
|
export declare function discoverAgents(cwd?: string): AgentDiscoveryResult;
|
|
34
29
|
export {};
|
package/dist/agent-discovery.js
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type AgentSession, type ModelRegistry } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import type { Api, Model } from "@mariozechner/pi-ai";
|
|
2
3
|
import type { AgentConfig } from "./agent-discovery.js";
|
|
4
|
+
export interface BootstrapContext {
|
|
5
|
+
model: Model<Api> | undefined;
|
|
6
|
+
modelRegistry: ModelRegistry;
|
|
7
|
+
parentSessionFile?: string;
|
|
8
|
+
}
|
|
3
9
|
interface BootstrapOptions {
|
|
4
10
|
agentConfig: AgentConfig;
|
|
5
11
|
cwd: string;
|
|
6
|
-
ctx:
|
|
12
|
+
ctx: BootstrapContext;
|
|
7
13
|
extensionResolvedPath: string;
|
|
8
|
-
parentSessionFile?: string;
|
|
9
14
|
}
|
|
10
|
-
export
|
|
15
|
+
export interface BootstrapResult {
|
|
16
|
+
session: AgentSession;
|
|
17
|
+
warnings: string[];
|
|
18
|
+
}
|
|
19
|
+
export declare function bootstrapSession(opts: BootstrapOptions): Promise<BootstrapResult>;
|
|
11
20
|
export {};
|
|
@@ -4,29 +4,35 @@ function resolveTools(agentConfig, cwd) {
|
|
|
4
4
|
return createSupportedTools(agentConfig.tools ?? SUPPORTED_TOOL_NAMES, cwd);
|
|
5
5
|
}
|
|
6
6
|
function resolveModel(agentConfig, ctx) {
|
|
7
|
+
const warnings = [];
|
|
7
8
|
const model = ctx.model;
|
|
8
9
|
if (!agentConfig.parsedModel)
|
|
9
|
-
return model;
|
|
10
|
+
return { model, warnings };
|
|
10
11
|
const found = ctx.modelRegistry.find(agentConfig.parsedModel.provider, agentConfig.parsedModel.modelId);
|
|
11
12
|
if (found)
|
|
12
|
-
return found;
|
|
13
|
-
|
|
14
|
-
return model;
|
|
13
|
+
return { model: found, warnings };
|
|
14
|
+
warnings.push(`Model "${agentConfig.model}" not found, using current session model`);
|
|
15
|
+
return { model, warnings };
|
|
15
16
|
}
|
|
16
|
-
function
|
|
17
|
+
function getSkillWarnings(agentConfig, resourceLoader) {
|
|
18
|
+
const warnings = [];
|
|
17
19
|
if (!agentConfig.skills)
|
|
18
|
-
return;
|
|
20
|
+
return warnings;
|
|
19
21
|
const availableSkillNames = new Set(resourceLoader.getSkills().skills.map((skill) => skill.name));
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
for (const skillName of agentConfig.skills) {
|
|
23
|
+
if (!availableSkillNames.has(skillName)) {
|
|
24
|
+
warnings.push(`Unknown skill "${skillName}" in subagent config, skipping`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return warnings;
|
|
24
28
|
}
|
|
25
29
|
export async function bootstrapSession(opts) {
|
|
26
|
-
const
|
|
30
|
+
const warnings = [];
|
|
31
|
+
const { agentConfig, cwd, ctx, extensionResolvedPath } = opts;
|
|
27
32
|
const authStorage = ctx.modelRegistry.authStorage;
|
|
28
33
|
const modelRegistry = ctx.modelRegistry;
|
|
29
|
-
const model = resolveModel(agentConfig, ctx);
|
|
34
|
+
const { model, warnings: modelWarnings } = resolveModel(agentConfig, ctx);
|
|
35
|
+
warnings.push(...modelWarnings);
|
|
30
36
|
const tools = resolveTools(agentConfig, cwd);
|
|
31
37
|
const resourceLoader = new DefaultResourceLoader({
|
|
32
38
|
cwd,
|
|
@@ -40,16 +46,18 @@ export async function bootstrapSession(opts) {
|
|
|
40
46
|
diagnostics: base.diagnostics,
|
|
41
47
|
})
|
|
42
48
|
: undefined,
|
|
43
|
-
appendSystemPromptOverride: (base) => agentConfig.systemPrompt.trim()
|
|
49
|
+
appendSystemPromptOverride: (base) => agentConfig.systemPrompt.trim()
|
|
50
|
+
? [...base, agentConfig.systemPrompt]
|
|
51
|
+
: base,
|
|
44
52
|
});
|
|
45
53
|
await resourceLoader.reload();
|
|
46
|
-
|
|
54
|
+
warnings.push(...getSkillWarnings(agentConfig, resourceLoader));
|
|
47
55
|
const settingsManager = SettingsManager.inMemory({
|
|
48
56
|
compaction: { enabled: agentConfig.compaction ?? true },
|
|
49
57
|
});
|
|
50
58
|
const sessionManager = SessionManager.create(cwd);
|
|
51
|
-
sessionManager.newSession({ parentSession: parentSessionFile });
|
|
52
|
-
|
|
59
|
+
sessionManager.newSession({ parentSession: ctx.parentSessionFile });
|
|
60
|
+
const result = await createAgentSession({
|
|
53
61
|
cwd,
|
|
54
62
|
model,
|
|
55
63
|
thinkingLevel: agentConfig.thinking,
|
|
@@ -60,4 +68,5 @@ export async function bootstrapSession(opts) {
|
|
|
60
68
|
authStorage,
|
|
61
69
|
modelRegistry,
|
|
62
70
|
});
|
|
71
|
+
return { session: result.session, warnings };
|
|
63
72
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,33 @@
|
|
|
1
1
|
import { dirname } from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
import { discoverAgents } from "./agent-discovery.js";
|
|
4
|
-
import {
|
|
4
|
+
import { crewRuntime, } from "./runtime/crew-runtime.js";
|
|
5
5
|
import { registerCrewIntegration } from "./integration.js";
|
|
6
6
|
import { formatAgentsForPrompt } from "./prompt-injection.js";
|
|
7
7
|
import { updateWidget } from "./status-widget.js";
|
|
8
8
|
const extensionDir = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
// Process-level cleanup for subagents on exit
|
|
10
|
+
let processHooksSetup = false;
|
|
11
|
+
function setupProcessHooks() {
|
|
12
|
+
if (processHooksSetup)
|
|
13
|
+
return;
|
|
14
|
+
processHooksSetup = true;
|
|
15
|
+
const abortAndExit = (signal) => {
|
|
16
|
+
crewRuntime.abortAll();
|
|
17
|
+
// Re-raise to restore default Node termination behavior
|
|
18
|
+
process.exit(128 + (signal === 'SIGINT' ? 2 : 15));
|
|
19
|
+
};
|
|
20
|
+
process.once('SIGINT', () => abortAndExit('SIGINT'));
|
|
21
|
+
process.once('SIGTERM', () => abortAndExit('SIGTERM'));
|
|
22
|
+
process.on('beforeExit', () => crewRuntime.abortAll());
|
|
23
|
+
}
|
|
9
24
|
export default function (pi) {
|
|
10
|
-
const crewManager = new CrewManager(extensionDir);
|
|
11
25
|
let currentCtx;
|
|
12
26
|
let cachedPromptSuffix = "";
|
|
27
|
+
setupProcessHooks();
|
|
13
28
|
const refreshWidget = () => {
|
|
14
29
|
if (currentCtx)
|
|
15
|
-
updateWidget(currentCtx,
|
|
30
|
+
updateWidget(currentCtx, crewRuntime);
|
|
16
31
|
};
|
|
17
32
|
const rebuildPromptCache = (cwd) => {
|
|
18
33
|
const { agents } = discoverAgents(cwd);
|
|
@@ -20,16 +35,31 @@ export default function (pi) {
|
|
|
20
35
|
};
|
|
21
36
|
const activateSession = (ctx) => {
|
|
22
37
|
currentCtx = ctx;
|
|
23
|
-
|
|
38
|
+
crewRuntime.activateSession({
|
|
39
|
+
sessionId: ctx.sessionManager.getSessionId(),
|
|
40
|
+
isIdle: () => ctx.isIdle(),
|
|
41
|
+
sendMessage: pi.sendMessage.bind(pi),
|
|
42
|
+
}, refreshWidget);
|
|
24
43
|
refreshWidget();
|
|
25
44
|
};
|
|
26
|
-
crewManager.onWidgetUpdate = refreshWidget;
|
|
27
45
|
pi.on("session_start", (_event, ctx) => {
|
|
28
46
|
rebuildPromptCache(ctx.cwd);
|
|
29
47
|
activateSession(ctx);
|
|
30
48
|
});
|
|
49
|
+
pi.on("session_before_switch", () => {
|
|
50
|
+
// Session is about to switch - no action needed here.
|
|
51
|
+
// Subagent cleanup is handled by process hooks, not session_shutdown.
|
|
52
|
+
});
|
|
53
|
+
pi.on("session_before_fork", () => {
|
|
54
|
+
// Session is about to fork - no action needed here.
|
|
55
|
+
// Subagent cleanup is handled by process hooks, not session_shutdown.
|
|
56
|
+
});
|
|
31
57
|
pi.on("session_shutdown", (_event, ctx) => {
|
|
32
|
-
|
|
58
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
59
|
+
// Deactivate delivery to this session, but don't abort subagents.
|
|
60
|
+
// Subagents continue running and will complete normally.
|
|
61
|
+
// Real cleanup happens in process exit hooks.
|
|
62
|
+
crewRuntime.deactivateSession(sessionId);
|
|
33
63
|
});
|
|
34
64
|
pi.on("before_agent_start", (event) => {
|
|
35
65
|
if (!cachedPromptSuffix)
|
|
@@ -43,5 +73,5 @@ export default function (pi) {
|
|
|
43
73
|
const after = event.systemPrompt.slice(idx);
|
|
44
74
|
return { systemPrompt: before + cachedPromptSuffix + after };
|
|
45
75
|
});
|
|
46
|
-
registerCrewIntegration(pi,
|
|
76
|
+
registerCrewIntegration(pi, crewRuntime, extensionDir);
|
|
47
77
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
import type {
|
|
3
|
-
export declare function registerCrewCommand(pi: ExtensionAPI,
|
|
2
|
+
import type { CrewRuntime } from "../runtime/crew-runtime.js";
|
|
3
|
+
export declare function registerCrewCommand(pi: ExtensionAPI, crew: CrewRuntime): void;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export function registerCrewCommand(pi,
|
|
1
|
+
export function registerCrewCommand(pi, crew) {
|
|
2
2
|
pi.registerCommand("pi-crew-abort", {
|
|
3
3
|
description: "Abort an active subagent",
|
|
4
4
|
getArgumentCompletions(argumentPrefix) {
|
|
5
|
-
const activeAgents =
|
|
5
|
+
const activeAgents = crew.getAbortableAgents();
|
|
6
6
|
if (activeAgents.length === 0)
|
|
7
7
|
return null;
|
|
8
8
|
return activeAgents
|
|
@@ -15,7 +15,7 @@ export function registerCrewCommand(pi, crewManager) {
|
|
|
15
15
|
async handler(args, ctx) {
|
|
16
16
|
const trimmed = args.trim();
|
|
17
17
|
if (trimmed) {
|
|
18
|
-
const success =
|
|
18
|
+
const success = crew.abort(trimmed, { reason: "Aborted by user command" });
|
|
19
19
|
if (!success) {
|
|
20
20
|
ctx.ui.notify(`No active subagent with id "${trimmed}"`, "error");
|
|
21
21
|
}
|
|
@@ -24,7 +24,7 @@ export function registerCrewCommand(pi, crewManager) {
|
|
|
24
24
|
}
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
|
-
const activeAgents =
|
|
27
|
+
const activeAgents = crew.getAbortableAgents();
|
|
28
28
|
if (activeAgents.length === 0) {
|
|
29
29
|
ctx.ui.notify("No active subagents", "info");
|
|
30
30
|
return;
|
|
@@ -39,7 +39,7 @@ export function registerCrewCommand(pi, crewManager) {
|
|
|
39
39
|
const selectedOption = options.find((option) => option.label === selected);
|
|
40
40
|
if (!selectedOption)
|
|
41
41
|
return;
|
|
42
|
-
const success =
|
|
42
|
+
const success = crew.abort(selectedOption.id, { reason: "Aborted by user command" });
|
|
43
43
|
if (success) {
|
|
44
44
|
ctx.ui.notify(`Subagent ${selectedOption.id} aborted`, "info");
|
|
45
45
|
}
|
|
@@ -26,6 +26,9 @@ export function registerCrewMessageRenderers(pi) {
|
|
|
26
26
|
const body = details?.body ?? (!details && message.content ? String(message.content) : undefined);
|
|
27
27
|
const box = new Box(1, 1, (text) => theme.bg("customMessageBg", text));
|
|
28
28
|
box.addChild(new Text(header, 0, 0));
|
|
29
|
+
if (details?.sessionFile) {
|
|
30
|
+
box.addChild(new Text(theme.fg("muted", `📁 ${details.sessionFile}`), 0, 0));
|
|
31
|
+
}
|
|
29
32
|
if (body) {
|
|
30
33
|
if (expanded) {
|
|
31
34
|
box.addChild(new Text("", 0, 0));
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
import type {
|
|
3
|
-
export declare function registerCrewTools(pi: ExtensionAPI,
|
|
2
|
+
import type { CrewRuntime } from "../runtime/crew-runtime.js";
|
|
3
|
+
export declare function registerCrewTools(pi: ExtensionAPI, crew: CrewRuntime, extensionDir: string): void;
|
|
@@ -3,7 +3,7 @@ import { registerCrewDoneTool } from "./tools/crew-done.js";
|
|
|
3
3
|
import { registerCrewListTool } from "./tools/crew-list.js";
|
|
4
4
|
import { registerCrewRespondTool } from "./tools/crew-respond.js";
|
|
5
5
|
import { registerCrewSpawnTool } from "./tools/crew-spawn.js";
|
|
6
|
-
export function registerCrewTools(pi,
|
|
6
|
+
export function registerCrewTools(pi, crew, extensionDir) {
|
|
7
7
|
const shownDiscoveryWarnings = new Set();
|
|
8
8
|
const notifyDiscoveryWarnings = (ctx, warnings) => {
|
|
9
9
|
if (!ctx.hasUI)
|
|
@@ -16,7 +16,7 @@ export function registerCrewTools(pi, crewManager) {
|
|
|
16
16
|
ctx.ui.notify(`${warning.message} (${warning.filePath})`, "error");
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
|
-
const deps = { pi,
|
|
19
|
+
const deps = { pi, crew, extensionDir, notifyDiscoveryWarnings };
|
|
20
20
|
registerCrewListTool(deps);
|
|
21
21
|
registerCrewSpawnTool(deps);
|
|
22
22
|
registerCrewAbortTool(deps);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
import { Text } from "@mariozechner/pi-tui";
|
|
2
|
+
import { Box, Text } from "@mariozechner/pi-tui";
|
|
3
3
|
export type ToolTheme = Parameters<Exclude<Parameters<ExtensionAPI["registerTool"]>[0]["renderCall"], undefined>>[1];
|
|
4
4
|
export type ToolResult = {
|
|
5
5
|
content: {
|
|
@@ -25,6 +25,5 @@ export declare function toolSuccess(text: string, details?: Record<string, unkno
|
|
|
25
25
|
}[];
|
|
26
26
|
details: Record<string, unknown>;
|
|
27
27
|
};
|
|
28
|
-
export declare function
|
|
29
|
-
export declare function renderCrewCall(theme: ToolTheme, name: string, id: string, preview?: string): Text;
|
|
28
|
+
export declare function renderCrewCall(theme: ToolTheme, name: string, id: string, preview?: string): Box;
|
|
30
29
|
export declare function renderCrewResult(result: ToolResult, theme: ToolTheme): Text;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Text } from "@mariozechner/pi-tui";
|
|
1
|
+
import { Box, Text } from "@mariozechner/pi-tui";
|
|
2
2
|
export function toolError(text) {
|
|
3
3
|
return {
|
|
4
4
|
content: [{ type: "text", text }],
|
|
@@ -12,14 +12,13 @@ export function toolSuccess(text, details = {}) {
|
|
|
12
12
|
details,
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
-
export function truncatePreview(text, max) {
|
|
16
|
-
return text.length > max ? `${text.slice(0, max)}...` : text;
|
|
17
|
-
}
|
|
18
15
|
export function renderCrewCall(theme, name, id, preview) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
const box = new Box(1, 1);
|
|
17
|
+
box.addChild(new Text(theme.fg("toolTitle", theme.bold(`${name} `)) + theme.fg("accent", id), 0, 0));
|
|
18
|
+
if (preview) {
|
|
19
|
+
box.addChild(new Text(theme.fg("dim", preview), 0, 0));
|
|
20
|
+
}
|
|
21
|
+
return box;
|
|
23
22
|
}
|
|
24
23
|
export function renderCrewResult(result, theme) {
|
|
25
24
|
const text = result.content[0];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { CrewToolDeps } from "./tool-deps.js";
|
|
2
|
-
export declare function registerCrewAbortTool({ pi,
|
|
2
|
+
export declare function registerCrewAbortTool({ pi, crew }: CrewToolDeps): void;
|
|
@@ -13,7 +13,7 @@ function formatAbortToolMessage(result) {
|
|
|
13
13
|
}
|
|
14
14
|
return parts.join("\n");
|
|
15
15
|
}
|
|
16
|
-
export function registerCrewAbortTool({ pi,
|
|
16
|
+
export function registerCrewAbortTool({ pi, crew }) {
|
|
17
17
|
pi.registerTool({
|
|
18
18
|
name: "crew_abort",
|
|
19
19
|
label: "Abort Crew",
|
|
@@ -38,7 +38,7 @@ export function registerCrewAbortTool({ pi, crewManager }) {
|
|
|
38
38
|
return toolError("Provide exactly one of: subagent_id, subagent_ids, or all=true.");
|
|
39
39
|
}
|
|
40
40
|
if (params.all) {
|
|
41
|
-
const abortedIds =
|
|
41
|
+
const abortedIds = crew.abortAllOwned(callerSessionId, {
|
|
42
42
|
reason: "Aborted by tool request",
|
|
43
43
|
});
|
|
44
44
|
if (abortedIds.length === 0) {
|
|
@@ -49,7 +49,7 @@ export function registerCrewAbortTool({ pi, crewManager }) {
|
|
|
49
49
|
const ids = params.subagent_id
|
|
50
50
|
? [params.subagent_id]
|
|
51
51
|
: (params.subagent_ids ?? []);
|
|
52
|
-
const result =
|
|
52
|
+
const result = crew.abortOwned(ids, callerSessionId, {
|
|
53
53
|
reason: "Aborted by tool request",
|
|
54
54
|
});
|
|
55
55
|
const message = formatAbortToolMessage(result);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { CrewToolDeps } from "./tool-deps.js";
|
|
2
|
-
export declare function registerCrewDoneTool({ pi,
|
|
2
|
+
export declare function registerCrewDoneTool({ pi, crew }: CrewToolDeps): void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import { renderCrewCall, renderCrewResult, toolError, toolSuccess, } from "../tool-presentation.js";
|
|
3
|
-
export function registerCrewDoneTool({ pi,
|
|
3
|
+
export function registerCrewDoneTool({ pi, crew }) {
|
|
4
4
|
pi.registerTool({
|
|
5
5
|
name: "crew_done",
|
|
6
6
|
label: "Done with Crew",
|
|
@@ -11,7 +11,7 @@ export function registerCrewDoneTool({ pi, crewManager }) {
|
|
|
11
11
|
promptSnippet: "Close an interactive subagent session when done.",
|
|
12
12
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
13
13
|
const callerSessionId = ctx.sessionManager.getSessionId();
|
|
14
|
-
const { error } =
|
|
14
|
+
const { error } = crew.done(params.subagent_id, callerSessionId);
|
|
15
15
|
if (error)
|
|
16
16
|
return toolError(error);
|
|
17
17
|
return toolSuccess(`Subagent ${params.subagent_id} closed.`, {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { CrewToolDeps } from "./tool-deps.js";
|
|
2
|
-
export declare function registerCrewListTool({ pi,
|
|
2
|
+
export declare function registerCrewListTool({ pi, crew, notifyDiscoveryWarnings, }: CrewToolDeps): void;
|