@leing2021/super-pi 0.22.0 → 0.22.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.
- package/LICENSE +21 -0
- package/README.md +148 -361
- package/THIRD-PARTY-NOTICES.md +35 -0
- package/extensions/subagent/__tests__/async-job-tracker.test.ts +21 -0
- package/extensions/subagent/__tests__/execution-activity.test.ts +15 -0
- package/extensions/subagent/__tests__/parallel-render-stress.test.ts +82 -0
- package/extensions/subagent/__tests__/render-dedup.test.ts +98 -0
- package/extensions/subagent/__tests__/render-widget.test.ts +28 -0
- package/extensions/subagent/__tests__/throttle.test.ts +90 -0
- package/extensions/subagent/agent-management.ts +3 -2
- package/extensions/subagent/agent-manager-chain-detail.ts +3 -2
- package/extensions/subagent/agent-manager-detail.ts +3 -2
- package/extensions/subagent/agent-manager-edit.ts +3 -2
- package/extensions/subagent/agent-manager-list.ts +3 -2
- package/extensions/subagent/agent-manager-parallel.ts +3 -2
- package/extensions/subagent/agent-manager.ts +3 -2
- package/extensions/subagent/agent-scope.ts +3 -2
- package/extensions/subagent/agent-selection.ts +3 -2
- package/extensions/subagent/agent-serializer.ts +3 -2
- package/extensions/subagent/agent-templates.ts +3 -2
- package/extensions/subagent/agents.ts +3 -2
- package/extensions/subagent/artifacts.ts +3 -2
- package/extensions/subagent/async-execution.ts +3 -2
- package/extensions/subagent/async-job-tracker.ts +28 -4
- package/extensions/subagent/async-status.ts +3 -2
- package/extensions/subagent/chain-clarify.ts +3 -2
- package/extensions/subagent/chain-execution.ts +3 -2
- package/extensions/subagent/chain-serializer.ts +3 -2
- package/extensions/subagent/completion-dedupe.ts +3 -2
- package/extensions/subagent/doctor.ts +3 -2
- package/extensions/subagent/execution.ts +13 -3
- package/extensions/subagent/file-coalescer.ts +3 -2
- package/extensions/subagent/fork-context.ts +3 -2
- package/extensions/subagent/formatters.ts +3 -2
- package/extensions/subagent/frontmatter.ts +3 -2
- package/extensions/subagent/index.ts +3 -2
- package/extensions/subagent/intercom-bridge.ts +3 -2
- package/extensions/subagent/jsonl-writer.ts +3 -2
- package/extensions/subagent/model-fallback.ts +3 -2
- package/extensions/subagent/notify.ts +3 -2
- package/extensions/subagent/parallel-utils.ts +3 -2
- package/extensions/subagent/pi-args.ts +3 -2
- package/extensions/subagent/pi-spawn.ts +3 -2
- package/extensions/subagent/post-exit-stdio-guard.ts +3 -2
- package/extensions/subagent/prompt-template-bridge.ts +3 -2
- package/extensions/subagent/render-helpers.ts +3 -2
- package/extensions/subagent/render.ts +81 -9
- package/extensions/subagent/result-intercom.ts +3 -2
- package/extensions/subagent/result-watcher.ts +3 -2
- package/extensions/subagent/run-history.ts +3 -2
- package/extensions/subagent/run-status.ts +3 -2
- package/extensions/subagent/schemas.ts +3 -2
- package/extensions/subagent/session-tokens.ts +3 -2
- package/extensions/subagent/settings.ts +3 -2
- package/extensions/subagent/single-output.ts +3 -2
- package/extensions/subagent/skills.ts +3 -2
- package/extensions/subagent/slash-bridge.ts +3 -2
- package/extensions/subagent/slash-commands.ts +3 -2
- package/extensions/subagent/slash-live-state.ts +3 -2
- package/extensions/subagent/subagent-control.ts +3 -2
- package/extensions/subagent/subagent-executor.ts +19 -3
- package/extensions/subagent/subagent-prompt-runtime.ts +3 -2
- package/extensions/subagent/subagent-runner.ts +3 -2
- package/extensions/subagent/subagents-status.ts +3 -2
- package/extensions/subagent/text-editor.ts +3 -2
- package/extensions/subagent/throttle.ts +77 -0
- package/extensions/subagent/top-level-async.ts +3 -2
- package/extensions/subagent/types.ts +3 -2
- package/extensions/subagent/utils.ts +3 -2
- package/extensions/subagent/worktree.ts +3 -2
- package/package.json +3 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
/**
|
|
4
5
|
* Core execution logic for running subagents
|
|
5
6
|
*/
|
|
@@ -406,6 +407,7 @@ async function runSingleAttempt(
|
|
|
406
407
|
};
|
|
407
408
|
|
|
408
409
|
if (controlConfig.enabled) {
|
|
410
|
+
const activityIntervalMs = resolveActivityTimerInterval();
|
|
409
411
|
activityTimer = setInterval(() => {
|
|
410
412
|
if (processClosed || settled || detached) return;
|
|
411
413
|
const now = Date.now();
|
|
@@ -413,7 +415,7 @@ async function runSingleAttempt(
|
|
|
413
415
|
progress.durationMs = now - startTime;
|
|
414
416
|
fireUpdate();
|
|
415
417
|
}
|
|
416
|
-
},
|
|
418
|
+
}, activityIntervalMs);
|
|
417
419
|
activityTimer.unref?.();
|
|
418
420
|
}
|
|
419
421
|
|
|
@@ -575,6 +577,14 @@ async function runSingleAttempt(
|
|
|
575
577
|
/**
|
|
576
578
|
* Run a subagent synchronously (blocking until complete)
|
|
577
579
|
*/
|
|
580
|
+
/**
|
|
581
|
+
* Resolve activity timer interval based on concurrency level.
|
|
582
|
+
* Higher concurrency → longer interval to reduce render pressure.
|
|
583
|
+
*/
|
|
584
|
+
export function resolveActivityTimerInterval(concurrentCount = 1): number {
|
|
585
|
+
return concurrentCount <= 1 ? 2000 : 3000;
|
|
586
|
+
}
|
|
587
|
+
|
|
578
588
|
export async function runSync(
|
|
579
589
|
runtimeCwd: string,
|
|
580
590
|
agents: AgentConfig[],
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
interface TimerApi {
|
|
4
5
|
setTimeout(handler: () => void, delayMs: number): unknown;
|
|
5
6
|
clearTimeout(handle: unknown): void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
export type SubagentExecutionContext = "fresh" | "fork";
|
|
4
5
|
|
|
5
6
|
interface ForkableSessionManagerStatic {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
/**
|
|
4
5
|
* Formatting utilities for display output
|
|
5
6
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
export function parseFrontmatter(content: string): { frontmatter: Record<string, string>; body: string } {
|
|
4
5
|
const frontmatter: Record<string, string> = {};
|
|
5
6
|
const normalized = content.replace(/\r\n/g, "\n");
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import * as os from "node:os";
|
|
5
6
|
import * as path from "node:path";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
|
|
5
6
|
export interface DrainableSource {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import type { Usage } from "./types.ts";
|
|
4
5
|
|
|
5
6
|
export interface AvailableModelInfo {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
/**
|
|
4
5
|
* Subagent completion notifications.
|
|
5
6
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
export interface RunnerSubagentStep {
|
|
4
5
|
agent: string;
|
|
5
6
|
task: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import * as os from "node:os";
|
|
5
6
|
import * as path from "node:path";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import { createRequire } from "node:module";
|
|
5
6
|
import * as path from "node:path";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import type { ChildProcess } from "node:child_process";
|
|
4
5
|
|
|
5
6
|
interface PostExitStdioGuardOptions {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
export const PROMPT_TEMPLATE_SUBAGENT_REQUEST_EVENT = "prompt-template:subagent:request";
|
|
4
5
|
export const PROMPT_TEMPLATE_SUBAGENT_STARTED_EVENT = "prompt-template:subagent:started";
|
|
5
6
|
export const PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT = "prompt-template:subagent:response";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import type { Theme } from "@mariozechner/pi-coding-agent";
|
|
4
5
|
import { truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
|
|
5
6
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
/**
|
|
4
5
|
* Rendering functions for subagent results
|
|
5
6
|
*/
|
|
@@ -82,11 +83,24 @@ function truncLine(text: string, maxWidth: number): string {
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
const SPINNER = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
85
|
-
const
|
|
86
|
+
const WIDGET_ANIMATION_BASE_MS = 250;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Resolve widget animation interval based on running job count.
|
|
90
|
+
* Higher parallelism → lower refresh rate to prevent render storms.
|
|
91
|
+
*/
|
|
92
|
+
export function resolveWidgetInterval(runningCount: number): number {
|
|
93
|
+
if (runningCount <= 2) return 250;
|
|
94
|
+
if (runningCount <= 4) return 400;
|
|
95
|
+
if (runningCount <= 6) return 600;
|
|
96
|
+
return 1000;
|
|
97
|
+
}
|
|
86
98
|
|
|
87
99
|
let widgetTimer: ReturnType<typeof setInterval> | undefined;
|
|
88
100
|
let latestWidgetCtx: ExtensionContext | undefined;
|
|
89
101
|
let latestWidgetJobs: AsyncJobState[] = [];
|
|
102
|
+
let lastWidgetRenderMs = 0;
|
|
103
|
+
let lastWidgetContentHash = "";
|
|
90
104
|
|
|
91
105
|
const resultAnimationTimers = new Map<ReturnType<typeof setInterval>, ResultAnimationContext["state"]>();
|
|
92
106
|
const outputActivityCache = new Map<string, { checkedAt: number; text: string }>();
|
|
@@ -97,7 +111,7 @@ export interface ResultAnimationContext {
|
|
|
97
111
|
}
|
|
98
112
|
|
|
99
113
|
function spinnerFrame(): string {
|
|
100
|
-
return SPINNER[Math.floor(Date.now() /
|
|
114
|
+
return SPINNER[Math.floor(Date.now() / WIDGET_ANIMATION_BASE_MS) % SPINNER.length]!;
|
|
101
115
|
}
|
|
102
116
|
|
|
103
117
|
function resultIsRunning(result: AgentToolResult<Details>): boolean {
|
|
@@ -120,7 +134,7 @@ export function syncResultAnimation(result: AgentToolResult<Details>, context: R
|
|
|
120
134
|
return;
|
|
121
135
|
}
|
|
122
136
|
if (context.state.subagentResultAnimationTimer) return;
|
|
123
|
-
const timer = setInterval(() => context.invalidate(),
|
|
137
|
+
const timer = setInterval(() => context.invalidate(), WIDGET_ANIMATION_BASE_MS);
|
|
124
138
|
timer.unref?.();
|
|
125
139
|
context.state.subagentResultAnimationTimer = timer;
|
|
126
140
|
resultAnimationTimers.set(timer, context.state);
|
|
@@ -352,21 +366,57 @@ export function buildWidgetLines(jobs: AsyncJobState[], theme: Theme, width = ge
|
|
|
352
366
|
return lines;
|
|
353
367
|
}
|
|
354
368
|
|
|
369
|
+
function computeWidgetHash(jobs: AsyncJobState[]): string {
|
|
370
|
+
// Lightweight hash based on status and key mutable fields
|
|
371
|
+
return jobs.map((j) =>
|
|
372
|
+
`${j.asyncId}:${j.status}:${j.currentTool ?? ""}:${j.currentStep ?? ""}:${j.lastActivityAt ?? 0}:${j.activityState ?? ""}:${j.updatedAt ?? 0}`
|
|
373
|
+
).join("|");
|
|
374
|
+
}
|
|
375
|
+
|
|
355
376
|
function refreshAnimatedWidget(): void {
|
|
356
377
|
if (!latestWidgetCtx?.hasUI || latestWidgetJobs.length === 0) return;
|
|
378
|
+
// Skip if called too recently (guard against overlapping timers)
|
|
379
|
+
const now = Date.now();
|
|
380
|
+
const runningCount = latestWidgetJobs.filter((j) => j.status === "running").length;
|
|
381
|
+
const minInterval = resolveWidgetInterval(runningCount);
|
|
382
|
+
if (now - lastWidgetRenderMs < minInterval * 0.8) return;
|
|
383
|
+
// Skip if content hasn't changed
|
|
384
|
+
const newHash = computeWidgetHash(latestWidgetJobs);
|
|
385
|
+
if (newHash === lastWidgetContentHash) return;
|
|
386
|
+
lastWidgetContentHash = newHash;
|
|
387
|
+
lastWidgetRenderMs = now;
|
|
357
388
|
latestWidgetCtx.ui.setWidget(WIDGET_KEY, buildWidgetLines(latestWidgetJobs, latestWidgetCtx.ui.theme));
|
|
358
389
|
latestWidgetCtx.ui.requestRender?.();
|
|
359
390
|
}
|
|
360
391
|
|
|
392
|
+
/** Stop animation timer only — preserves jobs/ctx/hash for dedup */
|
|
393
|
+
function stopAnimationTimer(): void {
|
|
394
|
+
if (widgetTimer) {
|
|
395
|
+
clearInterval(widgetTimer);
|
|
396
|
+
widgetTimer = undefined;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
361
400
|
function ensureWidgetAnimation(): void {
|
|
362
401
|
if (widgetTimer) return;
|
|
363
|
-
|
|
402
|
+
const runningCount = latestWidgetJobs.filter((j) => j.status === "running").length;
|
|
403
|
+
let interval = resolveWidgetInterval(runningCount);
|
|
404
|
+
const tick = () => {
|
|
364
405
|
if (!hasAnimatedWidgetJobs(latestWidgetJobs)) {
|
|
365
406
|
stopWidgetAnimation();
|
|
366
407
|
return;
|
|
367
408
|
}
|
|
409
|
+
// Dynamically adjust interval if running count changed
|
|
410
|
+
const currentRunning = latestWidgetJobs.filter((j) => j.status === "running").length;
|
|
411
|
+
const currentInterval = resolveWidgetInterval(currentRunning);
|
|
412
|
+
if (currentInterval !== interval) {
|
|
413
|
+
stopAnimationTimer();
|
|
414
|
+
ensureWidgetAnimation();
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
368
417
|
refreshAnimatedWidget();
|
|
369
|
-
}
|
|
418
|
+
};
|
|
419
|
+
widgetTimer = setInterval(tick, interval);
|
|
370
420
|
widgetTimer.unref?.();
|
|
371
421
|
}
|
|
372
422
|
|
|
@@ -377,6 +427,7 @@ export function stopWidgetAnimation(): void {
|
|
|
377
427
|
}
|
|
378
428
|
latestWidgetCtx = undefined;
|
|
379
429
|
latestWidgetJobs = [];
|
|
430
|
+
lastWidgetContentHash = "";
|
|
380
431
|
outputActivityCache.clear();
|
|
381
432
|
}
|
|
382
433
|
|
|
@@ -388,6 +439,14 @@ export function stopResultAnimations(): void {
|
|
|
388
439
|
resultAnimationTimers.clear();
|
|
389
440
|
}
|
|
390
441
|
|
|
442
|
+
/** @internal Test-only: reset module-level widget state */
|
|
443
|
+
export function _testResetWidgetState(): void {
|
|
444
|
+
stopWidgetAnimation();
|
|
445
|
+
stopResultAnimations();
|
|
446
|
+
lastWidgetRenderMs = 0;
|
|
447
|
+
lastWidgetContentHash = "";
|
|
448
|
+
}
|
|
449
|
+
|
|
391
450
|
/**
|
|
392
451
|
* Render the async jobs widget
|
|
393
452
|
*/
|
|
@@ -401,12 +460,25 @@ export function renderWidget(ctx: ExtensionContext, jobs: AsyncJobState[]): void
|
|
|
401
460
|
stopWidgetAnimation();
|
|
402
461
|
return;
|
|
403
462
|
}
|
|
463
|
+
|
|
464
|
+
// Content dedup: skip requestRender if widget data hasn't changed
|
|
465
|
+
const newHash = computeWidgetHash(jobs);
|
|
466
|
+
const contentChanged = newHash !== lastWidgetContentHash;
|
|
467
|
+
lastWidgetContentHash = newHash;
|
|
468
|
+
|
|
404
469
|
latestWidgetCtx = ctx;
|
|
405
470
|
latestWidgetJobs = [...jobs];
|
|
406
471
|
|
|
472
|
+
const hasAnimation = hasAnimatedWidgetJobs(jobs);
|
|
407
473
|
ctx.ui.setWidget(WIDGET_KEY, buildWidgetLines(jobs, ctx.ui.theme));
|
|
408
|
-
if (
|
|
409
|
-
|
|
474
|
+
if (contentChanged) {
|
|
475
|
+
ctx.ui.requestRender?.();
|
|
476
|
+
}
|
|
477
|
+
if (hasAnimation) ensureWidgetAnimation();
|
|
478
|
+
else {
|
|
479
|
+
stopAnimationTimer();
|
|
480
|
+
outputActivityCache.clear();
|
|
481
|
+
}
|
|
410
482
|
}
|
|
411
483
|
|
|
412
484
|
function renderSingleCompact(d: Details, r: Details["results"][number], theme: Theme): Component {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import { randomUUID } from "node:crypto";
|
|
4
5
|
import {
|
|
5
6
|
type Details,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import * as path from "node:path";
|
|
5
6
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import * as os from "node:os";
|
|
5
6
|
import * as path from "node:path";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import * as path from "node:path";
|
|
5
6
|
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
/**
|
|
4
5
|
* TypeBox schemas for subagent tool parameters
|
|
5
6
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import * as path from "node:path";
|
|
5
6
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
/**
|
|
4
5
|
* Chain behavior, template resolution, and directory management
|
|
5
6
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import * as path from "node:path";
|
|
5
6
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
/**
|
|
4
5
|
* Skill resolution and caching for subagent extension
|
|
5
6
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
|
4
5
|
import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
5
6
|
import type { SubagentParamsLike } from "./subagent-executor.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import { randomUUID } from "node:crypto";
|
|
4
5
|
import * as fs from "node:fs";
|
|
5
6
|
import * as path from "node:path";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
|
4
5
|
import type { Message } from "@mariozechner/pi-ai";
|
|
5
6
|
import type { SubagentParamsLike } from "./subagent-executor.ts";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import {
|
|
4
5
|
type ActivityState,
|
|
5
6
|
type ControlConfig,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import { randomUUID } from "node:crypto";
|
|
4
5
|
import * as fs from "node:fs";
|
|
5
6
|
import * as path from "node:path";
|
|
@@ -34,6 +35,7 @@ import { applyIntercomBridgeToAgent, INTERCOM_BRIDGE_MARKER, resolveIntercomBrid
|
|
|
34
35
|
import { formatControlIntercomMessage, formatControlNoticeMessage, resolveControlConfig, shouldNotifyControlEvent } from "./subagent-control.ts";
|
|
35
36
|
import { finalizeSingleOutput, injectSingleOutputInstruction, resolveSingleOutputPath } from "./single-output.ts";
|
|
36
37
|
import { compactForegroundDetails, getSingleResultOutput, mapConcurrent, readStatus, resolveChildCwd } from "./utils.ts";
|
|
38
|
+
import { createThrottle, resolveThrottleInterval } from "./throttle.ts";
|
|
37
39
|
import {
|
|
38
40
|
buildSubagentResultIntercomPayload,
|
|
39
41
|
deliverSubagentResultIntercomEvent,
|
|
@@ -966,7 +968,17 @@ function findDuplicateParallelOutputPath(input: {
|
|
|
966
968
|
}
|
|
967
969
|
|
|
968
970
|
async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Promise<SingleResult[]> {
|
|
969
|
-
|
|
971
|
+
// Throttle onUpdate to prevent render storms during high parallelism
|
|
972
|
+
const throttleMs = resolveThrottleInterval(input.tasks.length);
|
|
973
|
+
const rawOnUpdate = input.onUpdate;
|
|
974
|
+
let throttledOnUpdate: ((typeof rawOnUpdate) & { flush(): void; dispose(): void }) | undefined;
|
|
975
|
+
if (rawOnUpdate && throttleMs > 0) {
|
|
976
|
+
throttledOnUpdate = createThrottle(rawOnUpdate, throttleMs);
|
|
977
|
+
input = { ...input, onUpdate: throttledOnUpdate };
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
try {
|
|
981
|
+
return await mapConcurrent(input.tasks, input.concurrencyLimit, async (task, index) => {
|
|
970
982
|
const behavior = input.behaviors[index];
|
|
971
983
|
const effectiveSkills = behavior?.skills;
|
|
972
984
|
const taskCwd = resolveParallelTaskCwd(task, input.paramsCwd, input.worktreeSetup, index);
|
|
@@ -1056,6 +1068,10 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
1056
1068
|
}
|
|
1057
1069
|
});
|
|
1058
1070
|
});
|
|
1071
|
+
} finally {
|
|
1072
|
+
throttledOnUpdate?.flush();
|
|
1073
|
+
throttledOnUpdate?.dispose();
|
|
1074
|
+
}
|
|
1059
1075
|
}
|
|
1060
1076
|
|
|
1061
1077
|
async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps): Promise<AgentToolResult<Details>> {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
4
5
|
|
|
5
6
|
export const SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV = "PI_SUBAGENT_INHERIT_PROJECT_CONTEXT";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import { spawn, spawnSync } from "node:child_process";
|
|
4
5
|
import * as fs from "node:fs";
|
|
5
6
|
import { createRequire } from "node:module";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import * as path from "node:path";
|
|
5
6
|
import type { Theme } from "@mariozechner/pi-coding-agent";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
// MIT
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Nico Bailon
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Source: https://github.com/nicobailon/pi-subagents
|
|
3
4
|
import { matchesKey } from "@mariozechner/pi-tui";
|
|
4
5
|
|
|
5
6
|
export interface TextEditorState {
|