@leing2021/super-pi 0.20.0 → 0.22.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/README.md +40 -19
- package/extensions/ce-core/index.ts +7 -136
- package/extensions/subagent/agent-management.ts +595 -0
- package/extensions/subagent/agent-manager-chain-detail.ts +162 -0
- package/extensions/subagent/agent-manager-detail.ts +231 -0
- package/extensions/subagent/agent-manager-edit.ts +390 -0
- package/extensions/subagent/agent-manager-list.ts +278 -0
- package/extensions/subagent/agent-manager-parallel.ts +304 -0
- package/extensions/subagent/agent-manager.ts +705 -0
- package/extensions/subagent/agent-scope.ts +8 -0
- package/extensions/subagent/agent-selection.ts +25 -0
- package/extensions/subagent/agent-serializer.ts +123 -0
- package/extensions/subagent/agent-templates.ts +62 -0
- package/extensions/subagent/agents/context-builder.md +37 -0
- package/extensions/subagent/agents/delegate.md +9 -0
- package/extensions/subagent/agents/oracle.md +73 -0
- package/extensions/subagent/agents/planner.md +52 -0
- package/extensions/subagent/agents/researcher.md +50 -0
- package/extensions/subagent/agents/reviewer.md +38 -0
- package/extensions/subagent/agents/scout.md +48 -0
- package/extensions/subagent/agents/worker.md +52 -0
- package/extensions/subagent/agents.ts +761 -0
- package/extensions/subagent/artifacts.ts +100 -0
- package/extensions/subagent/async-execution.ts +520 -0
- package/extensions/subagent/async-job-tracker.ts +216 -0
- package/extensions/subagent/async-status.ts +241 -0
- package/extensions/subagent/chain-clarify.ts +1364 -0
- package/extensions/subagent/chain-execution.ts +853 -0
- package/extensions/subagent/chain-serializer.ts +126 -0
- package/extensions/subagent/completion-dedupe.ts +65 -0
- package/extensions/subagent/doctor.ts +200 -0
- package/extensions/subagent/execution.ts +738 -0
- package/extensions/subagent/file-coalescer.ts +42 -0
- package/extensions/subagent/fork-context.ts +63 -0
- package/extensions/subagent/formatters.ts +122 -0
- package/extensions/subagent/frontmatter.ts +31 -0
- package/extensions/subagent/index.ts +585 -0
- package/extensions/subagent/intercom-bridge.ts +240 -0
- package/extensions/subagent/jsonl-writer.ts +83 -0
- package/extensions/subagent/model-fallback.ts +108 -0
- package/extensions/subagent/notify.ts +110 -0
- package/extensions/subagent/parallel-utils.ts +108 -0
- package/extensions/subagent/pi-args.ts +138 -0
- package/extensions/subagent/pi-spawn.ts +100 -0
- package/extensions/subagent/post-exit-stdio-guard.ts +87 -0
- package/extensions/subagent/prompt-template-bridge.ts +399 -0
- package/extensions/subagent/prompts/gather-context-and-clarify.md +13 -0
- package/extensions/subagent/prompts/parallel-cleanup.md +42 -0
- package/extensions/subagent/prompts/parallel-research.md +50 -0
- package/extensions/subagent/prompts/parallel-review.md +40 -0
- package/extensions/subagent/render-helpers.ts +82 -0
- package/extensions/subagent/render.ts +836 -0
- package/extensions/subagent/result-intercom.ts +237 -0
- package/extensions/subagent/result-watcher.ts +171 -0
- package/extensions/subagent/run-history.ts +57 -0
- package/extensions/subagent/run-status.ts +136 -0
- package/extensions/subagent/schemas.ts +164 -0
- package/extensions/subagent/session-tokens.ts +50 -0
- package/extensions/subagent/settings.ts +367 -0
- package/extensions/subagent/single-output.ts +97 -0
- package/extensions/subagent/skills.ts +626 -0
- package/extensions/subagent/slash-bridge.ts +176 -0
- package/extensions/subagent/slash-commands.ts +303 -0
- package/extensions/subagent/slash-live-state.ts +294 -0
- package/extensions/subagent/subagent-control.ts +150 -0
- package/extensions/subagent/subagent-executor.ts +1899 -0
- package/extensions/subagent/subagent-prompt-runtime.ts +75 -0
- package/extensions/subagent/subagent-runner.ts +1470 -0
- package/extensions/subagent/subagents-status.ts +472 -0
- package/extensions/subagent/text-editor.ts +272 -0
- package/extensions/subagent/top-level-async.ts +15 -0
- package/extensions/subagent/types.ts +623 -0
- package/extensions/subagent/utils.ts +456 -0
- package/extensions/subagent/worktree.ts +579 -0
- package/extensions/super-pi-extension/agents/ce-worker.md +1 -1
- package/extensions/super-pi-extension/index.ts +2 -55
- package/package.json +12 -5
- package/skills/03-work/SKILL.md +3 -3
- package/skills/pi-subagents/SKILL.md +566 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// Based on pi-subagents by Nico Bailon (https://github.com/nicobailon/pi-subagents)
|
|
2
|
+
// MIT License
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import * as os from "node:os";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
9
|
+
const TASK_ARG_LIMIT = 8000;
|
|
10
|
+
const PROMPT_RUNTIME_EXTENSION_PATH = path.join(path.dirname(fileURLToPath(import.meta.url)), "subagent-prompt-runtime.ts");
|
|
11
|
+
|
|
12
|
+
export interface BuildPiArgsInput {
|
|
13
|
+
baseArgs: string[];
|
|
14
|
+
task: string;
|
|
15
|
+
sessionEnabled: boolean;
|
|
16
|
+
sessionDir?: string;
|
|
17
|
+
sessionFile?: string;
|
|
18
|
+
model?: string;
|
|
19
|
+
thinking?: string;
|
|
20
|
+
systemPromptMode?: "append" | "replace";
|
|
21
|
+
inheritProjectContext: boolean;
|
|
22
|
+
inheritSkills: boolean;
|
|
23
|
+
tools?: string[];
|
|
24
|
+
extensions?: string[];
|
|
25
|
+
systemPrompt?: string | null;
|
|
26
|
+
mcpDirectTools?: string[];
|
|
27
|
+
promptFileStem?: string;
|
|
28
|
+
intercomSessionName?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface BuildPiArgsResult {
|
|
32
|
+
args: string[];
|
|
33
|
+
env: Record<string, string | undefined>;
|
|
34
|
+
tempDir?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function applyThinkingSuffix(model: string | undefined, thinking: string | undefined): string | undefined {
|
|
38
|
+
if (!model || !thinking || thinking === "off") return model;
|
|
39
|
+
const colonIdx = model.lastIndexOf(":");
|
|
40
|
+
if (colonIdx !== -1 && THINKING_LEVELS.includes(model.substring(colonIdx + 1))) return model;
|
|
41
|
+
return `${model}:${thinking}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
45
|
+
const args = [...input.baseArgs];
|
|
46
|
+
|
|
47
|
+
if (input.sessionFile) {
|
|
48
|
+
fs.mkdirSync(path.dirname(input.sessionFile), { recursive: true });
|
|
49
|
+
args.push("--session", input.sessionFile);
|
|
50
|
+
} else {
|
|
51
|
+
if (!input.sessionEnabled) {
|
|
52
|
+
args.push("--no-session");
|
|
53
|
+
}
|
|
54
|
+
if (input.sessionDir) {
|
|
55
|
+
fs.mkdirSync(input.sessionDir, { recursive: true });
|
|
56
|
+
args.push("--session-dir", input.sessionDir);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const modelArg = applyThinkingSuffix(input.model, input.thinking);
|
|
61
|
+
if (modelArg) {
|
|
62
|
+
args.push("--model", modelArg);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const toolExtensionPaths: string[] = [];
|
|
66
|
+
if (input.tools?.length) {
|
|
67
|
+
const builtinTools: string[] = [];
|
|
68
|
+
for (const tool of input.tools) {
|
|
69
|
+
if (tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js")) {
|
|
70
|
+
toolExtensionPaths.push(tool);
|
|
71
|
+
} else {
|
|
72
|
+
builtinTools.push(tool);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (builtinTools.length > 0) {
|
|
76
|
+
args.push("--tools", builtinTools.join(","));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const runtimeExtensions = [PROMPT_RUNTIME_EXTENSION_PATH];
|
|
81
|
+
if (input.extensions !== undefined) {
|
|
82
|
+
args.push("--no-extensions");
|
|
83
|
+
for (const extPath of [...new Set([...runtimeExtensions, ...toolExtensionPaths, ...input.extensions])]) {
|
|
84
|
+
args.push("--extension", extPath);
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
for (const extPath of [...new Set([...runtimeExtensions, ...toolExtensionPaths])]) {
|
|
88
|
+
args.push("--extension", extPath);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!input.inheritSkills) {
|
|
93
|
+
args.push("--no-skills");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let tempDir: string | undefined;
|
|
97
|
+
if (input.systemPrompt !== undefined && input.systemPrompt !== null) {
|
|
98
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-"));
|
|
99
|
+
const stem = (input.promptFileStem ?? "prompt").replace(/[^\w.-]/g, "_");
|
|
100
|
+
const promptPath = path.join(tempDir, `${stem}.md`);
|
|
101
|
+
fs.writeFileSync(promptPath, input.systemPrompt, { mode: 0o600 });
|
|
102
|
+
args.push(input.systemPromptMode === "replace" ? "--system-prompt" : "--append-system-prompt", promptPath);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (input.task.length > TASK_ARG_LIMIT) {
|
|
106
|
+
if (!tempDir) {
|
|
107
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-"));
|
|
108
|
+
}
|
|
109
|
+
const taskFilePath = path.join(tempDir, "task.md");
|
|
110
|
+
fs.writeFileSync(taskFilePath, `Task: ${input.task}`, { mode: 0o600 });
|
|
111
|
+
args.push(`@${taskFilePath}`);
|
|
112
|
+
} else {
|
|
113
|
+
args.push(`Task: ${input.task}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const env: Record<string, string | undefined> = {};
|
|
117
|
+
env.PI_SUBAGENT_INHERIT_PROJECT_CONTEXT = input.inheritProjectContext ? "1" : "0";
|
|
118
|
+
env.PI_SUBAGENT_INHERIT_SKILLS = input.inheritSkills ? "1" : "0";
|
|
119
|
+
if (input.intercomSessionName) {
|
|
120
|
+
env.PI_SUBAGENT_INTERCOM_SESSION_NAME = input.intercomSessionName;
|
|
121
|
+
}
|
|
122
|
+
if (input.mcpDirectTools?.length) {
|
|
123
|
+
env.MCP_DIRECT_TOOLS = input.mcpDirectTools.join(",");
|
|
124
|
+
} else {
|
|
125
|
+
env.MCP_DIRECT_TOOLS = "__none__";
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return { args, env, tempDir };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function cleanupTempDir(tempDir: string | null | undefined): void {
|
|
132
|
+
if (!tempDir) return;
|
|
133
|
+
try {
|
|
134
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
135
|
+
} catch {
|
|
136
|
+
// Temp cleanup is best effort.
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Based on pi-subagents by Nico Bailon (https://github.com/nicobailon/pi-subagents)
|
|
2
|
+
// MIT License
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
|
|
9
|
+
export function resolvePiPackageRoot(): string | undefined {
|
|
10
|
+
try {
|
|
11
|
+
const entry = process.argv[1];
|
|
12
|
+
if (!entry) return undefined;
|
|
13
|
+
let dir = path.dirname(fs.realpathSync(entry));
|
|
14
|
+
while (dir !== path.dirname(dir)) {
|
|
15
|
+
try {
|
|
16
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(dir, "package.json"), "utf-8"));
|
|
17
|
+
if (pkg.name === "@mariozechner/pi-coding-agent") return dir;
|
|
18
|
+
} catch {}
|
|
19
|
+
dir = path.dirname(dir);
|
|
20
|
+
}
|
|
21
|
+
} catch {}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface PiSpawnDeps {
|
|
26
|
+
platform?: NodeJS.Platform;
|
|
27
|
+
execPath?: string;
|
|
28
|
+
argv1?: string;
|
|
29
|
+
existsSync?: (filePath: string) => boolean;
|
|
30
|
+
readFileSync?: (filePath: string, encoding: "utf-8") => string;
|
|
31
|
+
resolvePackageJson?: () => string;
|
|
32
|
+
piPackageRoot?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface PiSpawnCommand {
|
|
36
|
+
command: string;
|
|
37
|
+
args: string[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function isRunnableNodeScript(filePath: string, existsSync: (filePath: string) => boolean): boolean {
|
|
41
|
+
if (!existsSync(filePath)) return false;
|
|
42
|
+
return /\.(?:mjs|cjs|js)$/i.test(filePath);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function normalizePath(filePath: string): string {
|
|
46
|
+
return path.isAbsolute(filePath) ? filePath : path.resolve(filePath);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function resolveWindowsPiCliScript(deps: PiSpawnDeps = {}): string | undefined {
|
|
50
|
+
const existsSync = deps.existsSync ?? fs.existsSync;
|
|
51
|
+
const readFileSync = deps.readFileSync ?? ((filePath, encoding) => fs.readFileSync(filePath, encoding));
|
|
52
|
+
const argv1 = deps.argv1 ?? process.argv[1];
|
|
53
|
+
|
|
54
|
+
if (argv1) {
|
|
55
|
+
const argvPath = normalizePath(argv1);
|
|
56
|
+
if (isRunnableNodeScript(argvPath, existsSync)) {
|
|
57
|
+
return argvPath;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const resolvePackageJson = deps.resolvePackageJson ?? (() => {
|
|
63
|
+
const root = deps.piPackageRoot ?? resolvePiPackageRoot();
|
|
64
|
+
if (root) return path.join(root, "package.json");
|
|
65
|
+
return require.resolve("@mariozechner/pi-coding-agent/package.json");
|
|
66
|
+
});
|
|
67
|
+
const packageJsonPath = resolvePackageJson();
|
|
68
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8")) as {
|
|
69
|
+
bin?: string | Record<string, string>;
|
|
70
|
+
};
|
|
71
|
+
const binField = packageJson.bin;
|
|
72
|
+
const binPath = typeof binField === "string"
|
|
73
|
+
? binField
|
|
74
|
+
: binField?.pi ?? Object.values(binField ?? {})[0];
|
|
75
|
+
if (!binPath) return undefined;
|
|
76
|
+
const candidate = normalizePath(path.resolve(path.dirname(packageJsonPath), binPath));
|
|
77
|
+
if (isRunnableNodeScript(candidate, existsSync)) {
|
|
78
|
+
return candidate;
|
|
79
|
+
}
|
|
80
|
+
} catch {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function getPiSpawnCommand(args: string[], deps: PiSpawnDeps = {}): PiSpawnCommand {
|
|
88
|
+
const platform = deps.platform ?? process.platform;
|
|
89
|
+
if (platform === "win32") {
|
|
90
|
+
const piCliPath = resolveWindowsPiCliScript(deps);
|
|
91
|
+
if (piCliPath) {
|
|
92
|
+
return {
|
|
93
|
+
command: deps.execPath ?? process.execPath,
|
|
94
|
+
args: [piCliPath, ...args],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return { command: "pi", args };
|
|
100
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Based on pi-subagents by Nico Bailon (https://github.com/nicobailon/pi-subagents)
|
|
2
|
+
// MIT License
|
|
3
|
+
import type { ChildProcess } from "node:child_process";
|
|
4
|
+
|
|
5
|
+
interface PostExitStdioGuardOptions {
|
|
6
|
+
idleMs: number;
|
|
7
|
+
hardMs: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface ChildWithPipedStdio {
|
|
11
|
+
stdout: ChildProcess["stdout"];
|
|
12
|
+
stderr: ChildProcess["stderr"];
|
|
13
|
+
on: ChildProcess["on"];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface ChildWithKill {
|
|
17
|
+
kill(signal?: NodeJS.Signals | number): boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function trySignalChild(child: ChildWithKill, signal: NodeJS.Signals): boolean {
|
|
21
|
+
try {
|
|
22
|
+
return child.kill(signal);
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function attachPostExitStdioGuard(
|
|
29
|
+
child: ChildWithPipedStdio,
|
|
30
|
+
options: PostExitStdioGuardOptions,
|
|
31
|
+
): () => void {
|
|
32
|
+
const { idleMs, hardMs } = options;
|
|
33
|
+
let exited = false;
|
|
34
|
+
let stdoutEnded = false;
|
|
35
|
+
let stderrEnded = false;
|
|
36
|
+
let idleTimer: NodeJS.Timeout | undefined;
|
|
37
|
+
let hardTimer: NodeJS.Timeout | undefined;
|
|
38
|
+
|
|
39
|
+
const destroyUnendedStdio = () => {
|
|
40
|
+
if (!stdoutEnded) {
|
|
41
|
+
try { child.stdout?.destroy(); } catch {}
|
|
42
|
+
}
|
|
43
|
+
if (!stderrEnded) {
|
|
44
|
+
try { child.stderr?.destroy(); } catch {}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const clearTimers = () => {
|
|
49
|
+
if (idleTimer) {
|
|
50
|
+
clearTimeout(idleTimer);
|
|
51
|
+
idleTimer = undefined;
|
|
52
|
+
}
|
|
53
|
+
if (hardTimer) {
|
|
54
|
+
clearTimeout(hardTimer);
|
|
55
|
+
hardTimer = undefined;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const armIdleTimer = () => {
|
|
60
|
+
if (!exited) return;
|
|
61
|
+
if (idleTimer) clearTimeout(idleTimer);
|
|
62
|
+
idleTimer = setTimeout(destroyUnendedStdio, idleMs);
|
|
63
|
+
idleTimer.unref?.();
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
child.stdout?.on("data", armIdleTimer);
|
|
67
|
+
child.stderr?.on("data", armIdleTimer);
|
|
68
|
+
child.stdout?.on("end", () => {
|
|
69
|
+
stdoutEnded = true;
|
|
70
|
+
if (stdoutEnded && stderrEnded) clearTimers();
|
|
71
|
+
});
|
|
72
|
+
child.stderr?.on("end", () => {
|
|
73
|
+
stderrEnded = true;
|
|
74
|
+
if (stdoutEnded && stderrEnded) clearTimers();
|
|
75
|
+
});
|
|
76
|
+
child.on("exit", () => {
|
|
77
|
+
exited = true;
|
|
78
|
+
armIdleTimer();
|
|
79
|
+
if (hardTimer) return;
|
|
80
|
+
hardTimer = setTimeout(destroyUnendedStdio, hardMs);
|
|
81
|
+
hardTimer.unref?.();
|
|
82
|
+
});
|
|
83
|
+
child.on("close", clearTimers);
|
|
84
|
+
child.on("error", clearTimers);
|
|
85
|
+
|
|
86
|
+
return clearTimers;
|
|
87
|
+
}
|