pi-cohort 3.0.2 → 4.0.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 +5 -0
- package/README.md +78 -1157
- package/agents/reviewer.md +1 -1
- package/package.json +1 -1
- package/src/extension/schemas.ts +2 -2
- package/src/runs/foreground/chain-clarify.ts +24 -8
- package/src/runs/foreground/subagent-executor.ts +9 -11
- package/src/runs/shared/single-output.ts +9 -0
package/agents/reviewer.md
CHANGED
|
@@ -64,7 +64,7 @@ When asked to review for over-engineering, bloat, or "what can we delete", run a
|
|
|
64
64
|
|
|
65
65
|
## Working rules
|
|
66
66
|
- Read the plan, progress, and relevant files first when available.
|
|
67
|
-
-
|
|
67
|
+
- Top-level progress files exist only when the caller explicitly enables them. Do not ask consumer repositories to add cohort scratch files to `.gitignore`.
|
|
68
68
|
- Use `bash` only for read-only inspection (e.g., `git diff`, `git log`, `git show`, test runs).
|
|
69
69
|
- Do not invent issues. Only report problems you can justify from evidence.
|
|
70
70
|
- Prefer small corrective edits over broad rewrites.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-cohort",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Delegate Pi work to focused child agents: code review, scouting, implementation, parallel audits, saved chains, and background jobs.",
|
|
5
5
|
"author": "Jacek Juraszek",
|
|
6
6
|
"license": "MIT",
|
package/src/extension/schemas.ts
CHANGED
|
@@ -119,7 +119,7 @@ const TaskItem = Type.Object({
|
|
|
119
119
|
output: Type.Optional(OutputOverride),
|
|
120
120
|
outputMode: Type.Optional(OutputModeOverride),
|
|
121
121
|
reads: Type.Optional(ReadsOverride),
|
|
122
|
-
progress: Type.Optional(Type.Boolean({ description: "
|
|
122
|
+
progress: Type.Optional(Type.Boolean({ description: "Omit or set false to disable progress.md tracking for this task; true enables it." })),
|
|
123
123
|
model: Type.Optional(Type.String({ description: "Override model for this task (e.g. 'google/gemini-3-pro')" })),
|
|
124
124
|
skill: Type.Optional(SkillOverride),
|
|
125
125
|
acceptance: Type.Optional(AcceptanceOverride),
|
|
@@ -297,7 +297,7 @@ export const SubagentParams = Type.Object({
|
|
|
297
297
|
{ type: "string" },
|
|
298
298
|
{ type: "boolean" },
|
|
299
299
|
],
|
|
300
|
-
description: "
|
|
300
|
+
description: "Omit or set false to disable file output; true uses the agent-configured filename; a string sets the output path. Relative paths resolve against cwd.",
|
|
301
301
|
})),
|
|
302
302
|
outputMode: Type.Optional(OutputModeOverride),
|
|
303
303
|
skill: Type.Optional(SkillOverride),
|
|
@@ -494,7 +494,7 @@ export class ChainClarifyComponent implements Component {
|
|
|
494
494
|
return;
|
|
495
495
|
}
|
|
496
496
|
|
|
497
|
-
if (data === "w"
|
|
497
|
+
if (data === "w") {
|
|
498
498
|
this.enterEditMode("output");
|
|
499
499
|
return;
|
|
500
500
|
}
|
|
@@ -504,11 +504,15 @@ export class ChainClarifyComponent implements Component {
|
|
|
504
504
|
return;
|
|
505
505
|
}
|
|
506
506
|
|
|
507
|
-
if (data === "p" && this.mode
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
507
|
+
if (data === "p" && this.mode !== 'single') {
|
|
508
|
+
if (this.mode === 'chain') {
|
|
509
|
+
const anyEnabled = this.agentConfigs.some((_, i) => this.getEffectiveBehavior(i).progress);
|
|
510
|
+
const newState = !anyEnabled;
|
|
511
|
+
for (let i = 0; i < this.agentConfigs.length; i++) {
|
|
512
|
+
this.updateBehavior(i, "progress", newState);
|
|
513
|
+
}
|
|
514
|
+
} else {
|
|
515
|
+
this.updateBehavior(this.selectedStep, "progress", !this.getEffectiveBehavior(this.selectedStep).progress);
|
|
512
516
|
}
|
|
513
517
|
this.tui.requestRender();
|
|
514
518
|
return;
|
|
@@ -532,7 +536,9 @@ export class ChainClarifyComponent implements Component {
|
|
|
532
536
|
buffer = template.split("\n")[0] ?? "";
|
|
533
537
|
} else if (mode === "output") {
|
|
534
538
|
const behavior = this.getEffectiveBehavior(this.selectedStep);
|
|
535
|
-
buffer = behavior.output === false
|
|
539
|
+
buffer = behavior.output === false
|
|
540
|
+
? (this.mode === "chain" ? "" : this.agentConfigs[this.selectedStep]?.output ?? "")
|
|
541
|
+
: (behavior.output || "");
|
|
536
542
|
} else if (mode === "reads") {
|
|
537
543
|
const behavior = this.getEffectiveBehavior(this.selectedStep);
|
|
538
544
|
buffer = behavior.reads === false ? "" : (behavior.reads?.join(", ") || "");
|
|
@@ -1108,7 +1114,7 @@ export class ChainClarifyComponent implements Component {
|
|
|
1108
1114
|
case 'single':
|
|
1109
1115
|
return ` [Enter] Run • [Esc] Cancel • e m t w s ${bgLabel} `;
|
|
1110
1116
|
case 'parallel':
|
|
1111
|
-
return ` [Enter] Run • [Esc] Cancel • e m t s ${bgLabel} • ↑↓ Nav `;
|
|
1117
|
+
return ` [Enter] Run • [Esc] Cancel • e m t w p s ${bgLabel} • ↑↓ Nav `;
|
|
1112
1118
|
case 'chain':
|
|
1113
1119
|
return ` [Enter] Run • [Esc] Cancel • e m t w r p s ${bgLabel} • ↑↓ Nav `;
|
|
1114
1120
|
}
|
|
@@ -1207,6 +1213,16 @@ export class ChainClarifyComponent implements Component {
|
|
|
1207
1213
|
lines.push(this.row(` ${modelLabel}${truncateToWidth(modelValue, innerW - 13)}`));
|
|
1208
1214
|
|
|
1209
1215
|
const behavior = this.getEffectiveBehavior(i);
|
|
1216
|
+
const writesValue = behavior.output === false
|
|
1217
|
+
? th.fg("dim", "(disabled)")
|
|
1218
|
+
: (behavior.output || th.fg("dim", "(none)"));
|
|
1219
|
+
const writesLabel = th.fg("dim", "writes: ");
|
|
1220
|
+
lines.push(this.row(` ${writesLabel}${truncateToWidth(writesValue, innerW - 14)}`));
|
|
1221
|
+
|
|
1222
|
+
const progressValue = behavior.progress ? th.fg("success", "on") : th.fg("dim", "off");
|
|
1223
|
+
const progressLabel = th.fg("dim", "progress: ");
|
|
1224
|
+
lines.push(this.row(` ${progressLabel}${progressValue}`));
|
|
1225
|
+
|
|
1210
1226
|
const skillsValue = behavior.skills === false
|
|
1211
1227
|
? th.fg("dim", "(disabled)")
|
|
1212
1228
|
: (behavior.skills?.length ? behavior.skills.join(", ") : th.fg("dim", "(none)"));
|
|
@@ -3,7 +3,7 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
5
5
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
6
|
-
import {
|
|
6
|
+
import type { AgentConfig, AgentScope } from "../../agents/agents.ts";
|
|
7
7
|
import { getArtifactsDir } from "../../shared/artifacts.ts";
|
|
8
8
|
import { ChainClarifyComponent, type ChainClarifyResult } from "./chain-clarify.ts";
|
|
9
9
|
import { toModelInfo, type ModelInfo } from "../../shared/model-info.ts";
|
|
@@ -37,7 +37,7 @@ import { createForkContextResolver } from "../../shared/fork-context.ts";
|
|
|
37
37
|
import { resolveCurrentSessionId } from "../../shared/session-identity.ts";
|
|
38
38
|
import { applyIntercomBridgeToAgent, INTERCOM_BRIDGE_MARKER, resolveIntercomBridge, resolveIntercomSessionTarget, resolveSubagentIntercomTarget, type IntercomBridgeState } from "../../intercom/intercom-bridge.ts";
|
|
39
39
|
import { formatControlIntercomMessage, formatControlNoticeMessage, resolveControlConfig, shouldNotifyControlEvent } from "../shared/subagent-control.ts";
|
|
40
|
-
import { finalizeSingleOutput, injectSingleOutputInstruction,
|
|
40
|
+
import { finalizeSingleOutput, injectSingleOutputInstruction, normalizeTopLevelOutput, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.ts";
|
|
41
41
|
import { compactForegroundDetails, getSingleResultOutput, mapConcurrent, readStatus, resolveChildCwd } from "../../shared/utils.ts";
|
|
42
42
|
import {
|
|
43
43
|
attachNestedChildrenToResultChildren,
|
|
@@ -1102,10 +1102,10 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
1102
1102
|
cwd: task.cwd,
|
|
1103
1103
|
...(modelOverrides[index] ? { model: modelOverrides[index] } : {}),
|
|
1104
1104
|
...(skillOverrides[index] !== undefined ? { skill: skillOverrides[index] } : {}),
|
|
1105
|
-
|
|
1105
|
+
output: normalizeTopLevelOutput(task.output, agentConfigs[index]?.output),
|
|
1106
1106
|
...(task.outputMode !== undefined ? { outputMode: task.outputMode } : {}),
|
|
1107
1107
|
...(task.reads !== undefined && task.reads !== true ? { reads: task.reads } : {}),
|
|
1108
|
-
|
|
1108
|
+
progress: task.progress ?? false,
|
|
1109
1109
|
...(task.acceptance !== undefined ? { acceptance: task.acceptance } : {}),
|
|
1110
1110
|
}));
|
|
1111
1111
|
return executeAsyncChain(id, {
|
|
@@ -1174,8 +1174,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
1174
1174
|
details: { mode: "single" as const, results: [] },
|
|
1175
1175
|
};
|
|
1176
1176
|
}
|
|
1177
|
-
const
|
|
1178
|
-
const effectiveOutput = normalizeSingleOutputOverride(rawOutput, a.output);
|
|
1177
|
+
const effectiveOutput = normalizeTopLevelOutput(params.output, a.output);
|
|
1179
1178
|
const effectiveOutputMode = params.outputMode ?? "inline";
|
|
1180
1179
|
const normalizedSkills = normalizeSkillInput(params.skill);
|
|
1181
1180
|
const skills = normalizedSkills === false ? [] : normalizedSkills;
|
|
@@ -1630,10 +1629,10 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1630
1629
|
normalizeSkillInput(t.skill),
|
|
1631
1630
|
);
|
|
1632
1631
|
const behaviorOverrides: StepOverrides[] = tasks.map((task, index) => ({
|
|
1633
|
-
|
|
1632
|
+
output: normalizeTopLevelOutput(task.output, agentConfigs[index]?.output),
|
|
1634
1633
|
...(task.outputMode !== undefined ? { outputMode: task.outputMode } : {}),
|
|
1635
1634
|
...(task.reads !== undefined && task.reads !== true ? { reads: task.reads } : {}),
|
|
1636
|
-
|
|
1635
|
+
progress: task.progress ?? false,
|
|
1637
1636
|
...(skillOverrides[index] !== undefined ? { skills: skillOverrides[index] } : {}),
|
|
1638
1637
|
...(task.model ? { model: task.model } : {}),
|
|
1639
1638
|
}));
|
|
@@ -1939,8 +1938,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
1939
1938
|
currentProvider,
|
|
1940
1939
|
);
|
|
1941
1940
|
let skillOverride: string[] | false | undefined = normalizeSkillInput(params.skill);
|
|
1942
|
-
|
|
1943
|
-
let effectiveOutput = normalizeSingleOutputOverride(rawOutput, agentConfig.output);
|
|
1941
|
+
let effectiveOutput = normalizeTopLevelOutput(params.output, agentConfig.output);
|
|
1944
1942
|
const effectiveOutputMode = params.outputMode ?? "inline";
|
|
1945
1943
|
const currentMaxSubagentDepth = resolveCurrentMaxSubagentDepth(deps.config.maxSubagentDepth);
|
|
1946
1944
|
const maxSubagentDepth = resolveChildMaxSubagentDepth(currentMaxSubagentDepth, agentConfig.maxSubagentDepth);
|
|
@@ -1974,7 +1972,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
1974
1972
|
task = result.templates[0]!;
|
|
1975
1973
|
const override = result.behaviorOverrides[0];
|
|
1976
1974
|
if (override?.model) modelOverride = override.model;
|
|
1977
|
-
if (override?.output !== undefined) effectiveOutput =
|
|
1975
|
+
if (override?.output !== undefined) effectiveOutput = normalizeTopLevelOutput(override.output, agentConfig.output);
|
|
1978
1976
|
if (override?.skills !== undefined) skillOverride = override.skills;
|
|
1979
1977
|
|
|
1980
1978
|
if (result.runInBackground) {
|
|
@@ -18,6 +18,15 @@ export function normalizeSingleOutputOverride(
|
|
|
18
18
|
return undefined;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
export function normalizeTopLevelOutput(
|
|
22
|
+
output: string | boolean | undefined,
|
|
23
|
+
defaultOutput: string | undefined,
|
|
24
|
+
): string | false {
|
|
25
|
+
if (output === undefined || (typeof output === "string" && output.trim().length === 0)) return false;
|
|
26
|
+
const normalizedOutput = normalizeSingleOutputOverride(output, defaultOutput);
|
|
27
|
+
return typeof normalizedOutput === "string" && normalizedOutput.trim().length === 0 ? false : normalizedOutput ?? false;
|
|
28
|
+
}
|
|
29
|
+
|
|
21
30
|
export function resolveSingleOutputPath(
|
|
22
31
|
output: string | boolean | undefined,
|
|
23
32
|
runtimeCwd: string,
|