buninu 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -196,6 +196,87 @@ the right. Neither form invokes Bun Shell by itself; their purpose here is
196
196
  only to enter the highest-priority evaluator and then execute unrestricted
197
197
  JavaScript.
198
198
 
199
+ #### Use `$` to read and write shell variables
200
+
201
+ Inside JavaScript mode, `$` is the shell's own variable table — the live
202
+ object, not a copy — so the two languages share one set of variables instead of
203
+ passing strings between them:
204
+
205
+ ```sh
206
+ Bun.e, $.HOME # read
207
+ Bun.e, $.PATH.split(":").length # read, as a JavaScript value
208
+ Bun.e; void ($.TAG = "v" + Date.now())
209
+ echo "$TAG" # the shell sees what JavaScript wrote
210
+ ```
211
+
212
+ A shell variable is visible to JavaScript whether or not it was exported, and a
213
+ name JavaScript writes behaves like any other shell variable from that point
214
+ on, including being inherited by external child processes. `delete $.NAME`
215
+ unsets one, and `Object.keys($)` enumerates them.
216
+
217
+ An assignment is an expression, so its value is printed like any other result.
218
+ Wrap it in `void (...)` — as above — when the assignment is the point and the
219
+ echo is not.
220
+
221
+ **Everything the shell put there is a string.** A shell has no other type, so
222
+ `+` concatenates where you may have meant arithmetic — convert first:
223
+
224
+ ```sh
225
+ X=3
226
+ Bun.e, $.X + 1 # "31"
227
+ Bun.e, Number($.X) + 1 # 4
228
+ ```
229
+
230
+ The reverse direction does not convert for you either: `$.N = 42` stores the
231
+ number 42 in the table. The shell and any child process still read `42`,
232
+ because they stringify at their own boundary, but JavaScript now sees a number
233
+ under that name and a string under every name the shell set — so the same
234
+ expression means two different things depending on who last wrote the variable:
235
+
236
+ ```sh
237
+ X=3
238
+ Bun.e; void ($.N = 42)
239
+ Bun.e, [$.X + 1, $.N + 1] # [ "31", 43 ]
240
+ ```
241
+
242
+ Assign strings (`$.N = String(count)`) to keep one rule for every name.
243
+
244
+ Two things to know:
245
+
246
+ - `$` is bound only inside JavaScript mode, and only shadows the bare name.
247
+ `Bun.$`, Bun Shell's own API, is reached through the `Bun` object and is
248
+ unaffected.
249
+ - Writing through `$` mutates the table directly, so it bypasses `readonly`.
250
+ `readonly R=locked` still refuses `R=other` from the shell, but
251
+ `$.R = "other"` goes through. That makes it an escape hatch, and a way to
252
+ break an invariant the shell was asked to hold.
253
+
254
+ #### One line at a time
255
+
256
+ JavaScript mode runs the line it was given. It does not continue across lines
257
+ the way a shell command does, because the shell's continuation marker is not
258
+ JavaScript: a bare `\` at the end of a line is a syntax error there, not a
259
+ request for another line, so the prompt does not ask for one.
260
+
261
+ The exception is the place where JavaScript has a line continuation of its
262
+ own — inside a string or template literal — and there it works, because the
263
+ prompt keeps collecting lines while the quote is open and JavaScript joins them
264
+ itself:
265
+
266
+ ```sh
267
+ Bun.e, "abc\
268
+ def"
269
+ ```
270
+
271
+ ```text
272
+ abcdef
273
+ ```
274
+
275
+ An unbalanced bracket does not continue: the shell's parser is looking for
276
+ shell syntax, not JavaScript's, so `Bun.e; function f() {` runs as typed and
277
+ reports its own syntax error. For code that spans lines, put it in a file and
278
+ `import` it, or keep the statements on one line separated by `;`.
279
+
199
280
  #### Use `Bun.sha` as a shared area (hack)
200
281
 
201
282
  `Bun.sha` is normally Bun's SHA hashing function. JavaScript functions are
@@ -333,6 +414,61 @@ tab r # back to ~/project/src
333
414
 
334
415
  ## Special Interactions
335
416
 
417
+ ### Completion and ghost suggestions
418
+
419
+ Tab completes the word being typed, and a dim **ghost** shows the first match
420
+ inline ahead of the cursor; the Right arrow accepts it. What is offered depends
421
+ on where the cursor is:
422
+
423
+ | Where | Offered |
424
+ | --- | --- |
425
+ | A command name | Builtins, aliases, and executables on `PATH` |
426
+ | Inside `$(` | Command names again — a substitution starts a new command |
427
+ | A `$` being typed | Shell variable names |
428
+ | A JavaScript line | `$.` completes a variable name, a string literal a path |
429
+ | Anywhere else | Files and directories, and history for the ghost |
430
+
431
+ **Variables.** `$HO` suggests `$HOME`, and `${HO` suggests `${HOME}` — the
432
+ brace it opened is closed for it. `${#HO` works the same way. Names come from
433
+ the shell's own variable table, so unexported names and anything JavaScript
434
+ mode wrote through `$` are offered alongside the environment.
435
+
436
+ The suggestion follows the shell's own rules about when a `$` expands:
437
+
438
+ - It works wherever an expansion would: mid-word, on the right of an
439
+ assignment (`X=$HO`), inside double quotes, and where a command name would
440
+ go (`$ED`).
441
+ - Single quotes suppress it, because nothing expands inside them.
442
+ - Nothing is offered for the other things a `$` can start, since none of them
443
+ is a name in progress: `$(` (a command substitution), `$?`, `$1`, `$$`
444
+ (already complete), and `\$` (a literal dollar sign — the backslashes are
445
+ counted, so `\\$HO` does suggest).
446
+ - A bare `$` has no name to match on, so it ghosts nothing. Tab still lists
447
+ every variable, the way Tab on an empty word lists every file.
448
+
449
+ Where both could apply, history wins the ghost: it completes the whole line,
450
+ which reaches further than a single variable name.
451
+
452
+ **On a JavaScript line** — one starting with `Bun.`, the same test the
453
+ evaluator dispatches on — the line is read as JavaScript instead, because shell
454
+ word-splitting says nothing useful about it. Two things complete there:
455
+
456
+ ```sh
457
+ Bun.e, $.HO # -> $.HOME
458
+ Bun.e, Bun.file("/tm # -> a path, completed inside the string
459
+ ```
460
+
461
+ - After `$.`, shell variable names. A bare `$` completes nothing here: in
462
+ JavaScript it is the variable table itself, and a name only begins after the
463
+ dot.
464
+ - Inside an unclosed string literal — `"`, `'`, or a template — the text back
465
+ to the opening quote is completed as a path. No trailing space is needed to
466
+ make the completer see it, and nothing has to be trimmed back off afterwards.
467
+ - A template's `${...}` is code again, so `$.` completes inside it and the
468
+ path resumes after the closing brace.
469
+ - Where neither applies, only the history ghost is offered; shell completion
470
+ would just produce noise on a JavaScript line.
471
+
336
472
  ### Keyboard shortcuts
337
473
 
338
474
  - `Ctrl-C`: Interrupts the current input or foreground operation and returns to
@@ -453,7 +589,7 @@ Run `builtin` with no arguments to print the registered names at runtime.
453
589
  | `.`, `source` | `FILE [ARG ...]` |
454
590
  | `realpath` | One or more paths |
455
591
  | `umask` | No operand to display, or an octal mask |
456
- | `kill` | `-l`, `-SIGNAL`, `-NUMBER` |
592
+ | `kill` | `-l`, `-SIGNAL`, `-NUMBER`; on Windows, where the runtime can only `TerminateProcess` a subset of signals and never reaches the children, a terminating signal is sent as `taskkill /PID PID /T /F` instead, while `-0` still probes through the runtime |
457
593
  | `set` | No operand to list variables; `-- ARG ...` sets positional arguments |
458
594
  | `time` | Command and arguments; reports `real` elapsed time in milliseconds, with each decimal magnitude group shown in a different color |
459
595
  | `yes` | Optional output words; no flags |
@@ -661,6 +797,48 @@ unquoted `=on` / `=/index.html` / `=1` forms above work directly from a
661
797
  shell, no manual `--define 'process.env.SERVE_AUTO_OPEN="/index.html"'`
662
798
  quoting required.
663
799
 
800
+ ### The `curl` command
801
+
802
+ `curl [options] URL...` transfers a URL over HTTP or HTTPS on top of Bun's own
803
+ `fetch`, so a device with no `curl` binary can still run the download and API
804
+ scripts that expect one. It is a PATH-fallback builtin: a real `curl` in
805
+ `PATH` wins unless it is invoked as `builtin curl ...`.
806
+
807
+ - A URL with no scheme gets one — `http://` normally, `https://` when the port
808
+ is `443`, or whatever `--proto-default` names — so `curl localhost:8080` and
809
+ `curl example.com/page` work as they do with the real curl.
810
+ - Downloads: `-o`, `-O`, `-J`, `--output-dir`, `--create-dirs`, `-a`, and
811
+ `-C -` resume through a `Range` request, appending on `206`, rewriting on a
812
+ `200` that ignored the range, and stopping cleanly on `416`.
813
+ - Requests: `-X`, `-H`, `-d`/`--data-raw`/`--data-binary`/`--data-ascii`,
814
+ `--data-urlencode`, `--json`, `-G`, `-F`/`--form-string`, `-T`, `-u`,
815
+ `--oauth2-bearer`, `-A`, `-e`, `-b`, `-r`, `--compressed`, and `-x`.
816
+ `@file` and `@-` read a body from a file or stdin.
817
+ - Responses: `-i`, `-I`, `-D`, `-w` with the usual `%{variable}` set, `-L`
818
+ with `--max-redirs` and the `301`/`302`/`303` POST-to-GET rule, `-f`,
819
+ `--fail-with-body`, `-k`, `-m`, `--connect-timeout`, and `--retry`.
820
+ - Reporting: `-s`, `-S`, `-v`, `-#`, and a curl-shaped progress meter, shown
821
+ only when the body is not being painted on the terminal.
822
+ - curl's exit codes are reproduced: `22` for `-f` on an HTTP error, `6` for an
823
+ unresolved host, `7` for a refused connection, `28` for a timeout, `47` for
824
+ too many redirects, `60` for a certificate problem, `2` for bad usage.
825
+ - Bodies are streamed, so `curl -N` on a server-sent-events endpoint prints
826
+ each chunk as it arrives, and a large download never buffers in memory.
827
+
828
+ Enough to drive a JSON API:
829
+
830
+ ```sh
831
+ curl -sS https://api.openai.com/v1/chat/completions \
832
+ -H "Authorization: Bearer $OPENAI_API_KEY" \
833
+ -H 'Content-Type: application/json' \
834
+ -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"hi"}]}'
835
+ ```
836
+
837
+ Response headers come from `fetch`, which lower-cases them and hides the
838
+ negotiated HTTP version, so `-i`/`-I`/`-v` rebuild the conventional casing and
839
+ write `HTTP/1.1` status lines; Bun also adds a `Connection: keep-alive`
840
+ request header of its own. `builtin curl --help` documents the rest.
841
+
664
842
  ### PATH-fallback builtins
665
843
 
666
844
  Fallback builtins normally let an executable in `PATH` win. To use the fancy
@@ -670,6 +848,7 @@ aliases that explicitly select the builtin commands:
670
848
  ```sh
671
849
  alias cat='builtin catfancy'
672
850
  alias ls='builtin lsfancy'
851
+ alias ps='builtin pspac'
673
852
  ```
674
853
 
675
854
  After that, `cat README.md` renders Markdown with ANSI styling and terminal
@@ -701,10 +880,13 @@ hyperlinks, while `ls` uses the emoji and terminal-width-aware listing. Use
701
880
  | `ln` | `-s`, `-f`, `-T`, combinable (including `-sfT`) |
702
881
  | `chmod` | Octal modes, `+x`, `a+x` |
703
882
  | `uname` | `-a`, `-s`, `-n`, `-r`, `-v`, `-m`, `-p`, combinable (including `-mprs`); uses Node's OS APIs on Windows without `/proc` |
883
+ | `pspa` | Lists every process as a PID and its full command line, with no options; `ps -eo pid,args` passed through on POSIX, the same two columns queried from `Win32_Process` through PowerShell on Windows |
884
+ | `pspac` | The same listing, coloured: the PID as a number, and the command line highlighted as shell syntax with micro's `syntax/sh.yaml` rules and `colorschemes/monokai.micro` colours, plus a dimmed leading directory and the program's own name coloured as the command it is. Always colours, like `catfancy`; strip the colour and the output is `pspa`'s |
704
885
  | `find` | Paths plus `-name`, `-iname`, `-path`, `-ipath`, `-type f/d/l`, `-mindepth`, `-maxdepth`, `-print`, `-print0`, `!`/`-not`, `-exec COMMAND {} \;`, `-exec COMMAND {} +`; regular builtin on Windows, PATH fallback elsewhere |
705
886
  | `bunmsh` | Forwards all following arguments to this bunmsh entry point |
706
887
  | `bun` | Forwards all following arguments to the active Bun runtime |
707
888
  | `serve` | Auto-open, minapk WebView, and high-entropy random-URL flags; see [The `serve` command](#the-serve-command) above |
889
+ | `curl` | HTTP/HTTPS transfers on Bun's `fetch`, with automatic scheme guessing; `-o`, `-O`, `-J`, `--output-dir`, `--create-dirs`, `-a`, `-C`, `-D`, `-i`, `-I`, `-w`, `-X`, `-H`, `-d`, `--data-raw`, `--data-binary`, `--data-ascii`, `--data-urlencode`, `--json`, `-G`, `-F`, `--form-string`, `-T`, `-u`, `--oauth2-bearer`, `-A`, `-e`, `-b`, `-r`, `--compressed`, `-x`, `-L`, `--location-trusted`, `--max-redirs`, `-f`, `--fail-with-body`, `-k`, `-m`, `--connect-timeout`, `--retry` and friends, `-s`, `-S`, `-v`, `-#`, `--no-progress-meter`, `-V`, `--url`, `--proto-default`, combinable short clusters (`-kLO`, `-fsSL`, `-kfsS`, `-#k`); TLS-material and connection-tuning options are parsed and ignored; see [The `curl` command](#the-curl-command) above |
708
890
  | `ls`, `lsfancy` | The `ls` fallback is `lsfancy`: emoji and terminal-width-aware directory listing; `-a`, `-A`, `-d`, `-l`, `-h`, `-t`, `-r`, `-R`, `-S`, `-1`, `-F`, combinable (including `-lh`, `-ltr`, and `-lSF`); `-l` shows a symlink's target (`link -> target`, including a broken one), and a symlink whose target can't be resolved (missing, or a cycle) gets a 🚫 icon instead of 🔗; `-F` appends a classify suffix (`/` directory, `@` symlink, `*` executable, `=` socket, `\|` FIFO); always reads the directory without using the completion cache |
709
891
  | `lsbun` | Bun Shell's own `ls`, kept reachable under this name now that the `ls` fallback is `lsfancy`; currently implements `-a`, `-A`, `-d`, `-l`, `-R` |
710
892
  | `mv` | Bun Shell currently accepts `-f`, `-h`, `-i`, `-n`, `-v`, but they do not change its behaviour; notably, `-i` and `-n` do not prevent overwriting |
@@ -742,11 +924,17 @@ detailed compatibility snapshot.
742
924
  - Regular builtins, system-command-first fallback builtins, Bun Shell fallbacks,
743
925
  and explicit lookup through `command`, `builtin`, `whence`, `type`, and
744
926
  `which`.
745
- - Interactive history import/save/recall, command and file completion, ghost
927
+ - Interactive history import/save/recall, command, file, and shell-variable
928
+ completion, ghost
746
929
  suggestions, cwd tabs, keyboard shortcuts, optional mouse interactions,
747
930
  fancy directory listings, and a `PS2` continuation prompt while a
748
931
  here-document, an open quote/substitution, or an unfinished compound
749
932
  command is still being typed.
933
+ - A `curl` fallback built on `fetch`, covering downloads with resume, JSON and
934
+ form request bodies, redirects, timeouts, retries, `--write-out` reporting,
935
+ and curl's exit codes.
936
+ - A `pspa` process listing that works the same way on POSIX and Windows, and a
937
+ `pspac` that colours it as shell syntax.
750
938
  - Linux, Android/Termux, macOS, and Windows-aware paths, plus standalone builds
751
939
  and dynamic-linker re-execution support.
752
940
 
@@ -772,6 +960,17 @@ Both commands read their embedded copy first when running a standalone
772
960
  executable, then fall back to `README.md` or `CHANGELOG.md` in the repository
773
961
  during development.
774
962
 
963
+ Every builtin's `--help` page lives in `help/`, and `help/README.md` is the
964
+ concatenation of all of them. Regenerate it with the shell's own `cat` after
965
+ adding or editing a page:
966
+
967
+ ```sh
968
+ bun run genallhelp
969
+ ```
970
+
971
+ which runs `builtin cat --exclude help/README.md help/*.md` and writes the
972
+ result back over `help/README.md`.
973
+
775
974
  ## Standalone executable
776
975
 
777
976
  Build a single-file executable for the current platform:
@@ -799,3 +998,45 @@ The original bunmsh JavaScript implementation is released under the
799
998
 
800
999
  mksh is a separate upstream project and is **not** relicensed under MIT. Its
801
1000
  complete licence terms remain in [LICENSE-MKSH](LICENSE-MKSH).
1001
+
1002
+ ### Syntax highlighting
1003
+
1004
+ The shell-syntax colouring `pspac` applies to the COMMAND column follows
1005
+ `runtime/syntax/sh.yaml` from [micro](https://github.com/zyedidia/micro), the
1006
+ Go terminal editor. Nothing is bundled: its rules — the keyword,
1007
+ command-name, flag, variable, string, and comment patterns, the word lists
1008
+ behind them, and the order they resolve in — were transcribed into
1009
+ `src/shell.js`. Micro's syntax files are MIT ("Expat"), Copyright (c) 2020:
1010
+ Zachary Yedidia, et al.; micro's own `syntax/README.md` records that they
1011
+ originate from Nano's [`nanorc`](https://github.com/scopatz/nanorc)
1012
+ collection.
1013
+
1014
+ The colours those classes are painted in are the colour-links of micro's
1015
+ `runtime/colorschemes/monokai.micro` — micro itself is MIT, Copyright (c)
1016
+ 2016-2020: Zachary Yedidia, et al. — which renders the Monokai palette created
1017
+ by Wimer Hazenberg. `catfancy` takes five of the same colour-links for its
1018
+ JSON keys, strings, numbers, escapes, and constants, so both commands read as
1019
+ one scheme rather than two.
1020
+
1021
+ Micro's terms are in [LICENSE-MICRO](LICENSE-MICRO); upstream they are
1022
+ `runtime/syntax/LICENSE` and `LICENSE` in
1023
+ [zyedidia/micro](https://github.com/zyedidia/micro), which is where to trace
1024
+ either of them from.
1025
+
1026
+ ### Licences in a compiled executable
1027
+
1028
+ `LICENSE`, `LICENSE-MKSH`, and `LICENSE-MICRO` are packaged assets, so a
1029
+ standalone build carries them inside the binary rather than leaving the notices
1030
+ behind in the repository. Reading them back depends on which asset back end the
1031
+ build used:
1032
+
1033
+ ```sh
1034
+ ./bmsh --assets-extract # tar back end (the default)
1035
+ ./bmsh -cc builtin serve 'B:/~BUN' # ASSETS_BUNFS=1 build
1036
+ ```
1037
+
1038
+ [`--assets-extract`](#standalone-executable) writes every asset beside the
1039
+ executable, licences included, under `assets/bunmsh@<version>/`. For a bunfs
1040
+ build, [serving `B:/~BUN`](#serving-a-folder-packed-into-the-executable)
1041
+ browses the binary's own virtual root, where the same files sit under
1042
+ `/assets/bunmsh@<version>/`.
@@ -370,6 +370,187 @@ Output:
370
370
  ```text
371
371
  hello
372
372
  ```
373
+ ## curl
374
+
375
+ Transfer a URL over HTTP or HTTPS, built on Bun's own `fetch`.
376
+
377
+ This is a **fallback builtin**: a real `curl` found on `PATH` always wins, so
378
+ scripts keep the system binary where there is one and still run on a device
379
+ that has none. `builtin curl` selects this implementation explicitly.
380
+
381
+ ### Usage
382
+
383
+ ```sh
384
+ curl [OPTIONS] URL...
385
+ ```
386
+
387
+ A URL with no scheme gets one: `http://` by default, `https://` when the port
388
+ is `443`, or whatever `--proto-default` says. So `curl localhost:8080` and
389
+ `curl example.com/page` work the way they do with the real curl. Only `http`
390
+ and `https` are supported; anything else fails with exit code `1`.
391
+
392
+ ### Options and forms
393
+
394
+ #### Output and files
395
+
396
+ - `-o, --output FILE`: Write the body to `FILE` instead of stdout. `-o -`
397
+ means stdout. Repeat it to pair one target with each URL, in order.
398
+ - `-O, --remote-name`: Save under the filename from the URL path.
399
+ - `--remote-name-all`: Treat every URL as if it had its own `-O`.
400
+ - `-J, --remote-header-name`: With `-O`, prefer the name in the
401
+ `Content-Disposition` header.
402
+ - `--output-dir DIR`: Write `-o`/`-O` files under `DIR`.
403
+ - `--create-dirs`: Create missing parent directories for the output file.
404
+ - `-a, --append`: Append to the output file instead of truncating it.
405
+ - `-C, --continue-at OFFSET|-`: Resume a partial download. `-` sizes the
406
+ existing file and asks for the rest with a `Range` header; the file is
407
+ appended to when the server answers `206`, and rewritten when it answers
408
+ `200` and ignored the range. A `416` answer means the local file is already
409
+ complete: nothing is written and the exit status is `0`.
410
+ - `-D, --dump-header FILE`: Write the response headers to `FILE` (`-` for
411
+ stdout).
412
+ - `-i, --include`: Print the response headers before the body. With `-L`,
413
+ every hop's headers are printed, as the real curl does.
414
+ - `-I, --head`: Send `HEAD` and print the response headers.
415
+ - `-w, --write-out FORMAT`: Print `FORMAT` after the transfer, with
416
+ `%{variable}` substitutions and `\n`, `\t`, `\r` escapes. `@FILE` (or `@-`)
417
+ reads the format from a file. Supported variables: `url`, `url_effective`,
418
+ `method`, `scheme`, `http_code`, `response_code`, `http_version`,
419
+ `num_redirects`, `num_headers`, `redirect_url`, `size_download`,
420
+ `size_upload`, `size_header`, `size_request`, `speed_download`,
421
+ `speed_upload`, `content_type`, `filename_effective`, `remote_ip`,
422
+ `remote_port`, `ssl_verify_result`, `exitcode`, `errormsg`, `time_total`,
423
+ `time_namelookup`, `time_connect`, `time_appconnect`, `time_pretransfer`,
424
+ `time_starttransfer`, `time_redirect`, `header_json`, `json`, `stdout`,
425
+ `stderr`.
426
+
427
+ #### Request shaping
428
+
429
+ - `-X, --request METHOD`: Set the request method.
430
+ - `-H, --header 'Name: value'`: Add or replace a header. `'Name;'` sends an
431
+ empty value; `'Name:'` removes a header that would otherwise be sent.
432
+ - `-d, --data DATA`, `--data-ascii DATA`: `POST` body; `@file` reads a file
433
+ (newlines stripped) and `@-` reads stdin. Repeats join with `&`.
434
+ - `--data-raw DATA`: Same, but `@` has no special meaning.
435
+ - `--data-binary DATA`: Same, but a `@file` is sent byte for byte.
436
+ - `--data-urlencode DATA`: Percent-encode before sending. Accepts `content`,
437
+ `=content`, `name=content`, `@file`, and `name@file`.
438
+ - `--json DATA`: `--data-binary` plus `Content-Type: application/json` and
439
+ `Accept: application/json`. `@file` and `@-` work here too.
440
+ - `-G, --get`: Move the data onto the query string and send `GET`.
441
+ - `-F, --form 'name=value'`, `--form-string`: `multipart/form-data`. `@file`
442
+ attaches a file, `<file` sends its contents as the field value, and
443
+ `;type=` / `;filename=` set the part's type and name.
444
+ - `-T, --upload-file FILE`: `PUT` the file (`-` reads stdin).
445
+ - `-u, --user USER[:PASSWORD]`: HTTP basic authentication.
446
+ - `--oauth2-bearer TOKEN`: Send `Authorization: Bearer TOKEN`.
447
+ - `-A, --user-agent NAME`: Override the default `curl/8.14.1`.
448
+ - `-e, --referer URL`: Send a `Referer` header; a trailing `;auto` is ignored.
449
+ - `-b, --cookie 'k=v'`: Send a `Cookie` header.
450
+ - `-r, --range RANGE`: Send `Range: bytes=RANGE`.
451
+ - `--compressed`: Ask for and transparently decode a compressed response.
452
+ Without it, no `Accept-Encoding` is negotiated, matching curl's default.
453
+ - `-x, --proxy URL`: Send the request through a proxy.
454
+
455
+ #### Redirects, failure, and timing
456
+
457
+ - `-L, --location`: Follow redirects. `301`/`302`/`303` turn a `POST` into a
458
+ `GET`; `307`/`308` keep the method and body. `Authorization` is dropped when
459
+ the host changes, unless `--location-trusted` is given.
460
+ - `--max-redirs N`: Cap the redirect chain (default 50, `-1` for unlimited).
461
+ Exceeding it fails with exit code `47`.
462
+ - `-f, --fail`: No body output on HTTP errors; exit `22` instead.
463
+ - `--fail-with-body`: Print the body and still exit `22`.
464
+ - `-k, --insecure`: Do not verify the server certificate.
465
+ - `-m, --max-time SECONDS`, `--connect-timeout SECONDS`: Abort a slow
466
+ transfer with exit code `28`.
467
+ - `--retry N`, `--retry-delay SECONDS`, `--retry-all-errors`,
468
+ `--retry-connrefused`: Retry connection failures, timeouts, and the
469
+ transient statuses `408`, `429`, `500`, `502`, `503`, and `504`.
470
+
471
+ #### Reporting
472
+
473
+ - `-s, --silent`: No progress meter and no error messages.
474
+ - `-S, --show-error`: Keep error messages while `-s` is in effect.
475
+ - `-#, --progress-bar`: A single-bar progress display instead of the meter.
476
+ - `--no-progress-meter`: Keep errors, drop the meter.
477
+ - `-v, --verbose`: Trace the request and response headers on stderr.
478
+ - `-V, --version`: Print the version banner.
479
+
480
+ Like the real curl, the progress meter is shown only when the body is *not*
481
+ being painted on the terminal — a `-o`/`-O` download or a redirected stdout
482
+ gets a meter, `curl URL` at a prompt does not.
483
+
484
+ #### Accepted and ignored
485
+
486
+ These are parsed so a script does not die on them, and then have no effect,
487
+ because `fetch` either handles that part itself or does not expose it:
488
+ `--cacert`, `--capath`, `-E/--cert`, `--key`, `--interface`, `--limit-rate`,
489
+ `--resolve`, `--connect-to`, `--unix-socket`, `--noproxy`, `--proxy-user`,
490
+ `--proxy-header`, `-n/--netrc`, `-c/--cookie-jar`, `-z/--time-cond`,
491
+ `-R/--remote-time`, `-N/--no-buffer` (output is always streamed anyway),
492
+ `-g/--globoff` (URL globbing is not performed, so `{}` and `[]` are already
493
+ literal), `-q/--disable`, `-4`, `-6`, `--http1.0`, `--http1.1`, `--http2`,
494
+ `--http3`, `--tlsv1.x`, `--tcp-nodelay`, `--keepalive`, `--anyauth`,
495
+ `--basic`, `--digest`, `-Z/--parallel`, `--max-filesize`, `--path-as-is`.
496
+
497
+ ### Where it differs from the system curl
498
+
499
+ - `fetch` reports header names in lower case, so `-i`, `-I`, `-D`, and `-v`
500
+ rebuild the conventional capitalisation (`Content-Type`, `ETag`) and list
501
+ the headers in `fetch`'s order rather than the server's wire order.
502
+ - The negotiated HTTP version is not exposed, so status lines are written as
503
+ `HTTP/1.1`.
504
+ - Bun adds a `Connection: keep-alive` request header of its own.
505
+ - The progress meter is a look-alike: same columns, not the same arithmetic.
506
+ - URL globbing (`{a,b}`, `[1-10]`) is not implemented.
507
+ - `fetch` forbids a body on `GET` and `HEAD`, so `-X GET -d ...` sends the
508
+ request without the data; use `-G` to put it on the query string instead.
509
+
510
+ ### Exit status
511
+
512
+ `0` on success, `1` unsupported protocol, `2` bad usage, `3` malformed URL,
513
+ `6` host not resolved, `7` connection failed, `22` HTTP error with `-f`,
514
+ `23` write error, `26` local file could not be read, `28` timeout,
515
+ `47` too many redirects, `56` connection reset, `60` certificate problem.
516
+
517
+ ### Example
518
+
519
+ ```sh
520
+ curl -s -o /dev/null -w '%{http_code} %{content_type}\n' example.com
521
+ ```
522
+
523
+ Output:
524
+
525
+ ```text
526
+ 200 text/html
527
+ ```
528
+
529
+ The invocations a package script tends to use:
530
+
531
+ ```sh
532
+ curl -kLO https://example.com/pkg.tar.gz
533
+ curl -C - -kLO https://example.com/pkg.tar.gz
534
+ curl -fsSL https://example.com/install.sh | sh
535
+ curl -#k https://example.com/pkg.tar.gz.sha256
536
+ curl -kfsS https://example.com/probe >/dev/null 2>/dev/null
537
+ curl localhost:8080
538
+ ```
539
+
540
+ Calling a JSON API — enough for the OpenAI chat completions endpoint:
541
+
542
+ ```sh
543
+ curl -sS https://api.openai.com/v1/chat/completions \
544
+ -H "Authorization: Bearer $OPENAI_API_KEY" \
545
+ -H 'Content-Type: application/json' \
546
+ -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"hi"}]}'
547
+ ```
548
+
549
+ `--json` shortens that, and `-N` streaming responses arrive chunk by chunk:
550
+
551
+ ```sh
552
+ curl -sN --json @request.json https://api.openai.com/v1/chat/completions
553
+ ```
373
554
  ## cut
374
555
 
375
556
  Select character positions.
@@ -742,6 +923,22 @@ kill [-SIGNAL] PID ...
742
923
 
743
924
  - `-SIGNAL`: Select a signal by name or number; the default is SIGTERM.
744
925
  - `-0`: Check whether a process can be signalled without sending a signal.
926
+ - `-l`: List the signal names this runtime knows.
927
+
928
+ ### Windows
929
+
930
+ Windows has no signals to deliver. The runtime turns SIGTERM, SIGINT, and
931
+ SIGKILL into an unconditional `TerminateProcess`, refuses every other name,
932
+ and in no case touches the target's children. So on Windows every terminating
933
+ signal is sent as `taskkill /PID PID /T /F` instead: `/T` reaches the children
934
+ the runtime would leave running, and `/F` is what makes it work on a console
935
+ process that has no message loop to close.
936
+
937
+ The consequence is that the signal name is accepted but not honoured there —
938
+ `kill -HUP PID` terminates the process rather than failing, and nothing gets
939
+ the chance to shut down gracefully. `-0` is the exception: it asks whether the
940
+ PID exists without touching it, which `taskkill` cannot express, so it still
941
+ goes through the runtime.
745
942
 
746
943
  ### Example
747
944
 
@@ -1041,6 +1238,101 @@ Output:
1041
1238
  ```text
1042
1239
  answer=42
1043
1240
  ```
1241
+ ## pspa
1242
+
1243
+ List every process as a PID and its full command line.
1244
+
1245
+ ### Usage
1246
+
1247
+ ```sh
1248
+ pspa
1249
+ ```
1250
+
1251
+ It is a PATH-fallback builtin, so an executable named `pspa` found in `PATH`
1252
+ wins; `builtin pspa` selects this implementation. It takes no options — pipe
1253
+ it into `grep` to narrow the listing, and into `kill` to act on what you find.
1254
+
1255
+ [`pspac`](#pspac) prints the same listing with the PID and the command line
1256
+ coloured.
1257
+
1258
+ On POSIX systems this is `ps -eo pid,args`, and its output is passed through
1259
+ untouched. Reading `ps` over a pipe is also what keeps the command lines
1260
+ whole: procps truncates them at the terminal width when it is writing straight
1261
+ to a terminal.
1262
+
1263
+ Windows has no `ps`, so the same two columns are queried from
1264
+ `Win32_Process` through PowerShell and laid out the same way, with the image
1265
+ name standing in for a system process that reports no command line.
1266
+
1267
+ ### Example
1268
+
1269
+ ```sh
1270
+ pspa | grep bun
1271
+ ```
1272
+
1273
+ Output:
1274
+
1275
+ ```text
1276
+ 1004 bun ./src/main.js
1277
+ 1220 bun run dev
1278
+ ```
1279
+ ## pspac
1280
+
1281
+ The `pspa` process listing, coloured.
1282
+
1283
+ ### Usage
1284
+
1285
+ ```sh
1286
+ pspac
1287
+ ```
1288
+
1289
+ It is a PATH-fallback builtin taking no options, and it lists exactly what
1290
+ [`pspa`](#pspa) lists — same processes, same two columns, same order. Strip
1291
+ the colour off its output and you have `pspa`'s byte for byte.
1292
+
1293
+ Like `catfancy`, it always colours rather than sniffing for a terminal, so the
1294
+ plain listing is always one command away: use `pspa` when the output is going
1295
+ somewhere that wants plain text.
1296
+
1297
+ ### What gets coloured
1298
+
1299
+ The PID is painted as the number it is. The COMMAND column is a shell command
1300
+ line, so it is highlighted as one, using micro's `syntax/sh.yaml` rules and
1301
+ its `colorschemes/monokai.micro` colours — the same palette `catfancy` uses,
1302
+ so a command line reads the same here as in a previewed script:
1303
+
1304
+ - Command names, shell keywords, flags, numbers, variables, quoted strings,
1305
+ and comments each take their own colour.
1306
+ - Quoted strings and comments are regions, so a `#` inside an argument does
1307
+ not turn the rest of the line into a comment.
1308
+ - Later rules win, exactly as in the editor: `--cat` is a flag, not the
1309
+ coreutils `cat`.
1310
+
1311
+ Two things a process listing needs that a script does not:
1312
+
1313
+ - The directory in front of the program is dimmed. It is the part an absolute
1314
+ path buries the answer in, and `ps` prints a lot of it.
1315
+ - The program's own name is coloured as a command whether or not sh.yaml's
1316
+ word lists have heard of it — the file has to guess a command from a list,
1317
+ while here the first token is known to be one.
1318
+
1319
+ A kernel thread such as `[kworker/0:1]` has no program, path, or arguments to
1320
+ take apart, so it recedes as a whole.
1321
+
1322
+ ### Example
1323
+
1324
+ ```sh
1325
+ pspac
1326
+ ```
1327
+
1328
+ Output:
1329
+
1330
+ ```text
1331
+ PID COMMAND
1332
+ 1 /init
1333
+ 8824 /data/data/com.termux/files/usr/bin/bash -l
1334
+ 8955 bun run dev
1335
+ ```
1044
1336
  ## pwd
1045
1337
 
1046
1338
  Print the active directory.