Spaces:
Build error
Build error
Merge pull request #106 from JerrettDavis/fix/openclaw-local-install-hook
Browse files
plugins/openclaw/README.md
CHANGED
|
@@ -21,23 +21,40 @@ This plugin can auto-start a local `headroom proxy` when needed. OpenClaw treats
|
|
| 21 |
|
| 22 |
## Local Development Install (Detection-Friendly)
|
| 23 |
|
| 24 |
-
If you are testing from this repo, run npm install/build from the plugin directory so local launcher detection aligns with runtime paths:
|
| 25 |
|
| 26 |
```bash
|
| 27 |
cd plugins/openclaw
|
| 28 |
npm install
|
| 29 |
npm run build
|
| 30 |
openclaw plugins install --dangerously-force-unsafe-install --link .
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
```
|
| 32 |
|
| 33 |
Why this matters:
|
| 34 |
- The plugin checks launchers in this order: PATH -> local npm bin -> global npm -> python.
|
| 35 |
-
- "local npm bin" means `plugins/openclaw/node_modules/.bin/headroom` relative to the
|
| 36 |
-
- Using `--link .` from `
|
|
|
|
| 37 |
- 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.
|
| 38 |
|
| 39 |
## Configure
|
| 40 |
|
|
|
|
|
|
|
| 41 |
```json
|
| 42 |
{
|
| 43 |
"plugins": {
|
|
|
|
| 21 |
|
| 22 |
## Local Development Install (Detection-Friendly)
|
| 23 |
|
| 24 |
+
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:
|
| 25 |
|
| 26 |
```bash
|
| 27 |
cd plugins/openclaw
|
| 28 |
npm install
|
| 29 |
npm run build
|
| 30 |
openclaw plugins install --dangerously-force-unsafe-install --link .
|
| 31 |
+
openclaw plugins install --dangerously-force-unsafe-install --link dist
|
| 32 |
+
```
|
| 33 |
+
|
| 34 |
+
From the repo root, install the plugin directory explicitly:
|
| 35 |
+
|
| 36 |
+
```bash
|
| 37 |
+
openclaw plugins install --dangerously-force-unsafe-install --link ./plugins/openclaw
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
Or, from inside `dist/`:
|
| 41 |
+
|
| 42 |
+
```bash
|
| 43 |
+
cd plugins/openclaw/dist
|
| 44 |
+
openclaw plugins install --dangerously-force-unsafe-install --link .
|
| 45 |
```
|
| 46 |
|
| 47 |
Why this matters:
|
| 48 |
- The plugin checks launchers in this order: PATH -> local npm bin -> global npm -> python.
|
| 49 |
+
- "local npm bin" means `plugins/openclaw/node_modules/.bin/headroom` relative to the source checkout.
|
| 50 |
+
- 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.
|
| 51 |
+
- `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.
|
| 52 |
- 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.
|
| 53 |
|
| 54 |
## Configure
|
| 55 |
|
| 56 |
+
Install automatically selects the `contextEngine` slot for `headroom` on current OpenClaw releases. If you need to switch back manually, set `plugins.slots.contextEngine` to `"legacy"` or another engine id.
|
| 57 |
+
|
| 58 |
```json
|
| 59 |
{
|
| 60 |
"plugins": {
|
plugins/openclaw/hook-shim/HOOK.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: headroom-link-shim
|
| 3 |
+
description: "No-op hook shim so local plugin source paths are also valid OpenClaw hook-pack paths."
|
| 4 |
+
metadata:
|
| 5 |
+
{
|
| 6 |
+
"openclaw":
|
| 7 |
+
{
|
| 8 |
+
"emoji": "🪝",
|
| 9 |
+
"events": ["command"],
|
| 10 |
+
},
|
| 11 |
+
}
|
| 12 |
+
---
|
| 13 |
+
|
| 14 |
+
# Headroom Link Shim
|
| 15 |
+
|
| 16 |
+
This hook intentionally does nothing.
|
| 17 |
+
|
| 18 |
+
OpenClaw currently falls back to validating local plugin paths as hook packs when a
|
| 19 |
+
plugin install cannot proceed, such as when the plugin is already installed.
|
| 20 |
+
Including this no-op hook keeps `--link` installs from reporting a misleading
|
| 21 |
+
`package.json missing openclaw.hooks` error for valid Headroom plugin paths.
|
plugins/openclaw/hook-shim/handler.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export default async function headroomLinkShim() {
|
| 2 |
+
return undefined;
|
| 3 |
+
}
|
plugins/openclaw/openclaw.plugin.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
{
|
| 2 |
"id": "headroom",
|
|
|
|
| 3 |
"uiHints": {
|
| 4 |
"proxyUrl": {
|
| 5 |
"label": "Proxy URL",
|
|
|
|
| 1 |
{
|
| 2 |
"id": "headroom",
|
| 3 |
+
"kind": "context-engine",
|
| 4 |
"uiHints": {
|
| 5 |
"proxyUrl": {
|
| 6 |
"label": "Proxy URL",
|
plugins/openclaw/package.json
CHANGED
|
@@ -7,11 +7,12 @@
|
|
| 7 |
"types": "./dist/index.d.ts",
|
| 8 |
"files": [
|
| 9 |
"dist",
|
|
|
|
| 10 |
"openclaw.plugin.json",
|
| 11 |
"README.md"
|
| 12 |
],
|
| 13 |
"scripts": {
|
| 14 |
-
"build": "tsup",
|
| 15 |
"test": "vitest run",
|
| 16 |
"test:watch": "vitest",
|
| 17 |
"typecheck": "tsc --noEmit"
|
|
@@ -34,12 +35,9 @@
|
|
| 34 |
"vitest": "^2.0.0"
|
| 35 |
},
|
| 36 |
"openclaw": {
|
| 37 |
-
"hooks":
|
| 38 |
-
"
|
| 39 |
-
|
| 40 |
-
"dist/index.js"
|
| 41 |
-
]
|
| 42 |
-
},
|
| 43 |
"extensions": [
|
| 44 |
"./dist/index.js"
|
| 45 |
],
|
|
|
|
| 7 |
"types": "./dist/index.d.ts",
|
| 8 |
"files": [
|
| 9 |
"dist",
|
| 10 |
+
"hook-shim",
|
| 11 |
"openclaw.plugin.json",
|
| 12 |
"README.md"
|
| 13 |
],
|
| 14 |
"scripts": {
|
| 15 |
+
"build": "tsup && node prepare-dist.mjs",
|
| 16 |
"test": "vitest run",
|
| 17 |
"test:watch": "vitest",
|
| 18 |
"typecheck": "tsc --noEmit"
|
|
|
|
| 35 |
"vitest": "^2.0.0"
|
| 36 |
},
|
| 37 |
"openclaw": {
|
| 38 |
+
"hooks": [
|
| 39 |
+
"./hook-shim"
|
| 40 |
+
],
|
|
|
|
|
|
|
|
|
|
| 41 |
"extensions": [
|
| 42 |
"./dist/index.js"
|
| 43 |
],
|
plugins/openclaw/prepare-dist.mjs
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import fs from "node:fs/promises";
|
| 2 |
+
import path from "node:path";
|
| 3 |
+
import { fileURLToPath } from "node:url";
|
| 4 |
+
|
| 5 |
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
| 6 |
+
const rootDir = __dirname;
|
| 7 |
+
const distDir = path.join(rootDir, "dist");
|
| 8 |
+
|
| 9 |
+
const rootPackage = JSON.parse(
|
| 10 |
+
await fs.readFile(path.join(rootDir, "package.json"), "utf8"),
|
| 11 |
+
);
|
| 12 |
+
|
| 13 |
+
const distPackage = {
|
| 14 |
+
name: rootPackage.name,
|
| 15 |
+
version: rootPackage.version,
|
| 16 |
+
description: rootPackage.description,
|
| 17 |
+
type: rootPackage.type,
|
| 18 |
+
main: "./index.js",
|
| 19 |
+
types: "./index.d.ts",
|
| 20 |
+
license: rootPackage.license,
|
| 21 |
+
dependencies: rootPackage.dependencies,
|
| 22 |
+
peerDependencies: rootPackage.peerDependencies,
|
| 23 |
+
peerDependenciesMeta: rootPackage.peerDependenciesMeta,
|
| 24 |
+
openclaw: {
|
| 25 |
+
hooks: ["./hook-shim"],
|
| 26 |
+
extensions: ["./index.js"],
|
| 27 |
+
capabilities: rootPackage.openclaw?.capabilities ?? {},
|
| 28 |
+
},
|
| 29 |
+
};
|
| 30 |
+
|
| 31 |
+
await fs.mkdir(distDir, { recursive: true });
|
| 32 |
+
await fs.writeFile(
|
| 33 |
+
path.join(distDir, "package.json"),
|
| 34 |
+
`${JSON.stringify(distPackage, null, 2)}\n`,
|
| 35 |
+
"utf8",
|
| 36 |
+
);
|
| 37 |
+
|
| 38 |
+
await Promise.all([
|
| 39 |
+
fs.copyFile(
|
| 40 |
+
path.join(rootDir, "openclaw.plugin.json"),
|
| 41 |
+
path.join(distDir, "openclaw.plugin.json"),
|
| 42 |
+
),
|
| 43 |
+
fs.copyFile(path.join(rootDir, "README.md"), path.join(distDir, "README.md")),
|
| 44 |
+
fs.mkdir(path.join(distDir, "hook-shim"), { recursive: true }),
|
| 45 |
+
]);
|
| 46 |
+
|
| 47 |
+
await Promise.all([
|
| 48 |
+
fs.copyFile(
|
| 49 |
+
path.join(rootDir, "hook-shim", "HOOK.md"),
|
| 50 |
+
path.join(distDir, "hook-shim", "HOOK.md"),
|
| 51 |
+
),
|
| 52 |
+
fs.copyFile(
|
| 53 |
+
path.join(rootDir, "hook-shim", "handler.js"),
|
| 54 |
+
path.join(distDir, "hook-shim", "handler.js"),
|
| 55 |
+
),
|
| 56 |
+
]);
|