export interface GlobalLayout {
    /** Where extracted package trees live: `<prefix>/node_modules/<pkg>/`. */
    prefix: string;
    /** Where bin-name symlinks land. Typically `~/.local/bin`. */
    binDir: string;
}
/**
 * Compute the canonical global install layout for the current user. Honours
 * `XDG_DATA_HOME` (per the XDG Base Directory Spec) plus
 * `GJSIFY_GLOBAL_PREFIX` and `GJSIFY_GLOBAL_BIN_DIR` escape hatches for tests.
 */
export declare function defaultGlobalLayout(): GlobalLayout;
export interface LinkedBin {
    /** The bin-name (key from `bin` / `gjsify.bin`). */
    name: string;
    /** Absolute path to the file the symlink points at. */
    target: string;
    /** Absolute path to the symlink (under `binDir`). */
    link: string;
}
/**
 * Install each top-level package's bin entries into `binDir` as small POSIX
 * `sh` launchers that exec the real bin. Reads each package's installed
 * `package.json` to discover bins; prefers `gjsify.bin` (GJS-bundled bins)
 * over the npm `bin` field, falling back to npm `bin` when no GJS map is
 * declared. Stale launchers are replaced (latest install wins).
 *
 * Why launchers instead of symlinks:
 *
 *   When a GJS bundle is invoked via a symlink in $PATH, the kernel follows
 *   the symlink to find the executable but passes the original (symlink)
 *   path to it. The bundle's shebang then runs as `gjs -m <symlink-path>`,
 *   which makes `import.meta.url` resolve to the symlink directory — so any
 *   path computation relative to `import.meta.url` (e.g. ts-for-gir's
 *   `findTemplatesRoot()`, version-discovery `readFileSync`s, gjsify's own
 *   `import.meta.url` rewrites) looks for assets in the wrong place.
 *
 *   A `sh` launcher invokes the real path explicitly, so the bundle sees its
 *   real install location in `import.meta.url` and every relative read works.
 *   This costs ~50 bytes per bin and one extra `exec` per launch — both
 *   negligible compared to `gjs -m` cold-start time.
 *
 *   Plain Node bins are unaffected by either approach (Node defaults to
 *   resolving symlinks in ESM module URLs); launchers are uniform for
 *   simplicity and so we don't need to discriminate by runtime here.
 */
export declare function linkGlobalBins(packageNames: string[], layout: GlobalLayout): LinkedBin[];
/** Returns `true` if `binDir` is on the user's PATH. */
export declare function binDirOnPath(binDir: string): boolean;
/**
 * Extracts the package name from a spec like `name@1.2`, `@scope/name`,
 * or `@scope/name@latest`. Returns the unchanged string for plain names.
 */
export declare function specToPackageName(spec: string): string;
