Repository navigation
Commit 4e2d263
authored
feat(stdlib/bun): bun_run_capture — captured child-process run (#781)
<!-- DRAFT (2026-10-08). PR body for hyperpolymath/affinescript, branch
feat/bun-run-capture,
worktree developer/worktrees/affinescript-run-capture. Uncommitted until
the owner affirms with `git commit -S`. -->
## Summary
Adds a **captured** child-process run to the native Bun-ESM host
profile. `bun_run` inherits stdio, so it can return only an exit code.
Tools that need a program's output (git, scanners) have had no way to
read it.
- `stdlib/Bun.affine`: new record `RunResult { status: Int, stdout:
String, stderr: String }` and new extern `bun_run_capture(command,
arguments, cwd: Option<String>) -> RunResult`. `bun_run` is unchanged.
- `lib/codegen_deno.ml` (`bun_builtins`): lowers the call to
`spawnSync(cmd, args, { encoding: "utf8", stdio:
["ignore","pipe","pipe"], cwd })`.
- Stdin is closed, so a child that reads stdin cannot hang the caller.
- A host spawn error has no status. It maps to status 1, with the host's
message appended to `stderr`. This matches `bun_run`'s `?? 1`.
- `tests/codegen-bun/host_profile.{affine,harness.mjs}`: three planted
known-answer controls.
This is the first stdlib gap blocking SemGrip, an AffineScript CLI
around Semgrep and Opengrep (design:
`dev-notes/projects/semgrip/PLAN.adoc`, step A1).
Closes # <!-- no issue filed; findings go to the inbox, not new issues
(AGENTS.md §5e) -->
## Type of change
- [ ] 🐛 Bug fix: not applicable
- [x] ✨ New feature (non-breaking; a new extern and type, with `bun_run`
untouched)
- [ ] 💥 Breaking change: no existing signature changes
- [ ] 🕳️ Soundness fix: not applicable
- [ ] 📖 Documentation: only the doc comments on the new items
- [ ] 🧹 Refactor: not applicable
- [ ] ⚡ Performance: not applicable
- [ ] 🔧 Build / CI / tooling: no workflow changes
## 📌 New pins
Head SHA: **<fill in after the owner's signed commit>** (base
`e8f6a71e7ead38396ee651f351533bd5789c813a`). This PR adds and changes no
pins: no `uses:` refs, `actions.lock` entries, lockfiles or digests.
## How has this been verified?
All runs were in `worktrees/affinescript-run-capture`, with dune in opam
switch `as-sys` (OCaml 5.3.0) and Bun 1.4.2.
- `dune build bin/main.exe` succeeded; the only output was the existing
Menhir conflict warnings.
- `bash tools/run_codegen_bun_tests.sh` reported `All native Bun-ESM
tests passed (1 harnesses)`. It checks compilation, absence of legacy
runtime references, `bun --check`, reproducible emission, and the
harness, which includes the new controls:
- `sh -c 'echo hi; echo err >&2; exit 3'` gives status `3`, stdout
`"hi\n"` and stderr `"err\n"`.
- `pwd` run with `cwd = Some(dir)` prints `dir`.
- A missing program gives status `1`, with stderr naming the program.
Bun's text is `Executable not found in $PATH: "…"`, not Node's `ENOENT`.
- **Mutant killed:** forcing the lowering's `stdout` to `""` made the
harness fail with `capture stdout failed: ""`. Restoring it turned the
suite green again.
- `dune test`: the compiler's alcotest suite reported 562 tests, all OK.
`tools/res-to-affine/test` fails in a fresh worktree because
`tools/vendor/tree-sitter-rescript/src/parser.c` is absent (`just
install-grammar` was not run). That failure has nothing to do with this
change.
## Checklist
- [ ] My commits are **signed** (`git commit -S`). The owner signs on
affirmation; the agent did not commit.
- [x] I ran the project's own checks/tests locally and they pass (see
above, including the res-to-affine grammar caveat).
- [x] New files carry the correct SPDX identifier. No new files: all
four edits are to existing MPL-2.0 files, and no file was relicensed.
- [x] Docs are updated, and no public claim overstates what the code
does. Doc comments describe the status-1 mapping and closed stdin.
- [x] I have not introduced a soundness hole. The extern is host-only
and typed by its declaration. One limitation: as with every extern
(#245), a host mismatch is caught only at runtime.
## Notes for reviewers
- `RunResult` is a plain JS object, the same shape as the
`Http.Response` record. `cwd` uses the standard `{ tag, value }` Option
shape.
- Output size is bounded by the host `spawnSync` buffer. Exceeding it
surfaces as status 1 with an `ENOBUFS`-style message in `stderr`, never
as silent truncation. Callers with large output should write it to a
file, as SemGrip does with `--json-output=`.
- Only the Bun profile gets a lowering. Under other backends,
`bun_`-prefixed externs are rejected exactly as `bun_run` is.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01GVm3eGp5kZNPBDfd1tVJVD1 parent e8f6a71 commit 4e2d263
4 files changed
Lines changed: 54 additions & 1 deletion
File tree
- lib
- stdlib
- tests/codegen-bun
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1339 | 1339 | | |
1340 | 1340 | | |
1341 | 1341 | | |
| 1342 | + | |
| 1343 | + | |
| 1344 | + | |
| 1345 | + | |
| 1346 | + | |
| 1347 | + | |
| 1348 | + | |
| 1349 | + | |
| 1350 | + | |
| 1351 | + | |
| 1352 | + | |
| 1353 | + | |
1342 | 1354 | | |
1343 | 1355 | | |
1344 | 1356 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
19 | 36 | | |
20 | 37 | | |
21 | 38 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
27 | 40 | | |
28 | 41 | | |
29 | 42 | | |
| |||
0 commit comments