feat: package Pi extensions as Bun workspaces
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
||||
import { createCompletedTaskAutoClear } from "./src/auto-clear.ts";
|
||||
import { clearCurrentTask, reportCurrentTask } from "./src/herdr.ts";
|
||||
import {
|
||||
COMPACTION_REMINDER,
|
||||
COMPACTION_REMINDER_TYPE,
|
||||
hasUnfinishedTasks,
|
||||
} from "./src/prompt.ts";
|
||||
import { TASK_STATE_ENTRY_TYPE, TaskState } from "./src/state.ts";
|
||||
import { registerTaskTools } from "./src/tools.ts";
|
||||
import { clearTaskWidget, updateTaskWidget } from "./src/widget.ts";
|
||||
|
||||
export default function piTodoHerdr(pi: ExtensionAPI): void {
|
||||
const state = new TaskState();
|
||||
let widgetVisible = true;
|
||||
let activeContext: ExtensionContext | undefined;
|
||||
|
||||
const autoClear = createCompletedTaskAutoClear(state, () => {
|
||||
try {
|
||||
pi.appendEntry(TASK_STATE_ENTRY_TYPE, { tasks: [], nextId: 1 });
|
||||
} catch (error) {
|
||||
console.error("[pi-todo-herdr] failed to persist automatic task clear; retrying:", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
state.set("replace", [], false);
|
||||
if (activeContext !== undefined) {
|
||||
try {
|
||||
updateTaskWidget(state, activeContext, widgetVisible);
|
||||
void reportCurrentTask(state.list());
|
||||
} catch (error) {
|
||||
console.error("[pi-todo-herdr] failed to refresh task UI after automatic clear:", error);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
const refresh = (ctx: ExtensionContext, restartAutoClear = false) => {
|
||||
activeContext = ctx;
|
||||
updateTaskWidget(state, ctx, widgetVisible);
|
||||
void reportCurrentTask(state.list());
|
||||
autoClear.sync(restartAutoClear);
|
||||
};
|
||||
|
||||
const restore = (ctx: ExtensionContext) => {
|
||||
state.loadFromSession(ctx);
|
||||
refresh(ctx, true);
|
||||
};
|
||||
|
||||
pi.on("session_start", async (_event, ctx) => restore(ctx));
|
||||
pi.on("session_tree", async (_event, ctx) => restore(ctx));
|
||||
pi.on("session_shutdown", async (event) => {
|
||||
autoClear.cancel();
|
||||
if (activeContext !== undefined) clearTaskWidget(activeContext);
|
||||
activeContext = undefined;
|
||||
if (event.reason === "quit") await clearCurrentTask();
|
||||
});
|
||||
pi.on("session_compact", () => {
|
||||
if (!hasUnfinishedTasks(state.list())) return;
|
||||
pi.sendMessage(
|
||||
{
|
||||
customType: COMPACTION_REMINDER_TYPE,
|
||||
content: COMPACTION_REMINDER,
|
||||
display: false,
|
||||
},
|
||||
{ deliverAs: "steer" },
|
||||
);
|
||||
});
|
||||
|
||||
registerTaskTools(pi, state, refresh);
|
||||
|
||||
pi.registerCommand("todo", {
|
||||
description: "Show or hide the todo tree widget",
|
||||
handler: async (_args, ctx) => {
|
||||
if (state.list().length === 0) {
|
||||
clearTaskWidget(ctx);
|
||||
ctx.ui.notify("No todos yet.", "info");
|
||||
return;
|
||||
}
|
||||
|
||||
widgetVisible = !widgetVisible;
|
||||
if (widgetVisible) {
|
||||
updateTaskWidget(state, ctx, true);
|
||||
ctx.ui.notify("Todo widget shown.", "info");
|
||||
} else {
|
||||
clearTaskWidget(ctx);
|
||||
ctx.ui.notify("Todo widget hidden.", "info");
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user