FN-7397: pass plugin context to lifecycle hooks
Ensure task lifecycle plugin hooks receive a PluginContext when fired through runtime event bridges. - Append the plugin context for task-created, task-moved, and task-completed hooks when callers only provide raw lifecycle arguments. - Preserve existing explicit-context hook calls and add coverage for loader and runner lifecycle dispatch paths. - Cover Compound Engineering sync completion handling so taskStore is available in onTaskCompleted. Files changed: .changeset/fn-7397-plugin-hook-context.md | 7 +++ packages/core/src/__tests__/plugin-loader.test.ts | 52 +++++++++++++++++++++- packages/core/src/plugin-loader.ts | 34 +++++++++++++- .../engine/src/__tests__/plugin-runner.test.ts | 25 ++++++++++- .../src/__tests__/sync.test.ts | 29 +++++++++++- 5 files changed, 141 insertions(+), 6 deletions(-) Fusion-Task-Id: FN-7397 Fusion-Task-Lineage: 7661714c-cf2a-4f4d-bec1-fc6bc11c0613 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
@@ -4,7 +4,7 @@ import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { InteractiveAiSessionEvent, PluginContext, Task } from "@fusion/core";
|
||||
import { TaskStore } from "@fusion/core";
|
||||
import { PluginLoader, PluginStore, TaskStore } from "@fusion/core";
|
||||
import plugin, {
|
||||
CeOrchestrator,
|
||||
CE_PLUGIN_ID,
|
||||
@@ -137,6 +137,33 @@ describe("U8 inbound hooks (board → pipeline)", () => {
|
||||
// The hook awaits NOTHING heavy; it returns synchronously-ish.
|
||||
expect(Date.now() - start).toBeLessThan(1000);
|
||||
});
|
||||
|
||||
it("runtime loader invocation gives onTaskCompleted a context and enqueues task_completed sync", async () => {
|
||||
const pluginStore = new PluginStore(rootDir, { inMemoryDb: true, centralGlobalDir: rootDir });
|
||||
await pluginStore.init();
|
||||
await pluginStore.registerPlugin({
|
||||
manifest: plugin.manifest,
|
||||
path: join(rootDir, "compound-engineering.js"),
|
||||
settings: { reconcileOnHooks: false },
|
||||
});
|
||||
const loader = new PluginLoader({ pluginStore, taskStore });
|
||||
(loader as unknown as { plugins: Map<string, typeof plugin> }).plugins.set(CE_PLUGIN_ID, plugin);
|
||||
|
||||
const { task } = await landPipeline("plan");
|
||||
await moveTo(task.id, "done");
|
||||
await expect(loader.invokeHook("onTaskCompleted", { ...task, column: "done" })).resolves.toBeUndefined();
|
||||
|
||||
const installed = await pluginStore.getPlugin(CE_PLUGIN_ID);
|
||||
expect(installed.state).not.toBe("error");
|
||||
const pending = getCePipelineStore(ctx).listPendingSync();
|
||||
expect(pending).toContainEqual(expect.objectContaining({
|
||||
taskId: task.id,
|
||||
reason: "task_completed",
|
||||
fromColumn: null,
|
||||
toColumn: "done",
|
||||
processedAt: null,
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("U8 reconciler (convergence + outbound)", () => {
|
||||
|
||||
Reference in New Issue
Block a user