pi-messenger 0.14.0 → 0.15.0
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/CHANGELOG.md +31 -1
- package/README.md +81 -6
- package/config-overlay.ts +11 -12
- package/config.ts +11 -5
- package/crew/agents/crew-worker.md +3 -3
- package/crew/agents.ts +39 -22
- package/crew/handlers/coordination.ts +72 -15
- package/crew/handlers/plan.ts +104 -38
- package/crew/handlers/review.ts +20 -11
- package/crew/handlers/revise.ts +15 -13
- package/crew/handlers/status.ts +10 -10
- package/crew/handlers/sync.ts +11 -10
- package/crew/handlers/task.ts +173 -26
- package/crew/handlers/team.ts +235 -0
- package/crew/handlers/work.ts +71 -29
- package/crew/index.ts +44 -29
- package/crew/live-progress.ts +1 -1
- package/crew/lobby.ts +18 -15
- package/crew/prompt.ts +115 -19
- package/crew/registry.ts +1 -1
- package/crew/spawn.ts +21 -16
- package/crew/state-autonomous.ts +1 -1
- package/crew/state-planning.ts +1 -1
- package/crew/state.ts +2 -2
- package/crew/store.ts +39 -10
- package/crew/task-actions.ts +13 -5
- package/crew/team/store.ts +479 -0
- package/crew/team/subagent-roles.ts +87 -0
- package/crew/team/types.ts +50 -0
- package/crew/types.ts +25 -5
- package/crew/utils/artifacts.ts +11 -1
- package/crew/utils/config.ts +1 -1
- package/crew/utils/discover.ts +1 -1
- package/crew/utils/progress.ts +73 -6
- package/crew/utils/risk-labels.ts +7 -0
- package/crew/utils/task-format.ts +14 -0
- package/crew/utils/team-roles.ts +28 -0
- package/feed.ts +52 -11
- package/handlers.ts +34 -30
- package/index.ts +183 -114
- package/install.mjs +30 -2
- package/overlay-actions.ts +12 -12
- package/overlay-coordinator.ts +1 -1
- package/overlay-render.ts +54 -30
- package/overlay.ts +76 -43
- package/package.json +14 -3
- package/skills/pi-messenger-crew/SKILL.md +38 -4
- package/store.ts +4 -4
package/crew/handlers/plan.ts
CHANGED
|
@@ -7,14 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
import * as fs from "node:fs";
|
|
9
9
|
import * as path from "node:path";
|
|
10
|
-
import type { ExtensionContext } from "@
|
|
11
|
-
import type { CrewParams } from "../types.
|
|
12
|
-
import { result } from "../utils/result.
|
|
13
|
-
import { spawnAgents } from "../agents.
|
|
14
|
-
import { discoverCrewAgents, discoverCrewSkills, type CrewSkillInfo } from "../utils/discover.
|
|
15
|
-
import { loadCrewConfig } from "../utils/config.
|
|
16
|
-
import { parseVerdict, type ParsedReview } from "../utils/verdict.
|
|
17
|
-
import { logFeedEvent } from "../../feed.
|
|
10
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
11
|
+
import type { CrewParams } from "../types.ts";
|
|
12
|
+
import { result } from "../utils/result.ts";
|
|
13
|
+
import { spawnAgents } from "../agents.ts";
|
|
14
|
+
import { discoverCrewAgents, discoverCrewSkills, type CrewSkillInfo } from "../utils/discover.ts";
|
|
15
|
+
import { loadCrewConfig } from "../utils/config.ts";
|
|
16
|
+
import { parseVerdict, type ParsedReview } from "../utils/verdict.ts";
|
|
17
|
+
import { logFeedEvent } from "../../feed.ts";
|
|
18
18
|
import {
|
|
19
19
|
finishPlanningRun,
|
|
20
20
|
isPlanningCancelled,
|
|
@@ -24,9 +24,12 @@ import {
|
|
|
24
24
|
setPlanningPhase,
|
|
25
25
|
startPlanningRun,
|
|
26
26
|
type PlanningPhase,
|
|
27
|
-
} from "../state.
|
|
28
|
-
import { getLiveWorkers } from "../live-progress.
|
|
29
|
-
import * as store from "../store.
|
|
27
|
+
} from "../state.ts";
|
|
28
|
+
import { getLiveWorkers } from "../live-progress.ts";
|
|
29
|
+
import * as store from "../store.ts";
|
|
30
|
+
import * as teamStore from "../team/store.ts";
|
|
31
|
+
import type { TeamProfile, TeamRoleDefinition } from "../team/types.ts";
|
|
32
|
+
import { taskMetadataMarkers } from "../utils/task-format.ts";
|
|
30
33
|
|
|
31
34
|
const PRD_PATTERNS = [
|
|
32
35
|
"PRD.md", "prd.md",
|
|
@@ -202,8 +205,9 @@ export async function execute(
|
|
|
202
205
|
ctx: ExtensionContext,
|
|
203
206
|
agentName: string,
|
|
204
207
|
onProgress?: () => void,
|
|
208
|
+
sessionModel?: string,
|
|
205
209
|
) {
|
|
206
|
-
const cwd = ctx.cwd
|
|
210
|
+
const cwd = ctx.cwd;
|
|
207
211
|
const { prd, prompt } = params;
|
|
208
212
|
const reportProgress = () => onProgress?.();
|
|
209
213
|
resetPlanningCancellation();
|
|
@@ -299,6 +303,10 @@ export async function execute(
|
|
|
299
303
|
const maxPasses = Math.max(1, config.planning.maxPasses);
|
|
300
304
|
const hasReviewer = availableAgents.some(a => a.name === "crew-reviewer");
|
|
301
305
|
const skills = discoverCrewSkills(cwd);
|
|
306
|
+
const activeTeam = teamStore.getActiveTeam(cwd);
|
|
307
|
+
const activeProfile = activeTeam ? teamStore.loadActiveProfile(cwd) : null;
|
|
308
|
+
const teamRoles = activeTeam ? teamStore.resolveRoles(cwd) : {};
|
|
309
|
+
const approvalLabels = activeTeam ? teamStore.activeApprovalLabels(cwd) : [];
|
|
302
310
|
|
|
303
311
|
const existingProgress = readProgressForPrompt(cwd);
|
|
304
312
|
|
|
@@ -328,13 +336,13 @@ export async function execute(
|
|
|
328
336
|
notify(ctx, `Planning pass ${pass}/${maxPasses} in progress`, "info");
|
|
329
337
|
|
|
330
338
|
const plannerPrompt = pass === 1
|
|
331
|
-
? buildFirstPassPrompt(prdPath, prdContent, existingProgress, isPromptBased, skills)
|
|
332
|
-
: buildRefinementPrompt(prdPath, prdContent, readProgressForPrompt(cwd), isPromptBased, skills);
|
|
339
|
+
? buildFirstPassPrompt(prdPath, prdContent, existingProgress, isPromptBased, skills, activeTeam?.name, activeProfile, teamRoles, approvalLabels)
|
|
340
|
+
: buildRefinementPrompt(prdPath, prdContent, readProgressForPrompt(cwd), isPromptBased, skills, activeTeam?.name, activeProfile, teamRoles, approvalLabels);
|
|
333
341
|
|
|
334
342
|
const [plannerResult] = await spawnAgents([{
|
|
335
343
|
agent: PLANNER_AGENT,
|
|
336
344
|
task: plannerPrompt,
|
|
337
|
-
modelOverride: config.models?.planner,
|
|
345
|
+
modelOverride: config.models?.planner ?? sessionModel,
|
|
338
346
|
taskId: "__planner__",
|
|
339
347
|
}], cwd);
|
|
340
348
|
|
|
@@ -387,7 +395,7 @@ export async function execute(
|
|
|
387
395
|
const [reviewResult] = await spawnAgents([{
|
|
388
396
|
agent: "crew-reviewer",
|
|
389
397
|
task: reviewPrompt,
|
|
390
|
-
modelOverride: config.models?.reviewer,
|
|
398
|
+
modelOverride: config.models?.reviewer ?? sessionModel,
|
|
391
399
|
taskId: "__reviewer__",
|
|
392
400
|
}], cwd);
|
|
393
401
|
|
|
@@ -420,7 +428,7 @@ export async function execute(
|
|
|
420
428
|
const outlineContent = sections
|
|
421
429
|
? `# Planning Outline\n\n## 1. PRD Understanding Summary\n${sections.prdSummary}\n\n## 2. Relevant Code/Docs/Resources Reviewed\n${sections.resourcesReviewed}\n\n## 3. Sequential Implementation Steps\n${sections.sequentialSteps}\n\n## 4. Parallelized Task Graph\n${sections.parallelTaskGraph}\n`
|
|
422
430
|
: `# Planning Outline\n\nStructured sections were not detected. Full planner output is included below.\n\n${lastPlannerOutput}`;
|
|
423
|
-
|
|
431
|
+
setPlanningOutline(cwd, outlineContent);
|
|
424
432
|
|
|
425
433
|
if (tasks.length === 0) {
|
|
426
434
|
store.setPlanSpec(cwd, lastPlannerOutput);
|
|
@@ -436,13 +444,21 @@ export async function execute(
|
|
|
436
444
|
});
|
|
437
445
|
}
|
|
438
446
|
|
|
439
|
-
const createdTasks: { id: string; title: string; dependsOn: string[]
|
|
447
|
+
const createdTasks: { id: string; title: string; dependsOn: string[] }[] = [];
|
|
440
448
|
const titleToId = new Map<string, string>();
|
|
441
449
|
|
|
442
450
|
for (let i = 0; i < tasks.length; i++) {
|
|
443
451
|
const task = tasks[i];
|
|
444
|
-
const
|
|
445
|
-
|
|
452
|
+
const role = teamStore.canonicalRoleForTask(cwd, task.role);
|
|
453
|
+
const riskLabels = teamStore.normalizeRiskLabels(task.riskLabels);
|
|
454
|
+
const approval = teamStore.approvalForTask(cwd, role, riskLabels);
|
|
455
|
+
const created = store.createTask(cwd, task.title, task.description, undefined, {
|
|
456
|
+
...(role ? { role } : {}),
|
|
457
|
+
...(riskLabels && riskLabels.length > 0 ? { risk_labels: riskLabels } : {}),
|
|
458
|
+
...(approval ? { approval } : {}),
|
|
459
|
+
...(task.skills && task.skills.length > 0 ? { skills: task.skills } : {}),
|
|
460
|
+
});
|
|
461
|
+
createdTasks.push({ id: created.id, title: task.title, dependsOn: task.dependsOn });
|
|
446
462
|
titleToId.set(task.title.toLowerCase(), created.id);
|
|
447
463
|
titleToId.set(`task ${i + 1}`, created.id);
|
|
448
464
|
titleToId.set(`task-${i + 1}`, created.id);
|
|
@@ -462,9 +478,6 @@ export async function execute(
|
|
|
462
478
|
}
|
|
463
479
|
}
|
|
464
480
|
|
|
465
|
-
if (task.skills && task.skills.length > 0) {
|
|
466
|
-
store.updateTask(cwd, task.id, { skills: task.skills });
|
|
467
|
-
}
|
|
468
481
|
}
|
|
469
482
|
|
|
470
483
|
pruneTransitiveDeps(cwd, createdTasks.map(t => t.id));
|
|
@@ -474,7 +487,8 @@ export async function execute(
|
|
|
474
487
|
const taskList = createdTasks.map(t => {
|
|
475
488
|
const task = store.getTask(cwd, t.id);
|
|
476
489
|
const deps = task?.depends_on.length ? ` → deps: ${task.depends_on.join(", ")}` : "";
|
|
477
|
-
|
|
490
|
+
const markers = task ? taskMetadataMarkers(task) : "";
|
|
491
|
+
return ` - ${t.id}: ${t.title}${markers}${deps}`;
|
|
478
492
|
}).join("\n");
|
|
479
493
|
|
|
480
494
|
const passLabel = passesCompleted === 1 ? "pass" : "passes";
|
|
@@ -503,12 +517,20 @@ export async function execute(
|
|
|
503
517
|
|
|
504
518
|
const successLabel = isPromptBased ? `"${runLabel}"` : `**${prdPath}**`;
|
|
505
519
|
const shouldAutoWork = params.autoWork !== false;
|
|
506
|
-
|
|
507
|
-
? `Workers will start automatically.`
|
|
508
|
-
: `**Next steps:**
|
|
520
|
+
let nextSteps = `**Next steps:**
|
|
509
521
|
- Review tasks: \`pi_messenger({ action: "task.list" })\`
|
|
510
522
|
- Start work: \`pi_messenger({ action: "work" })\`
|
|
511
523
|
- Autonomous: \`pi_messenger({ action: "work", autonomous: true })\``;
|
|
524
|
+
if (shouldAutoWork) {
|
|
525
|
+
const ready = store.getReadyTasks(cwd, { advisory: config.dependencies === "advisory" });
|
|
526
|
+
const startable = ready.filter(t => !teamStore.taskNeedsApproval(t));
|
|
527
|
+
const needsApproval = ready.filter(teamStore.taskNeedsApproval);
|
|
528
|
+
nextSteps = startable.length > 0
|
|
529
|
+
? `Workers will start automatically.`
|
|
530
|
+
: needsApproval.length > 0
|
|
531
|
+
? `Ready tasks need lead approval before workers can start:\n${needsApproval.map(t => `- \`pi_messenger({ action: "task.approve", id: "${t.id}" })\` — ${t.title}`).join("\n")}`
|
|
532
|
+
: `No tasks are startable yet. Review dependencies with \`pi_messenger({ action: "task.ready" })\`.`;
|
|
533
|
+
}
|
|
512
534
|
|
|
513
535
|
const text = `✅ Plan created from ${successLabel}
|
|
514
536
|
|
|
@@ -558,26 +580,60 @@ ${lines.join("\n")}
|
|
|
558
580
|
`;
|
|
559
581
|
}
|
|
560
582
|
|
|
561
|
-
function
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
583
|
+
function formatTeamForPlanner(teamName: string | undefined, profile: TeamProfile | null, roles: Record<string, TeamRoleDefinition>, approvalLabels: string[]): string {
|
|
584
|
+
if (!teamName) return "";
|
|
585
|
+
const roleLines = Object.values(roles)
|
|
586
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
587
|
+
.map(role => ` ${role.name}${role.description ? ` — ${role.description}` : ""}${role.model ? ` (model: ${role.model})` : ""}`);
|
|
588
|
+
const approvalLine = approvalLabels.length > 0
|
|
589
|
+
? `\nHigh-risk labels requiring lead approval for editing roles: ${approvalLabels.join(", ")}\n`
|
|
590
|
+
: "";
|
|
591
|
+
|
|
592
|
+
return `
|
|
593
|
+
## Active Team
|
|
594
|
+
|
|
595
|
+
Team: ${teamName}${profile?.name ? `\nProfile: ${profile.name}` : ""}
|
|
596
|
+
|
|
597
|
+
Available roles for task assignment:
|
|
598
|
+
${roleLines.join("\n")}${approvalLine}
|
|
599
|
+
These are Team role labels and prompt context; Crew still runs tasks through Crew agents and does not launch pi-subagents.
|
|
600
|
+
When creating tasks, include optional \`role\` and \`riskLabels\` fields where useful. Use non-editing roles such as scout, researcher, reviewer, planner, oracle, and context-builder for investigation, planning, decision, or review tasks.
|
|
601
|
+
|
|
602
|
+
`;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
function tasksJsonFormatHint(skills: CrewSkillInfo[], teamActive: boolean): string {
|
|
606
|
+
const fields = ["title", "description", "dependsOn"];
|
|
607
|
+
if (skills.length > 0) fields.push("optionally skills (array of skill names from the Available Skills list that are relevant to the task)");
|
|
608
|
+
if (teamActive) fields.push("role", "riskLabels (array of high-risk labels such as auth or api-contract)");
|
|
609
|
+
return `${fields.slice(0, -1).join(", ")}${fields.length > 1 ? ", and " : ""}${fields[fields.length - 1]}`;
|
|
565
610
|
}
|
|
566
611
|
|
|
567
|
-
function buildFirstPassPrompt(
|
|
612
|
+
function buildFirstPassPrompt(
|
|
613
|
+
prdPath: string,
|
|
614
|
+
prdContent: string,
|
|
615
|
+
existingProgress: string,
|
|
616
|
+
isPromptBased: boolean,
|
|
617
|
+
skills: CrewSkillInfo[],
|
|
618
|
+
teamName?: string,
|
|
619
|
+
profile: TeamProfile | null = null,
|
|
620
|
+
roles: Record<string, TeamRoleDefinition> = {},
|
|
621
|
+
approvalLabels: string[] = [],
|
|
622
|
+
): string {
|
|
568
623
|
const specType = isPromptBased ? "request" : "PRD";
|
|
569
624
|
const specLabel = isPromptBased ? "Request" : `PRD: ${prdPath}`;
|
|
570
625
|
const progressSection = existingProgress
|
|
571
626
|
? `\n## Previous Planning Context\n${existingProgress}\n`
|
|
572
627
|
: "";
|
|
573
628
|
const skillsSection = formatSkillsForPlanner(skills);
|
|
629
|
+
const teamSection = formatTeamForPlanner(teamName, profile, roles, approvalLabels);
|
|
574
630
|
|
|
575
631
|
return `Create a task breakdown for implementing this ${specType}.
|
|
576
632
|
|
|
577
633
|
## ${specLabel}
|
|
578
634
|
|
|
579
635
|
${prdContent}
|
|
580
|
-
${progressSection}${skillsSection}
|
|
636
|
+
${progressSection}${skillsSection}${teamSection}
|
|
581
637
|
You must follow this sequence strictly:
|
|
582
638
|
1) Understand the ${specType}
|
|
583
639
|
2) Review relevant code/docs/reference resources
|
|
@@ -592,7 +648,7 @@ Return output in this exact section order and headings:
|
|
|
592
648
|
|
|
593
649
|
In section 4, include both:
|
|
594
650
|
- markdown task breakdown
|
|
595
|
-
- a \`tasks-json\` fenced block with task objects containing ${tasksJsonFormatHint(skills)}.`;
|
|
651
|
+
- a \`tasks-json\` fenced block with task objects containing ${tasksJsonFormatHint(skills, !!teamName)}.`;
|
|
596
652
|
}
|
|
597
653
|
|
|
598
654
|
function buildRefinementPrompt(
|
|
@@ -601,14 +657,19 @@ function buildRefinementPrompt(
|
|
|
601
657
|
progressFileContent: string,
|
|
602
658
|
isPromptBased: boolean,
|
|
603
659
|
skills: CrewSkillInfo[],
|
|
660
|
+
teamName?: string,
|
|
661
|
+
profile: TeamProfile | null = null,
|
|
662
|
+
roles: Record<string, TeamRoleDefinition> = {},
|
|
663
|
+
approvalLabels: string[] = [],
|
|
604
664
|
): string {
|
|
605
665
|
const specLabel = isPromptBased ? "Request" : `PRD: ${prdPath}`;
|
|
606
666
|
const skillsSection = formatSkillsForPlanner(skills);
|
|
667
|
+
const teamSection = formatTeamForPlanner(teamName, profile, roles, approvalLabels);
|
|
607
668
|
return `Refine your task breakdown based on review feedback.
|
|
608
669
|
|
|
609
670
|
## ${specLabel}
|
|
610
671
|
${prdContent}
|
|
611
|
-
${skillsSection}
|
|
672
|
+
${skillsSection}${teamSection}
|
|
612
673
|
## Planning Progress
|
|
613
674
|
${progressFileContent}
|
|
614
675
|
|
|
@@ -624,7 +685,7 @@ Return output in this exact section order and headings:
|
|
|
624
685
|
|
|
625
686
|
In section 4, include both:
|
|
626
687
|
- markdown task breakdown
|
|
627
|
-
- a \`tasks-json\` fenced block with task objects containing ${tasksJsonFormatHint(skills)}.`;
|
|
688
|
+
- a \`tasks-json\` fenced block with task objects containing ${tasksJsonFormatHint(skills, !!teamName)}.`;
|
|
628
689
|
}
|
|
629
690
|
|
|
630
691
|
function buildPlanReviewPrompt(
|
|
@@ -681,6 +742,8 @@ interface ParsedTask {
|
|
|
681
742
|
description: string;
|
|
682
743
|
dependsOn: string[];
|
|
683
744
|
skills?: string[];
|
|
745
|
+
role?: string;
|
|
746
|
+
riskLabels?: string[];
|
|
684
747
|
}
|
|
685
748
|
|
|
686
749
|
function extractPlanSections(output: string): PlanSections | null {
|
|
@@ -726,12 +789,15 @@ function parseJsonTaskBlock(output: string): ParsedTask[] | null {
|
|
|
726
789
|
const parsed = JSON.parse(match[1]);
|
|
727
790
|
if (!Array.isArray(parsed)) return null;
|
|
728
791
|
const tasks = parsed
|
|
729
|
-
.filter((t: Record<string, unknown>
|
|
730
|
-
.
|
|
792
|
+
.filter((t: unknown): t is Record<string, unknown> => !!t && typeof t === "object" && !Array.isArray(t))
|
|
793
|
+
.filter(t => typeof t.title === "string" && t.title.trim().length > 0)
|
|
794
|
+
.map(t => ({
|
|
731
795
|
title: (t.title as string).trim(),
|
|
732
796
|
description: typeof t.description === "string" ? t.description : "",
|
|
733
797
|
dependsOn: Array.isArray(t.dependsOn) ? t.dependsOn.filter((d: unknown) => typeof d === "string") : [],
|
|
734
798
|
skills: Array.isArray(t.skills) ? t.skills.filter((s: unknown) => typeof s === "string") : undefined,
|
|
799
|
+
role: typeof t.role === "string" && t.role.trim().length > 0 ? t.role.trim() : undefined,
|
|
800
|
+
riskLabels: Array.isArray(t.riskLabels) ? t.riskLabels.filter((s: unknown) => typeof s === "string") : undefined,
|
|
735
801
|
}));
|
|
736
802
|
return tasks.length > 0 ? tasks : null;
|
|
737
803
|
} catch {
|
package/crew/handlers/review.ts
CHANGED
|
@@ -6,23 +6,24 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { execSync } from "node:child_process";
|
|
9
|
-
import type { ExtensionContext } from "@
|
|
10
|
-
import type { CrewParams } from "../types.
|
|
11
|
-
import { result } from "../utils/result.
|
|
12
|
-
import { spawnAgents } from "../agents.
|
|
13
|
-
import { discoverCrewAgents } from "../utils/discover.
|
|
14
|
-
import { loadCrewConfig } from "../utils/config.
|
|
15
|
-
import { parseVerdict, type ParsedReview } from "../utils/verdict.
|
|
16
|
-
import * as store from "../store.
|
|
9
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
10
|
+
import type { CrewParams } from "../types.ts";
|
|
11
|
+
import { result } from "../utils/result.ts";
|
|
12
|
+
import { spawnAgents } from "../agents.ts";
|
|
13
|
+
import { discoverCrewAgents } from "../utils/discover.ts";
|
|
14
|
+
import { loadCrewConfig } from "../utils/config.ts";
|
|
15
|
+
import { parseVerdict, type ParsedReview } from "../utils/verdict.ts";
|
|
16
|
+
import * as store from "../store.ts";
|
|
17
17
|
|
|
18
18
|
export async function execute(
|
|
19
19
|
params: CrewParams,
|
|
20
|
-
ctx: ExtensionContext
|
|
20
|
+
ctx: ExtensionContext,
|
|
21
|
+
sessionModel?: string,
|
|
21
22
|
) {
|
|
22
|
-
const cwd = ctx.cwd
|
|
23
|
+
const cwd = ctx.cwd;
|
|
23
24
|
const { target, type } = params;
|
|
24
25
|
const config = loadCrewConfig(store.getCrewDir(cwd));
|
|
25
|
-
const reviewerModel = config.models?.reviewer;
|
|
26
|
+
const reviewerModel = config.models?.reviewer ?? sessionModel;
|
|
26
27
|
|
|
27
28
|
if (!target) {
|
|
28
29
|
return result("Error: target (task ID) required for review action.\n\nUsage: pi_messenger({ action: \"review\", target: \"task-1\" })", {
|
|
@@ -41,6 +42,14 @@ export async function execute(
|
|
|
41
42
|
});
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
if (type && type !== "impl" && type !== "plan") {
|
|
46
|
+
return result("Error: review type must be 'impl' or 'plan'.", {
|
|
47
|
+
mode: "review",
|
|
48
|
+
error: "invalid_type",
|
|
49
|
+
type,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
// Determine review type: "impl" for task, "plan" for plan review
|
|
45
54
|
const reviewType = type ?? (target.startsWith("task-") ? "impl" : "plan");
|
|
46
55
|
|
package/crew/handlers/revise.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import type { MessengerState } from "../../lib.
|
|
4
|
-
import type { CrewParams, Task } from "../types.
|
|
5
|
-
import { result } from "../utils/result.
|
|
6
|
-
import * as store from "../store.
|
|
7
|
-
import { logFeedEvent } from "../../feed.
|
|
8
|
-
import { spawnAgents } from "../agents.
|
|
9
|
-
import { getLiveWorkers } from "../live-progress.
|
|
10
|
-
import { isAutonomousForCwd, isPlanningForCwd } from "../state.
|
|
11
|
-
import { loadCrewConfig } from "../utils/config.
|
|
3
|
+
import type { MessengerState } from "../../lib.ts";
|
|
4
|
+
import type { CrewParams, Task } from "../types.ts";
|
|
5
|
+
import { result } from "../utils/result.ts";
|
|
6
|
+
import * as store from "../store.ts";
|
|
7
|
+
import { logFeedEvent } from "../../feed.ts";
|
|
8
|
+
import { spawnAgents } from "../agents.ts";
|
|
9
|
+
import { getLiveWorkers } from "../live-progress.ts";
|
|
10
|
+
import { isAutonomousForCwd, isPlanningForCwd } from "../state.ts";
|
|
11
|
+
import { loadCrewConfig } from "../utils/config.ts";
|
|
12
12
|
|
|
13
13
|
export interface ReviseResult {
|
|
14
14
|
success: boolean;
|
|
@@ -24,6 +24,7 @@ export async function executeRevise(
|
|
|
24
24
|
taskId: string,
|
|
25
25
|
prompt: string | undefined,
|
|
26
26
|
agentName: string,
|
|
27
|
+
sessionModel?: string,
|
|
27
28
|
): Promise<ReviseResult> {
|
|
28
29
|
const task = store.getTask(cwd, taskId);
|
|
29
30
|
if (!task) return { success: false, message: `Task ${taskId} not found` };
|
|
@@ -50,7 +51,7 @@ export async function executeRevise(
|
|
|
50
51
|
agent: "crew-planner",
|
|
51
52
|
task: revisePrompt,
|
|
52
53
|
taskId: "__reviser__",
|
|
53
|
-
modelOverride: config.models?.planner,
|
|
54
|
+
modelOverride: config.models?.planner ?? sessionModel,
|
|
54
55
|
}], cwd);
|
|
55
56
|
|
|
56
57
|
if (agentResult.exitCode !== 0) {
|
|
@@ -84,7 +85,7 @@ export async function taskRevise(cwd: string, params: CrewParams, state: Messeng
|
|
|
84
85
|
const { id, prompt } = params;
|
|
85
86
|
if (!id) return result("Error: id required for task.revise", { mode: "task.revise", error: "missing_id" });
|
|
86
87
|
|
|
87
|
-
const r = await executeRevise(cwd, id, prompt ?? undefined, state.agentName || "unknown");
|
|
88
|
+
const r = await executeRevise(cwd, id, prompt ?? undefined, state.agentName || "unknown", state.model || undefined);
|
|
88
89
|
if (!r.success) {
|
|
89
90
|
return result(`Error: ${r.message}`, { mode: "task.revise", error: "revision_failed", id });
|
|
90
91
|
}
|
|
@@ -100,6 +101,7 @@ export async function executeReviseTree(
|
|
|
100
101
|
taskId: string,
|
|
101
102
|
prompt: string | undefined,
|
|
102
103
|
agentName: string,
|
|
104
|
+
sessionModel?: string,
|
|
103
105
|
): Promise<ReviseResult> {
|
|
104
106
|
const target = store.getTask(cwd, taskId);
|
|
105
107
|
if (!target) return { success: false, message: `Task ${taskId} not found` };
|
|
@@ -134,7 +136,7 @@ export async function executeReviseTree(
|
|
|
134
136
|
agent: "crew-planner",
|
|
135
137
|
task: revisePrompt,
|
|
136
138
|
taskId: "__reviser__",
|
|
137
|
-
modelOverride: config.models?.planner,
|
|
139
|
+
modelOverride: config.models?.planner ?? sessionModel,
|
|
138
140
|
}], cwd);
|
|
139
141
|
|
|
140
142
|
if (agentResult.exitCode !== 0) {
|
|
@@ -227,7 +229,7 @@ export async function taskReviseTree(cwd: string, params: CrewParams, state: Mes
|
|
|
227
229
|
const { id, prompt } = params;
|
|
228
230
|
if (!id) return result("Error: id required for task.revise-tree", { mode: "task.revise-tree", error: "missing_id" });
|
|
229
231
|
|
|
230
|
-
const r = await executeReviseTree(cwd, id, prompt ?? undefined, state.agentName || "unknown");
|
|
232
|
+
const r = await executeReviseTree(cwd, id, prompt ?? undefined, state.agentName || "unknown", state.model || undefined);
|
|
231
233
|
if (!r.success) {
|
|
232
234
|
return result(`Error: ${r.message}`, { mode: "task.revise-tree", error: "revision_failed", id });
|
|
233
235
|
}
|
package/crew/handlers/status.ts
CHANGED
|
@@ -4,20 +4,20 @@
|
|
|
4
4
|
* Shows plan progress and task status.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type { ExtensionContext } from "@
|
|
8
|
-
import { result } from "../utils/result.
|
|
9
|
-
import { discoverCrewAgents } from "../utils/discover.
|
|
10
|
-
import { uninstallAgents } from "../utils/install.
|
|
11
|
-
import { loadCrewConfig } from "../utils/config.
|
|
12
|
-
import { formatDuration } from "../../lib.
|
|
13
|
-
import * as store from "../store.
|
|
14
|
-
import { autonomousState, getPlanningUpdateAgeMs, isAutonomousForCwd, isPlanningForCwd, isPlanningStalled, planningState, PLANNING_STALE_TIMEOUT_MS } from "../state.
|
|
7
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
8
|
+
import { result } from "../utils/result.ts";
|
|
9
|
+
import { discoverCrewAgents } from "../utils/discover.ts";
|
|
10
|
+
import { uninstallAgents } from "../utils/install.ts";
|
|
11
|
+
import { loadCrewConfig } from "../utils/config.ts";
|
|
12
|
+
import { formatDuration } from "../../lib.ts";
|
|
13
|
+
import * as store from "../store.ts";
|
|
14
|
+
import { autonomousState, getPlanningUpdateAgeMs, isAutonomousForCwd, isPlanningForCwd, isPlanningStalled, planningState, PLANNING_STALE_TIMEOUT_MS } from "../state.ts";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Execute status action - shows plan progress.
|
|
18
18
|
*/
|
|
19
19
|
export async function execute(ctx: ExtensionContext) {
|
|
20
|
-
const cwd = ctx.cwd
|
|
20
|
+
const cwd = ctx.cwd;
|
|
21
21
|
const plan = store.getPlan(cwd);
|
|
22
22
|
|
|
23
23
|
if (!plan) {
|
|
@@ -197,7 +197,7 @@ export async function executeCrew(
|
|
|
197
197
|
op: string,
|
|
198
198
|
ctx: ExtensionContext
|
|
199
199
|
) {
|
|
200
|
-
const cwd = ctx.cwd
|
|
200
|
+
const cwd = ctx.cwd;
|
|
201
201
|
|
|
202
202
|
switch (op) {
|
|
203
203
|
case "status": {
|
package/crew/handlers/sync.ts
CHANGED
|
@@ -5,19 +5,20 @@
|
|
|
5
5
|
* Works with current plan's tasks.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { ExtensionContext } from "@
|
|
9
|
-
import type { CrewParams } from "../types.
|
|
10
|
-
import { result } from "../utils/result.
|
|
11
|
-
import { spawnAgents } from "../agents.
|
|
12
|
-
import { discoverCrewAgents } from "../utils/discover.
|
|
13
|
-
import { loadCrewConfig } from "../utils/config.
|
|
14
|
-
import * as store from "../store.
|
|
8
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
9
|
+
import type { CrewParams } from "../types.ts";
|
|
10
|
+
import { result } from "../utils/result.ts";
|
|
11
|
+
import { spawnAgents } from "../agents.ts";
|
|
12
|
+
import { discoverCrewAgents } from "../utils/discover.ts";
|
|
13
|
+
import { loadCrewConfig } from "../utils/config.ts";
|
|
14
|
+
import * as store from "../store.ts";
|
|
15
15
|
|
|
16
16
|
export async function execute(
|
|
17
17
|
params: CrewParams,
|
|
18
|
-
ctx: ExtensionContext
|
|
18
|
+
ctx: ExtensionContext,
|
|
19
|
+
sessionModel?: string,
|
|
19
20
|
) {
|
|
20
|
-
const cwd = ctx.cwd
|
|
21
|
+
const cwd = ctx.cwd;
|
|
21
22
|
const { target } = params;
|
|
22
23
|
|
|
23
24
|
if (!target) {
|
|
@@ -126,7 +127,7 @@ Follow the output format in your instructions.`;
|
|
|
126
127
|
const [syncResult] = await spawnAgents([{
|
|
127
128
|
agent: "crew-plan-sync",
|
|
128
129
|
task: prompt,
|
|
129
|
-
modelOverride: config.models?.analyst,
|
|
130
|
+
modelOverride: config.models?.analyst ?? sessionModel,
|
|
130
131
|
}], cwd);
|
|
131
132
|
|
|
132
133
|
if (syncResult.exitCode !== 0) {
|