diff --git a/plugins/openclaw/README.md b/plugins/openclaw/README.md index 61d8dd36d..032bceb9d 100644 --- a/plugins/openclaw/README.md +++ b/plugins/openclaw/README.md @@ -13,15 +13,22 @@ This plugin can auto-start a local `headroom proxy` when needed. OpenClaw treats ## Local Development Install (Detection-Friendly) -If you are testing from this repo, run npm install/build from the plugin directory so local launcher detection aligns with runtime paths. The build now emits a self-contained `dist/` plugin root, so either of these linked installs works: +If you are testing from this repo, run npm install/build from the plugin directory so local launcher detection aligns with runtime paths. These linked installs are supported: ```bash cd plugins/openclaw npm install npm run build +openclaw plugins install --dangerously-force-unsafe-install --link . openclaw plugins install --dangerously-force-unsafe-install --link dist ``` +From the repo root, install the plugin directory explicitly: + +```bash +openclaw plugins install --dangerously-force-unsafe-install --link ./plugins/openclaw +``` + Or, from inside `dist/`: ```bash @@ -33,6 +40,7 @@ Why this matters: - The plugin checks launchers in this order: PATH -> local npm bin -> global npm -> python. - "local npm bin" means `plugins/openclaw/node_modules/.bin/headroom` relative to the source checkout. - Using `--link dist` (or `--link .` from `dist/`) still keeps runtime code adjacent to the checkout, and launcher detection falls back to PATH/global/python if a local npm bin is not present under the installed root. +- `plugins/openclaw` also carries a no-op hook shim so OpenClaw's hook-pack fallback treats the path as valid instead of emitting a misleading `package.json missing openclaw.hooks` warning. - If you install from a `.tgz`, local npm bin may not exist in the installed extension and detection will fall back to PATH/global/python. ## Configure diff --git a/plugins/openclaw/hook-shim/HOOK.md b/plugins/openclaw/hook-shim/HOOK.md new file mode 100644 index 000000000..cd4e3e5fc --- /dev/null +++ b/plugins/openclaw/hook-shim/HOOK.md @@ -0,0 +1,21 @@ +--- +name: headroom-link-shim +description: "No-op hook shim so local plugin source paths are also valid OpenClaw hook-pack paths." +metadata: + { + "openclaw": + { + "emoji": "🪝", + "events": ["command"], + }, + } +--- + +# Headroom Link Shim + +This hook intentionally does nothing. + +OpenClaw currently falls back to validating local plugin paths as hook packs when a +plugin install cannot proceed, such as when the plugin is already installed. +Including this no-op hook keeps `--link` installs from reporting a misleading +`package.json missing openclaw.hooks` error for valid Headroom plugin paths. diff --git a/plugins/openclaw/hook-shim/handler.js b/plugins/openclaw/hook-shim/handler.js new file mode 100644 index 000000000..51941f5a3 --- /dev/null +++ b/plugins/openclaw/hook-shim/handler.js @@ -0,0 +1,3 @@ +export default async function headroomLinkShim() { + return undefined; +} diff --git a/plugins/openclaw/package.json b/plugins/openclaw/package.json index c34372ad7..def40a74e 100644 --- a/plugins/openclaw/package.json +++ b/plugins/openclaw/package.json @@ -7,6 +7,7 @@ "types": "./dist/index.d.ts", "files": [ "dist", + "hook-shim", "openclaw.plugin.json", "README.md" ], @@ -34,6 +35,9 @@ "vitest": "^2.0.0" }, "openclaw": { + "hooks": [ + "./hook-shim" + ], "extensions": [ "./dist/index.js" ], diff --git a/plugins/openclaw/prepare-dist.mjs b/plugins/openclaw/prepare-dist.mjs index a431bffd5..6fa9aa3c5 100644 --- a/plugins/openclaw/prepare-dist.mjs +++ b/plugins/openclaw/prepare-dist.mjs @@ -22,6 +22,7 @@ const distPackage = { peerDependencies: rootPackage.peerDependencies, peerDependenciesMeta: rootPackage.peerDependenciesMeta, openclaw: { + hooks: ["./hook-shim"], extensions: ["./index.js"], capabilities: rootPackage.openclaw?.capabilities ?? {}, }, @@ -40,4 +41,16 @@ await Promise.all([ path.join(distDir, "openclaw.plugin.json"), ), fs.copyFile(path.join(rootDir, "README.md"), path.join(distDir, "README.md")), + fs.mkdir(path.join(distDir, "hook-shim"), { recursive: true }), +]); + +await Promise.all([ + fs.copyFile( + path.join(rootDir, "hook-shim", "HOOK.md"), + path.join(distDir, "hook-shim", "HOOK.md"), + ), + fs.copyFile( + path.join(rootDir, "hook-shim", "handler.js"), + path.join(distDir, "hook-shim", "handler.js"), + ), ]);