From 62905ca47236cfe831fd052aecb311a0e5f95d59 Mon Sep 17 00:00:00 2001 From: Eva Date: Mon, 4 May 2026 03:33:55 +0700 Subject: [PATCH] fix: allow run context during activation --- .../run-context-lifecycle.contract.test.ts | 33 +++++++++++++++++++ src/plugins/registry.ts | 9 ++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/plugins/contracts/run-context-lifecycle.contract.test.ts b/src/plugins/contracts/run-context-lifecycle.contract.test.ts index 0f2148b563e..b1c9a77f86d 100644 --- a/src/plugins/contracts/run-context-lifecycle.contract.test.ts +++ b/src/plugins/contracts/run-context-lifecycle.contract.test.ts @@ -118,6 +118,39 @@ describe("plugin run context lifecycle", () => { ).toEqual({ restored: true }); }); + it("allows run-context initialization during activating plugin registration", () => { + const { config, registry } = createPluginRegistryFixture(); + const api = registry.createApi( + createPluginRecord({ + id: "registration-run-context-plugin", + name: "Registration Run Context Plugin", + }), + { config }, + ); + + expect( + api.setRunContext({ + runId: "run-registration", + namespace: "state", + value: { initialized: true }, + }), + ).toBe(true); + expect( + getPluginRunContext({ + pluginId: "registration-run-context-plugin", + get: { runId: "run-registration", namespace: "state" }, + }), + ).toEqual({ initialized: true }); + + api.clearRunContext({ runId: "run-registration", namespace: "state" }); + expect( + getPluginRunContext({ + pluginId: "registration-run-context-plugin", + get: { runId: "run-registration", namespace: "state" }, + }), + ).toBeUndefined(); + }); + it("keeps restored active registry state after stale async cleanup finishes", async () => { let releaseCleanup: (() => void) | undefined; let markCleanupStarted: (() => void) | undefined; diff --git a/src/plugins/registry.ts b/src/plugins/registry.ts index 940b9a1eb69..6ce09bb6f9b 100644 --- a/src/plugins/registry.ts +++ b/src/plugins/registry.ts @@ -2194,10 +2194,17 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) { const registrationCapabilities = resolvePluginRegistrationCapabilities(registrationMode); pluginRuntimeRecordById.set(record.id, record); const sideEffectGuard = createPluginSideEffectGuard(record.id); + const isLoadedRecordInRegistry = () => + registry.plugins.some((plugin) => plugin.id === record.id && plugin.status === "loaded"); + const isActivatingLoadedRecord = () => + registryParams.activateGlobalSideEffects !== false && + record.enabled && + record.status === "loaded" && + !registry.plugins.some((plugin) => plugin.id === record.id); const shouldCommitWorkflowSideEffect = () => sideEffectGuard.active && !isPluginRegistryRetired(registry) && - registry.plugins.some((plugin) => plugin.id === record.id && plugin.status === "loaded"); + (isLoadedRecordInRegistry() || isActivatingLoadedRecord()); return buildPluginApi({ id: record.id, name: record.name,