pi extension update
This commit is contained in:
157
pi/.pi/agent/extensions/postpone.ts
Normal file
157
pi/.pi/agent/extensions/postpone.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
/**
|
||||
* Postpone Extension
|
||||
*
|
||||
* Allows users to postpone sending a prompt by X minutes.
|
||||
* When the timer reaches 0, the prompt is automatically sent.
|
||||
*
|
||||
* Usage:
|
||||
* /postpone <minutes> <prompt>
|
||||
*
|
||||
* Example:
|
||||
* /postpone 5 Remember to check the build status
|
||||
*/
|
||||
|
||||
export default function postponeExtension(pi: ExtensionAPI) {
|
||||
// Interface for postponed prompt data stored in session
|
||||
interface PostponedPromptData {
|
||||
prompt: string;
|
||||
delayMs: number;
|
||||
timestamp: number; // When it was postponed
|
||||
sendAs?: "steer" | "followUp" | "nextTurn"; // How to send it
|
||||
}
|
||||
|
||||
// Restore postponed prompts from session on startup
|
||||
pi.on("session_start", async (_event, ctx) => {
|
||||
// Get all entries from current branch
|
||||
const branchEntries = ctx.sessionManager.getBranch();
|
||||
|
||||
// Look for postponed prompt entries
|
||||
for (const entry of branchEntries) {
|
||||
if (entry.type === "custom" && entry.customType === "postponed-prompt") {
|
||||
const data = entry.data as PostponedPromptData | undefined;
|
||||
if (data) {
|
||||
const elapsed = Date.now() - data.timestamp;
|
||||
const remaining = data.delayMs - elapsed;
|
||||
|
||||
// If time is still remaining, set up a new timeout
|
||||
if (remaining > 0) {
|
||||
setTimeout(() => {
|
||||
sendPostponedPrompt(data, ctx);
|
||||
}, remaining);
|
||||
} else {
|
||||
// Time's up, send it now
|
||||
sendPostponedPrompt(data, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Function to actually send a postponed prompt
|
||||
function sendPostponedPrompt(data: PostponedPromptData, ctx: ExtensionContext) {
|
||||
// Send as user message
|
||||
pi.sendUserMessage(data.prompt, {
|
||||
deliverAs: data.sendAs || "steer"
|
||||
});
|
||||
|
||||
// Notify user
|
||||
ctx.ui.notify("Postponed prompt sent", "info");
|
||||
}
|
||||
|
||||
// Register the /postpone command
|
||||
pi.registerCommand("postpone", {
|
||||
description: "Postpone sending a prompt by X minutes",
|
||||
handler: async (args, ctx) => {
|
||||
// Parse args: first argument should be minutes, rest is the prompt
|
||||
const parts = args.trim().split(/\s+/);
|
||||
if (parts.length < 2) {
|
||||
ctx.ui.notify("Usage: /postpone <minutes> <prompt>", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
const minutes = parseInt(parts[0], 10);
|
||||
if (isNaN(minutes) || minutes <= 0) {
|
||||
ctx.ui.notify("Please provide a valid number of minutes", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
const prompt = parts.slice(1).join(" ");
|
||||
if (!prompt.trim()) {
|
||||
ctx.ui.notify("Please provide a prompt to postpone", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
const delayMs = minutes * 60 * 1000;
|
||||
const timestamp = Date.now();
|
||||
|
||||
// Store in session for persistence
|
||||
pi.appendEntry<PostponedPromptData>("postponed-prompt", {
|
||||
prompt,
|
||||
delayMs,
|
||||
timestamp,
|
||||
sendAs: "steer" // Default to steer
|
||||
});
|
||||
|
||||
// Set up timeout
|
||||
setTimeout(() => {
|
||||
sendPostponedPrompt({ prompt, delayMs, timestamp, sendAs: "steer" }, ctx);
|
||||
}, delayMs);
|
||||
|
||||
ctx.ui.notify(`Prompt postponed for ${minutes} minute(s)`, "info");
|
||||
}
|
||||
});
|
||||
|
||||
// Optional: Add a command to list pending postponed prompts
|
||||
pi.registerCommand("postponed", {
|
||||
description: "List postponed prompts",
|
||||
handler: async (_args, ctx) => {
|
||||
const branchEntries = ctx.sessionManager.getBranch();
|
||||
const postponed = branchEntries.filter(
|
||||
entry => entry.type === "custom" && entry.customType === "postponed-prompt"
|
||||
);
|
||||
|
||||
if (postponed.length === 0) {
|
||||
ctx.ui.notify("No postponed prompts", "info");
|
||||
return;
|
||||
}
|
||||
|
||||
let message = "Postponed prompts:\n";
|
||||
postponed.forEach((entry, index) => {
|
||||
const data = entry.data as PostponedPromptData;
|
||||
const elapsed = Date.now() - data.timestamp;
|
||||
const remaining = data.delayMs - elapsed;
|
||||
const minutesLeft = Math.ceil(remaining / 60000);
|
||||
|
||||
message += `${index + 1}. ${data.prompt} (${minutesLeft} minute(s) left)\n`;
|
||||
});
|
||||
|
||||
ctx.ui.notify(message.trim(), "info");
|
||||
}
|
||||
});
|
||||
|
||||
// Optional: Add a command to cancel all postponed prompts
|
||||
pi.registerCommand("postpone-cancel", {
|
||||
description: "Cancel all postponed prompts",
|
||||
handler: async (_args, ctx) => {
|
||||
const branchEntries = ctx.sessionManager.getBranch();
|
||||
let cancelled = 0;
|
||||
|
||||
for (const entry of branchEntries) {
|
||||
if (entry.type === "custom" && entry.customType === "postponed-prompt") {
|
||||
// We can't actually remove entries, but we can add a marker
|
||||
// For simplicity, we'll just notify the user that we've cleared the list
|
||||
// In a real implementation, we might want to track active timeouts
|
||||
cancelled++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cancelled > 0) {
|
||||
ctx.ui.notify(`Cancelled ${cancelled} postponed prompt(s)`, "info");
|
||||
} else {
|
||||
ctx.ui.notify("No postponed prompts to cancel", "info");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user