mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-28 12:12:47 +00:00
* refactor(plugins): make lifecycle hook timing explicit Use one registration method and subject.operation.step names so plugin authors can read whether an operation waits. Preserve old registrations through a single SDK adapter and keep timing and payloads unchanged. * fix(plugins): align hook notes and example fixtures with release contracts Keep the changelog inside its versioned beta entry for app parsing. Run current plugin examples against the checkout version so their declared requirements remain valid. * docs(plugins): align translated hook dependency guidance * fix(plugins): align hook exports and release documentation * feat(plugins): use lifecycle positions and await worktree initialization * test(plugins): cover first-agent worktree initialization * test(plugins): verify rollback against workspace catalog entries
97 lines
2.6 KiB
TypeScript
97 lines
2.6 KiB
TypeScript
import type { PluginServerContext } from "@getpaseo/plugin/server";
|
|
import { latestOutputText, shellCommand } from "./server/inspect";
|
|
|
|
export default function contribute(server: PluginServerContext) {
|
|
server.addHook("workspace.create.before", async ({ request }) => {
|
|
if (request.title === "Isolated lifecycle example" && request.source.kind === "directory") {
|
|
return {
|
|
...request,
|
|
source: {
|
|
kind: "worktree",
|
|
cwd: request.source.path,
|
|
action: "branch-off",
|
|
branchName: "lifecycle-example",
|
|
},
|
|
};
|
|
}
|
|
return request;
|
|
});
|
|
|
|
server.addHook("agent.turn.after", async (event, context) => {
|
|
if (event.outcome.kind === "canceled") {
|
|
return;
|
|
}
|
|
const agent = context.paseo.agents.ref(event.agent.id);
|
|
const page = await agent.timeline.refetch({ direction: "tail", limit: 20 });
|
|
const text = latestOutputText(page.entries.map(({ item }) => item));
|
|
if (/out of credits/i.test(text)) {
|
|
console.log("Sending a follow-up after out of credits", event.agent.id);
|
|
await agent.send("Try again.");
|
|
}
|
|
});
|
|
|
|
server.addHook("agent.permission.before", async (event, context) => {
|
|
const command = shellCommand(event.request);
|
|
if (command === null) {
|
|
return;
|
|
}
|
|
|
|
const agent = context.paseo.agents.ref(event.agent.id);
|
|
if (/\brm\s+-rf\b/.test(command)) {
|
|
await agent.respondToPermission({
|
|
requestId: event.request.id,
|
|
response: {
|
|
behavior: "deny",
|
|
message: "Recursive deletion is blocked by the example plugin.",
|
|
},
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (command.trim() === "git status") {
|
|
await agent.respondToPermission({
|
|
requestId: event.request.id,
|
|
response: { behavior: "allow" },
|
|
});
|
|
}
|
|
});
|
|
|
|
server.addHook("agent.create.before", async ({ request }) => {
|
|
return {
|
|
...request,
|
|
env: {
|
|
...request.env,
|
|
PASEO_HOOK_CREATE_EXAMPLE: "created",
|
|
},
|
|
};
|
|
});
|
|
|
|
server.addHook("agent.create.before", async ({ request }) => {
|
|
if (request.config.provider === "codex") {
|
|
return {
|
|
...request,
|
|
config: {
|
|
...request.config,
|
|
provider: "claude",
|
|
model: "haiku",
|
|
modeId: "default",
|
|
providerOptions: undefined,
|
|
},
|
|
};
|
|
}
|
|
return request;
|
|
});
|
|
|
|
server.addHook("agent.open.before", async ({ request }) => {
|
|
return {
|
|
...request,
|
|
env: {
|
|
...request.env,
|
|
PASEO_HOOK_OPEN_EXAMPLE: "opened",
|
|
},
|
|
};
|
|
});
|
|
|
|
return () => {};
|
|
}
|