Adding skills
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
||||
import { UpdateFailure, updatePiAndExtensions, type UpdateReporter, type UpdateResult } from "./updater.ts";
|
||||
|
||||
const STATUS_KEY = "pi-update";
|
||||
|
||||
function conciseError(error: unknown): string {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
const lines = message.split(/\r?\n/).filter(Boolean);
|
||||
return lines.slice(Math.max(0, lines.length - 12)).join("\n");
|
||||
}
|
||||
|
||||
function notify(ctx: ExtensionContext, message: string, level: "info" | "warning" | "error" = "info"): void {
|
||||
if (ctx.hasUI) {
|
||||
ctx.ui.notify(message, level);
|
||||
} else if (level === "error") {
|
||||
console.error(message);
|
||||
} else if (level === "warning") {
|
||||
console.warn(message);
|
||||
} else {
|
||||
console.log(message);
|
||||
}
|
||||
}
|
||||
|
||||
function makeReporter(ctx: ExtensionContext): UpdateReporter {
|
||||
return {
|
||||
info(message) {
|
||||
ctx.ui.setStatus(STATUS_KEY, message);
|
||||
notify(ctx, message, "info");
|
||||
},
|
||||
retry(message) {
|
||||
ctx.ui.setStatus(STATUS_KEY, message);
|
||||
notify(ctx, message, "warning");
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function formatResult(result: UpdateResult): string {
|
||||
const versionChange =
|
||||
result.beforeVersion === result.afterVersion
|
||||
? `Pi remains at v${result.afterVersion}`
|
||||
: `Pi updated: v${result.beforeVersion} → v${result.afterVersion}`;
|
||||
const extensionStatus = result.extensionsChecked
|
||||
? "Configured Pi extension packages were checked successfully."
|
||||
: "Extension package checking did not complete.";
|
||||
return `${versionChange}\nInstall method: ${result.method}\n${extensionStatus}\nRestart Pi to load updated code.`;
|
||||
}
|
||||
|
||||
export default function updateExtension(pi: ExtensionAPI): void {
|
||||
let activeUpdate: Promise<UpdateResult> | undefined;
|
||||
let updateFlagHandled = false;
|
||||
|
||||
pi.registerFlag("update", {
|
||||
description: "Update Pi and all configured extension packages, then exit",
|
||||
type: "boolean",
|
||||
default: false,
|
||||
});
|
||||
|
||||
async function runUpdate(ctx: ExtensionContext): Promise<UpdateResult> {
|
||||
if (!activeUpdate) {
|
||||
ctx.ui.setStatus(STATUS_KEY, "Preparing Pi update");
|
||||
activeUpdate = updatePiAndExtensions(pi, makeReporter(ctx), {
|
||||
projectTrusted: ctx.isProjectTrusted(),
|
||||
}).finally(() => {
|
||||
ctx.ui.setStatus(STATUS_KEY, undefined);
|
||||
activeUpdate = undefined;
|
||||
});
|
||||
}
|
||||
return activeUpdate;
|
||||
}
|
||||
|
||||
async function handleUpdate(ctx: ExtensionContext, exitAfterUpdate: boolean): Promise<void> {
|
||||
try {
|
||||
const result = await runUpdate(ctx);
|
||||
notify(ctx, formatResult(result), "info");
|
||||
if (exitAfterUpdate || result.requiresShutdown) ctx.shutdown();
|
||||
} catch (error) {
|
||||
notify(ctx, `Update failed\n${conciseError(error)}`, "error");
|
||||
if (exitAfterUpdate) process.exitCode = 1;
|
||||
if (exitAfterUpdate || (error instanceof UpdateFailure && error.requiresShutdown)) ctx.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
pi.registerCommand("update", {
|
||||
description: "Update Pi and all configured extension packages",
|
||||
handler: async (_args: string, ctx: ExtensionCommandContext) => {
|
||||
await ctx.waitForIdle();
|
||||
await handleUpdate(ctx, false);
|
||||
},
|
||||
});
|
||||
|
||||
pi.on("session_start", async (_event, ctx) => {
|
||||
if (updateFlagHandled || pi.getFlag("update") !== true) return;
|
||||
updateFlagHandled = true;
|
||||
await handleUpdate(ctx, true);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user