dotfiles/config/pi/extensions/worktree-agent/index.ts
2026-07-18 19:59:58 +07:00

75 lines
2.7 KiB
TypeScript

import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { registerWorkerGuard } from "./guard.ts";
import { WorktreeAgentParameters, type ProgressReporter } from "./types.ts";
import { runWorker } from "./worker.ts";
import { isParentClean, prepareWorktree } from "./worktree.ts";
function shellQuote(value: string): string {
return `'${value.replace(/'/g, `'"'"'`)}'`;
}
export default function worktreeAgentExtension(pi: ExtensionAPI) {
const workerRoot = process.env.PI_WORKTREE_ROOT;
if (process.env.PI_WORKTREE_AGENT === "1" && workerRoot) {
registerWorkerGuard(pi, workerRoot);
return;
}
pi.registerTool({
name: "run_issue_in_worktree",
label: "Run issue in worktree",
description:
"Create an isolated Git worktree for a retrieved Linear issue and run a child Pi agent there. " +
"Call this only after retrieving and understanding the Linear issue. The call remains active until the child finishes.",
promptSnippet: "Run a retrieved Linear issue in an isolated Git worktree using a child Pi agent",
promptGuidelines: [
"Use run_issue_in_worktree only after retrieving the Linear issue, then let the child agent perform all repository modifications.",
"When run_issue_in_worktree is active, do not modify files in the parent checkout.",
],
parameters: WorktreeAgentParameters,
async execute(_toolCallId, params, signal, onUpdate, ctx) {
const report: ProgressReporter = (message, details) => {
onUpdate?.({ content: [{ type: "text", text: message }], details });
};
const worktree = await prepareWorktree(pi, ctx.cwd, params, report);
const workerReport = await runWorker({
input: params,
worktree,
model: ctx.model,
thinkingLevel: pi.getThinkingLevel(),
signal,
report,
});
const parentClean = await isParentClean(pi, worktree.repoRoot);
const resumeCommand =
`cd ${shellQuote(worktree.worktreePath)} && ` +
'PI_WORKTREE_AGENT=1 PI_WORKTREE_ROOT="$PWD" pi -c';
const parentWarning = parentClean
? ""
: "\n\nWARNING: The parent working tree is no longer clean; inspect it before continuing.";
return {
content: [
{
type: "text",
text:
`Child Pi finished in ${worktree.worktreePath}.\n` +
`Branch: ${worktree.branchName}\n` +
`Resume: ${resumeCommand}\n\n${workerReport}${parentWarning}`,
},
],
details: {
phase: "complete",
branchName: worktree.branchName,
worktreePath: worktree.worktreePath,
parentClean,
resumeCommand,
workerReport,
},
};
},
});
}