# bellpull

> Every export of bellpull, with its signature and doc comment: ambientRuntime, DEFAULT_GRACE, DEFAULT_TIMEOUT, escapeArgument, escapeCommand, extensionCandidates and 20 more, plus 9 types.

Source: https://bellpull.interlace.tools/docs/api

<!-- Generated by scripts/api-reference.ts from the built dist/*.d.ts. Do not edit; run `npx tsx scripts/api-reference.ts`. -->

bellpull — run another program and get back a result you can read.

A bellpull is the cord you pull in one room to ring a bell in another. Request work at a
distance; the work happens elsewhere; **someone comes back to you**. That last clause is
the package: {@link run} returns a {@link Result} for every outcome a process can have,
including the ones the incumbents raise as exceptions.

Four things, and the boundaries between them are the design:

- {@link run} — spawn, collect, and come back with a record. A non-zero exit is data.
- {@link whichSync} / {@link searchPath} — resolution that reports **which `PATH` entry
  the executable came from**, which is the open position in this layer.
- {@link format} / {@link toJson} / {@link toEvent} — one result, three renderings.
- the `resolvers` plugin host, at `bellpull/plugin`.

The drop-in path for `cross-spawn` is `bellpull/cross-spawn` and is not re-exported here:
it reads the ambient `process` because its callers expect it to, and this entry does not,
so a program importing `bellpull` never picks that up by accident.

**Honest scope.** `execa`'s surface is not reproduced — its streaming API and its
template-literal form are a different product and are recorded as out of scope in
`spec.md`. What is here is the result shape and the resolution, which is what the
intent's kill gate says to build on.

```ts
import { ambientRuntime, DEFAULT_GRACE, DEFAULT_TIMEOUT, … } from 'bellpull';
```

## Functions

### ambientRuntime

The runtime of the process this is running in, or a runtime that admits it knows nothing.

A missing `process` yields `platform: ''`, an empty environment and `cwd: '.'`. Every one
of those is a truthful answer that makes resolution fail rather than guess: an empty
`PATH` finds nothing, and finding nothing is the correct result when there is no
environment to look in.

`uid`/`gid` are only read where the platform has them. On Windows `process.getuid` is
absent, and `undefined` is what tells `which.ts` to skip the ownership half of the
executable-bit check rather than compare against a number nobody supplied.

```ts
function ambientRuntime(): Runtime;
```

**Returns** `Runtime`

### escapeArgument

Escape one argument so `cmd.exe` and then the callee's argv parser both give it back
unchanged.

`doubleEscape` is for a `node_modules/.bin/*.cmd` shim, which re-enters `cmd.exe`.

```ts
function escapeArgument(argument: unknown, doubleEscape?: boolean): string;
```

| Parameter | Type |
| :-- | :-- |
| `argument` | `unknown` |
| `doubleEscape` (optional) | `boolean` |

**Returns** `string`

### escapeCommand

Escape a command *name* for `cmd.exe`.

Only pass (2): the command is not quoted, because `cmd.exe` resolves it before the C
runtime parses anything, and a quoted command with a caret in it is not found.

```ts
function escapeCommand(command: string): string;
```

| Parameter | Type |
| :-- | :-- |
| `command` | `string` |

**Returns** `string`

### format

How a result reads to a person: one line, and the failure's output when there is one.

```ts
function format(result: Result): string;
```

| Parameter | Type |
| :-- | :-- |
| `result` | `Result` |

**Returns** `string`

### isWindows

Whether this runtime plays by Windows' rules. Cygwin and msys announce themselves in `OSTYPE`.

```ts
function isWindows(runtime: Runtime): boolean;
```

| Parameter | Type |
| :-- | :-- |
| `runtime` | `Runtime` |

**Returns** `boolean`

### pathDelimiter

The separator between `PATH` entries: `;` on Windows, `:` everywhere else.

```ts
function pathDelimiter(runtime: Runtime): string;
```

| Parameter | Type |
| :-- | :-- |
| `runtime` | `Runtime` |

**Returns** `string`

### pathKey

The key `PATH` is spelled under in this environment.

`path-key`, 244.9 M downloads a week, is this function. Windows environment variables are
case-insensitive but a plain JavaScript object's keys are not, so an environment copied
out of `process.env` on Windows can carry `Path`, and a lookup for `PATH` misses it. The
last matching key wins, which is what `path-key` does and what the shell does.

```ts
function pathKey(runtime: Runtime): string;
```

| Parameter | Type |
| :-- | :-- |
| `runtime` | `Runtime` |

**Returns** `string`

### pathOf

The `PATH` value for this runtime, under whichever key it is spelled.

```ts
function pathOf(runtime: Runtime): string;
```

| Parameter | Type |
| :-- | :-- |
| `runtime` | `Runtime` |

**Returns** `string`

### readShebang

The interpreter the file at `file` declares, or `undefined` — for a file that is not there,
is not readable, is a directory, or simply has no shebang.

Every one of those is the same answer to the caller ("no interpreter to use"), so they are
one return rather than four. The distinction that matters — whether the file exists —
belongs to resolution, which has already been done by the time this is asked.

```ts
function readShebang(file: string): string | undefined;
```

| Parameter | Type |
| :-- | :-- |
| `file` | `string` |

**Returns** `string \| undefined`

### run

Run a program and come back with a {@link Result}.

Rejects with {@link NotFoundError } when the executable does not resolve and
{@link SpawnError} when the spawn itself fails. Everything else — any exit code, any
signal, a breached deadline — resolves.

```ts
function run(command: string, args: readonly unknown[] | undefined, options: RunOptions): Promise<Result>;
```

| Parameter | Type |
| :-- | :-- |
| `command` | `string` |
| `args` | `readonly unknown[] \| undefined` |
| `options` | `RunOptions` |

**Returns** `Promise<Result>`

### shebangCommand

The interpreter a `#!` line names, or `undefined`.

`#!/usr/bin/env node` is `node`: `env` is a launcher, so its *argument* is the interpreter
and the path in front of it is discarded. `#!/bin/sh -e` is `sh -e` — the flag is kept,
because dropping it changes what the script does.

An empty argument is no argument, as it is to `shebang-command`, which tests it for truth:
`#!/bin/sh` followed by a trailing space is `sh`, not `sh` plus a space — a name nothing on
`PATH` answers to — and `#!/usr/bin/env` followed by two spaces and `node` names no
interpreter rather than an empty one.

```ts
function shebangCommand(source: string): string | undefined;
```

| Parameter | Type |
| :-- | :-- |
| `source` | `string` |

**Returns** `string \| undefined`

### toEvent

The agent form: {@link outcomeOf}'s one word, plus the record's own fields.

```ts
function toEvent(result: Result): RunEvent;
```

| Parameter | Type |
| :-- | :-- |
| `result` | `Result` |

**Returns** `RunEvent`

### toJson

The `--json` envelope: the record, flat, with nothing computed that is not in it.

```ts
function toJson(result: Result): Record<string, unknown>;
```

| Parameter | Type |
| :-- | :-- |
| `result` | `Result` |

**Returns** `Record<string, unknown>`

## Classes

### SpawnError

Spawning failed for a reason that is not a missing executable.

`ERR_`, not `E_`. The `E_…` codes are the *plugin* vocabulary — `E_PLUGIN_SCHEMA` and the
rest — which `plugin-contract` R8 requires every layer to share and
`scripts/plugin-error-vocabulary-lock.test.ts` enforces by refusing any `'E_…'` literal a
host ships that is not in its declared union. This is a runtime failure rather than a
refused plugin, so it takes Node's own convention for a runtime error code and stays out
of a vocabulary it is not part of.

```ts
class SpawnError extends Error {
    readonly command: string;
    readonly cause: unknown;
    readonly code = "ERR_SPAWN_FAILED";
    constructor(command: string, cause: unknown);
}
```

## Constants

### DEFAULT_GRACE

Milliseconds between `SIGTERM` and `SIGKILL`, for a child that declines to leave.

```ts
const DEFAULT_GRACE = 5000;
```

### DEFAULT_TIMEOUT

Milliseconds a child may take before it is killed. Finite by default — Y10.

```ts
const DEFAULT_TIMEOUT = 30000;
```

### name

The package's own name, kept from the reserved-name release so nothing that read it breaks.

```ts
const name: "bellpull";
```

## Interfaces

### ExitHost

A host that can register work to run when the process is shutting down.

```ts
interface ExitHost {
    /** Register; the returned function unregisters. `closeout`'s `Registry.add` fits as-is. */
    add(handler: () => unknown, spec?: unknown): () => void;
}
```

### Result

What a run produced. One value, three renderings (see `project.ts`).

```ts
interface Result {
    /** The exit was 0 and the run was not killed. The only field most callers branch on. */
    ok: boolean;
    /** The exit code, or `null` when the child died of a signal — the shape Node reports. */
    code: number | null;
    /** The signal that killed it, or `null`. */
    signal: NodeJS.Signals | null;
    /** Everything the child wrote to stdout. `''` when stdio was not captured. */
    stdout: string;
    /** Everything the child wrote to stderr. */
    stderr: string;
    /**
     * Wall-clock milliseconds from spawn to close — **including Node's own scheduling**, not
     * the child's CPU time (design R11). Stated here rather than in a README because the
     * caveat is what makes the number usable: it is the right figure for "how long did the
     * user wait" and the wrong one for "how expensive is this program".
     */
    duration: number;
    /** The command as the caller wrote it. */
    command: string;
    /** The arguments as the caller wrote them. */
    args: readonly string[];
    /**
     * The file that actually ran, and the `PATH` entry it came from — the field that answers
     * "which binary was this" without a second investigation. `undefined` when resolution was
     * skipped (`shell: true`, where the shell resolves).
     */
    executable: {
        path: string;
        from: string;
    } | undefined;
    /** The deadline fired and the child was killed. `ok` is `false`. */
    timedOut: boolean;
}
```

### RunEvent

One event on an agent stream. `type` is what a consumer switches on.

```ts
interface RunEvent {
    type: 'run';
    outcome: Outcome;
    command: string;
    args: readonly string[];
    code: number | null;
    signal: string | null;
    durationMs: number;
    executable: string | null;
    /** Where the executable came from, so an agent can report a `PATH` surprise itself. */
    from: string | null;
}
```

### RunOptions

```ts
interface RunOptions extends SpawnOptions {
    /** The ambient state. Required: nothing here reads `process` (Y9). */
    runtime: Runtime;
    /** Milliseconds before the child is killed. `0` disables the deadline, deliberately. */
    timeout?: number | undefined;
    /** Milliseconds between `SIGTERM` and `SIGKILL` on a breach. */
    grace?: number | undefined;
    /**
     * Where to register the child's kill so it is not orphaned if the parent is shut down.
     *
     * **This is the `bellpull → closeout` seam, and it is a parameter rather than an import
     * on purpose.** `closeout` owns bounded exit paths; a parent that is killed while a child
     * is running must not leave that child behind. But `package-shape-lock.test.ts` asserts
     * that a foundation package depends on *nothing* — bellpull and closeout are both in that
     * tier, so a package edge between them is forbidden by a lock on main. The shape is
     * declared structurally instead (the family's R3 idiom), so
     * `run(cmd, args, { exitHost: closeoutRegistry })` composes with nothing imported.
     *
     * Given none, **no signal handler is registered at all**. Registering one silently would
     * be this package deciding to own the process's signals, which is the layer above's job.
     */
    exitHost?: ExitHost | undefined;
    /** Passed to `child_process`. `'inherit'` is what a pass-through subcommand wants. */
    stdio?: 'pipe' | 'inherit' | 'ignore' | readonly unknown[] | undefined;
}
```

### Runtime

The ambient state this package reads. Structural on purpose: a caller may pass Node's own
`process`, a fake, or an object assembled from a container's environment.

```ts
interface Runtime {
    /** `process.platform`. `win32` selects `PATHEXT`, backslashes and the cmd.exe rules. */
    readonly platform: Platform;
    /** The environment. `PATH` (or whichever case Windows used) is read out of it. */
    readonly env: Readonly<Record<string, string | undefined>>;
    /** The working directory a relative command or `cwd` option is resolved against. */
    readonly cwd: string;
    /** Effective uid, where the platform has one. Absent means "do not check ownership". */
    readonly uid?: number | undefined;
    /** Effective gid, where the platform has one. */
    readonly gid?: number | undefined;
}
```

## Types

### Platform

A platform string, as `process.platform` spells it. Only `win32` is ever special-cased.

```ts
type Platform = string;
```

## Re-exported

Documented on the page of the entry point that declares them.

| Export | Kind | Documented in |
| :-- | :-- | :-- |
| `extensionCandidates` | function | [`bellpull/which`](/docs/api/which#extensioncandidates) |
| `pathExtensions` | function | [`bellpull/which`](/docs/api/which#pathextensions) |
| `resolveExecutable` | function | [`bellpull/which`](/docs/api/which#resolveexecutable) |
| `runPath` | function | [`bellpull/which`](/docs/api/which#runpath) |
| `searchPath` | function | [`bellpull/which`](/docs/api/which#searchpath) |
| `whichAllSync` | function | [`bellpull/which`](/docs/api/which#whichallsync) |
| `whichOrThrowSync` | function | [`bellpull/which`](/docs/api/which#whichorthrowsync) |
| `whichSync` | function | [`bellpull/which`](/docs/api/which#whichsync) |
| `NotFoundError` | class | [`bellpull/which`](/docs/api/which#notfounderror) |
| `Resolution` | interface | [`bellpull/which`](/docs/api/which#resolution) |
| `SearchEntry` | interface | [`bellpull/which`](/docs/api/which#searchentry) |
| `WhichOptions` | interface | [`bellpull/which`](/docs/api/which#whichoptions) |
