From b79cc1eb847ee34e5eb20c09e2bf470eb34f8195 Mon Sep 17 00:00:00 2001 From: zhi Date: Tue, 3 Mar 2026 18:16:47 +0000 Subject: [PATCH 1/4] fix: use api.resolvePath for plugin directory - Replace import.meta.url with api.resolvePath('.') for reliable path resolution - Fixes no-reply API not starting due to incorrect pluginDir calculation --- plugin/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugin/index.ts b/plugin/index.ts index eb2748e..350fe85 100644 --- a/plugin/index.ts +++ b/plugin/index.ts @@ -508,7 +508,8 @@ export default { ensurePolicyStateLoaded(api, liveAtRegister); // Resolve plugin directory for locating sibling modules (no-reply-api/) - const pluginDir = path.dirname(new URL(import.meta.url).pathname); + // Use api.resolvePath to get the actual plugin directory in OpenClaw environment + const pluginDir = api.resolvePath("."); // Gateway lifecycle: start/stop no-reply API and moderator bot with the gateway api.on("gateway_start", () => { From a177150554755a914b87d5b7fadc1f5dca11016c Mon Sep 17 00:00:00 2001 From: zhi Date: Tue, 3 Mar 2026 18:20:48 +0000 Subject: [PATCH 2/4] fix(install): uninstall always deletes plugin entry - For uninstall, always delete plugins.entries.dirigent - Don't try to restore old config (which may fail validation due to missing required fields) - Provider restoration still works (replaced providers are restored) --- scripts/install-dirigent-openclaw.mjs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/install-dirigent-openclaw.mjs b/scripts/install-dirigent-openclaw.mjs index 2623702..149f6fa 100755 --- a/scripts/install-dirigent-openclaw.mjs +++ b/scripts/install-dirigent-openclaw.mjs @@ -318,13 +318,14 @@ else { } } - // ── Handle REPLACED entries: restore old value ──────────────────────── + // ── Handle REPLACED entries: for uninstall, we still delete (not restore) + // because the user wants to remove the plugin, not restore the old broken config if (delta.replaced[PATH_PLUGIN_ENTRY] !== undefined) { const plugins = getJson("plugins") || {}; plugins.entries = plugins.entries || {}; - plugins.entries.dirigent = delta.replaced[PATH_PLUGIN_ENTRY]; + delete plugins.entries.dirigent; setJson("plugins", plugins); - console.log("[dirigent] restored previous plugins.entries.dirigent"); + console.log("[dirigent] removed plugins.entries.dirigent (had replaced previous config)"); } if (delta.replaced[PATH_PROVIDER_ENTRY] !== undefined) { From cd0ce6a910a77cdb4c8ec62f6445f3d43986fdc0 Mon Sep 17 00:00:00 2001 From: zhi Date: Tue, 3 Mar 2026 18:23:01 +0000 Subject: [PATCH 3/4] fix(install): use unsetPath for plugin entry removal - Use openclaw config unset instead of get-modify-set - Avoids triggering full plugins config validation - Handles both added and replaced entries uniformly --- scripts/install-dirigent-openclaw.mjs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/scripts/install-dirigent-openclaw.mjs b/scripts/install-dirigent-openclaw.mjs index 149f6fa..64ea4ba 100755 --- a/scripts/install-dirigent-openclaw.mjs +++ b/scripts/install-dirigent-openclaw.mjs @@ -280,11 +280,8 @@ else { try { // ── Handle ADDED entries: remove them ───────────────────────────────── - if (delta.added[PATH_PLUGIN_ENTRY] !== undefined) { - const plugins = getJson("plugins") || {}; - plugins.entries = plugins.entries || {}; - delete plugins.entries.dirigent; - setJson("plugins", plugins); + if (delta.added[PATH_PLUGIN_ENTRY] !== undefined || delta.replaced[PATH_PLUGIN_ENTRY] !== undefined) { + unsetPath(PATH_PLUGIN_ENTRY); console.log("[dirigent] removed plugins.entries.dirigent"); } @@ -318,16 +315,7 @@ else { } } - // ── Handle REPLACED entries: for uninstall, we still delete (not restore) - // because the user wants to remove the plugin, not restore the old broken config - if (delta.replaced[PATH_PLUGIN_ENTRY] !== undefined) { - const plugins = getJson("plugins") || {}; - plugins.entries = plugins.entries || {}; - delete plugins.entries.dirigent; - setJson("plugins", plugins); - console.log("[dirigent] removed plugins.entries.dirigent (had replaced previous config)"); - } - + // ── Handle REPLACED provider: restore old value ─────────────────────── if (delta.replaced[PATH_PROVIDER_ENTRY] !== undefined) { const providers = getJson(PATH_PROVIDERS) || {}; providers[NO_REPLY_PROVIDER_ID] = delta.replaced[PATH_PROVIDER_ENTRY]; From 92799176bf445e1be0b40cd0861317450a3e72e7 Mon Sep 17 00:00:00 2001 From: zhi Date: Tue, 3 Mar 2026 18:28:44 +0000 Subject: [PATCH 4/4] fix(install): fix uninstall order to satisfy config validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove from plugins.allow BEFORE deleting plugins.entries.dirigent - OpenClaw validates that allow[] entries must exist in entries{} - New order: allow → entry → paths → provider --- scripts/install-dirigent-openclaw.mjs | 37 +++++++++++++++------------ 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/scripts/install-dirigent-openclaw.mjs b/scripts/install-dirigent-openclaw.mjs index 64ea4ba..d5fb9c5 100755 --- a/scripts/install-dirigent-openclaw.mjs +++ b/scripts/install-dirigent-openclaw.mjs @@ -279,19 +279,25 @@ else { const delta = rec.delta || { added: {}, replaced: {}, removed: {} }; try { - // ── Handle ADDED entries: remove them ───────────────────────────────── + // ── IMPORTANT: Order matters for OpenClaw config validation ──────────── + // 1. First remove from allow (before deleting entry, otherwise validation fails) + if (delta.added[PATH_PLUGINS_ALLOW] !== undefined) { + const allowList = getJson(PATH_PLUGINS_ALLOW) || []; + const idx = allowList.indexOf("dirigent"); + if (idx !== -1) { + allowList.splice(idx, 1); + setJson(PATH_PLUGINS_ALLOW, allowList); + console.log("[dirigent] removed 'dirigent' from plugins.allow"); + } + } + + // 2. Then remove entry if (delta.added[PATH_PLUGIN_ENTRY] !== undefined || delta.replaced[PATH_PLUGIN_ENTRY] !== undefined) { unsetPath(PATH_PLUGIN_ENTRY); console.log("[dirigent] removed plugins.entries.dirigent"); } - if (delta.added[PATH_PROVIDER_ENTRY] !== undefined) { - const providers = getJson(PATH_PROVIDERS) || {}; - delete providers[NO_REPLY_PROVIDER_ID]; - setJson(PATH_PROVIDERS, providers); - console.log(`[dirigent] removed models.providers.${NO_REPLY_PROVIDER_ID}`); - } - + // 3. Then remove plugin path (after entry is gone) if (delta.added[PATH_PLUGINS_LOAD] !== undefined) { const plugins = getJson("plugins") || {}; const paths = plugins.load?.paths || []; @@ -304,15 +310,12 @@ else { } } - // ── Handle plugins.allow ────────────────────────────────────────────── - if (delta.added[PATH_PLUGINS_ALLOW] !== undefined) { - const allowList = getJson(PATH_PLUGINS_ALLOW) || []; - const idx = allowList.indexOf("dirigent"); - if (idx !== -1) { - allowList.splice(idx, 1); - setJson(PATH_PLUGINS_ALLOW, allowList); - console.log("[dirigent] removed 'dirigent' from plugins.allow"); - } + // 4. Finally remove provider + if (delta.added[PATH_PROVIDER_ENTRY] !== undefined) { + const providers = getJson(PATH_PROVIDERS) || {}; + delete providers[NO_REPLY_PROVIDER_ID]; + setJson(PATH_PROVIDERS, providers); + console.log(`[dirigent] removed models.providers.${NO_REPLY_PROVIDER_ID}`); } // ── Handle REPLACED provider: restore old value ───────────────────────