# core/adapters/shell.adapter.ts

> 44 lines of code and 12 definitions.

Tree: GovLab Docs
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/docs#file-docs-core-adapters-shell-adapter-ts
Source text: https://banes-lab.com/source/docs/core/adapters/shell.adapter.ts.txt

Listed in [core/adapters](https://banes-lab.com/api/source/docs/core/adapters.md), after [core/adapters/markdown.adapter.ts](https://banes-lab.com/source/docs/core/adapters/markdown.adapter.ts.md) and before [core/adapters/vcs.adapter.ts](https://banes-lab.com/source/docs/core/adapters/vcs.adapter.ts.md).

## Definitions

- `settle` (lexical_declaration, line 23, exported)
- `superviseJob` (lexical_declaration, line 15, exported)
- `TIMEOUT_CODE` (lexical_declaration, line 6)
- `FAILURE_CODE` (lexical_declaration, line 7)
- `KILL_SIGNAL` (lexical_declaration, line 8)
- `runInherited` (lexical_declaration, line 10, exported)
- `outcome` (lexical_declaration, line 11, exported)
- `child` (lexical_declaration, line 17, exported)
- `chunks` (lexical_declaration, line 18, exported)
- `state` (lexical_declaration, line 19, exported)
- `collect` (lexical_declaration, line 20, exported)
- `timer` (lexical_declaration, line 31, exported)

## Contained in

- [core/adapters](https://banes-lab.com/anatomy/docs/folder-docs-core-adapters.md)

## Uses

- [configuration/strings/invocation.strings.ts](https://banes-lab.com/source/docs/configuration/strings/invocation.strings.ts.md)

## Used by

- [runtime/entrypoints/readme.entrypoint.ts](https://banes-lab.com/source/docs/runtime/entrypoints/readme.entrypoint.ts.md)

## Linked from

- [configuration/strings](https://banes-lab.com/anatomy/docs/folder-docs-configuration-strings.md)
- [core/adapters](https://banes-lab.com/anatomy/docs/folder-docs-core-adapters.md)
- [runtime/entrypoints](https://banes-lab.com/anatomy/docs/folder-docs-runtime-entrypoints.md)

## Source

```typescript
import type { JobResult, JobSpec } from "#types/index.types";
import { jobFailed, jobTimedOut } from "#configuration/strings/invocation.strings";
import { spawn, spawnSync } from "node:child_process";
import process from "node:process";

const TIMEOUT_CODE = 124;
const FAILURE_CODE = 1;
const KILL_SIGNAL = "SIGKILL";

export const runInherited = function runInherited(script: string, args: readonly string[]): number {
    const outcome = spawnSync(process.execPath, [script, ...args], { stdio: "inherit" });
    return outcome.status ?? FAILURE_CODE;
};

export const superviseJob = async function superviseJob(spec: JobSpec): Promise<JobResult> {
    return new Promise((resolve) => {
        const child = spawn(spec.command, spec.args, { cwd: spec.cwd, stdio: ["ignore", "pipe", "pipe"] });
        const chunks: string[] = [];
        const state = { settled: false, timedOut: false };
        const collect = (buffer: Buffer): void => {
            chunks.push(buffer.toString("utf8"));
        };
        const settle = (code: number): void => {
            if (state.settled) {
                return;
            }
            state.settled = true;
            clearTimeout(timer);
            resolve({ code, label: spec.label, out: chunks.join(""), timedOut: state.timedOut });
        };
        const timer = setTimeout(() => {
            state.timedOut = true;
            chunks.push(jobTimedOut(spec.label, spec.timeoutMs));
            child.kill(KILL_SIGNAL);
            settle(TIMEOUT_CODE);
        }, spec.timeoutMs);
        child.stdout.on("data", collect);
        child.stderr.on("data", collect);
        child.on("error", (error: Error) => {
            chunks.push(jobFailed(spec.label, error.message));
            settle(FAILURE_CODE);
        });
        child.on("close", (code: number | null) => {
            settle(code ?? FAILURE_CODE);
        });
    });
};
```
