Skip to content
3 min read · 637 words

Function: __resolveWrapperPathViaSelfReference() ​

ts
function __resolveWrapperPathViaSelfReference(
  wrapperBasename: string,
  seams?: SelfReferenceResolutionSeams,
): Promise<SelfReferenceResolution>;

Defined in: src/batteries/llm/claude_code_cli/adapter.ts:224

Resolve the wrapper asset's sibling path relative to THIS PACKAGE's own already-published main entry, rather than relative to the (possibly relocated-by-bundling) adapter module. Node's package self-reference feature — a package resolving its own name as a bare specifier — is depth-independent within @nhtio/adk's own tree, so this survives the adapter code being moved around WITHIN the package by a bundler. It only breaks once the calling code has been physically bundled OUTSIDE @nhtio/adk's own directory tree (e.g. into a consumer's Electron main-process bundle) — at that point self-reference falls back to ordinary node_modules bare-specifier resolution, which succeeds exactly when @nhtio/adk is still installed as a resolvable dependency from the bundled code's new location. That is the same "normal case" the published wrapperPath override already exists for, so this fallback is a strict improvement with no new failure mode: when it can't resolve, behavior degrades to the pre-existing "throw a clear error" path below rather than a worse outcome.

Deliberately resolves this package's exports['.'] main entry (already published, no exports map change needed) and derives the wrapper's path as a sibling of that entry's directory — every vite.config.mts build.lib.entry key (including the un-tagged wrapper) emits to a flat dist/ directory, so dirname(mainEntry) === dirname(wrapperAsset).

Two independent ways to reach a require-like resolver are tried, in this order, because a bundled consumer may land in either shape and each leaves the OTHER unusable:

  1. A real ambient require — present when THIS MODULE has itself been bundled into a CJS output (e.g. esbuild --platform=node --format=cjs, which is common for an Electron main-process bundle, the issue's reported scenario). Reused verbatim is the exact same discriminator resolveDefaultWrapperPath above already documents: typeof require === 'function' && typeof require.resolve === 'function' — because a bundled ESM output can ALSO leave a truthy require behind as a dynamic-require shim/Proxy (rolldown and esbuild both do this) whose .resolve is not itself a function, and calling it would throw rather than genuinely resolving anything. In a genuine CJS bundle this ambient require.resolve('@nhtio/adk') works directly with no createRequire bridge needed.
  2. createRequire(import.meta.url) — the ESM path, used only when step 1 didn't yield a usable resolver. Verified empirically that esbuild's --format=cjs output rewrites every import.meta reference in bundled source to a plain var import_meta = {}, so import.meta.url is undefined there — createRequire(undefined) throws ERR_INVALID_ARG_VALUE outright, so this branch is skipped by checking typeof import.meta.url === 'string' first rather than letting that throw surface as an opaque, unrelated-looking error. createRequire (rather than import.meta.resolve) is used here because — unlike import.meta.resolve — its .resolve performs a real filesystem existence check (verified directly: import.meta.resolve happily returns a URL for a target file that does not exist, since it only resolves the exports map syntactically; require.resolve, including through createRequire, throws MODULE_NOT_FOUND for a missing target), so a resolved path here is already known to exist and only the derived wrapper sibling still needs its own explicit check below.

tried always accounts for BOTH routes once step 1 has not already produced a mainEntry: step 2 either resolves, records its own failure, or — when import.meta.url isn't even a string — records an explicit "skipped: import.meta.url unavailable" entry, so the thrown error's "Tried:" list never silently omits a route just because it was never attempted.

A process.cwd()-anchored resolution attempt is deliberately NOT included as a further fallback: resolution should stay anchored to the bundle's own module identity, not to a mutable, launch-directory-dependent value that has no necessary relationship to where the bundle — or @nhtio/adk — actually live. Failing clearly and pointing at wrapperPath is a better outcome than a resolution that silently varies with the process's current working directory.

Parameters ​

ParameterType
wrapperBasenamestring
seamsSelfReferenceResolutionSeams

Returns ​

Promise<SelfReferenceResolution>