shell-dsl 0.0.39 → 0.0.40

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.
Files changed (50) hide show
  1. package/README.md +117 -3
  2. package/dist/cjs/package.json +1 -1
  3. package/dist/cjs/src/commands/exit/exit.cjs +84 -0
  4. package/dist/cjs/src/commands/exit/exit.cjs.map +10 -0
  5. package/dist/cjs/src/commands/index.cjs +18 -2
  6. package/dist/cjs/src/commands/index.cjs.map +3 -3
  7. package/dist/cjs/src/commands/sh/sh.cjs +134 -0
  8. package/dist/cjs/src/commands/sh/sh.cjs.map +10 -0
  9. package/dist/cjs/src/index.cjs +2 -1
  10. package/dist/cjs/src/index.cjs.map +3 -3
  11. package/dist/cjs/src/interpreter/context.cjs +4 -1
  12. package/dist/cjs/src/interpreter/context.cjs.map +3 -3
  13. package/dist/cjs/src/interpreter/index.cjs +2 -1
  14. package/dist/cjs/src/interpreter/index.cjs.map +3 -3
  15. package/dist/cjs/src/interpreter/interpreter.cjs +301 -76
  16. package/dist/cjs/src/interpreter/interpreter.cjs.map +3 -3
  17. package/dist/cjs/src/lexer/lexer.cjs +13 -1
  18. package/dist/cjs/src/lexer/lexer.cjs.map +3 -3
  19. package/dist/cjs/src/parser/parser.cjs +11 -1
  20. package/dist/cjs/src/parser/parser.cjs.map +3 -3
  21. package/dist/cjs/src/types.cjs.map +2 -2
  22. package/dist/mjs/package.json +1 -1
  23. package/dist/mjs/src/commands/exit/exit.mjs +44 -0
  24. package/dist/mjs/src/commands/exit/exit.mjs.map +10 -0
  25. package/dist/mjs/src/commands/index.mjs +18 -2
  26. package/dist/mjs/src/commands/index.mjs.map +3 -3
  27. package/dist/mjs/src/commands/sh/sh.mjs +94 -0
  28. package/dist/mjs/src/commands/sh/sh.mjs.map +10 -0
  29. package/dist/mjs/src/index.mjs +3 -2
  30. package/dist/mjs/src/index.mjs.map +3 -3
  31. package/dist/mjs/src/interpreter/context.mjs +4 -1
  32. package/dist/mjs/src/interpreter/context.mjs.map +3 -3
  33. package/dist/mjs/src/interpreter/index.mjs +3 -2
  34. package/dist/mjs/src/interpreter/index.mjs.map +2 -2
  35. package/dist/mjs/src/interpreter/interpreter.mjs +301 -76
  36. package/dist/mjs/src/interpreter/interpreter.mjs.map +3 -3
  37. package/dist/mjs/src/lexer/lexer.mjs +13 -1
  38. package/dist/mjs/src/lexer/lexer.mjs.map +3 -3
  39. package/dist/mjs/src/parser/parser.mjs +11 -1
  40. package/dist/mjs/src/parser/parser.mjs.map +3 -3
  41. package/dist/mjs/src/types.mjs.map +2 -2
  42. package/dist/types/src/commands/exit/exit.d.ts +2 -0
  43. package/dist/types/src/commands/index.d.ts +2 -0
  44. package/dist/types/src/commands/sh/sh.d.ts +5 -0
  45. package/dist/types/src/index.d.ts +2 -2
  46. package/dist/types/src/interpreter/context.d.ts +2 -1
  47. package/dist/types/src/interpreter/index.d.ts +1 -1
  48. package/dist/types/src/interpreter/interpreter.d.ts +24 -0
  49. package/dist/types/src/types.d.ts +13 -0
  50. package/package.json +1 -1
package/README.md CHANGED
@@ -33,6 +33,7 @@ bun add shell-dsl memfs
33
33
  - **Virtual filesystem** — Uses memfs for complete isolation from the real filesystem
34
34
  - **Real filesystem** — Optional sandboxed access to real files with path containment and permissions
35
35
  - **Explicit command registry** — Only registered commands can execute
36
+ - **Executable scripts** — Run virtual-filesystem scripts with `./script`, `sh`, `source`, and shebang dispatch
36
37
  - **Automatic escaping** — Interpolated values are escaped by default for safety
37
38
  - **POSIX-inspired syntax** — Pipes, redirects, control flow operators, and more
38
39
  - **Streaming pipelines** — Commands communicate via async iteration
@@ -234,6 +235,15 @@ await sh`echo $USER`.text(); // "alice\n"
234
235
  await sh`echo "Home: $HOME"`.text(); // "Home: /home/alice\n"
235
236
  ```
236
237
 
238
+ `$?` expands to the previous command's exit code:
239
+
240
+ ```ts
241
+ await sh`false; echo exit:$?; true; echo ok:$?`.text();
242
+ // "exit:1\nok:0\n"
243
+
244
+ await sh`logs clear backend; restart-backend; echo exit:$?; logs backend 100`;
245
+ ```
246
+
237
247
  ### Quoting Semantics
238
248
 
239
249
  | Quote | Behavior |
@@ -374,6 +384,101 @@ Nested substitution is supported:
374
384
  await sh`echo "Files: $(ls $(pwd))"`.text();
375
385
  ```
376
386
 
387
+ ## Executable Scripts
388
+
389
+ Command names containing `/` are treated as virtual-filesystem script paths when no registered command matches. Scripts run inside shell-dsl, not through the host OS:
390
+
391
+ ```ts
392
+ await fs.writeFile("/hello", `
393
+ echo "script: $0"
394
+ echo "args: $1 / $#"
395
+ `.trimStart());
396
+
397
+ await sh`./hello Alice`.text();
398
+ // "script: ./hello\nargs: Alice / 1\n"
399
+ ```
400
+
401
+ Scripts without a shebang run as shell-dsl scripts. `#!/bin/sh` and `#!/usr/bin/env sh` do the same thing:
402
+
403
+ ```ts
404
+ await fs.writeFile("/greet", `
405
+ #!/bin/sh
406
+ echo "Hello, $1"
407
+ `.trimStart());
408
+
409
+ await sh`./greet Alice`.text(); // "Hello, Alice\n"
410
+ ```
411
+
412
+ Script execution is subprocess-like: variables and `cd` inside `./script` do not leak back to the caller. Use `source` or `.` when you want the script to mutate the current shell state:
413
+
414
+ ```ts
415
+ await fs.writeFile("/env", "NAME=Alice\ncd /work\n");
416
+
417
+ await sh`source ./env; echo "$NAME"; pwd`.text();
418
+ // "Alice\n/work\n"
419
+ ```
420
+
421
+ ### Positional Parameters
422
+
423
+ Scripts and `sh -c` support common shell parameters:
424
+
425
+ | Parameter | Meaning |
426
+ |-----------|---------|
427
+ | `$0` | Script name or `sh -c` argv0 |
428
+ | `$1`, `$2`, ... | Positional arguments |
429
+ | `$#` | Number of positional arguments |
430
+ | `$*` | Positional arguments joined with spaces |
431
+ | `$@` | Positional arguments; quoted `"$@"` expands as separate fields |
432
+ | `$?` | Previous command's exit code |
433
+
434
+ ```ts
435
+ await sh`sh -c 'echo "$0:$1:$#"' name value`.text();
436
+ // "name:value:1\n"
437
+ ```
438
+
439
+ Scripts can stop with an explicit status via `exit`:
440
+
441
+ ```ts
442
+ await fs.writeFile("/restart", "restart-backend\nexit $?\n");
443
+
444
+ const result = await sh`./restart`.nothrow();
445
+ result.exitCode; // restart-backend's exit code
446
+ ```
447
+
448
+ ### Shebang Dispatch
449
+
450
+ Non-`sh` shebangs dispatch to registered commands by interpreter basename. For example, `#!/bin/cat` runs the registered `cat` command with the script path as its first argument:
451
+
452
+ ```ts
453
+ await fs.writeFile("/show", "#!/bin/cat\nhello\n");
454
+ await sh`./show`.text(); // "#!/bin/cat\nhello\n"
455
+ ```
456
+
457
+ Custom shebangs work the same way:
458
+
459
+ ```ts
460
+ const customCommand: Command = async (ctx) => {
461
+ await ctx.stdout.writeText(JSON.stringify(ctx.args) + "\n");
462
+ return 0;
463
+ };
464
+
465
+ const sh = createShellDSL({
466
+ fs,
467
+ cwd: "/",
468
+ env: {},
469
+ commands: { ...builtinCommands, custom_command: customCommand },
470
+ });
471
+
472
+ await fs.writeFile("/run", "#!/bin/custom_command\n");
473
+ await sh`./run arg`.text(); // "[\"./run\",\"arg\"]\n"
474
+ ```
475
+
476
+ `#!/bin/bash` is not enabled by default. If you intentionally want that alias, register one explicitly:
477
+
478
+ ```ts
479
+ commands: { ...builtinCommands, bash: builtinCommands.sh }
480
+ ```
481
+
377
482
  ## Defining Custom Commands
378
483
 
379
484
  Commands are async functions that receive a `CommandContext` and return an exit code (0 = success):
@@ -406,6 +511,9 @@ interface CommandContext {
406
511
  fs: VirtualFS; // Virtual filesystem
407
512
  cwd: string; // Current working directory
408
513
  env: Record<string, string>; // Environment variables
514
+ setCwd(path: string): void; // Change current working directory
515
+ exec?: (name: string, args: string[]) => Promise<ExecResult>;
516
+ shell?: ShellCommandApi; // Evaluate shell-dsl source from commands
409
517
  }
410
518
  ```
411
519
 
@@ -567,7 +675,7 @@ import { builtinCommands } from "shell-dsl/commands";
567
675
  Or import individually:
568
676
 
569
677
  ```ts
570
- import { echo, printf, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk, cut, od } from "shell-dsl/commands";
678
+ import { echo, printf, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk, cut, od, sh, evalCmd, source, dot, exitCmd } from "shell-dsl/commands";
571
679
  ```
572
680
 
573
681
  | Command | Description |
@@ -595,6 +703,10 @@ import { echo, printf, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk,
595
703
  | `awk` | Pattern scanning (`{print $1}`, `-F`, `NF`, `NR`) |
596
704
  | `cut` | Select fields/characters (`-f`, `-d`, `-c`, `-b`, `-s`, `--complement`) |
597
705
  | `od` | Dump binary/text data (`-A`, `-t x1/x2/o1/o2/c`, `-j`, `-N`, `-v`) |
706
+ | `sh` | Run shell-dsl source from a file, stdin, or `-c` string |
707
+ | `eval` | Evaluate arguments as shell-dsl source in the current shell state |
708
+ | `source` / `.` | Execute a script in the current shell state |
709
+ | `exit` | Stop the current shell with an optional exit code |
598
710
  | `test` / `[` | File and string tests (`-f`, `-d`, `-e`, `-z`, `-n`, `=`, `!=`) |
599
711
  | `true` | Exit with code 0 |
600
712
  | `false` | Exit with code 1 |
@@ -948,8 +1060,8 @@ await sh`echo ${{ raw: "$(date)" }}`.text();
948
1060
 
949
1061
  1. **No host access** — All commands run in-process against a virtual filesystem
950
1062
  2. **Automatic escaping** — Interpolated values are escaped by default
951
- 3. **Explicit command registry** — Only registered commands can execute
952
- 4. **No shell spawning** — Never invokes `/bin/sh` or similar
1063
+ 3. **Explicit command registry** — Only registered commands can execute, including shebang-dispatched interpreters
1064
+ 4. **No shell spawning** — Never invokes `/bin/sh` or similar; `#!/bin/sh` maps to shell-dsl's in-process `sh`
953
1065
 
954
1066
  The `{ raw: ... }` escape hatch exists for advanced use cases but should be used with extreme caution.
955
1067
 
@@ -968,6 +1080,8 @@ import type {
968
1080
  FileStat,
969
1081
  ExecResult,
970
1082
  ShellConfig,
1083
+ ShellCommandApi,
1084
+ ShellRunOptions,
971
1085
  RawValue,
972
1086
  Permission,
973
1087
  PermissionRules,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "shell-dsl",
3
- "version": "0.0.39",
3
+ "version": "0.0.40",
4
4
  "type": "commonjs"
5
5
  }
@@ -0,0 +1,84 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ function __accessProp(key) {
6
+ return this[key];
7
+ }
8
+ var __toCommonJS = (from) => {
9
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(entry, key))
16
+ __defProp(entry, key, {
17
+ get: __accessProp.bind(from, key),
18
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
+ });
20
+ }
21
+ __moduleCache.set(from, entry);
22
+ return entry;
23
+ };
24
+ var __moduleCache;
25
+ var __returnValue = (v) => v;
26
+ function __exportSetter(name, newValue) {
27
+ this[name] = __returnValue.bind(null, newValue);
28
+ }
29
+ var __export = (target, all) => {
30
+ for (var name in all)
31
+ __defProp(target, name, {
32
+ get: all[name],
33
+ enumerable: true,
34
+ configurable: true,
35
+ set: __exportSetter.bind(all, name)
36
+ });
37
+ };
38
+
39
+ // src/commands/exit/exit.ts
40
+ var exports_exit = {};
41
+ __export(exports_exit, {
42
+ exitCmd: () => exitCmd
43
+ });
44
+ module.exports = __toCommonJS(exports_exit);
45
+ function parseExitCode(value) {
46
+ if (!/^[+-]?\d+$/.test(value)) {
47
+ return null;
48
+ }
49
+ return Number(value);
50
+ }
51
+ var exitCmd = async (ctx) => {
52
+ if (!ctx.shell) {
53
+ await ctx.stderr.writeText(`exit: shell control not supported
54
+ `);
55
+ return 1;
56
+ }
57
+ if (ctx.args.length === 0) {
58
+ ctx.shell.exit(ctx.shell.getLastExitCode());
59
+ return 0;
60
+ }
61
+ const rawExitCode = ctx.args[0];
62
+ const exitCode = parseExitCode(rawExitCode);
63
+ if (exitCode === null) {
64
+ await ctx.stderr.writeText(`exit: ${rawExitCode}: numeric argument required
65
+ `);
66
+ ctx.shell.exit(2);
67
+ return 0;
68
+ }
69
+ if (!Number.isFinite(exitCode)) {
70
+ await ctx.stderr.writeText(`exit: ${rawExitCode}: numeric argument required
71
+ `);
72
+ ctx.shell.exit(2);
73
+ return 0;
74
+ }
75
+ if (ctx.args.length > 1) {
76
+ await ctx.stderr.writeText(`exit: too many arguments
77
+ `);
78
+ return 1;
79
+ }
80
+ ctx.shell.exit(exitCode);
81
+ return 0;
82
+ };
83
+
84
+ //# debugId=03868A825C7B459964756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/commands/exit/exit.ts"],
4
+ "sourcesContent": [
5
+ "import type { Command } from \"../../types.cjs\";\n\nfunction parseExitCode(value: string): number | null {\n if (!/^[+-]?\\d+$/.test(value)) {\n return null;\n }\n return Number(value);\n}\n\nexport const exitCmd: Command = async (ctx) => {\n if (!ctx.shell) {\n await ctx.stderr.writeText(\"exit: shell control not supported\\n\");\n return 1;\n }\n\n if (ctx.args.length === 0) {\n ctx.shell.exit(ctx.shell.getLastExitCode());\n return 0;\n }\n\n const rawExitCode = ctx.args[0]!;\n const exitCode = parseExitCode(rawExitCode);\n if (exitCode === null) {\n await ctx.stderr.writeText(`exit: ${rawExitCode}: numeric argument required\\n`);\n ctx.shell.exit(2);\n return 0;\n }\n\n if (!Number.isFinite(exitCode)) {\n await ctx.stderr.writeText(`exit: ${rawExitCode}: numeric argument required\\n`);\n ctx.shell.exit(2);\n return 0;\n }\n\n if (ctx.args.length > 1) {\n await ctx.stderr.writeText(\"exit: too many arguments\\n\");\n return 1;\n }\n\n ctx.shell.exit(exitCode);\n return 0;\n};\n"
6
+ ],
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,SAAS,aAAa,CAAC,OAA8B;AAAA,EACnD,IAAI,CAAC,aAAa,KAAK,KAAK,GAAG;AAAA,IAC7B,OAAO;AAAA,EACT;AAAA,EACA,OAAO,OAAO,KAAK;AAAA;AAGd,IAAM,UAAmB,OAAO,QAAQ;AAAA,EAC7C,IAAI,CAAC,IAAI,OAAO;AAAA,IACd,MAAM,IAAI,OAAO,UAAU;AAAA,CAAqC;AAAA,IAChE,OAAO;AAAA,EACT;AAAA,EAEA,IAAI,IAAI,KAAK,WAAW,GAAG;AAAA,IACzB,IAAI,MAAM,KAAK,IAAI,MAAM,gBAAgB,CAAC;AAAA,IAC1C,OAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAc,IAAI,KAAK;AAAA,EAC7B,MAAM,WAAW,cAAc,WAAW;AAAA,EAC1C,IAAI,aAAa,MAAM;AAAA,IACrB,MAAM,IAAI,OAAO,UAAU,SAAS;AAAA,CAA0C;AAAA,IAC9E,IAAI,MAAM,KAAK,CAAC;AAAA,IAChB,OAAO;AAAA,EACT;AAAA,EAEA,IAAI,CAAC,OAAO,SAAS,QAAQ,GAAG;AAAA,IAC9B,MAAM,IAAI,OAAO,UAAU,SAAS;AAAA,CAA0C;AAAA,IAC9E,IAAI,MAAM,KAAK,CAAC;AAAA,IAChB,OAAO;AAAA,EACT;AAAA,EAEA,IAAI,IAAI,KAAK,SAAS,GAAG;AAAA,IACvB,MAAM,IAAI,OAAO,UAAU;AAAA,CAA4B;AAAA,IACvD,OAAO;AAAA,EACT;AAAA,EAEA,IAAI,MAAM,KAAK,QAAQ;AAAA,EACvB,OAAO;AAAA;",
8
+ "debugId": "03868A825C7B459964756E2164756E21",
9
+ "names": []
10
+ }
@@ -48,7 +48,9 @@ __export(exports_commands, {
48
48
  test: () => import_test.test,
49
49
  tee: () => import_tee.tee,
50
50
  tail: () => import_tail.tail,
51
+ source: () => import_sh.source,
51
52
  sort: () => import_sort.sort,
53
+ sh: () => import_sh.sh,
52
54
  sed: () => import_sed.sed,
53
55
  rm: () => import_rm.rm,
54
56
  pwd: () => import_pwd.pwd,
@@ -61,7 +63,12 @@ __export(exports_commands, {
61
63
  grep: () => import_grep.grep,
62
64
  find: () => import_find.find,
63
65
  falseCmd: () => import_true_false.falseCmd,
66
+ exitCmd: () => import_exit.exitCmd,
67
+ exit: () => import_exit.exitCmd,
68
+ evalCmd: () => import_sh.evalCmd,
69
+ eval: () => import_sh.evalCmd,
64
70
  echo: () => import_echo.echo,
71
+ dot: () => import_sh.dot,
65
72
  cut: () => import_cut.cut,
66
73
  cp: () => import_cp.cp,
67
74
  continueCmd: () => import_break_continue.continueCmd,
@@ -103,6 +110,8 @@ var import_cd = require("./cd/cd.cjs");
103
110
  var import_tr = require("./tr/tr.cjs");
104
111
  var import_cut = require("./cut/cut.cjs");
105
112
  var import_od = require("./od/od.cjs");
113
+ var import_sh = require("./sh/sh.cjs");
114
+ var import_exit = require("./exit/exit.cjs");
106
115
  var import_echo2 = require("./echo/echo.cjs");
107
116
  var import_printf2 = require("./printf/printf.cjs");
108
117
  var import_cat2 = require("./cat/cat.cjs");
@@ -132,6 +141,8 @@ var import_cd2 = require("./cd/cd.cjs");
132
141
  var import_tr2 = require("./tr/tr.cjs");
133
142
  var import_cut2 = require("./cut/cut.cjs");
134
143
  var import_od2 = require("./od/od.cjs");
144
+ var import_sh2 = require("./sh/sh.cjs");
145
+ var import_exit2 = require("./exit/exit.cjs");
135
146
  var builtinCommands = {
136
147
  echo: import_echo2.echo,
137
148
  printf: import_printf2.printf,
@@ -164,7 +175,12 @@ var builtinCommands = {
164
175
  cd: import_cd2.cd,
165
176
  tr: import_tr2.tr,
166
177
  cut: import_cut2.cut,
167
- od: import_od2.od
178
+ od: import_od2.od,
179
+ sh: import_sh2.sh,
180
+ eval: import_sh2.evalCmd,
181
+ source: import_sh2.source,
182
+ ".": import_sh2.dot,
183
+ exit: import_exit2.exitCmd
168
184
  };
169
185
 
170
- //# debugId=2377F0DD6264750A64756E2164756E21
186
+ //# debugId=4755929D925B13DC64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/commands/index.ts"],
4
4
  "sourcesContent": [
5
- "import type { Command } from \"../types.cjs\";\n\nexport { echo } from \"./echo/echo.cjs\";\nexport { printf } from \"./printf/printf.cjs\";\nexport { cat } from \"./cat/cat.cjs\";\nexport { grep } from \"./grep/grep.cjs\";\nexport { wc } from \"./wc/wc.cjs\";\nexport { head } from \"./head/head.cjs\";\nexport { tail } from \"./tail/tail.cjs\";\nexport { sort } from \"./sort/sort.cjs\";\nexport { uniq } from \"./uniq/uniq.cjs\";\nexport { pwd } from \"./pwd/pwd.cjs\";\nexport { ls } from \"./ls/ls.cjs\";\nexport { mkdir } from \"./mkdir/mkdir.cjs\";\nexport { rm } from \"./rm/rm.cjs\";\nexport { test, bracket } from \"./test/test.cjs\";\nexport { trueCmd, falseCmd } from \"./true-false/true-false.cjs\";\nexport { touch } from \"./touch/touch.cjs\";\nexport { cp } from \"./cp/cp.cjs\";\nexport { mv } from \"./mv/mv.cjs\";\nexport { tee } from \"./tee/tee.cjs\";\nexport { tree } from \"./tree/tree.cjs\";\nexport { find } from \"./find/find.cjs\";\nexport { sed } from \"./sed/sed.cjs\";\nexport { awk } from \"./awk/awk.cjs\";\nexport { breakCmd, continueCmd } from \"./break-continue/break-continue.cjs\";\nexport { colon } from \"./colon/colon.cjs\";\nexport { cd } from \"./cd/cd.cjs\";\nexport { tr } from \"./tr/tr.cjs\";\nexport { cut } from \"./cut/cut.cjs\";\nexport { od } from \"./od/od.cjs\";\n\n// Re-export all commands as a bundle\nimport { echo } from \"./echo/echo.cjs\";\nimport { printf } from \"./printf/printf.cjs\";\nimport { cat } from \"./cat/cat.cjs\";\nimport { grep } from \"./grep/grep.cjs\";\nimport { wc } from \"./wc/wc.cjs\";\nimport { head } from \"./head/head.cjs\";\nimport { tail } from \"./tail/tail.cjs\";\nimport { sort } from \"./sort/sort.cjs\";\nimport { uniq } from \"./uniq/uniq.cjs\";\nimport { pwd } from \"./pwd/pwd.cjs\";\nimport { ls } from \"./ls/ls.cjs\";\nimport { mkdir } from \"./mkdir/mkdir.cjs\";\nimport { rm } from \"./rm/rm.cjs\";\nimport { test, bracket } from \"./test/test.cjs\";\nimport { trueCmd, falseCmd } from \"./true-false/true-false.cjs\";\nimport { touch } from \"./touch/touch.cjs\";\nimport { cp } from \"./cp/cp.cjs\";\nimport { mv } from \"./mv/mv.cjs\";\nimport { tee } from \"./tee/tee.cjs\";\nimport { tree } from \"./tree/tree.cjs\";\nimport { find } from \"./find/find.cjs\";\nimport { sed } from \"./sed/sed.cjs\";\nimport { awk } from \"./awk/awk.cjs\";\nimport { breakCmd, continueCmd } from \"./break-continue/break-continue.cjs\";\nimport { colon } from \"./colon/colon.cjs\";\nimport { cd } from \"./cd/cd.cjs\";\nimport { tr } from \"./tr/tr.cjs\";\nimport { cut } from \"./cut/cut.cjs\";\nimport { od } from \"./od/od.cjs\";\n\nexport const builtinCommands: Record<string, Command> = {\n echo,\n printf,\n cat,\n grep,\n wc,\n head,\n tail,\n sort,\n uniq,\n pwd,\n ls,\n mkdir,\n rm,\n test,\n \"[\": bracket,\n true: trueCmd,\n false: falseCmd,\n touch,\n cp,\n mv,\n tee,\n tree,\n find,\n sed,\n awk,\n break: breakCmd,\n continue: continueCmd,\n \":\": colon,\n cd,\n tr,\n cut,\n od,\n};\n"
5
+ "import type { Command } from \"../types.cjs\";\n\nexport { echo } from \"./echo/echo.cjs\";\nexport { printf } from \"./printf/printf.cjs\";\nexport { cat } from \"./cat/cat.cjs\";\nexport { grep } from \"./grep/grep.cjs\";\nexport { wc } from \"./wc/wc.cjs\";\nexport { head } from \"./head/head.cjs\";\nexport { tail } from \"./tail/tail.cjs\";\nexport { sort } from \"./sort/sort.cjs\";\nexport { uniq } from \"./uniq/uniq.cjs\";\nexport { pwd } from \"./pwd/pwd.cjs\";\nexport { ls } from \"./ls/ls.cjs\";\nexport { mkdir } from \"./mkdir/mkdir.cjs\";\nexport { rm } from \"./rm/rm.cjs\";\nexport { test, bracket } from \"./test/test.cjs\";\nexport { trueCmd, falseCmd } from \"./true-false/true-false.cjs\";\nexport { touch } from \"./touch/touch.cjs\";\nexport { cp } from \"./cp/cp.cjs\";\nexport { mv } from \"./mv/mv.cjs\";\nexport { tee } from \"./tee/tee.cjs\";\nexport { tree } from \"./tree/tree.cjs\";\nexport { find } from \"./find/find.cjs\";\nexport { sed } from \"./sed/sed.cjs\";\nexport { awk } from \"./awk/awk.cjs\";\nexport { breakCmd, continueCmd } from \"./break-continue/break-continue.cjs\";\nexport { colon } from \"./colon/colon.cjs\";\nexport { cd } from \"./cd/cd.cjs\";\nexport { tr } from \"./tr/tr.cjs\";\nexport { cut } from \"./cut/cut.cjs\";\nexport { od } from \"./od/od.cjs\";\nexport { sh, evalCmd as eval, evalCmd, source, dot } from \"./sh/sh.cjs\";\nexport { exitCmd as exit, exitCmd } from \"./exit/exit.cjs\";\n\n// Re-export all commands as a bundle\nimport { echo } from \"./echo/echo.cjs\";\nimport { printf } from \"./printf/printf.cjs\";\nimport { cat } from \"./cat/cat.cjs\";\nimport { grep } from \"./grep/grep.cjs\";\nimport { wc } from \"./wc/wc.cjs\";\nimport { head } from \"./head/head.cjs\";\nimport { tail } from \"./tail/tail.cjs\";\nimport { sort } from \"./sort/sort.cjs\";\nimport { uniq } from \"./uniq/uniq.cjs\";\nimport { pwd } from \"./pwd/pwd.cjs\";\nimport { ls } from \"./ls/ls.cjs\";\nimport { mkdir } from \"./mkdir/mkdir.cjs\";\nimport { rm } from \"./rm/rm.cjs\";\nimport { test, bracket } from \"./test/test.cjs\";\nimport { trueCmd, falseCmd } from \"./true-false/true-false.cjs\";\nimport { touch } from \"./touch/touch.cjs\";\nimport { cp } from \"./cp/cp.cjs\";\nimport { mv } from \"./mv/mv.cjs\";\nimport { tee } from \"./tee/tee.cjs\";\nimport { tree } from \"./tree/tree.cjs\";\nimport { find } from \"./find/find.cjs\";\nimport { sed } from \"./sed/sed.cjs\";\nimport { awk } from \"./awk/awk.cjs\";\nimport { breakCmd, continueCmd } from \"./break-continue/break-continue.cjs\";\nimport { colon } from \"./colon/colon.cjs\";\nimport { cd } from \"./cd/cd.cjs\";\nimport { tr } from \"./tr/tr.cjs\";\nimport { cut } from \"./cut/cut.cjs\";\nimport { od } from \"./od/od.cjs\";\nimport { sh, evalCmd, source, dot } from \"./sh/sh.cjs\";\nimport { exitCmd } from \"./exit/exit.cjs\";\n\nexport const builtinCommands: Record<string, Command> = {\n echo,\n printf,\n cat,\n grep,\n wc,\n head,\n tail,\n sort,\n uniq,\n pwd,\n ls,\n mkdir,\n rm,\n test,\n \"[\": bracket,\n true: trueCmd,\n false: falseCmd,\n touch,\n cp,\n mv,\n tee,\n tree,\n find,\n sed,\n awk,\n break: breakCmd,\n continue: continueCmd,\n \":\": colon,\n cd,\n tr,\n cut,\n od,\n sh,\n eval: evalCmd,\n source,\n \".\": dot,\n exit: exitCmd,\n};\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEqB,IAArB;AACuB,IAAvB;AACoB,IAApB;AACqB,IAArB;AACmB,IAAnB;AACqB,IAArB;AACqB,IAArB;AACqB,IAArB;AACqB,IAArB;AACoB,IAApB;AACmB,IAAnB;AACsB,IAAtB;AACmB,IAAnB;AAC8B,IAA9B;AACkC,IAAlC;AACsB,IAAtB;AACmB,IAAnB;AACmB,IAAnB;AACoB,IAApB;AACqB,IAArB;AACqB,IAArB;AACoB,IAApB;AACoB,IAApB;AACsC,IAAtC;AACsB,IAAtB;AACmB,IAAnB;AACmB,IAAnB;AACoB,IAApB;AACmB,IAAnB;AAGqB,IAArB;AACuB,IAAvB;AACoB,IAApB;AACqB,IAArB;AACmB,IAAnB;AACqB,IAArB;AACqB,IAArB;AACqB,IAArB;AACqB,IAArB;AACoB,IAApB;AACmB,IAAnB;AACsB,IAAtB;AACmB,IAAnB;AAC8B,IAA9B;AACkC,IAAlC;AACsB,IAAtB;AACmB,IAAnB;AACmB,IAAnB;AACoB,IAApB;AACqB,IAArB;AACqB,IAArB;AACoB,IAApB;AACoB,IAApB;AACsC,IAAtC;AACsB,IAAtB;AACmB,IAAnB;AACmB,IAAnB;AACoB,IAApB;AACmB,IAAnB;AAEO,IAAM,kBAA2C;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,UAAU;AAAA,EACV,KAAK;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;",
8
- "debugId": "2377F0DD6264750A64756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEqB,IAArB;AACuB,IAAvB;AACoB,IAApB;AACqB,IAArB;AACmB,IAAnB;AACqB,IAArB;AACqB,IAArB;AACqB,IAArB;AACqB,IAArB;AACoB,IAApB;AACmB,IAAnB;AACsB,IAAtB;AACmB,IAAnB;AAC8B,IAA9B;AACkC,IAAlC;AACsB,IAAtB;AACmB,IAAnB;AACmB,IAAnB;AACoB,IAApB;AACqB,IAArB;AACqB,IAArB;AACoB,IAApB;AACoB,IAApB;AACsC,IAAtC;AACsB,IAAtB;AACmB,IAAnB;AACmB,IAAnB;AACoB,IAApB;AACmB,IAAnB;AAC0D,IAA1D;AACyC,IAAzC;AAGqB,IAArB;AACuB,IAAvB;AACoB,IAApB;AACqB,IAArB;AACmB,IAAnB;AACqB,IAArB;AACqB,IAArB;AACqB,IAArB;AACqB,IAArB;AACoB,IAApB;AACmB,IAAnB;AACsB,IAAtB;AACmB,IAAnB;AAC8B,IAA9B;AACkC,IAAlC;AACsB,IAAtB;AACmB,IAAnB;AACmB,IAAnB;AACoB,IAApB;AACqB,IAArB;AACqB,IAArB;AACoB,IAApB;AACoB,IAApB;AACsC,IAAtC;AACsB,IAAtB;AACmB,IAAnB;AACmB,IAAnB;AACoB,IAApB;AACmB,IAAnB;AACyC,IAAzC;AACwB,IAAxB;AAEO,IAAM,kBAA2C;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,UAAU;AAAA,EACV,KAAK;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA,KAAK;AAAA,EACL,MAAM;AACR;",
8
+ "debugId": "4755929D925B13DC64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -0,0 +1,134 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ function __accessProp(key) {
6
+ return this[key];
7
+ }
8
+ var __toCommonJS = (from) => {
9
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(entry, key))
16
+ __defProp(entry, key, {
17
+ get: __accessProp.bind(from, key),
18
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
+ });
20
+ }
21
+ __moduleCache.set(from, entry);
22
+ return entry;
23
+ };
24
+ var __moduleCache;
25
+ var __returnValue = (v) => v;
26
+ function __exportSetter(name, newValue) {
27
+ this[name] = __returnValue.bind(null, newValue);
28
+ }
29
+ var __export = (target, all) => {
30
+ for (var name in all)
31
+ __defProp(target, name, {
32
+ get: all[name],
33
+ enumerable: true,
34
+ configurable: true,
35
+ set: __exportSetter.bind(all, name)
36
+ });
37
+ };
38
+
39
+ // src/commands/sh/sh.ts
40
+ var exports_sh = {};
41
+ __export(exports_sh, {
42
+ source: () => source,
43
+ sh: () => sh,
44
+ evalCmd: () => evalCmd,
45
+ dot: () => dot
46
+ });
47
+ module.exports = __toCommonJS(exports_sh);
48
+ async function readShellFile(fs, cwd, pathName, stderr) {
49
+ const path = fs.resolve(cwd, pathName);
50
+ if (!await fs.exists(path)) {
51
+ await stderr.writeText(`sh: ${pathName}: No such file or directory
52
+ `);
53
+ return { ok: false, exitCode: 127 };
54
+ }
55
+ const stat = await fs.stat(path);
56
+ if (stat.isDirectory()) {
57
+ await stderr.writeText(`sh: ${pathName}: is a directory
58
+ `);
59
+ return { ok: false, exitCode: 126 };
60
+ }
61
+ if (!stat.isFile()) {
62
+ await stderr.writeText(`sh: ${pathName}: not a file
63
+ `);
64
+ return { ok: false, exitCode: 126 };
65
+ }
66
+ try {
67
+ return { ok: true, source: await fs.readFile(path, "utf-8") };
68
+ } catch (err) {
69
+ const message = err instanceof Error ? err.message : String(err);
70
+ await stderr.writeText(`sh: ${pathName}: ${message}
71
+ `);
72
+ return { ok: false, exitCode: 126 };
73
+ }
74
+ }
75
+ var sh = async (ctx) => {
76
+ if (!ctx.shell) {
77
+ await ctx.stderr.writeText(`sh: shell evaluation not supported
78
+ `);
79
+ return 1;
80
+ }
81
+ if (ctx.args.length === 0) {
82
+ return ctx.shell.runShell(await ctx.stdin.text(), { argv0: "sh", args: [] });
83
+ }
84
+ const first = ctx.args[0];
85
+ if (first === "-c") {
86
+ const source = ctx.args[1];
87
+ if (source === undefined) {
88
+ await ctx.stderr.writeText(`sh: -c requires an argument
89
+ `);
90
+ return 2;
91
+ }
92
+ const argv0 = ctx.args[2] ?? "sh";
93
+ const args = ctx.args[2] === undefined ? [] : ctx.args.slice(3);
94
+ return ctx.shell.runShell(source, { argv0, args });
95
+ }
96
+ if (first.startsWith("-")) {
97
+ await ctx.stderr.writeText(`sh: unsupported option: ${first}
98
+ `);
99
+ return 2;
100
+ }
101
+ const loaded = await readShellFile(ctx.fs, ctx.cwd, first, ctx.stderr);
102
+ if (!loaded.ok) {
103
+ return loaded.exitCode;
104
+ }
105
+ return ctx.shell.runShell(loaded.source, { argv0: first, args: ctx.args.slice(1) });
106
+ };
107
+ var evalCmd = async (ctx) => {
108
+ if (!ctx.shell) {
109
+ await ctx.stderr.writeText(`eval: shell evaluation not supported
110
+ `);
111
+ return 1;
112
+ }
113
+ if (ctx.args.length === 0) {
114
+ return 0;
115
+ }
116
+ return ctx.shell.eval(ctx.args.join(" "));
117
+ };
118
+ var source = async (ctx) => {
119
+ if (!ctx.shell) {
120
+ await ctx.stderr.writeText(`source: shell evaluation not supported
121
+ `);
122
+ return 1;
123
+ }
124
+ const path = ctx.args[0];
125
+ if (path === undefined) {
126
+ await ctx.stderr.writeText(`source: filename argument required
127
+ `);
128
+ return 2;
129
+ }
130
+ return ctx.shell.source(path, ctx.args.slice(1));
131
+ };
132
+ var dot = source;
133
+
134
+ //# debugId=21C185C9E381C0F564756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/commands/sh/sh.ts"],
4
+ "sourcesContent": [
5
+ "import type { Command, Stderr, VirtualFS } from \"../../types.cjs\";\n\nasync function readShellFile(\n fs: VirtualFS,\n cwd: string,\n pathName: string,\n stderr: Stderr\n): Promise<{ ok: true; source: string } | { ok: false; exitCode: number }> {\n const path = fs.resolve(cwd, pathName);\n\n if (!(await fs.exists(path))) {\n await stderr.writeText(`sh: ${pathName}: No such file or directory\\n`);\n return { ok: false, exitCode: 127 };\n }\n\n const stat = await fs.stat(path);\n if (stat.isDirectory()) {\n await stderr.writeText(`sh: ${pathName}: is a directory\\n`);\n return { ok: false, exitCode: 126 };\n }\n if (!stat.isFile()) {\n await stderr.writeText(`sh: ${pathName}: not a file\\n`);\n return { ok: false, exitCode: 126 };\n }\n\n try {\n return { ok: true, source: await fs.readFile(path, \"utf-8\") };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n await stderr.writeText(`sh: ${pathName}: ${message}\\n`);\n return { ok: false, exitCode: 126 };\n }\n}\n\nexport const sh: Command = async (ctx) => {\n if (!ctx.shell) {\n await ctx.stderr.writeText(\"sh: shell evaluation not supported\\n\");\n return 1;\n }\n\n if (ctx.args.length === 0) {\n return ctx.shell.runShell(await ctx.stdin.text(), { argv0: \"sh\", args: [] });\n }\n\n const first = ctx.args[0]!;\n if (first === \"-c\") {\n const source = ctx.args[1];\n if (source === undefined) {\n await ctx.stderr.writeText(\"sh: -c requires an argument\\n\");\n return 2;\n }\n\n const argv0 = ctx.args[2] ?? \"sh\";\n const args = ctx.args[2] === undefined ? [] : ctx.args.slice(3);\n return ctx.shell.runShell(source, { argv0, args });\n }\n\n if (first.startsWith(\"-\")) {\n await ctx.stderr.writeText(`sh: unsupported option: ${first}\\n`);\n return 2;\n }\n\n const loaded = await readShellFile(ctx.fs, ctx.cwd, first, ctx.stderr);\n if (!loaded.ok) {\n return loaded.exitCode;\n }\n\n return ctx.shell.runShell(loaded.source, { argv0: first, args: ctx.args.slice(1) });\n};\n\nexport const evalCmd: Command = async (ctx) => {\n if (!ctx.shell) {\n await ctx.stderr.writeText(\"eval: shell evaluation not supported\\n\");\n return 1;\n }\n if (ctx.args.length === 0) {\n return 0;\n }\n return ctx.shell.eval(ctx.args.join(\" \"));\n};\n\nexport const source: Command = async (ctx) => {\n if (!ctx.shell) {\n await ctx.stderr.writeText(\"source: shell evaluation not supported\\n\");\n return 1;\n }\n const path = ctx.args[0];\n if (path === undefined) {\n await ctx.stderr.writeText(\"source: filename argument required\\n\");\n return 2;\n }\n return ctx.shell.source(path, ctx.args.slice(1));\n};\n\nexport const dot = source;\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "21C185C9E381C0F564756E2164756E21",
9
+ "names": []
10
+ }
@@ -79,6 +79,7 @@ __export(exports_src, {
79
79
  LexError: () => import_errors.LexError,
80
80
  Interpreter: () => import_interpreter.Interpreter,
81
81
  FileSystem: () => import_fs2.FileSystem,
82
+ ExitException: () => import_interpreter.ExitException,
82
83
  ContinueException: () => import_interpreter.ContinueException,
83
84
  BreakException: () => import_interpreter.BreakException
84
85
  });
@@ -98,4 +99,4 @@ var import_io2 = require("./io/index.cjs");
98
99
  var import_utils = require("./utils/index.cjs");
99
100
  var import_vcs = require("./vcs/index.cjs");
100
101
 
101
- //# debugId=188D4F3252D1BB8C64756E2164756E21
102
+ //# debugId=A1C14CC7E153FA4864756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "// Main class exports\nexport { ShellDSL, createShellDSL, type Program } from \"./shell-dsl.cjs\";\nexport { ShellPromise, type ShellPromiseOptions } from \"./shell-promise.cjs\";\n\n// Types\nexport type {\n VirtualFS,\n VirtualFSWritable,\n FileStat,\n Command,\n CommandContext,\n Stdin,\n Stdout,\n Stderr,\n OutputCollector,\n ExecResult,\n ShellConfig,\n RawValue,\n} from \"./types.cjs\";\nexport { isRawValue } from \"./types.cjs\";\n\n// Errors\nexport { ShellError, LexError, ParseError } from \"./errors.cjs\";\n\n// Lexer\nexport { Lexer, lex, tokenToString } from \"./lexer/index.cjs\";\nexport type { Token, RedirectMode } from \"./lexer/index.cjs\";\n\n// Parser\nexport { Parser, parse } from \"./parser/index.cjs\";\nexport type {\n ASTNode,\n Redirect,\n CommandNode,\n PipelineNode,\n AndNode,\n OrNode,\n SequenceNode,\n WordNode,\n WordPart,\n TextPart,\n VariablePart,\n SubstitutionPart,\n ArithmeticPart,\n IfNode,\n ForNode,\n WhileNode,\n UntilNode,\n CaseNode,\n CaseClause,\n} from \"./parser/index.cjs\";\nexport {\n isWordNode,\n isCommandNode,\n isPipelineNode,\n isAndNode,\n isOrNode,\n isSequenceNode,\n isIfNode,\n isForNode,\n isWhileNode,\n isUntilNode,\n isCaseNode,\n} from \"./parser/index.cjs\";\n\n// Interpreter\nexport { Interpreter, type InterpreterOptions, BreakException, ContinueException } from \"./interpreter/index.cjs\";\n\n// Filesystem\nexport { createVirtualFS } from \"./fs/index.cjs\";\nexport {\n FileSystem,\n ReadOnlyFileSystem,\n WebFileSystem,\n createWebUnderlyingFS,\n type PathOps,\n type Permission,\n type PermissionRules,\n type UnderlyingFS,\n} from \"./fs/index.cjs\";\n\n// I/O\nexport { createStdin, StdinImpl } from \"./io/index.cjs\";\nexport { createStdout, createStderr, createPipe, OutputCollectorImpl, PipeBuffer } from \"./io/index.cjs\";\n\n// Utilities\nexport { escape, escapeForInterpolation, globVirtualFS } from \"./utils/index.cjs\";\nexport type { GlobVirtualFS, GlobOptions } from \"./utils/index.cjs\";\n\n// Version Control\nexport { VersionControlSystem } from \"./vcs/index.cjs\";\nexport type {\n VCSConfig,\n VCSAttributeRule,\n VCSResolvedAttributes,\n VCSDiffMode,\n VCSPatchSuppressionReason,\n Revision,\n DiffEntry,\n TreeManifest,\n TreeEntry,\n FileEntry,\n DirectoryEntry,\n VCSIndexEntry,\n VCSIndexFile,\n CommitOptions,\n CheckoutOptions,\n LogOptions,\n LogEntry,\n BranchInfo,\n} from \"./vcs/index.cjs\";\n"
5
+ "// Main class exports\nexport { ShellDSL, createShellDSL, type Program } from \"./shell-dsl.cjs\";\nexport { ShellPromise, type ShellPromiseOptions } from \"./shell-promise.cjs\";\n\n// Types\nexport type {\n VirtualFS,\n VirtualFSWritable,\n FileStat,\n Command,\n CommandContext,\n Stdin,\n Stdout,\n Stderr,\n OutputCollector,\n ExecResult,\n ShellConfig,\n ShellCommandApi,\n ShellRunOptions,\n RawValue,\n} from \"./types.cjs\";\nexport { isRawValue } from \"./types.cjs\";\n\n// Errors\nexport { ShellError, LexError, ParseError } from \"./errors.cjs\";\n\n// Lexer\nexport { Lexer, lex, tokenToString } from \"./lexer/index.cjs\";\nexport type { Token, RedirectMode } from \"./lexer/index.cjs\";\n\n// Parser\nexport { Parser, parse } from \"./parser/index.cjs\";\nexport type {\n ASTNode,\n Redirect,\n CommandNode,\n PipelineNode,\n AndNode,\n OrNode,\n SequenceNode,\n WordNode,\n WordPart,\n TextPart,\n VariablePart,\n SubstitutionPart,\n ArithmeticPart,\n IfNode,\n ForNode,\n WhileNode,\n UntilNode,\n CaseNode,\n CaseClause,\n} from \"./parser/index.cjs\";\nexport {\n isWordNode,\n isCommandNode,\n isPipelineNode,\n isAndNode,\n isOrNode,\n isSequenceNode,\n isIfNode,\n isForNode,\n isWhileNode,\n isUntilNode,\n isCaseNode,\n} from \"./parser/index.cjs\";\n\n// Interpreter\nexport { Interpreter, type InterpreterOptions, BreakException, ContinueException, ExitException } from \"./interpreter/index.cjs\";\n\n// Filesystem\nexport { createVirtualFS } from \"./fs/index.cjs\";\nexport {\n FileSystem,\n ReadOnlyFileSystem,\n WebFileSystem,\n createWebUnderlyingFS,\n type PathOps,\n type Permission,\n type PermissionRules,\n type UnderlyingFS,\n} from \"./fs/index.cjs\";\n\n// I/O\nexport { createStdin, StdinImpl } from \"./io/index.cjs\";\nexport { createStdout, createStderr, createPipe, OutputCollectorImpl, PipeBuffer } from \"./io/index.cjs\";\n\n// Utilities\nexport { escape, escapeForInterpolation, globVirtualFS } from \"./utils/index.cjs\";\nexport type { GlobVirtualFS, GlobOptions } from \"./utils/index.cjs\";\n\n// Version Control\nexport { VersionControlSystem } from \"./vcs/index.cjs\";\nexport type {\n VCSConfig,\n VCSAttributeRule,\n VCSResolvedAttributes,\n VCSDiffMode,\n VCSPatchSuppressionReason,\n Revision,\n DiffEntry,\n TreeManifest,\n TreeEntry,\n FileEntry,\n DirectoryEntry,\n VCSIndexEntry,\n VCSIndexFile,\n CommitOptions,\n CheckoutOptions,\n LogOptions,\n LogEntry,\n BranchInfo,\n} from \"./vcs/index.cjs\";\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACuD,IAAvD;AACuD,IAAvD;AAiB2B,IAA3B;AAGiD,IAAjD;AAG0C,IAA1C;AAI8B,IAA9B;AAkCO,IAZP;AAewF,IAAxF;AAGgC,IAAhC;AAUO,IATP;AAYuC,IAAvC;AACwF,IAAxF;AAG8D,IAA9D;AAIqC,IAArC;",
8
- "debugId": "188D4F3252D1BB8C64756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACuD,IAAvD;AACuD,IAAvD;AAmB2B,IAA3B;AAGiD,IAAjD;AAG0C,IAA1C;AAI8B,IAA9B;AAkCO,IAZP;AAeuG,IAAvG;AAGgC,IAAhC;AAUO,IATP;AAYuC,IAAvC;AACwF,IAAxF;AAG8D,IAA9D;AAIqC,IAArC;",
8
+ "debugId": "A1C14CC7E153FA4864756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -56,7 +56,10 @@ function createCommandContext(options) {
56
56
  if (options.exec) {
57
57
  ctx.exec = options.exec;
58
58
  }
59
+ if (options.shell) {
60
+ ctx.shell = options.shell;
61
+ }
59
62
  return ctx;
60
63
  }
61
64
 
62
- //# debugId=F914897FD3ECFE8664756E2164756E21
65
+ //# debugId=A1213B6F49E1441764756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/interpreter/context.ts"],
4
4
  "sourcesContent": [
5
- "import type { CommandContext, VirtualFS, Stdin, Stdout, Stderr, ExecResult } from \"../types.cjs\";\n\nexport interface ContextOptions {\n args: string[];\n stdin: Stdin;\n stdout: Stdout;\n stderr: Stderr;\n fs: VirtualFS;\n cwd: string;\n env: Record<string, string>;\n setCwd: (path: string) => void;\n exec?: (name: string, args: string[]) => Promise<ExecResult>;\n}\n\nexport function createCommandContext(options: ContextOptions): CommandContext {\n const ctx: CommandContext = {\n args: options.args,\n stdin: options.stdin,\n stdout: options.stdout,\n stderr: options.stderr,\n fs: options.fs,\n cwd: options.cwd,\n env: options.env,\n setCwd: options.setCwd,\n };\n if (options.exec) {\n ctx.exec = options.exec;\n }\n return ctx;\n}\n"
5
+ "import type { CommandContext, VirtualFS, Stdin, Stdout, Stderr, ExecResult, ShellCommandApi } from \"../types.cjs\";\n\nexport interface ContextOptions {\n args: string[];\n stdin: Stdin;\n stdout: Stdout;\n stderr: Stderr;\n fs: VirtualFS;\n cwd: string;\n env: Record<string, string>;\n setCwd: (path: string) => void;\n exec?: (name: string, args: string[]) => Promise<ExecResult>;\n shell?: ShellCommandApi;\n}\n\nexport function createCommandContext(options: ContextOptions): CommandContext {\n const ctx: CommandContext = {\n args: options.args,\n stdin: options.stdin,\n stdout: options.stdout,\n stderr: options.stderr,\n fs: options.fs,\n cwd: options.cwd,\n env: options.env,\n setCwd: options.setCwd,\n };\n if (options.exec) {\n ctx.exec = options.exec;\n }\n if (options.shell) {\n ctx.shell = options.shell;\n }\n return ctx;\n}\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcO,SAAS,oBAAoB,CAAC,SAAyC;AAAA,EAC5E,MAAM,MAAsB;AAAA,IAC1B,MAAM,QAAQ;AAAA,IACd,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ;AAAA,IAChB,QAAQ,QAAQ;AAAA,IAChB,IAAI,QAAQ;AAAA,IACZ,KAAK,QAAQ;AAAA,IACb,KAAK,QAAQ;AAAA,IACb,QAAQ,QAAQ;AAAA,EAClB;AAAA,EACA,IAAI,QAAQ,MAAM;AAAA,IAChB,IAAI,OAAO,QAAQ;AAAA,EACrB;AAAA,EACA,OAAO;AAAA;",
8
- "debugId": "F914897FD3ECFE8664756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeO,SAAS,oBAAoB,CAAC,SAAyC;AAAA,EAC5E,MAAM,MAAsB;AAAA,IAC1B,MAAM,QAAQ;AAAA,IACd,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ;AAAA,IAChB,QAAQ,QAAQ;AAAA,IAChB,IAAI,QAAQ;AAAA,IACZ,KAAK,QAAQ;AAAA,IACb,KAAK,QAAQ;AAAA,IACb,QAAQ,QAAQ;AAAA,EAClB;AAAA,EACA,IAAI,QAAQ,MAAM;AAAA,IAChB,IAAI,OAAO,QAAQ;AAAA,EACrB;AAAA,EACA,IAAI,QAAQ,OAAO;AAAA,IACjB,IAAI,QAAQ,QAAQ;AAAA,EACtB;AAAA,EACA,OAAO;AAAA;",
8
+ "debugId": "A1213B6F49E1441764756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -41,6 +41,7 @@ var exports_interpreter = {};
41
41
  __export(exports_interpreter, {
42
42
  createCommandContext: () => import_context.createCommandContext,
43
43
  Interpreter: () => import_interpreter.Interpreter,
44
+ ExitException: () => import_interpreter.ExitException,
44
45
  ContinueException: () => import_interpreter.ContinueException,
45
46
  BreakException: () => import_interpreter.BreakException
46
47
  });
@@ -48,4 +49,4 @@ module.exports = __toCommonJS(exports_interpreter);
48
49
  var import_interpreter = require("./interpreter.cjs");
49
50
  var import_context = require("./context.cjs");
50
51
 
51
- //# debugId=D80D067B497FC53D64756E2164756E21
52
+ //# debugId=478C5E50B11BB65664756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/interpreter/index.ts"],
4
4
  "sourcesContent": [
5
- "export { Interpreter, type InterpreterOptions, BreakException, ContinueException } from \"./interpreter.cjs\";\nexport { createCommandContext, type ContextOptions } from \"./context.cjs\";\n"
5
+ "export { Interpreter, type InterpreterOptions, BreakException, ContinueException, ExitException } from \"./interpreter.cjs\";\nexport { createCommandContext, type ContextOptions } from \"./context.cjs\";\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAwF,IAAxF;AAC0D,IAA1D;",
8
- "debugId": "D80D067B497FC53D64756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAuG,IAAvG;AAC0D,IAA1D;",
8
+ "debugId": "478C5E50B11BB65664756E2164756E21",
9
9
  "names": []
10
10
  }