Skip to content

fix(memos-local-openclaw): ship compiled JS for OpenClaw plugin loader (#1619)#1622

Open
fancyboi999 wants to merge 2 commits intoMemTensor:mainfrom
fancyboi999:fix/openclaw-plugin-1619-publish-compiled-output
Open

fix(memos-local-openclaw): ship compiled JS for OpenClaw plugin loader (#1619)#1622
fancyboi999 wants to merge 2 commits intoMemTensor:mainfrom
fancyboi999:fix/openclaw-plugin-1619-publish-compiled-output

Conversation

@fancyboi999
Copy link
Copy Markdown
Contributor

Summary

Closes #1619.

The @memtensor/memos-local-openclaw-plugin npm package was publishing TypeScript source only, so OpenClaw 2026.5.4's plugin loader rejected it with expected ./dist/index.js, ./dist/index.mjs, ./dist/index.cjs. Investigating the apps/memos-local-openclaw/ source surfaced three layers of misconfiguration that all had to be fixed together — just adding a build step would not have sufficed:

  1. tsconfig.json had rootDir: "src" + include: ["src"], so the OpenClaw plugin entry (root index.ts) was never in the compile graph at all. The pre-existing dist/index.js from npm run build was actually src/index.ts's output (a separate library-style entry), not the plugin entry — a silent footgun.
  2. package.json main / openclaw.extensions pointed at index.ts, prepublishOnly was a placeholder echo, and files did not include dist.
  3. The root entry uses import.meta.url, and several src/* files use bare __dirname. ESM-only on the entry side, CJS-only on the helper side — both had to be reconciled before any build output could actually load.

Changes

Layer What Why
Build config tsconfig.jsonrootDir: ".", include root index.ts, emit ESM (module: ESNext, moduleResolution: bundler, target: ES2022) Pull the actual plugin entry into the compile graph; produce ESM since the entry uses import.meta.url
Package metadata maindist/index.js; files includes dist; openclaw.extensions./dist/index.js; prepublishOnlyrm -rf dist && tsc && node scripts/fix-esm-imports.cjs Publish the compiled artifact OpenClaw's loader expects
Plugin manifest openclaw.plugin.json extensions./dist/index.js Same
Build post-process New scripts/fix-esm-imports.cjs (~50 lines, no new deps) moduleResolution: bundler emits relative imports without .js suffixes, but Node's native ESM loader requires them. Rewriting at build time keeps source clean
Core abstraction New src/shared/plugin-root.ts (findPluginRoot(import.meta.url)) The new dist/src/* layout is one level deeper than the old dist/*, so every hard-coded __dirname/../.. in bundled-memory-guide.ts, ensure-binding.ts, telemetry.ts, and viewer/server.ts would have silently pointed at the wrong directory. Marker-based lookup (walks up to a package.json whose name starts with memos-local) decouples runtime path resolution from emit layout. viewer/server.ts already had a 6-level local version of this — now consolidated
Type shim New src/openclaw-sdk.d.ts (declare module "openclaw/plugin-sdk") OpenClaw injects this at runtime; without a dev-time shim, strict tsc cannot compile the root entry
Strict-mode fixes index.ts — 5× (context: any) annotations, 1× ?? [] null guard The root entry had never been compiled under strict mode; minimal annotations matching the file's existing any style

Verification

$ rm -rf dist && npx tsc && node scripts/fix-esm-imports.cjs
[fix-esm-imports] rewrote imports in 32 file(s)

$ node --input-type=module -e "import('./dist/index.js').then(m => console.log('OK', m.default?.id, typeof m.default?.register))"
OK memos-local-openclaw-plugin function

$ npm pack --dry-run
package size: 486.4 kB
unpacked size: 2.6 MB
total files: 229   # dist/index.js (124 kB) + dist/src/** included
  • tsc compiles clean
  • Node 25 native ESM loader resolves dist/index.js, exporting {id, register, ...} — matches the OpenClaw plugin contract
  • npm pack now ships compiled artifacts; raw index.ts and src/*.ts no longer published
  • Test suite: 213 passed / 4 failed — verified against main baseline (same 4 pre-existing failures in accuracy.test.ts, task-processor.test.ts, update-install.test.ts); no regressions from this change

Test plan

  • Bump version (suggest 1.0.11 or 1.0.9-beta.2) and npm publish
  • Run the install script from the issue: curl -fsSL https://cdn.memtensor.com.cn/memos-local-openclaw/install.sh | bash
  • Confirm ~/.openclaw/extensions/memos-local-openclaw-plugin/dist/index.js exists
  • Restart gateway, confirm plugins.slots.memory resolves to memos-local-openclaw-plugin without the previous "plugin not found" error
  • Verify memory_search, memory_get, memory_viewer tools register correctly

MemTensor#1619)

The npm package previously published only TypeScript source, so
OpenClaw 2026.5.4's plugin loader rejected it with
"expected ./dist/index.js, ./dist/index.mjs, ./dist/index.cjs".

- tsconfig: rootDir=., include root index.ts, emit ESM (ES2022)
- package.json / openclaw.plugin.json: entry -> dist/index.js,
  files include dist, prepublishOnly does a clean tsc build
- scripts/fix-esm-imports.cjs: append .js suffix to relative imports
  in dist/ so Node's native ESM loader can resolve them
  (moduleResolution: bundler omits suffixes during emit)
- src/shared/plugin-root.ts: marker-based plugin-root lookup,
  replacing fragile __dirname/../.. paths that no longer match the
  new dist/src/* layout (4 call sites unified)
- src/openclaw-sdk.d.ts: dev-time type shim for openclaw/plugin-sdk
- index.ts: add type annotations + null guard so the previously
  uncompiled root entry passes strict-mode tsc

Verified: tsc compiles clean, fix-esm-imports rewrites 32 files,
Node 25 ESM loader resolves dist/index.js -> exports {id, register},
which matches OpenClaw's plugin contract.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes the OpenClaw plugin packaging/build pipeline for @memtensor/memos-local-openclaw-plugin so it publishes compiled ESM (dist/index.js + declarations) that OpenClaw’s plugin loader can actually load, and updates runtime path resolution to be stable across src/ vs dist/src/ layouts.

Changes:

  • Reconfigured TypeScript compilation to include the real plugin entry (index.ts) and emit ESM into dist/.
  • Updated package + OpenClaw manifests to reference ./dist/index.js, and ensured dist/ is included in the published npm package.
  • Added a post-build import-rewrite script and consolidated plugin-root path discovery via a shared helper.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
apps/memos-local-openclaw/tsconfig.json Switch to ESM output, include root index.ts, and adjust module resolution for bundler-style imports.
apps/memos-local-openclaw/package.json Publish compiled output (main/typesdist/*), ship dist/, and build on publish.
apps/memos-local-openclaw/openclaw.plugin.json Point OpenClaw manifest extensions at the compiled entry (./dist/index.js).
apps/memos-local-openclaw/index.ts Minimal strict-mode type/guard fixes so the real plugin entry compiles under strict.
apps/memos-local-openclaw/src/shared/plugin-root.ts New shared helper to find the plugin install root reliably across emit layouts.
apps/memos-local-openclaw/src/viewer/server.ts Replace fragile __dirname traversal with findPluginRoot(import.meta.url) usage.
apps/memos-local-openclaw/src/telemetry.ts Resolve telemetry credentials via plugin-root discovery instead of __dirname assumptions.
apps/memos-local-openclaw/src/storage/ensure-binding.ts Update plugin-root resolution for prebuild/native binding restore flow under ESM.
apps/memos-local-openclaw/src/skill/bundled-memory-guide.ts Resolve bundled skill markdown via plugin-root discovery for dist layout.
apps/memos-local-openclaw/src/openclaw-sdk.d.ts Add a dev-time module shim for the runtime-injected OpenClaw SDK.
apps/memos-local-openclaw/scripts/fix-esm-imports.cjs New post-build script to add .js suffixes required by Node’s native ESM loader.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/memos-local-openclaw/src/shared/plugin-root.ts
Comment thread apps/memos-local-openclaw/scripts/fix-esm-imports.cjs Outdated
…import rewrite

- plugin-root.ts: tighten the matching predicate from substring
  `includes("memos-local")` to an exact-match Set
  ({memos-local-openclaw-plugin, @memtensor/memos-local-openclaw-plugin}).
  In monorepo layouts the sibling `memos-local-plugin` could otherwise
  be selected as the root by accident.

- fix-esm-imports.cjs: extend regex to also rewrite side-effect
  imports (`import "./polyfills";`). Verified with a negative test
  that bare identifiers like `important` are not falsely matched.

Re-verified end-to-end: tsc clean, 32 files rewritten, Node 25 ESM
loader resolves dist/index.js -> exports {id, register}.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: npm package ships TypeScript source only — no compiled output (dist/)

2 participants