Dev guide

This commit is contained in:
Raven Scott
2026-04-03 05:43:13 -04:00
parent 2d26a0b8d1
commit 6259c25d4c
25 changed files with 1207 additions and 25 deletions
@@ -0,0 +1,96 @@
# Chapter 4 — User scripts and PATH resolution
This chapter is the practical “how do I run my own `.js` file?” guide. Resolution logic lives in **`runBinCommand`** in [`kernel-runner.js`](../packages/bare-os-booter/lib/kernel-runner.js); the **shell** calls that function for non-builtin commands.
---
## The entrypoint contract (again)
Your script file must define:
```js
async function run(ctx, argv) {
// argv[0] is conventionally the script name or command word
}
```
The booter wraps the file body in:
```js
new AsyncFunction('ctx', 'argv', source + '\nif (typeof run !== "function") throw ...\nreturn run(ctx, argv)\n')
```
So **`run`** must exist at the top level of the evaluated string—same as `/bin` utilities.
---
## Resolution order (simplified)
When the user types a command, roughly:
1. **Git delegation** — If the command is **`git`** (and not `./git`), the booter runs the **hosted** git CLI instead of `/bin/git` bytes.
2. **Path with slash** — If `argv[0]` contains **`/`**, treat as a path: resolve via **`ctx.vfs`**, read bytes from the routed drive, evaluate as script.
3. **Ends with `.js`** — Resolve `cmd` as a logical path (e.g. `foo.js` in `$PWD`), read from VFS if found, evaluate.
4. **PATH search** — For each directory in **`$PATH`** (default `/bin`), try **`unixPathResolve(dir, cmd)`** on the **system** drive only; first hit wins.
Implications:
- **`./my.js`** and **`/home/user/my.js`** use **VFS** (personal or system as appropriate).
- **`hello.js`** in the current directory is tried **before** `/bin` if the file exists on the routed drive.
- **`ls`** resolves to **`/bin/ls`** on the system drive (unless shadowed by a same-named `*.js` in cwd—know this edge case).
---
## Shebang
A leading line like `#!/usr/bin/env bare` is **stripped** before compilation. It is for human readers and future tooling; the booter does not exec a binary interpreter—it always uses `AsyncFunction`.
---
## Stdin in pipelines
The shell does **not** give your script a POSIX `fd 0`. For pipeline stages, stdin is simulated: the shell captures **`console.log`** output from the left stage as a **string** and passes **`ctx.shellStdin`** on a cloned `ctx` to the right stage. Utilities that want stdin read **`bareStdin(ctx)`** from the **coreutils prelude**—but **user scripts on the home drive do not get that prelude** unless you copy the helper into your file.
Minimal stdin read in a user script:
```js
async function run(ctx, argv) {
const stdin =
typeof ctx.shellStdin === 'string' ? ctx.shellStdin : ''
ctx.console.log('got bytes:', stdin.length)
}
```
---
## Environment and `cd`
- **`ctx.env`** is the same object mutated by **`export`** and **`cd`** (via **`vfs.chdir`** and **`PWD`**).
- Paths like **`~/doc`** are expanded by the VFS when you use **`vfs.readFile`** and friends—prefer **`ctx.vfs`** over raw drive access for user-level scripts.
---
## Git and special cases
- Prefer the **`git`** command for version control; it is **not** the same as evaluating `/bin/git` as JS.
- **`command -v`** / **`type`** use **`resolveBinInPath`** (system drive PATH only) plus builtin tables.
---
## Debugging “not found”
1. **`unknown command: foo`** — Not in PATH on system drive and not a resolvable `*.js` / path.
2. **`not found: ./foo.js`** — VFS could not read the path (typo, wrong drive, or missing file).
3. **Silent failure with stack in `console.error`** — Runtime error inside `run`; fix the script logic.
---
## See also
- [Chapter 5 — Modules](05-modules-and-imports.md)
- [Chapter 6 — Extending `/bin`](06-extending-bin-coreutils.md)
- [Handbook — POSIX utilities](../handbook/09-posix-utilities-shell-and-vfs.md)
---
[← Kernel](03-kernel-boot-init.md) · [Modules →](05-modules-and-imports.md)