pi-subagents 0.23.0 → 0.23.1

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.
@@ -220,6 +220,25 @@ export function resolveStepBehavior(
220
220
  return { output, outputMode, reads, progress, skills, model };
221
221
  }
222
222
 
223
+ export function resolveTaskTextForFileUpdatePolicy(task: string | undefined, originalTask?: string): string | undefined {
224
+ if (!task) return originalTask;
225
+ return originalTask ? task.replaceAll("{task}", originalTask) : task;
226
+ }
227
+
228
+ export function taskDisallowsFileUpdates(task: string | undefined): boolean {
229
+ if (!task) return false;
230
+ return /\breview[- ]only\b/i.test(task)
231
+ || /\bread[- ]only\s+(?:review|audit|inspection|pass)\b/i.test(task)
232
+ || /\b(?:no|without)\s+(?:file\s+)?edits?\b/i.test(task)
233
+ || /\b(?:do not|don't|must not)\s+(?:edit|modify|write|touch)\b/i.test(task)
234
+ || /\bleave\s+files?\s+unchanged\b/i.test(task);
235
+ }
236
+
237
+ export function suppressProgressForReadOnlyTask(behavior: ResolvedStepBehavior, task: string | undefined, originalTask?: string): ResolvedStepBehavior {
238
+ const policyTask = resolveTaskTextForFileUpdatePolicy(task, originalTask);
239
+ return behavior.progress && taskDisallowsFileUpdates(policyTask) ? { ...behavior, progress: false } : behavior;
240
+ }
241
+
223
242
  // =============================================================================
224
243
  // Chain Instruction Injection
225
244
  // =============================================================================
@@ -207,6 +207,7 @@ export interface SingleResult {
207
207
 
208
208
  export interface Details {
209
209
  mode: SubagentRunMode | "management";
210
+ runId?: string;
210
211
  context?: "fresh" | "fork";
211
212
  results: SingleResult[];
212
213
  controlEvents?: ControlEvent[];
@@ -296,6 +297,7 @@ export interface AsyncStatus {
296
297
  steps?: Array<{
297
298
  agent: string;
298
299
  status: "pending" | "running" | "complete" | "completed" | "failed" | "paused";
300
+ sessionFile?: string;
299
301
  activityState?: ActivityState;
300
302
  lastActivityAt?: number;
301
303
  currentTool?: string;
@@ -360,10 +362,26 @@ export interface AsyncJobState {
360
362
  controlEventCursor?: number;
361
363
  }
362
364
 
365
+ export interface ForegroundResumeChild {
366
+ agent: string;
367
+ index: number;
368
+ sessionFile?: string;
369
+ status: SubagentResultStatus;
370
+ }
371
+
372
+ export interface ForegroundResumeRun {
373
+ runId: string;
374
+ mode: SubagentRunMode;
375
+ cwd: string;
376
+ updatedAt: number;
377
+ children: ForegroundResumeChild[];
378
+ }
379
+
363
380
  export interface SubagentState {
364
381
  baseCwd: string;
365
382
  currentSessionId: string | null;
366
383
  asyncJobs: Map<string, AsyncJobState>;
384
+ foregroundRuns?: Map<string, ForegroundResumeRun>;
367
385
  foregroundControls: Map<string, {
368
386
  runId: string;
369
387
  mode: SubagentRunMode;
@@ -279,6 +279,7 @@ async function runSlashSubagent(
279
279
  ctx: ExtensionContext,
280
280
  params: SubagentParamsLike,
281
281
  ): Promise<void> {
282
+ if (ctx.hasUI) ctx.ui.setToolsExpanded(false);
282
283
  const requestId = randomUUID();
283
284
  const initialDetails = buildSlashInitialResult(requestId, params);
284
285
  const initialText = extractSlashMessageText(initialDetails.result.content) || "Running subagent...";
package/src/tui/render.ts CHANGED
@@ -626,8 +626,9 @@ function foregroundStyleWidgetStepLines(
626
626
  expanded: boolean,
627
627
  width: number,
628
628
  ): string[] {
629
+ const status = widgetStepStatus(step.status, theme);
629
630
  const stats = widgetStepStats(theme, step);
630
- const lines = [` ${widgetStepGlyph(step.status, theme)} ${itemTitle} ${index}/${total}: ${themeBold(theme, step.agent)}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`];
631
+ const lines = [` ${widgetStepGlyph(step.status, theme)} ${itemTitle} ${index}/${total}: ${themeBold(theme, step.agent)} ${theme.fg("dim", "·")} ${status}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`];
631
632
  const activity = widgetStepActivityLine(step, width, expanded);
632
633
  if (activity) lines.push(` ${theme.fg("dim", `⎿ ${activity}`)}`);
633
634
  if (step.status === "running") {
@@ -683,10 +684,11 @@ function compactSingleWidgetLines(job: AsyncJobState, theme: Theme, width: numbe
683
684
  const itemTitle = job.mode === "parallel" || job.activeParallelGroup ? "Agent" : "Step";
684
685
  const lines = fullLines.slice(0, 2);
685
686
  for (const [index, step] of job.steps.entries()) {
686
- const stepStats = widgetStepStats(theme, step);
687
+ const status = widgetStepStatus(step.status, theme);
687
688
  const activity = widgetStepActivityLine(step, width, false);
689
+ const stepStats = widgetStepStats(theme, step);
688
690
  const activitySuffix = activity ? ` ${theme.fg("dim", "·")} ${theme.fg("dim", activity)}` : "";
689
- lines.push(` ${widgetStepGlyph(step.status, theme)} ${itemTitle} ${index + 1}/${total}: ${themeBold(theme, step.agent)}${stepStats ? ` ${theme.fg("dim", "·")} ${stepStats}` : ""}${activitySuffix}`);
691
+ lines.push(` ${widgetStepGlyph(step.status, theme)} ${itemTitle} ${index + 1}/${total}: ${themeBold(theme, step.agent)} ${theme.fg("dim", "·")} ${status}${activitySuffix}${stepStats ? ` ${theme.fg("dim", "·")} ${stepStats}` : ""}`);
690
692
  }
691
693
  if (job.steps.some((step) => step.status === "running")) lines.push(theme.fg("accent", " Press Ctrl+O for live detail · /subagents-status for output paths"));
692
694
  return lines.map((line) => truncLine(line, width));