import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { Text } from "@earendil-works/pi-tui"; import type { CorridorRuntime } from "../application/corridor-runtime.ts"; import { GraphPatchSchema, type GraphPatchParams } from "../domain/schemas.ts"; import type { GraphCheckpointDetails } from "../domain/types.ts"; function resultText(details: GraphCheckpointDetails): string { if (details.status === "applied") { const now = details.attention?.now ?? "No active action"; return `Intent path advanced to revision ${details.revision}. NOW: ${now}`; } if (details.status === "already_applied") { return `Intent path patch was already applied at revision ${details.revision}.`; } return `Intent path ${details.status}: ${details.error ?? "unknown error"}. Current revision: ${details.revision}.`; } export function registerUpdateActionPathTool(pi: ExtensionAPI, runtime: CorridorRuntime): void { pi.registerTool({ name: "update_action_path", label: "Update Action Path", description: "Declare or revise the current operational intent path as one atomic, revisioned GraphPatch. This updates only the human-facing action map; it does not execute project code.", promptSnippet: "Declare or revise the current operational action path as an atomic GraphPatch", promptGuidelines: [ "Use update_action_path at genuine action or strategy boundaries, not for every tool call.", "Use update_action_path before changing the active action, after evidence invalidates the current path, after repeated failure, before asking the user, and before claiming completion.", "The current active leaf and every active ancestor shell must be committed. Use hierarchical refinement for meaningful substeps; never turn ordinary tool calls into graph nodes.", "When establishing a new goal or stage, declare 1–3 immediate committed/provisional next transitions and 1–3 directional outcomes when they are genuinely known; if none are known, leave future undeclared rather than inventing steps.", "Future transitions may be provisional or directional. Mark provisional paths with dependencies or reconsiderWhen, and promote them to committed before activation.", "In update_action_path, record operational intent, why-now, expected evidence, exit conditions, failure behavior, and planning-change reasons; never record hidden reasoning or chain-of-thought.", "Do not use update_action_path merely to report activity. Use schemaVersion 2 and the current baseRevision supplied in the Intent Petri context.", ], parameters: GraphPatchSchema, executionMode: "sequential", async execute(toolCallId, params: GraphPatchParams, _signal, _onUpdate, ctx) { const details = runtime.apply(params, ctx, toolCallId); return { content: [{ type: "text", text: resultText(details) }], details, }; }, renderCall(args, theme) { return new Text( theme.fg("toolTitle", theme.bold("intent path ")) + theme.fg("muted", `${args.patchId} @ r${args.baseRevision} · ${args.ops.length} op(s)`), 0, 0, ); }, renderResult(result, { expanded }, theme) { const details = result.details; const color = details.status === "applied" || details.status === "already_applied" ? "success" : "warning"; let text = theme.fg(color, `${details.status === "applied" ? "✓" : "!"} r${details.revision}`); text += ` ${theme.fg("muted", details.attention?.now ?? details.error ?? "No active action")}`; if (expanded && details.batch) { text += `\n${theme.fg("dim", details.batch.events.map((event) => event.kind).join(" → "))}`; text += `\n${theme.fg("dim", details.snapshotHash)}`; } return new Text(text, 0, 0); }, }); }