Skip to content

fix: compile bundled hook handlers during build#11488

Closed
ssh-22-dev wants to merge 5 commits intoopenclaw:mainfrom
ssh-22-dev:fix/build-bundled-hooks
Closed

fix: compile bundled hook handlers during build#11488
ssh-22-dev wants to merge 5 commits intoopenclaw:mainfrom
ssh-22-dev:fix/build-bundled-hooks

Conversation

@ssh-22-dev
Copy link

@ssh-22-dev ssh-22-dev commented Feb 7, 2026

Summary

Fixes #11348. Bundled hook handler.ts files are not compiled to handler.js during build, causing all hooks to fail on npm/git installs.

lobster-biscuit

Repro Steps

  1. npm install -g openclaw@latest (or clone + pnpm build)
  2. ls dist/hooks/bundled/session-memory/ → only HOOK.md, no handler.js
  3. openclaw hooks list --verbose → "No hooks found"

Root Cause

tsdown.config.ts only compiles main entry points. scripts/copy-hook-metadata.ts copies HOOK.md but never compiles handler.tshandler.js. Hook discovery requires handler.js to exist.

Behavior Changes

  • New build step: scripts/build-hooks.ts runs after tsdown
  • Compiles src/hooks/bundled/*/handler.tsdist/hooks/bundled/*/handler.js
  • Hooks now discoverable on npm/git installs

Codebase and GitHub Search

Tests

  • No new tests added (build script)
  • Existing hook tests pass

Manual Testing

Prerequisites
  • Clean clone of repo
Steps
  1. pnpm install && pnpm build
  2. ls dist/hooks/bundled/*/handler.js — should list handler files
  3. openclaw hooks list --verbose — should show hooks as "ready"

Evidence

Verified on VPS with npm global install — hooks now load correctly.

Sign-Off

  • Models used: Claude Opus 4.5
  • Submitter effort: Discovered issue independently while debugging hooks on VPS, diagnosed root cause, implemented fix
  • Agent notes: Claude assisted with esbuild configuration, PR formatting, and addressing Greptile review comments.

Greptile Overview

Greptile Summary

This PR updates the build pipeline to ensure bundled hook handlers are included in published artifacts. It adds a new scripts/build-hooks.ts step (run after tsdown) that scans src/hooks/bundled/*/handler.ts and uses esbuild to emit dist/hooks/bundled/*/handler.js, so hook discovery works on npm/git installs where only dist/** is present.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk.
  • Changes are isolated to the build pipeline and a new script that compiles bundled hook handlers; the script includes existence checks and creates output directories before invoking esbuild, and the Node target aligns with the repo’s Node engine baseline (>=22).
  • No files require special attention

Bundled hooks (session-memory, command-logger, etc.) have handler.ts
files that were never compiled to handler.js during build. Only HOOK.md
metadata was copied. This caused "No hooks found" on all npm/git installs.

Add scripts/build-hooks.ts to compile handlers with esbuild after tsdown.

Fixes openclaw#11348
@openclaw-barnacle openclaw-barnacle bot added the scripts Repository scripts label Feb 7, 2026
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

package.json Outdated
"android:run": "cd apps/android && ./gradlew :app:installDebug && adb shell am start -n ai.openclaw.android/.MainActivity",
"android:test": "cd apps/android && ./gradlew :app:testDebugUnitTest",
"build": "pnpm canvas:a2ui:bundle && tsdown && pnpm build:plugin-sdk:dts && node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-compat.ts",
"build": "pnpm canvas:a2ui:bundle && tsdown && node --import tsx scripts/build-hooks.ts && pnpm build:plugin-sdk:dts && node --import tsx scripts/write-plugin-sdk-entry-dts.ts && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/write-build-info.ts && node --import tsx scripts/write-cli-compat.ts",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace in script

The build script line ends with extra spaces after the closing quote, which will fail formatting checks in repos that enforce JSON formatting (and adds noise to diffs). Please remove the trailing whitespace at the end of this line.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: package.json
Line: 35:35

Comment:
**Trailing whitespace in script**

The `build` script line ends with extra spaces after the closing quote, which will fail formatting checks in repos that enforce JSON formatting (and adds noise to diffs). Please remove the trailing whitespace at the end of this line.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 13 to 14
const HOOKS_SRC = "src/hooks/bundled";
const HOOKS_DIST = "dist/hooks/bundled";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CWD-dependent paths

HOOKS_SRC/HOOKS_DIST are relative paths, so running this script from anywhere other than repo root will read/write the wrong locations. Since it’s wired into pnpm build this usually works, but it will break if the build pipeline invokes it with a different working directory. Anchoring these paths to the project root (like copy-hook-metadata.ts does) avoids that class of build failures.

Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/build-hooks.ts
Line: 13:14

Comment:
**CWD-dependent paths**

`HOOKS_SRC`/`HOOKS_DIST` are relative paths, so running this script from anywhere other than repo root will read/write the wrong locations. Since it’s wired into `pnpm build` this usually works, but it will break if the build pipeline invokes it with a different working directory. Anchoring these paths to the project root (like `copy-hook-metadata.ts` does) avoids that class of build failures.

How can I resolve this? If you propose a fix, please make it concise.

@ssh-22-dev
Copy link
Author

@greptile-apps can you check again to see if the issues are resolved?

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +54 to +56
outfile: join(HOOKS_DIST, hook, "handler.js"),
external: EXTERNAL_DEPS,
logLevel: "warning",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing output directory

outfile targets dist/hooks/bundled/${hook}/handler.js, but this script never creates dist/hooks/bundled/${hook} (or even dist/hooks/bundled) beforehand. On a clean build where those directories don’t exist, esbuild will fail with ENOENT and this script will eventually process.exit(1), breaking pnpm build and still not emitting handler files. Create the output dir (e.g., mkdirSync(join(HOOKS_DIST, hook), { recursive: true })) before calling build().

Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/build-hooks.ts
Line: 54:56

Comment:
**Missing output directory**

`outfile` targets `dist/hooks/bundled/${hook}/handler.js`, but this script never creates `dist/hooks/bundled/${hook}` (or even `dist/hooks/bundled`) beforehand. On a clean build where those directories don’t exist, esbuild will fail with ENOENT and this script will eventually `process.exit(1)`, breaking `pnpm build` and still not emitting handler files. Create the output dir (e.g., `mkdirSync(join(HOOKS_DIST, hook), { recursive: true })`) before calling `build()`.


How can I resolve this? If you propose a fix, please make it concise.

esbuild fails with ENOENT on clean builds when dist/hooks/bundled/<hook>
doesn't exist. Add mkdirSync with recursive flag before build call.
@ssh-22-dev
Copy link
Author

@greptile-apps another go at this, please?

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@ssh-22-dev
Copy link
Author

@greptile-apps The project's engines.node is >=22.12.0, so target: "node22" is aligned with the minimum supported version. One final check, please.

@tariqc80
Copy link

tariqc80 commented Feb 8, 2026

I had a branch I was ready to push to fix this then saw you got it. Thanks!

@ssh-22-dev
Copy link
Author

Closing in favor of #9295 which takes a cleaner approach (native tsdown entries vs. separate esbuild script) and fixes both the path resolution and handler compilation issues in one PR. Thanks @patrickshao!

@ssh-22-dev ssh-22-dev closed this Feb 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scripts Repository scripts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Bundled hook handler files not compiled to dist (npm global install)

2 participants

Comments