75 lines
2.7 KiB
TypeScript
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,
|
|
},
|
|
};
|
|
},
|
|
});
|
|
}
|