shell-dsl 0.0.21 → 0.0.23

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 (40) hide show
  1. package/README.md +50 -2
  2. package/dist/cjs/package.json +1 -1
  3. package/dist/cjs/src/commands/cut/cut.cjs +188 -0
  4. package/dist/cjs/src/commands/cut/cut.cjs.map +10 -0
  5. package/dist/cjs/src/commands/index.cjs +6 -2
  6. package/dist/cjs/src/commands/index.cjs.map +3 -3
  7. package/dist/cjs/src/commands/ls/ls.cjs +2 -2
  8. package/dist/cjs/src/commands/ls/ls.cjs.map +3 -3
  9. package/dist/cjs/src/interpreter/interpreter.cjs +5 -3
  10. package/dist/cjs/src/interpreter/interpreter.cjs.map +3 -3
  11. package/dist/cjs/src/io/stdout.cjs +11 -5
  12. package/dist/cjs/src/io/stdout.cjs.map +3 -3
  13. package/dist/cjs/src/parser/parser.cjs +3 -2
  14. package/dist/cjs/src/parser/parser.cjs.map +3 -3
  15. package/dist/cjs/src/shell-dsl.cjs +9 -4
  16. package/dist/cjs/src/shell-dsl.cjs.map +3 -3
  17. package/dist/cjs/src/types.cjs.map +2 -2
  18. package/dist/mjs/package.json +1 -1
  19. package/dist/mjs/src/commands/cut/cut.mjs +158 -0
  20. package/dist/mjs/src/commands/cut/cut.mjs.map +10 -0
  21. package/dist/mjs/src/commands/index.mjs +6 -2
  22. package/dist/mjs/src/commands/index.mjs.map +3 -3
  23. package/dist/mjs/src/commands/ls/ls.mjs +2 -2
  24. package/dist/mjs/src/commands/ls/ls.mjs.map +3 -3
  25. package/dist/mjs/src/interpreter/interpreter.mjs +5 -3
  26. package/dist/mjs/src/interpreter/interpreter.mjs.map +3 -3
  27. package/dist/mjs/src/io/stdout.mjs +11 -5
  28. package/dist/mjs/src/io/stdout.mjs.map +3 -3
  29. package/dist/mjs/src/parser/parser.mjs +3 -5
  30. package/dist/mjs/src/parser/parser.mjs.map +3 -3
  31. package/dist/mjs/src/shell-dsl.mjs +9 -4
  32. package/dist/mjs/src/shell-dsl.mjs.map +3 -3
  33. package/dist/mjs/src/types.mjs.map +2 -2
  34. package/dist/types/src/commands/cut/cut.d.ts +2 -0
  35. package/dist/types/src/commands/index.d.ts +1 -0
  36. package/dist/types/src/interpreter/interpreter.d.ts +2 -0
  37. package/dist/types/src/io/stdout.d.ts +6 -2
  38. package/dist/types/src/shell-dsl.d.ts +1 -0
  39. package/dist/types/src/types.d.ts +3 -0
  40. package/package.json +1 -1
package/README.md CHANGED
@@ -279,6 +279,52 @@ await sh`echo $API_KEY`.text(); // "secret\n"
279
279
  sh.resetEnv(); // Restore initial environment
280
280
  ```
281
281
 
282
+ ## TTY Detection
283
+
284
+ Commands can check `ctx.stdout.isTTY` to vary their output format depending on whether they're writing to a terminal or a pipe/file, just like real shell commands do (e.g. `ls` uses columnar output on a terminal but one-per-line when piped).
285
+
286
+ Enable TTY mode via the `isTTY` config option (default `false`):
287
+
288
+ ```ts
289
+ const sh = createShellDSL({
290
+ fs: createVirtualFS(createFsFromVolume(vol)),
291
+ cwd: "/",
292
+ env: {},
293
+ commands: builtinCommands,
294
+ isTTY: true,
295
+ });
296
+
297
+ // Standalone command — stdout.isTTY is true
298
+ await sh`ls /dir`.text(); // "file1.txt file2.txt subdir\n"
299
+
300
+ // Piped command — intermediate stdout.isTTY is always false
301
+ await sh`ls /dir | grep file`.text(); // "file1.txt\nfile2.txt\n"
302
+ ```
303
+
304
+ | Context | `stdout.isTTY` |
305
+ |---------|----------------|
306
+ | Standalone command, shell has `isTTY: true` | `true` |
307
+ | Intermediate command in pipeline | `false` |
308
+ | Output redirected to file (`> file`) | `false` |
309
+ | Command substitution (`$(cmd)`) | `false` |
310
+ | Shell has `isTTY: false` (default) | `false` |
311
+
312
+ ### Using isTTY in Custom Commands
313
+
314
+ ```ts
315
+ const myls: Command = async (ctx) => {
316
+ const entries = await ctx.fs.readdir(ctx.cwd);
317
+ if (ctx.stdout.isTTY) {
318
+ await ctx.stdout.writeText(entries.join(" ") + "\n");
319
+ } else {
320
+ for (const entry of entries) {
321
+ await ctx.stdout.writeText(entry + "\n");
322
+ }
323
+ }
324
+ return 0;
325
+ };
326
+ ```
327
+
282
328
  ## Glob Expansion
283
329
 
284
330
  Globs are expanded by the interpreter before command execution:
@@ -356,6 +402,7 @@ interface Stdin {
356
402
  interface Stdout {
357
403
  write(chunk: Uint8Array): Promise<void>; // Write bytes
358
404
  writeText(str: string): Promise<void>; // Write UTF-8 string
405
+ isTTY: boolean; // Whether output is a terminal
359
406
  }
360
407
  ```
361
408
 
@@ -496,7 +543,7 @@ import { builtinCommands } from "shell-dsl/commands";
496
543
  Or import individually:
497
544
 
498
545
  ```ts
499
- import { echo, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk } from "shell-dsl/commands";
546
+ import { echo, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk, cut } from "shell-dsl/commands";
500
547
  ```
501
548
 
502
549
  | Command | Description |
@@ -510,7 +557,7 @@ import { echo, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk } from "s
510
557
  | `sort` | Sort lines (`-r` reverse, `-n` numeric) |
511
558
  | `uniq` | Remove duplicate adjacent lines (`-c` count) |
512
559
  | `pwd` | Print working directory |
513
- | `ls` | List directory contents |
560
+ | `ls` | List directory contents (TTY-aware: space-separated on TTY, one-per-line when piped) |
514
561
  | `mkdir` | Create directories (`-p` parents) |
515
562
  | `rm` | Remove files/directories (`-r` recursive, `-f` force) |
516
563
  | `cp` | Copy files/directories (`-r` recursive, `-n` no-clobber) |
@@ -521,6 +568,7 @@ import { echo, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk } from "s
521
568
  | `find` | Search for files (`-name`, `-iname`, `-type f\|d`, `-maxdepth`, `-mindepth`) |
522
569
  | `sed` | Stream editor (`s///`, `d`, `p`, `-n`, `-e`) |
523
570
  | `awk` | Pattern scanning (`{print $1}`, `-F`, `NF`, `NR`) |
571
+ | `cut` | Select fields/characters (`-f`, `-d`, `-c`, `-b`, `-s`, `--complement`) |
524
572
  | `test` / `[` | File and string tests (`-f`, `-d`, `-e`, `-z`, `-n`, `=`, `!=`) |
525
573
  | `true` | Exit with code 0 |
526
574
  | `false` | Exit with code 1 |
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "shell-dsl",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "type": "commonjs"
5
5
  }
@@ -0,0 +1,188 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
6
+ var __toCommonJS = (from) => {
7
+ var entry = __moduleCache.get(from), desc;
8
+ if (entry)
9
+ return entry;
10
+ entry = __defProp({}, "__esModule", { value: true });
11
+ if (from && typeof from === "object" || typeof from === "function")
12
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
13
+ get: () => from[key],
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ }));
16
+ __moduleCache.set(from, entry);
17
+ return entry;
18
+ };
19
+ var __export = (target, all) => {
20
+ for (var name in all)
21
+ __defProp(target, name, {
22
+ get: all[name],
23
+ enumerable: true,
24
+ configurable: true,
25
+ set: (newValue) => all[name] = () => newValue
26
+ });
27
+ };
28
+
29
+ // src/commands/cut/cut.ts
30
+ var exports_cut = {};
31
+ __export(exports_cut, {
32
+ cut: () => cut
33
+ });
34
+ module.exports = __toCommonJS(exports_cut);
35
+ var import_flag_parser = require("../../utils/flag-parser.cjs");
36
+ var spec = {
37
+ name: "cut",
38
+ flags: [
39
+ { short: "b", long: "bytes", takesValue: true },
40
+ { short: "c", long: "characters", takesValue: true },
41
+ { short: "d", long: "delimiter", takesValue: true },
42
+ { short: "f", long: "fields", takesValue: true },
43
+ { short: "s", long: "only-delimited" },
44
+ { long: "complement" },
45
+ { long: "output-delimiter", takesValue: true }
46
+ ],
47
+ usage: `cut -b list [-n] [file ...]
48
+ cut -c list [file ...]
49
+ cut -f list [-d delim] [-s] [file ...]`
50
+ };
51
+ var defaults = {
52
+ bytes: null,
53
+ characters: null,
54
+ delimiter: "\t",
55
+ fields: null,
56
+ onlyDelimited: false,
57
+ complement: false,
58
+ outputDelimiter: null
59
+ };
60
+ var handler = (flags, flag, value) => {
61
+ if (flag.short === "b")
62
+ flags.bytes = value ?? null;
63
+ if (flag.short === "c")
64
+ flags.characters = value ?? null;
65
+ if (flag.short === "d")
66
+ flags.delimiter = value ?? "\t";
67
+ if (flag.short === "f")
68
+ flags.fields = value ?? null;
69
+ if (flag.short === "s")
70
+ flags.onlyDelimited = true;
71
+ if (flag.long === "complement")
72
+ flags.complement = true;
73
+ if (flag.long === "output-delimiter")
74
+ flags.outputDelimiter = value ?? null;
75
+ };
76
+ var parser = import_flag_parser.createFlagParser(spec, defaults, handler);
77
+ function parseListSpec(listStr) {
78
+ const ranges = [];
79
+ for (const part of listStr.split(",")) {
80
+ const trimmed = part.trim();
81
+ if (trimmed.includes("-")) {
82
+ const [startStr, endStr] = trimmed.split("-", 2);
83
+ const start = startStr === "" ? null : parseInt(startStr, 10);
84
+ const end = endStr === "" ? null : parseInt(endStr, 10);
85
+ ranges.push({ start, end });
86
+ } else {
87
+ const n = parseInt(trimmed, 10);
88
+ ranges.push({ start: n, end: n });
89
+ }
90
+ }
91
+ return (index, total) => {
92
+ for (const { start, end } of ranges) {
93
+ const s = start ?? 1;
94
+ const e = end ?? total;
95
+ if (index >= s && index <= e)
96
+ return true;
97
+ }
98
+ return false;
99
+ };
100
+ }
101
+ var cut = async (ctx) => {
102
+ const result = parser.parse(ctx.args);
103
+ if (result.error) {
104
+ await parser.writeError(result.error, ctx.stderr);
105
+ return 1;
106
+ }
107
+ const { bytes, characters, fields, delimiter, onlyDelimited, complement, outputDelimiter } = result.flags;
108
+ const modeCount = [bytes, characters, fields].filter((v) => v !== null).length;
109
+ if (modeCount === 0) {
110
+ await ctx.stderr.writeText(`cut: you must specify a list of bytes, characters, or fields
111
+ `);
112
+ return 1;
113
+ }
114
+ if (modeCount > 1) {
115
+ await ctx.stderr.writeText(`cut: only one type of list may be specified
116
+ `);
117
+ return 1;
118
+ }
119
+ const listStr = bytes ?? characters ?? fields;
120
+ const selector = parseListSpec(listStr);
121
+ const mode = bytes !== null ? "bytes" : characters !== null ? "chars" : "fields";
122
+ const processLine = async (line) => {
123
+ if (mode === "fields") {
124
+ if (!line.includes(delimiter)) {
125
+ if (onlyDelimited)
126
+ return;
127
+ await ctx.stdout.writeText(line + `
128
+ `);
129
+ return;
130
+ }
131
+ const parts = line.split(delimiter);
132
+ const total = parts.length;
133
+ const selected = [];
134
+ for (let i = 0;i < total; i++) {
135
+ const idx = i + 1;
136
+ const isSelected = selector(idx, total);
137
+ if (complement ? !isSelected : isSelected) {
138
+ selected.push(parts[i]);
139
+ }
140
+ }
141
+ const outDelim = outputDelimiter ?? delimiter;
142
+ await ctx.stdout.writeText(selected.join(outDelim) + `
143
+ `);
144
+ } else {
145
+ const chars = [...line];
146
+ const total = chars.length;
147
+ const selected = [];
148
+ for (let i = 0;i < total; i++) {
149
+ const idx = i + 1;
150
+ const isSelected = selector(idx, total);
151
+ if (complement ? !isSelected : isSelected) {
152
+ selected.push(chars[i]);
153
+ }
154
+ }
155
+ const outDelim = outputDelimiter ?? "";
156
+ await ctx.stdout.writeText(selected.join(outDelim) + `
157
+ `);
158
+ }
159
+ };
160
+ const files = result.args;
161
+ if (files.length === 0) {
162
+ for await (const line of ctx.stdin.lines()) {
163
+ await processLine(line);
164
+ }
165
+ } else {
166
+ for (const file of files) {
167
+ try {
168
+ const path = ctx.fs.resolve(ctx.cwd, file);
169
+ const content = (await ctx.fs.readFile(path)).toString();
170
+ const lines = content.split(`
171
+ `);
172
+ if (lines.length > 0 && lines[lines.length - 1] === "") {
173
+ lines.pop();
174
+ }
175
+ for (const line of lines) {
176
+ await processLine(line);
177
+ }
178
+ } catch {
179
+ await ctx.stderr.writeText(`cut: ${file}: No such file or directory
180
+ `);
181
+ return 1;
182
+ }
183
+ }
184
+ }
185
+ return 0;
186
+ };
187
+
188
+ //# debugId=27E02324E2E46D1D64756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/commands/cut/cut.ts"],
4
+ "sourcesContent": [
5
+ "import type { Command } from \"../../types.cjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.cjs\";\n\ninterface CutFlags {\n bytes: string | null;\n characters: string | null;\n delimiter: string;\n fields: string | null;\n onlyDelimited: boolean;\n complement: boolean;\n outputDelimiter: string | null;\n}\n\nconst spec = {\n name: \"cut\",\n flags: [\n { short: \"b\", long: \"bytes\", takesValue: true },\n { short: \"c\", long: \"characters\", takesValue: true },\n { short: \"d\", long: \"delimiter\", takesValue: true },\n { short: \"f\", long: \"fields\", takesValue: true },\n { short: \"s\", long: \"only-delimited\" },\n { long: \"complement\" },\n { long: \"output-delimiter\", takesValue: true },\n ] as FlagDefinition[],\n usage: \"cut -b list [-n] [file ...]\\n cut -c list [file ...]\\n cut -f list [-d delim] [-s] [file ...]\",\n};\n\nconst defaults: CutFlags = {\n bytes: null,\n characters: null,\n delimiter: \"\\t\",\n fields: null,\n onlyDelimited: false,\n complement: false,\n outputDelimiter: null,\n};\n\nconst handler = (flags: CutFlags, flag: FlagDefinition, value?: string) => {\n if (flag.short === \"b\") flags.bytes = value ?? null;\n if (flag.short === \"c\") flags.characters = value ?? null;\n if (flag.short === \"d\") flags.delimiter = value ?? \"\\t\";\n if (flag.short === \"f\") flags.fields = value ?? null;\n if (flag.short === \"s\") flags.onlyDelimited = true;\n if (flag.long === \"complement\") flags.complement = true;\n if (flag.long === \"output-delimiter\") flags.outputDelimiter = value ?? null;\n};\n\nconst parser = createFlagParser(spec, defaults, handler);\n\n/**\n * Parse a list specification like \"1\", \"1,3,5\", \"1-3\", \"1-\", \"-3\", \"1-3,7,9-\"\n * Returns a function that checks if a 1-based index is selected.\n */\nfunction parseListSpec(\n listStr: string\n): (index: number, total: number) => boolean {\n const ranges: Array<{ start: number | null; end: number | null }> = [];\n\n for (const part of listStr.split(\",\")) {\n const trimmed = part.trim();\n if (trimmed.includes(\"-\")) {\n const [startStr, endStr] = trimmed.split(\"-\", 2);\n const start = startStr === \"\" ? null : parseInt(startStr!, 10);\n const end = endStr === \"\" ? null : parseInt(endStr!, 10);\n ranges.push({ start, end });\n } else {\n const n = parseInt(trimmed, 10);\n ranges.push({ start: n, end: n });\n }\n }\n\n return (index: number, total: number): boolean => {\n for (const { start, end } of ranges) {\n const s = start ?? 1;\n const e = end ?? total;\n if (index >= s && index <= e) return true;\n }\n return false;\n };\n}\n\nexport const cut: Command = async (ctx) => {\n const result = parser.parse(ctx.args);\n\n if (result.error) {\n await parser.writeError(result.error, ctx.stderr);\n return 1;\n }\n\n const { bytes, characters, fields, delimiter, onlyDelimited, complement, outputDelimiter } =\n result.flags;\n\n // Validate: exactly one of -b, -c, -f must be given\n const modeCount = [bytes, characters, fields].filter((v) => v !== null).length;\n if (modeCount === 0) {\n await ctx.stderr.writeText(\n \"cut: you must specify a list of bytes, characters, or fields\\n\"\n );\n return 1;\n }\n if (modeCount > 1) {\n await ctx.stderr.writeText(\n \"cut: only one type of list may be specified\\n\"\n );\n return 1;\n }\n\n const listStr = (bytes ?? characters ?? fields)!;\n const selector = parseListSpec(listStr);\n const mode = bytes !== null ? \"bytes\" : characters !== null ? \"chars\" : \"fields\";\n\n const processLine = async (line: string) => {\n if (mode === \"fields\") {\n // Check if delimiter exists in line\n if (!line.includes(delimiter)) {\n if (onlyDelimited) return;\n await ctx.stdout.writeText(line + \"\\n\");\n return;\n }\n\n const parts = line.split(delimiter);\n const total = parts.length;\n const selected: string[] = [];\n\n for (let i = 0; i < total; i++) {\n const idx = i + 1; // 1-based\n const isSelected = selector(idx, total);\n if (complement ? !isSelected : isSelected) {\n selected.push(parts[i]!);\n }\n }\n\n const outDelim = outputDelimiter ?? delimiter;\n await ctx.stdout.writeText(selected.join(outDelim) + \"\\n\");\n } else {\n // bytes/chars mode (equivalent for simplicity)\n const chars = [...line];\n const total = chars.length;\n const selected: string[] = [];\n\n for (let i = 0; i < total; i++) {\n const idx = i + 1; // 1-based\n const isSelected = selector(idx, total);\n if (complement ? !isSelected : isSelected) {\n selected.push(chars[i]!);\n }\n }\n\n const outDelim = outputDelimiter ?? \"\";\n await ctx.stdout.writeText(selected.join(outDelim) + \"\\n\");\n }\n };\n\n const files = result.args;\n\n if (files.length === 0) {\n // Read from stdin\n for await (const line of ctx.stdin.lines()) {\n await processLine(line);\n }\n } else {\n for (const file of files) {\n try {\n const path = ctx.fs.resolve(ctx.cwd, file);\n const content = (await ctx.fs.readFile(path)).toString();\n const lines = content.split(\"\\n\");\n // Remove trailing empty line from final newline\n if (lines.length > 0 && lines[lines.length - 1] === \"\") {\n lines.pop();\n }\n for (const line of lines) {\n await processLine(line);\n }\n } catch {\n await ctx.stderr.writeText(`cut: ${file}: No such file or directory\\n`);\n return 1;\n }\n }\n }\n\n return 0;\n};\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "27E02324E2E46D1D64756E2164756E21",
9
+ "names": []
10
+ }
@@ -50,6 +50,7 @@ __export(exports_commands, {
50
50
  find: () => import_find.find,
51
51
  falseCmd: () => import_true_false.falseCmd,
52
52
  echo: () => import_echo.echo,
53
+ cut: () => import_cut.cut,
53
54
  cp: () => import_cp.cp,
54
55
  continueCmd: () => import_break_continue.continueCmd,
55
56
  colon: () => import_colon.colon,
@@ -87,6 +88,7 @@ var import_break_continue = require("./break-continue/break-continue.cjs");
87
88
  var import_colon = require("./colon/colon.cjs");
88
89
  var import_cd = require("./cd/cd.cjs");
89
90
  var import_tr = require("./tr/tr.cjs");
91
+ var import_cut = require("./cut/cut.cjs");
90
92
  var import_echo2 = require("./echo/echo.cjs");
91
93
  var import_cat2 = require("./cat/cat.cjs");
92
94
  var import_grep2 = require("./grep/grep.cjs");
@@ -113,6 +115,7 @@ var import_break_continue2 = require("./break-continue/break-continue.cjs");
113
115
  var import_colon2 = require("./colon/colon.cjs");
114
116
  var import_cd2 = require("./cd/cd.cjs");
115
117
  var import_tr2 = require("./tr/tr.cjs");
118
+ var import_cut2 = require("./cut/cut.cjs");
116
119
  var builtinCommands = {
117
120
  echo: import_echo2.echo,
118
121
  cat: import_cat2.cat,
@@ -142,7 +145,8 @@ var builtinCommands = {
142
145
  continue: import_break_continue2.continueCmd,
143
146
  ":": import_colon2.colon,
144
147
  cd: import_cd2.cd,
145
- tr: import_tr2.tr
148
+ tr: import_tr2.tr,
149
+ cut: import_cut2.cut
146
150
  };
147
151
 
148
- //# debugId=17598CDDC0006B1664756E2164756E21
152
+ //# debugId=BFE70ED48B7DB93D64756E2164756E21
@@ -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 { 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\";\n\n// Re-export all commands as a bundle\nimport { echo } from \"./echo/echo.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\";\n\nexport const builtinCommands: Record<string, Command> = {\n echo,\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};\n"
5
+ "import type { Command } from \"../types.cjs\";\n\nexport { echo } from \"./echo/echo.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\";\n\n// Re-export all commands as a bundle\nimport { echo } from \"./echo/echo.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\";\n\nexport const builtinCommands: Record<string, Command> = {\n echo,\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};\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEqB,IAArB;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;AAGqB,IAArB;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;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,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;AACF;",
8
- "debugId": "17598CDDC0006B1664756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEqB,IAArB;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;AAGqB,IAArB;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;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,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;AACF;",
8
+ "debugId": "BFE70ED48B7DB93D64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -94,7 +94,7 @@ var ls = async (ctx) => {
94
94
  `);
95
95
  }
96
96
  }
97
- } else if (onePerLine) {
97
+ } else if (onePerLine || !ctx.stdout.isTTY) {
98
98
  for (const entry of entries) {
99
99
  await ctx.stdout.writeText(entry + `
100
100
  `);
@@ -139,4 +139,4 @@ var ls = async (ctx) => {
139
139
  return 0;
140
140
  };
141
141
 
142
- //# debugId=5A080C64ADFFC97C64756E2164756E21
142
+ //# debugId=74ED3BA04DAC332A64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/commands/ls/ls.ts"],
4
4
  "sourcesContent": [
5
- "import type { Command } from \"../../types.cjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.cjs\";\n\ninterface LsFlags {\n all: boolean;\n long: boolean;\n onePerLine: boolean;\n recursive: boolean;\n}\n\nconst spec = {\n name: \"ls\",\n flags: [\n { short: \"a\", long: \"all\" },\n { short: \"l\" },\n { short: \"1\" },\n { short: \"R\" },\n ] as FlagDefinition[],\n usage: \"ls [-alR1] [file ...]\",\n};\n\nconst defaults: LsFlags = { all: false, long: false, onePerLine: false, recursive: false };\n\nconst handler = (flags: LsFlags, flag: FlagDefinition) => {\n if (flag.short === \"a\") flags.all = true;\n if (flag.short === \"l\") flags.long = true;\n if (flag.short === \"1\") flags.onePerLine = true;\n if (flag.short === \"R\") flags.recursive = true;\n};\n\nconst parser = createFlagParser(spec, defaults, handler);\n\nexport const ls: Command = async (ctx) => {\n const result = parser.parse(ctx.args);\n\n if (result.error) {\n await parser.writeError(result.error, ctx.stderr);\n return 1;\n }\n\n const { all: showAll, long: longFormat, onePerLine, recursive } = result.flags;\n const paths = result.args.length === 0 ? [\".\"] : result.args;\n let needsBlankLine = false;\n\n const listDir = async (dirPath: string, displayPath: string, showHeader: boolean) => {\n if (needsBlankLine) await ctx.stdout.writeText(\"\\n\");\n needsBlankLine = true;\n\n if (showHeader) {\n await ctx.stdout.writeText(`${displayPath}:\\n`);\n }\n\n let entries = await ctx.fs.readdir(dirPath);\n\n if (!showAll) {\n entries = entries.filter((e) => !e.startsWith(\".\"));\n }\n\n entries.sort();\n\n if (longFormat) {\n for (const entry of entries) {\n const entryPath = ctx.fs.resolve(dirPath, entry);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n const type = entryStat.isDirectory() ? \"d\" : \"-\";\n const perms = \"rwxr-xr-x\";\n const size = String(entryStat.size).padStart(8);\n const date = entryStat.mtime.toISOString().slice(0, 10);\n await ctx.stdout.writeText(`${type}${perms} ${size} ${date} ${entry}\\n`);\n } catch {\n await ctx.stdout.writeText(`?????????? ${entry}\\n`);\n }\n }\n } else if (onePerLine) {\n for (const entry of entries) {\n await ctx.stdout.writeText(entry + \"\\n\");\n }\n } else {\n if (entries.length > 0) {\n await ctx.stdout.writeText(entries.join(\" \") + \"\\n\");\n }\n }\n\n if (recursive) {\n for (const entry of entries) {\n const entryPath = ctx.fs.resolve(dirPath, entry);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n if (entryStat.isDirectory()) {\n const subDisplay = displayPath === \".\" ? entry : `${displayPath}/${entry}`;\n await listDir(entryPath, subDisplay, true);\n }\n } catch {\n // skip entries we can't stat\n }\n }\n }\n };\n\n for (let i = 0; i < paths.length; i++) {\n const pathArg = paths[i]!;\n const path = ctx.fs.resolve(ctx.cwd, pathArg);\n\n try {\n const stat = await ctx.fs.stat(path);\n\n if (stat.isFile()) {\n await ctx.stdout.writeText(ctx.fs.basename(path) + \"\\n\");\n continue;\n }\n\n const showHeader = recursive || paths.length > 1;\n await listDir(path, pathArg, showHeader);\n } catch (err) {\n await ctx.stderr.writeText(`ls: cannot access '${pathArg}': No such file or directory\\n`);\n return 1;\n }\n }\n\n return 0;\n};\n"
5
+ "import type { Command } from \"../../types.cjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.cjs\";\n\ninterface LsFlags {\n all: boolean;\n long: boolean;\n onePerLine: boolean;\n recursive: boolean;\n}\n\nconst spec = {\n name: \"ls\",\n flags: [\n { short: \"a\", long: \"all\" },\n { short: \"l\" },\n { short: \"1\" },\n { short: \"R\" },\n ] as FlagDefinition[],\n usage: \"ls [-alR1] [file ...]\",\n};\n\nconst defaults: LsFlags = { all: false, long: false, onePerLine: false, recursive: false };\n\nconst handler = (flags: LsFlags, flag: FlagDefinition) => {\n if (flag.short === \"a\") flags.all = true;\n if (flag.short === \"l\") flags.long = true;\n if (flag.short === \"1\") flags.onePerLine = true;\n if (flag.short === \"R\") flags.recursive = true;\n};\n\nconst parser = createFlagParser(spec, defaults, handler);\n\nexport const ls: Command = async (ctx) => {\n const result = parser.parse(ctx.args);\n\n if (result.error) {\n await parser.writeError(result.error, ctx.stderr);\n return 1;\n }\n\n const { all: showAll, long: longFormat, onePerLine, recursive } = result.flags;\n const paths = result.args.length === 0 ? [\".\"] : result.args;\n let needsBlankLine = false;\n\n const listDir = async (dirPath: string, displayPath: string, showHeader: boolean) => {\n if (needsBlankLine) await ctx.stdout.writeText(\"\\n\");\n needsBlankLine = true;\n\n if (showHeader) {\n await ctx.stdout.writeText(`${displayPath}:\\n`);\n }\n\n let entries = await ctx.fs.readdir(dirPath);\n\n if (!showAll) {\n entries = entries.filter((e) => !e.startsWith(\".\"));\n }\n\n entries.sort();\n\n if (longFormat) {\n for (const entry of entries) {\n const entryPath = ctx.fs.resolve(dirPath, entry);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n const type = entryStat.isDirectory() ? \"d\" : \"-\";\n const perms = \"rwxr-xr-x\";\n const size = String(entryStat.size).padStart(8);\n const date = entryStat.mtime.toISOString().slice(0, 10);\n await ctx.stdout.writeText(`${type}${perms} ${size} ${date} ${entry}\\n`);\n } catch {\n await ctx.stdout.writeText(`?????????? ${entry}\\n`);\n }\n }\n } else if (onePerLine || !ctx.stdout.isTTY) {\n for (const entry of entries) {\n await ctx.stdout.writeText(entry + \"\\n\");\n }\n } else {\n if (entries.length > 0) {\n await ctx.stdout.writeText(entries.join(\" \") + \"\\n\");\n }\n }\n\n if (recursive) {\n for (const entry of entries) {\n const entryPath = ctx.fs.resolve(dirPath, entry);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n if (entryStat.isDirectory()) {\n const subDisplay = displayPath === \".\" ? entry : `${displayPath}/${entry}`;\n await listDir(entryPath, subDisplay, true);\n }\n } catch {\n // skip entries we can't stat\n }\n }\n }\n };\n\n for (let i = 0; i < paths.length; i++) {\n const pathArg = paths[i]!;\n const path = ctx.fs.resolve(ctx.cwd, pathArg);\n\n try {\n const stat = await ctx.fs.stat(path);\n\n if (stat.isFile()) {\n await ctx.stdout.writeText(ctx.fs.basename(path) + \"\\n\");\n continue;\n }\n\n const showHeader = recursive || paths.length > 1;\n await listDir(path, pathArg, showHeader);\n } catch (err) {\n await ctx.stderr.writeText(`ls: cannot access '${pathArg}': No such file or directory\\n`);\n return 1;\n }\n }\n\n return 0;\n};\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "5A080C64ADFFC97C64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "74ED3BA04DAC332A64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -61,19 +61,21 @@ class Interpreter {
61
61
  commands;
62
62
  redirectObjects;
63
63
  loopDepth = 0;
64
+ isTTY;
64
65
  constructor(options) {
65
66
  this.fs = options.fs;
66
67
  this.cwd = options.cwd;
67
68
  this.env = { ...options.env };
68
69
  this.commands = options.commands;
69
70
  this.redirectObjects = options.redirectObjects ?? {};
71
+ this.isTTY = options.isTTY ?? false;
70
72
  }
71
73
  getLoopDepth() {
72
74
  return this.loopDepth;
73
75
  }
74
76
  async execute(ast) {
75
- const stdout = import_stdout.createStdout();
76
- const stderr = import_stdout.createStderr();
77
+ const stdout = import_stdout.createStdout(this.isTTY);
78
+ const stderr = import_stdout.createStderr(this.isTTY);
77
79
  const exitCode = await this.executeNode(ast, null, stdout, stderr);
78
80
  stdout.close();
79
81
  stderr.close();
@@ -810,4 +812,4 @@ class Interpreter {
810
812
  }
811
813
  }
812
814
 
813
- //# debugId=DA8D03FA6D96307064756E2164756E21
815
+ //# debugId=7B263C6315A30CB564756E2164756E21