just-bash 2.4.4 → 2.5.1

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 (91) hide show
  1. package/README.md +42 -4
  2. package/dist/AGENTS.md +2 -2
  3. package/dist/bin/chunks/base64-O7TCK5TL.js +6 -0
  4. package/dist/bin/{shell/chunks/cat-ZEMMQGY5.js → chunks/cat-AJXZOSPN.js} +1 -1
  5. package/dist/bin/chunks/{chunk-45SNFRCY.js → chunk-5WFYIUU2.js} +2 -2
  6. package/dist/bin/chunks/chunk-CTLU5QUH.js +17 -0
  7. package/dist/bin/{shell/chunks/chunk-GX4MPCG6.js → chunks/chunk-Y5QKO4KO.js} +5 -5
  8. package/dist/bin/chunks/{cut-WWPJ2PYT.js → cut-IHF6BEOO.js} +1 -1
  9. package/dist/bin/chunks/grep-QCXXYC54.js +9 -0
  10. package/dist/bin/{shell/chunks/gzip-MNCJB6OR.js → chunks/gzip-YXK3WZQL.js} +22 -22
  11. package/dist/bin/{shell/chunks/jq-XH2PXRWE.js → chunks/jq-XXZPU5CA.js} +1 -1
  12. package/dist/bin/chunks/{md5sum-VGXAOUBA.js → md5sum-2VAAFCTS.js} +1 -1
  13. package/dist/bin/chunks/rg-GVIT6FTE.js +33 -0
  14. package/dist/bin/chunks/{sha1sum-BIUH233Z.js → sha1sum-67P4ME4N.js} +1 -1
  15. package/dist/bin/{shell/chunks/sha256sum-SUIK2MT2.js → chunks/sha256sum-MV3WQ4QF.js} +1 -1
  16. package/dist/bin/{shell/chunks/sort-C3F6LCNY.js → chunks/sort-KUHOCH5S.js} +1 -1
  17. package/dist/bin/chunks/tar-C27YYUAS.js +63 -0
  18. package/dist/bin/{shell/chunks/uniq-DKS7RIAE.js → chunks/uniq-IXHB2FVS.js} +1 -1
  19. package/dist/bin/chunks/{wc-4LMTC3QD.js → wc-QSBRKIF5.js} +1 -1
  20. package/dist/bin/chunks/{xan-WNN2ZOAX.js → xan-6K2NGTHM.js} +1 -1
  21. package/dist/bin/just-bash.js +78 -78
  22. package/dist/bin/shell/chunks/base64-O7TCK5TL.js +6 -0
  23. package/dist/bin/{chunks/cat-ZEMMQGY5.js → shell/chunks/cat-AJXZOSPN.js} +1 -1
  24. package/dist/bin/shell/chunks/{chunk-45SNFRCY.js → chunk-5WFYIUU2.js} +2 -2
  25. package/dist/bin/shell/chunks/chunk-CTLU5QUH.js +17 -0
  26. package/dist/bin/{chunks/chunk-GX4MPCG6.js → shell/chunks/chunk-Y5QKO4KO.js} +5 -5
  27. package/dist/bin/shell/chunks/{cut-WWPJ2PYT.js → cut-IHF6BEOO.js} +1 -1
  28. package/dist/bin/shell/chunks/grep-QCXXYC54.js +9 -0
  29. package/dist/bin/{chunks/gzip-MNCJB6OR.js → shell/chunks/gzip-YXK3WZQL.js} +22 -22
  30. package/dist/bin/{chunks/jq-XH2PXRWE.js → shell/chunks/jq-XXZPU5CA.js} +1 -1
  31. package/dist/bin/shell/chunks/{md5sum-VGXAOUBA.js → md5sum-2VAAFCTS.js} +1 -1
  32. package/dist/bin/shell/chunks/rg-GVIT6FTE.js +33 -0
  33. package/dist/bin/shell/chunks/{sha1sum-BIUH233Z.js → sha1sum-67P4ME4N.js} +1 -1
  34. package/dist/bin/{chunks/sha256sum-SUIK2MT2.js → shell/chunks/sha256sum-MV3WQ4QF.js} +1 -1
  35. package/dist/bin/{chunks/sort-C3F6LCNY.js → shell/chunks/sort-KUHOCH5S.js} +1 -1
  36. package/dist/bin/shell/chunks/tar-C27YYUAS.js +63 -0
  37. package/dist/bin/{chunks/uniq-DKS7RIAE.js → shell/chunks/uniq-IXHB2FVS.js} +1 -1
  38. package/dist/bin/shell/chunks/{wc-4LMTC3QD.js → wc-QSBRKIF5.js} +1 -1
  39. package/dist/bin/shell/chunks/{xan-WNN2ZOAX.js → xan-6K2NGTHM.js} +1 -1
  40. package/dist/bin/shell/shell.js +100 -100
  41. package/dist/bundle/browser.js +557 -517
  42. package/dist/bundle/chunks/base64-3BME25ON.js +5 -0
  43. package/dist/bundle/chunks/{cat-W5XITXDC.js → cat-MV4K6AUA.js} +1 -1
  44. package/dist/bundle/chunks/{chunk-4ACWXGKW.js → chunk-7L36YK2X.js} +2 -2
  45. package/dist/bundle/chunks/{chunk-46TSKXFW.js → chunk-GFLIVSUW.js} +5 -5
  46. package/dist/bundle/chunks/chunk-OHJS5H37.js +16 -0
  47. package/dist/bundle/chunks/{cut-KKAAQJVD.js → cut-NVKWEAZF.js} +1 -1
  48. package/dist/bundle/chunks/grep-TUWLGQC2.js +8 -0
  49. package/dist/bundle/chunks/{gzip-7QAS5P2Y.js → gzip-L3NDJG3F.js} +22 -22
  50. package/dist/bundle/chunks/{jq-AAWVUTC4.js → jq-3YU5HRKE.js} +1 -1
  51. package/dist/bundle/chunks/{md5sum-LJHKXLVT.js → md5sum-KLHZSRUA.js} +1 -1
  52. package/dist/bundle/chunks/rg-KTCMPGU6.js +32 -0
  53. package/dist/bundle/chunks/{sha1sum-NRUZZ4Q6.js → sha1sum-WKWTIZGQ.js} +1 -1
  54. package/dist/bundle/chunks/{sha256sum-5ZGJ4NJL.js → sha256sum-IUVNMBTA.js} +1 -1
  55. package/dist/bundle/chunks/{sort-JHO22QVO.js → sort-EJUT5LXD.js} +1 -1
  56. package/dist/bundle/chunks/tar-QWBXMF7K.js +62 -0
  57. package/dist/bundle/chunks/{uniq-SEKCFR7B.js → uniq-47QVBRNC.js} +1 -1
  58. package/dist/bundle/chunks/{wc-52FZ4QGS.js → wc-DFQKWSIZ.js} +1 -1
  59. package/dist/bundle/chunks/{xan-ZHXYF6B4.js → xan-2R2APJJ4.js} +1 -1
  60. package/dist/bundle/index.js +119 -119
  61. package/dist/commands/registry.d.ts +1 -1
  62. package/dist/commands/rg/file-types.d.ts +49 -0
  63. package/dist/commands/rg/gitignore.d.ts +98 -0
  64. package/dist/commands/rg/rg-options.d.ts +61 -0
  65. package/dist/commands/rg/rg-parser.d.ts +20 -0
  66. package/dist/commands/rg/rg-search.d.ts +15 -0
  67. package/dist/commands/rg/rg.d.ts +12 -0
  68. package/dist/commands/search-engine/index.d.ts +10 -0
  69. package/dist/commands/search-engine/matcher.d.ts +57 -0
  70. package/dist/commands/search-engine/regex.d.ts +27 -0
  71. package/dist/commands/tar/archive.d.ts +107 -0
  72. package/dist/commands/tar/tar.d.ts +8 -0
  73. package/dist/fs/in-memory-fs/in-memory-fs.d.ts +51 -0
  74. package/dist/fs/in-memory-fs/index.d.ts +1 -0
  75. package/dist/fs/init.d.ts +12 -0
  76. package/dist/fs/interface.d.ts +203 -0
  77. package/dist/fs/mountable-fs/index.d.ts +1 -0
  78. package/dist/fs/mountable-fs/mountable-fs.d.ts +108 -0
  79. package/dist/fs/overlay-fs/index.d.ts +1 -0
  80. package/dist/fs/overlay-fs/overlay-fs.d.ts +107 -0
  81. package/dist/fs/read-write-fs/index.d.ts +1 -0
  82. package/dist/fs/read-write-fs/read-write-fs.d.ts +47 -0
  83. package/dist/fs/utils.d.ts +17 -0
  84. package/dist/index.d.ts +1 -0
  85. package/package.json +12 -7
  86. package/dist/bin/chunks/base64-RJX7MYGG.js +0 -6
  87. package/dist/bin/chunks/grep-U2RCKOEG.js +0 -15
  88. package/dist/bin/shell/chunks/base64-RJX7MYGG.js +0 -6
  89. package/dist/bin/shell/chunks/grep-U2RCKOEG.js +0 -15
  90. package/dist/bundle/chunks/base64-F5R4G5EG.js +0 -5
  91. package/dist/bundle/chunks/grep-CTJRP2G3.js +0 -14
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Supported buffer encodings
3
+ */
4
+ export type BufferEncoding = "utf8" | "utf-8" | "ascii" | "binary" | "base64" | "hex" | "latin1";
5
+ /**
6
+ * File content can be string or Buffer
7
+ */
8
+ export type FileContent = string | Uint8Array;
9
+ /**
10
+ * Options for reading files
11
+ */
12
+ export interface ReadFileOptions {
13
+ encoding?: BufferEncoding | null;
14
+ }
15
+ /**
16
+ * Options for writing files
17
+ */
18
+ export interface WriteFileOptions {
19
+ encoding?: BufferEncoding;
20
+ }
21
+ /**
22
+ * File system entry types
23
+ */
24
+ export interface FileEntry {
25
+ type: "file";
26
+ content: string | Uint8Array;
27
+ mode: number;
28
+ mtime: Date;
29
+ }
30
+ export interface DirectoryEntry {
31
+ type: "directory";
32
+ mode: number;
33
+ mtime: Date;
34
+ }
35
+ export interface SymlinkEntry {
36
+ type: "symlink";
37
+ target: string;
38
+ mode: number;
39
+ mtime: Date;
40
+ }
41
+ export type FsEntry = FileEntry | DirectoryEntry | SymlinkEntry;
42
+ /**
43
+ * Directory entry with type information (similar to Node's Dirent)
44
+ * Used by readdirWithFileTypes for efficient directory listing without stat calls
45
+ */
46
+ export interface DirentEntry {
47
+ name: string;
48
+ isFile: boolean;
49
+ isDirectory: boolean;
50
+ isSymbolicLink: boolean;
51
+ }
52
+ /**
53
+ * Stat result from the filesystem
54
+ */
55
+ export interface FsStat {
56
+ isFile: boolean;
57
+ isDirectory: boolean;
58
+ isSymbolicLink: boolean;
59
+ mode: number;
60
+ size: number;
61
+ mtime: Date;
62
+ }
63
+ /**
64
+ * Options for mkdir operation
65
+ */
66
+ export interface MkdirOptions {
67
+ recursive?: boolean;
68
+ }
69
+ /**
70
+ * Options for rm operation
71
+ */
72
+ export interface RmOptions {
73
+ recursive?: boolean;
74
+ force?: boolean;
75
+ }
76
+ /**
77
+ * Options for cp operation
78
+ */
79
+ export interface CpOptions {
80
+ recursive?: boolean;
81
+ }
82
+ /**
83
+ * Abstract filesystem interface that can be implemented by different backends.
84
+ * This allows BashEnv to work with:
85
+ * - InMemoryFs (in-memory, default)
86
+ * - Real filesystem (via node:fs)
87
+ * - Custom implementations (e.g., remote storage, browser IndexedDB)
88
+ */
89
+ export interface IFileSystem {
90
+ /**
91
+ * Read the contents of a file as a string (default: utf8)
92
+ * @throws Error if file doesn't exist or is a directory
93
+ */
94
+ readFile(path: string, options?: ReadFileOptions | BufferEncoding): Promise<string>;
95
+ /**
96
+ * Read the contents of a file as a Uint8Array (binary)
97
+ * @throws Error if file doesn't exist or is a directory
98
+ */
99
+ readFileBuffer(path: string): Promise<Uint8Array>;
100
+ /**
101
+ * Write content to a file, creating it if it doesn't exist
102
+ */
103
+ writeFile(path: string, content: FileContent, options?: WriteFileOptions | BufferEncoding): Promise<void>;
104
+ /**
105
+ * Append content to a file, creating it if it doesn't exist
106
+ */
107
+ appendFile(path: string, content: FileContent, options?: WriteFileOptions | BufferEncoding): Promise<void>;
108
+ /**
109
+ * Check if a path exists
110
+ */
111
+ exists(path: string): Promise<boolean>;
112
+ /**
113
+ * Get file/directory information
114
+ * @throws Error if path doesn't exist
115
+ */
116
+ stat(path: string): Promise<FsStat>;
117
+ /**
118
+ * Create a directory
119
+ * @throws Error if parent doesn't exist (unless recursive) or path exists
120
+ */
121
+ mkdir(path: string, options?: MkdirOptions): Promise<void>;
122
+ /**
123
+ * Read directory contents
124
+ * @returns Array of entry names (not full paths)
125
+ * @throws Error if path doesn't exist or is not a directory
126
+ */
127
+ readdir(path: string): Promise<string[]>;
128
+ /**
129
+ * Read directory contents with file type information (optional)
130
+ * This is more efficient than readdir + stat for each entry
131
+ * @returns Array of DirentEntry objects with name and type
132
+ * @throws Error if path doesn't exist or is not a directory
133
+ */
134
+ readdirWithFileTypes?(path: string): Promise<DirentEntry[]>;
135
+ /**
136
+ * Remove a file or directory
137
+ * @throws Error if path doesn't exist (unless force) or directory not empty (unless recursive)
138
+ */
139
+ rm(path: string, options?: RmOptions): Promise<void>;
140
+ /**
141
+ * Copy a file or directory
142
+ * @throws Error if source doesn't exist or trying to copy directory without recursive
143
+ */
144
+ cp(src: string, dest: string, options?: CpOptions): Promise<void>;
145
+ /**
146
+ * Move/rename a file or directory
147
+ */
148
+ mv(src: string, dest: string): Promise<void>;
149
+ /**
150
+ * Resolve a relative path against a base path
151
+ */
152
+ resolvePath(base: string, path: string): string;
153
+ /**
154
+ * Get all paths in the filesystem (useful for glob matching)
155
+ * Optional - implementations may return empty array if not supported
156
+ */
157
+ getAllPaths(): string[];
158
+ /**
159
+ * Change file/directory permissions
160
+ * @throws Error if path doesn't exist
161
+ */
162
+ chmod(path: string, mode: number): Promise<void>;
163
+ /**
164
+ * Create a symbolic link
165
+ * @param target - The path the symlink should point to
166
+ * @param linkPath - The path where the symlink will be created
167
+ * @throws Error if linkPath already exists
168
+ */
169
+ symlink(target: string, linkPath: string): Promise<void>;
170
+ /**
171
+ * Create a hard link
172
+ * @param existingPath - The existing file to link to
173
+ * @param newPath - The path where the new link will be created
174
+ * @throws Error if existingPath doesn't exist or newPath already exists
175
+ */
176
+ link(existingPath: string, newPath: string): Promise<void>;
177
+ /**
178
+ * Read the target of a symbolic link
179
+ * @throws Error if path doesn't exist or is not a symlink
180
+ */
181
+ readlink(path: string): Promise<string>;
182
+ /**
183
+ * Get file/directory information without following symlinks
184
+ * @throws Error if path doesn't exist
185
+ */
186
+ lstat(path: string): Promise<FsStat>;
187
+ }
188
+ /**
189
+ * Extended file initialization options with optional metadata
190
+ */
191
+ export interface FileInit {
192
+ content: FileContent;
193
+ mode?: number;
194
+ mtime?: Date;
195
+ }
196
+ /**
197
+ * Initial files can be simple content or extended options with metadata
198
+ */
199
+ export type InitialFiles = Record<string, FileContent | FileInit>;
200
+ /**
201
+ * Factory function type for creating filesystem instances
202
+ */
203
+ export type FileSystemFactory = (initialFiles?: InitialFiles) => IFileSystem;
@@ -0,0 +1 @@
1
+ export { MountableFs, type MountableFsOptions, type MountConfig, } from "./mountable-fs.js";
@@ -0,0 +1,108 @@
1
+ import type { BufferEncoding, CpOptions, FileContent, FsStat, IFileSystem, MkdirOptions, ReadFileOptions, RmOptions, WriteFileOptions } from "../interface.js";
2
+ /**
3
+ * Configuration for a mount point
4
+ */
5
+ export interface MountConfig {
6
+ /** Virtual path where the filesystem is mounted */
7
+ mountPoint: string;
8
+ /** The filesystem to mount at this path */
9
+ filesystem: IFileSystem;
10
+ }
11
+ /**
12
+ * Options for creating a MountableFs
13
+ */
14
+ export interface MountableFsOptions {
15
+ /** Base filesystem used for unmounted paths (defaults to InMemoryFs) */
16
+ base?: IFileSystem;
17
+ /** Initial mounts to configure */
18
+ mounts?: MountConfig[];
19
+ }
20
+ /**
21
+ * A filesystem that supports mounting other filesystems at specific paths.
22
+ *
23
+ * This allows combining multiple filesystem backends into a unified namespace.
24
+ * For example, mounting a read-only knowledge base at /mnt/knowledge and a
25
+ * read-write workspace at /home/agent.
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const fs = new MountableFs({ base: new InMemoryFs() });
30
+ * fs.mount('/mnt/knowledge', new OverlayFs({ root: "/path/to/knowledge", readOnly: true }));
31
+ * fs.mount('/home/agent', new ReadWriteFs({ root: "/path/to/workspace" }));
32
+ * ```
33
+ */
34
+ export declare class MountableFs implements IFileSystem {
35
+ private baseFs;
36
+ private mounts;
37
+ constructor(options?: MountableFsOptions);
38
+ /**
39
+ * Mount a filesystem at the specified virtual path.
40
+ *
41
+ * @param mountPoint - The virtual path where the filesystem will be accessible
42
+ * @param filesystem - The filesystem to mount
43
+ * @throws Error if mounting at root '/' or inside an existing mount
44
+ */
45
+ mount(mountPoint: string, filesystem: IFileSystem): void;
46
+ /**
47
+ * Unmount the filesystem at the specified path.
48
+ *
49
+ * @param mountPoint - The virtual path to unmount
50
+ * @throws Error if no filesystem is mounted at this path
51
+ */
52
+ unmount(mountPoint: string): void;
53
+ /**
54
+ * Get all current mounts.
55
+ */
56
+ getMounts(): ReadonlyArray<{
57
+ mountPoint: string;
58
+ filesystem: IFileSystem;
59
+ }>;
60
+ /**
61
+ * Check if a path is exactly a mount point.
62
+ */
63
+ isMountPoint(path: string): boolean;
64
+ /**
65
+ * Validate mount path format before normalization.
66
+ * Rejects paths containing . or .. segments.
67
+ */
68
+ private validateMountPath;
69
+ /**
70
+ * Validate that a mount point is allowed.
71
+ */
72
+ private validateMount;
73
+ /**
74
+ * Normalize a path to a consistent format.
75
+ */
76
+ private normalizePath;
77
+ /**
78
+ * Route a path to the appropriate filesystem.
79
+ * Returns the filesystem and the relative path within that filesystem.
80
+ */
81
+ private routePath;
82
+ /**
83
+ * Get mount points that are immediate children of a directory.
84
+ */
85
+ private getChildMountPoints;
86
+ readFile(path: string, options?: ReadFileOptions | BufferEncoding): Promise<string>;
87
+ readFileBuffer(path: string): Promise<Uint8Array>;
88
+ writeFile(path: string, content: FileContent, options?: WriteFileOptions | BufferEncoding): Promise<void>;
89
+ appendFile(path: string, content: FileContent, options?: WriteFileOptions | BufferEncoding): Promise<void>;
90
+ exists(path: string): Promise<boolean>;
91
+ stat(path: string): Promise<FsStat>;
92
+ lstat(path: string): Promise<FsStat>;
93
+ mkdir(path: string, options?: MkdirOptions): Promise<void>;
94
+ readdir(path: string): Promise<string[]>;
95
+ rm(path: string, options?: RmOptions): Promise<void>;
96
+ cp(src: string, dest: string, options?: CpOptions): Promise<void>;
97
+ mv(src: string, dest: string): Promise<void>;
98
+ resolvePath(base: string, path: string): string;
99
+ getAllPaths(): string[];
100
+ chmod(path: string, mode: number): Promise<void>;
101
+ symlink(target: string, linkPath: string): Promise<void>;
102
+ link(existingPath: string, newPath: string): Promise<void>;
103
+ readlink(path: string): Promise<string>;
104
+ /**
105
+ * Perform a cross-mount copy operation.
106
+ */
107
+ private crossMountCopy;
108
+ }
@@ -0,0 +1 @@
1
+ export { OverlayFs, type OverlayFsOptions } from "./overlay-fs.js";
@@ -0,0 +1,107 @@
1
+ /**
2
+ * OverlayFs - Copy-on-write filesystem backed by a real directory
3
+ *
4
+ * Reads come from the real filesystem, writes go to an in-memory layer.
5
+ * Changes don't persist to disk and can't escape the root directory.
6
+ */
7
+ import type { CpOptions, DirentEntry, FsStat, IFileSystem, MkdirOptions, ReadFileOptions, RmOptions, WriteFileOptions } from "../interface.js";
8
+ import { type FileContent } from "../utils.js";
9
+ export interface OverlayFsOptions {
10
+ /**
11
+ * The root directory on the real filesystem.
12
+ * All paths are relative to this root and cannot escape it.
13
+ */
14
+ root: string;
15
+ /**
16
+ * The virtual mount point where the root directory appears.
17
+ * Defaults to "/home/user/project".
18
+ */
19
+ mountPoint?: string;
20
+ /**
21
+ * If true, all write operations will throw an error.
22
+ * Useful for truly read-only access to the filesystem.
23
+ * Defaults to false.
24
+ */
25
+ readOnly?: boolean;
26
+ }
27
+ export declare class OverlayFs implements IFileSystem {
28
+ private readonly root;
29
+ private readonly mountPoint;
30
+ private readonly readOnly;
31
+ private readonly memory;
32
+ private readonly deleted;
33
+ constructor(options: OverlayFsOptions);
34
+ /**
35
+ * Throws an error if the filesystem is in read-only mode.
36
+ */
37
+ private assertWritable;
38
+ /**
39
+ * Create directory entries for the mount point path
40
+ */
41
+ private createMountPointDirs;
42
+ /**
43
+ * Get the mount point for this overlay
44
+ */
45
+ getMountPoint(): string;
46
+ /**
47
+ * Create a virtual directory in memory (sync, for initialization)
48
+ */
49
+ mkdirSync(path: string, _options?: MkdirOptions): void;
50
+ /**
51
+ * Create a virtual file in memory (sync, for initialization)
52
+ */
53
+ writeFileSync(path: string, content: string | Uint8Array): void;
54
+ private getDirname;
55
+ /**
56
+ * Normalize a virtual path (resolve . and .., ensure starts with /)
57
+ */
58
+ private normalizePath;
59
+ /**
60
+ * Check if a normalized virtual path is under the mount point.
61
+ * Returns the relative path within the mount point, or null if not under it.
62
+ */
63
+ private getRelativeToMount;
64
+ /**
65
+ * Convert a virtual path to a real filesystem path.
66
+ * Returns null if the path is not under the mount point or would escape the root.
67
+ */
68
+ private toRealPath;
69
+ private dirname;
70
+ private ensureParentDirs;
71
+ /**
72
+ * Check if a path exists in the overlay (memory + real fs - deleted)
73
+ */
74
+ private existsInOverlay;
75
+ readFile(path: string, options?: ReadFileOptions | BufferEncoding): Promise<string>;
76
+ readFileBuffer(path: string, seen?: Set<string>): Promise<Uint8Array>;
77
+ writeFile(path: string, content: FileContent, options?: WriteFileOptions | BufferEncoding): Promise<void>;
78
+ appendFile(path: string, content: FileContent, options?: WriteFileOptions | BufferEncoding): Promise<void>;
79
+ exists(path: string): Promise<boolean>;
80
+ stat(path: string, seen?: Set<string>): Promise<FsStat>;
81
+ lstat(path: string): Promise<FsStat>;
82
+ private resolveSymlink;
83
+ mkdir(path: string, options?: MkdirOptions): Promise<void>;
84
+ /**
85
+ * Core readdir implementation that returns entries with file types.
86
+ * Both readdir and readdirWithFileTypes use this shared implementation.
87
+ */
88
+ private readdirCore;
89
+ /**
90
+ * Follow symlinks to resolve the final directory path.
91
+ * Returns outsideOverlay: true if the symlink points outside the overlay or
92
+ * the resolved target doesn't exist (security - broken symlinks return []).
93
+ */
94
+ private resolveForReaddir;
95
+ readdir(path: string): Promise<string[]>;
96
+ readdirWithFileTypes(path: string): Promise<DirentEntry[]>;
97
+ rm(path: string, options?: RmOptions): Promise<void>;
98
+ cp(src: string, dest: string, options?: CpOptions): Promise<void>;
99
+ mv(src: string, dest: string): Promise<void>;
100
+ resolvePath(base: string, path: string): string;
101
+ getAllPaths(): string[];
102
+ private scanRealFs;
103
+ chmod(path: string, mode: number): Promise<void>;
104
+ symlink(target: string, linkPath: string): Promise<void>;
105
+ link(existingPath: string, newPath: string): Promise<void>;
106
+ readlink(path: string): Promise<string>;
107
+ }
@@ -0,0 +1 @@
1
+ export { ReadWriteFs, type ReadWriteFsOptions } from "./read-write-fs.js";
@@ -0,0 +1,47 @@
1
+ /**
2
+ * ReadWriteFs - Direct wrapper around the real filesystem
3
+ *
4
+ * All operations go directly to the underlying Node.js filesystem.
5
+ * This is a true read-write filesystem with no overlay or sandboxing.
6
+ */
7
+ import type { CpOptions, DirentEntry, FsStat, IFileSystem, MkdirOptions, ReadFileOptions, RmOptions, WriteFileOptions } from "../interface.js";
8
+ import { type FileContent } from "../utils.js";
9
+ export interface ReadWriteFsOptions {
10
+ /**
11
+ * The root directory on the real filesystem.
12
+ * All paths are relative to this root.
13
+ */
14
+ root: string;
15
+ }
16
+ export declare class ReadWriteFs implements IFileSystem {
17
+ private readonly root;
18
+ constructor(options: ReadWriteFsOptions);
19
+ /**
20
+ * Convert a virtual path to a real filesystem path.
21
+ */
22
+ private toRealPath;
23
+ /**
24
+ * Normalize a virtual path (resolve . and .., ensure starts with /)
25
+ */
26
+ private normalizePath;
27
+ readFile(path: string, options?: ReadFileOptions | BufferEncoding): Promise<string>;
28
+ readFileBuffer(path: string): Promise<Uint8Array>;
29
+ writeFile(path: string, content: FileContent, options?: WriteFileOptions | BufferEncoding): Promise<void>;
30
+ appendFile(path: string, content: FileContent, options?: WriteFileOptions | BufferEncoding): Promise<void>;
31
+ exists(path: string): Promise<boolean>;
32
+ stat(path: string): Promise<FsStat>;
33
+ lstat(path: string): Promise<FsStat>;
34
+ mkdir(path: string, options?: MkdirOptions): Promise<void>;
35
+ readdir(path: string): Promise<string[]>;
36
+ readdirWithFileTypes(path: string): Promise<DirentEntry[]>;
37
+ rm(path: string, options?: RmOptions): Promise<void>;
38
+ cp(src: string, dest: string, options?: CpOptions): Promise<void>;
39
+ mv(src: string, dest: string): Promise<void>;
40
+ resolvePath(base: string, path: string): string;
41
+ getAllPaths(): string[];
42
+ private scanDir;
43
+ chmod(path: string, mode: number): Promise<void>;
44
+ symlink(target: string, linkPath: string): Promise<void>;
45
+ link(existingPath: string, newPath: string): Promise<void>;
46
+ readlink(path: string): Promise<string>;
47
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Shared utilities for filesystem implementations
3
+ */
4
+ import type { BufferEncoding, ReadFileOptions, WriteFileOptions } from "./interface.js";
5
+ export type FileContent = string | Uint8Array;
6
+ /**
7
+ * Helper to convert content to Uint8Array
8
+ */
9
+ export declare function toBuffer(content: FileContent, encoding?: BufferEncoding): Uint8Array;
10
+ /**
11
+ * Helper to convert Uint8Array to string with encoding
12
+ */
13
+ export declare function fromBuffer(buffer: Uint8Array, encoding?: BufferEncoding | null): string;
14
+ /**
15
+ * Helper to get encoding from options
16
+ */
17
+ export declare function getEncoding(options?: ReadFileOptions | WriteFileOptions | BufferEncoding | string | null): BufferEncoding | undefined;
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export type { CustomCommand, LazyCommand } from "./custom-commands.js";
6
6
  export { defineCommand } from "./custom-commands.js";
7
7
  export { InMemoryFs } from "./fs/in-memory-fs/index.js";
8
8
  export type { BufferEncoding, CpOptions, DirectoryEntry, FileContent, FileEntry, FileInit, FileSystemFactory, FsEntry, FsStat, InitialFiles, MkdirOptions, RmOptions, SymlinkEntry, } from "./fs/interface.js";
9
+ export { MountableFs, type MountableFsOptions, type MountConfig, } from "./fs/mountable-fs/index.js";
9
10
  export { OverlayFs, type OverlayFsOptions } from "./fs/overlay-fs/index.js";
10
11
  export { ReadWriteFs, type ReadWriteFsOptions, } from "./fs/read-write-fs/index.js";
11
12
  export type { NetworkConfig } from "./network/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "just-bash",
3
- "version": "2.4.4",
3
+ "version": "2.5.1",
4
4
  "description": "A simulated bash environment with virtual filesystem",
5
5
  "repository": {
6
6
  "type": "git",
@@ -30,10 +30,9 @@
30
30
  "dist/*.d.ts",
31
31
  "dist/ast/*.d.ts",
32
32
  "dist/commands/**/*.d.ts",
33
- "dist/expander/*.d.ts",
33
+ "dist/fs/**/*.d.ts",
34
34
  "dist/interpreter/**/*.d.ts",
35
35
  "dist/network/**/*.d.ts",
36
- "dist/overlay-fs/*.d.ts",
37
36
  "dist/parser/*.d.ts",
38
37
  "dist/sandbox/*.d.ts",
39
38
  "dist/utils/*.d.ts",
@@ -64,11 +63,14 @@
64
63
  "vitest": "^4.0.16"
65
64
  },
66
65
  "dependencies": {
66
+ "@mongodb-js/zstd": "^7.0.0",
67
+ "compressjs": "^1.0.3",
67
68
  "diff": "^8.0.2",
68
69
  "fast-xml-parser": "^5.3.3",
69
70
  "file-type": "^21.2.0",
70
71
  "ini": "^6.0.0",
71
72
  "minimatch": "^10.1.1",
73
+ "modern-tar": "^0.7.3",
72
74
  "papaparse": "^5.5.3",
73
75
  "smol-toml": "^1.6.0",
74
76
  "sprintf-js": "^1.1.3",
@@ -76,14 +78,17 @@
76
78
  "turndown": "^7.2.2",
77
79
  "yaml": "^2.8.2"
78
80
  },
81
+ "optionalDependencies": {
82
+ "node-liblzma": "^2.0.3"
83
+ },
79
84
  "packageManager": "pnpm@8.15.9+sha512.499434c9d8fdd1a2794ebf4552b3b25c0a633abcee5bb15e7b5de90f32f47b513aca98cd5cfd001c31f0db454bc3804edccd578501e4ca293a6816166bbd9f81",
80
85
  "scripts": {
81
86
  "build": "rm -rf dist && tsc && pnpm build:lib && pnpm build:browser && pnpm build:cli && pnpm build:shell && pnpm build:clean && sed '1,/^-->/d' AGENTS.npm.md > dist/AGENTS.md",
82
87
  "build:clean": "find dist -name '*.test.js' -delete && find dist -name '*.test.d.ts' -delete",
83
- "build:lib": "esbuild dist/index.js --bundle --splitting --platform=node --format=esm --minify --outdir=dist/bundle --chunk-names=chunks/[name]-[hash] --external:diff --external:minimatch --external:sprintf-js --external:turndown --external:sql.js",
84
- "build:browser": "esbuild dist/browser.js --bundle --platform=browser --format=esm --minify --outfile=dist/bundle/browser.js --external:diff --external:minimatch --external:sprintf-js --external:turndown --external:node:* --define:__BROWSER__=true",
85
- "build:cli": "esbuild dist/cli/just-bash.js --bundle --splitting --platform=node --format=esm --minify --outdir=dist/bin --entry-names=[name] --chunk-names=chunks/[name]-[hash] --banner:js='#!/usr/bin/env node' --external:sql.js",
86
- "build:shell": "esbuild dist/cli/shell.js --bundle --splitting --platform=node --format=esm --minify --outdir=dist/bin/shell --entry-names=[name] --chunk-names=chunks/[name]-[hash] --banner:js='#!/usr/bin/env node' --external:sql.js",
88
+ "build:lib": "esbuild dist/index.js --bundle --splitting --platform=node --format=esm --minify --outdir=dist/bundle --chunk-names=chunks/[name]-[hash] --external:diff --external:minimatch --external:sprintf-js --external:turndown --external:sql.js --external:@mongodb-js/zstd --external:node-liblzma --external:compressjs",
89
+ "build:browser": "esbuild dist/browser.js --bundle --platform=browser --format=esm --minify --outfile=dist/bundle/browser.js --external:diff --external:minimatch --external:sprintf-js --external:turndown --external:node:* --external:@mongodb-js/zstd --external:node-liblzma --external:compressjs --define:__BROWSER__=true",
90
+ "build:cli": "esbuild dist/cli/just-bash.js --bundle --splitting --platform=node --format=esm --minify --outdir=dist/bin --entry-names=[name] --chunk-names=chunks/[name]-[hash] --banner:js='#!/usr/bin/env node' --external:sql.js --external:@mongodb-js/zstd --external:node-liblzma --external:compressjs",
91
+ "build:shell": "esbuild dist/cli/shell.js --bundle --splitting --platform=node --format=esm --minify --outdir=dist/bin/shell --entry-names=[name] --chunk-names=chunks/[name]-[hash] --banner:js='#!/usr/bin/env node' --external:sql.js --external:@mongodb-js/zstd --external:node-liblzma --external:compressjs",
87
92
  "validate": "pnpm lint && pnpm knip && pnpm typecheck && pnpm build && pnpm test:run && pnpm test:dist",
88
93
  "typecheck": "tsc --noEmit",
89
94
  "lint": "biome check .",
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env node
2
- import{a as f}from"./chunk-TA7RUHGQ.js";import{a as l,b as u}from"./chunk-GTNBSMZR.js";import"./chunk-KGOUQS5A.js";var g={name:"base64",summary:"base64 encode/decode data and print to standard output",usage:"base64 [OPTION]... [FILE]",options:["-d, --decode decode data","-w, --wrap=COLS wrap encoded lines after COLS character (default 76, 0 to disable)"," --help display this help and exit"]},m={decode:{short:"d",long:"decode",type:"boolean"},wrap:{short:"w",long:"wrap",type:"number",default:76}};async function p(o,r,n){if(r.length===0||r.length===1&&r[0]==="-")return{ok:!0,data:new TextEncoder().encode(o.stdin)};let s=[];for(let e of r){if(e==="-"){s.push(new TextEncoder().encode(o.stdin));continue}try{let t=o.fs.resolvePath(o.cwd,e),a=await o.fs.readFileBuffer(t);s.push(a)}catch{return{ok:!1,error:{stdout:"",stderr:`${n}: ${e}: No such file or directory
3
- `,exitCode:1}}}}let c=s.reduce((e,t)=>e+t.length,0),i=new Uint8Array(c),d=0;for(let e of s)i.set(e,d),d+=e.length;return{ok:!0,data:i}}var x={name:"base64",async execute(o,r){if(u(o))return l(g);let n=f("base64",o,m);if(!n.ok)return n.error;let s=n.result.flags.decode,c=n.result.flags.wrap,i=n.result.positional;try{if(s){let t=await p(r,i,"base64");if(!t.ok)return t.error;let h=new TextDecoder().decode(t.data).replace(/\s/g,""),w=Uint8Array.from(atob(h),b=>b.charCodeAt(0));return{stdout:new TextDecoder().decode(w),stderr:"",exitCode:0}}let d=await p(r,i,"base64");if(!d.ok)return d.error;let e=btoa(String.fromCharCode(...d.data));if(c>0){let t=[];for(let a=0;a<e.length;a+=c)t.push(e.slice(a,a+c));e=t.join(`
4
- `)+(e.length>0?`
5
- `:"")}return{stdout:e,stderr:"",exitCode:0}}catch{return{stdout:"",stderr:`base64: invalid input
6
- `,exitCode:1}}}};export{x as base64Command};
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env node
2
- import{a as N}from"./chunk-26Q3PZQ6.js";import{a as j,b as Z,c as q}from"./chunk-GTNBSMZR.js";import"./chunk-KGOUQS5A.js";var Y={name:"grep",summary:"print lines that match patterns",usage:"grep [OPTION]... PATTERN [FILE]...",options:["-E, --extended-regexp PATTERN is an extended regular expression","-P, --perl-regexp PATTERN is a Perl regular expression","-F, --fixed-strings PATTERN is a set of newline-separated strings","-i, --ignore-case ignore case distinctions","-v, --invert-match select non-matching lines","-w, --word-regexp match only whole words","-x, --line-regexp match only whole lines","-c, --count print only a count of matching lines","-l, --files-with-matches print only names of files with matches","-L, --files-without-match print names of files with no matches","-m NUM, --max-count=NUM stop after NUM matches","-n, --line-number print line number with output lines","-h, --no-filename suppress the file name prefix on output","-o, --only-matching show only nonempty parts of lines that match","-q, --quiet, --silent suppress all normal output","-r, -R, --recursive search directories recursively","-A NUM print NUM lines of trailing context","-B NUM print NUM lines of leading context","-C NUM print NUM lines of context","-e PATTERN use PATTERN for matching"," --include=GLOB search only files matching GLOB"," --exclude=GLOB skip files matching GLOB"," --exclude-dir=DIR skip directories matching DIR"," --help display this help and exit"]},z={name:"grep",async execute(s,e){if(Z(s))return j(Y);let l=!1,i=!1,f=!1,o=!1,w=!1,h=!1,r=!1,$=!1,y=!1,d=!1,m=!1,P=!1,I=!1,R=!1,M=!1,c=0,T=0,a=0,n=[],C=[],S=[],x=null,O=[];for(let p=0;p<s.length;p++){let u=s[p];if(u.startsWith("-")&&u!=="-"){if(u==="-e"&&p+1<s.length){x=s[++p];continue}if(u.startsWith("--include=")){n.push(u.slice(10));continue}if(u.startsWith("--exclude=")){C.push(u.slice(10));continue}if(u.startsWith("--exclude-dir=")){S.push(u.slice(14));continue}if(u.startsWith("--max-count=")){c=parseInt(u.slice(12),10);continue}let A=u.match(/^-m(\d+)$/);if(A){c=parseInt(A[1],10);continue}if(u==="-m"&&p+1<s.length){c=parseInt(s[++p],10);continue}let g=u.match(/^-([ABC])(\d+)$/);if(g){let t=parseInt(g[2],10);g[1]==="A"?a=t:g[1]==="B"?T=t:g[1]==="C"&&(T=t,a=t);continue}if((u==="-A"||u==="-B"||u==="-C")&&p+1<s.length){let t=parseInt(s[++p],10);u==="-A"?a=t:u==="-B"?T=t:(T=t,a=t);continue}let F=u.startsWith("--")?[u]:u.slice(1).split("");for(let t of F)if(t==="i"||t==="--ignore-case")l=!0;else if(t==="n"||t==="--line-number")i=!0;else if(t==="v"||t==="--invert-match")f=!0;else if(t==="c"||t==="--count")o=!0;else if(t==="l"||t==="--files-with-matches")w=!0;else if(t==="L"||t==="--files-without-match")h=!0;else if(t==="r"||t==="R"||t==="--recursive")r=!0;else if(t==="w"||t==="--word-regexp")$=!0;else if(t==="x"||t==="--line-regexp")y=!0;else if(t==="E"||t==="--extended-regexp")d=!0;else if(t==="P"||t==="--perl-regexp")m=!0;else if(t==="F"||t==="--fixed-strings")P=!0;else if(t==="o"||t==="--only-matching")I=!0;else if(t==="h"||t==="--no-filename")R=!0;else if(t==="q"||t==="--quiet"||t==="--silent")M=!0;else{if(t.startsWith("--"))return q("grep",t);if(t.length===1)return q("grep",`-${t}`)}}else x===null?x=u:O.push(u)}if(x===null)return{stdout:"",stderr:`grep: missing pattern
3
- `,exitCode:2};let W;P?W=x.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"):d||m?W=x:W=ee(x),$&&(W=`\\b${W}\\b`),y&&(W=`^${W}$`);let U;try{U=new RegExp(W,l?"gi":"g")}catch{return{stdout:"",stderr:`grep: invalid regular expression: ${x}
4
- `,exitCode:2}}if(O.length===0&&e.stdin){let p=_(e.stdin,U,f,i,o,"",I,T,a,c);return M?{stdout:"",stderr:"",exitCode:p.matched?0:1}:{stdout:p.output,stderr:"",exitCode:p.matched?0:1}}if(O.length===0)return{stdout:"",stderr:`grep: no input files
5
- `,exitCode:2};let E="",G="",D=!1,H=!1,v=[];for(let p of O)if(p.includes("*")||p.includes("?")||p.includes("[")){let u=await te(p,e);if(r)for(let A of u){let g=await Q(A.path,e,n,C,S,A.isFile);v.push(...g)}else v.push(...u)}else if(r){let u=await Q(p,e,n,C,S);v.push(...u)}else v.push({path:p});let K=(v.length>1||r)&&!R,k=50;for(let p=0;p<v.length;p+=k){let u=v.slice(p,p+k),A=await Promise.all(u.map(async g=>{let F=g.path,t=F.split("/").pop()||F;if(C.length>0&&!r&&C.some(B=>N(t,B,{stripQuotes:!0}))||n.length>0&&!r&&!n.some(B=>N(t,B,{stripQuotes:!0})))return null;try{let B=e.fs.resolvePath(e.cwd,F),b=!1;if(g.isFile===void 0?b=(await e.fs.stat(B)).isDirectory:b=!g.isFile,b)return r?null:{error:`grep: ${F}: Is a directory
6
- `};let V=await e.fs.readFile(B),X=_(V,U,f,i,o,K?F:"",I,T,a,c);return{file:F,result:X}}catch{return{error:`grep: ${F}: No such file or directory
7
- `}}}));for(let g of A){if(g===null)continue;if("error"in g&&g.error){G+=g.error,g.error.includes("Is a directory")||(H=!0);continue}if(!("file"in g)||!g.result)continue;let{file:F,result:t}=g;if(t.matched){if(D=!0,M)return{stdout:"",stderr:"",exitCode:0};w?E+=`${F}
8
- `:h||(E+=t.output)}else h?E+=`${F}
9
- `:o&&!w&&(E+=t.output)}}let L;return H?L=2:h?L=E.length>0?0:1:L=D?0:1,M?{stdout:"",stderr:"",exitCode:L}:{stdout:E,stderr:G,exitCode:L}}};function ee(s){let e="",l=0;for(;l<s.length;){let i=s[l];if(i==="\\"&&l+1<s.length){let f=s[l+1];if(f==="|"||f==="("||f===")"){e+=f,l+=2;continue}else if(f==="{"||f==="}"){e+=`\\${f}`,l+=2;continue}}i==="+"||i==="?"||i==="|"||i==="("||i===")"||i==="{"||i==="}"?e+=`\\${i}`:e+=i,l++}return e}function _(s,e,l,i,f,o,w=!1,h=0,r=0,$=0){let y=s.split(`
10
- `),d=y.length,m=d>0&&y[d-1]===""?d-1:d;if(f){let c=0;for(let a=0;a<m;a++)e.lastIndex=0,e.test(y[a])!==l&&c++;return{output:`${o?`${o}:${c}`:String(c)}
11
- `,matched:c>0}}if(h===0&&r===0){let c=[],T=!1,a=0;for(let n=0;n<m&&!($>0&&a>=$);n++){let C=y[n];if(e.lastIndex=0,e.test(C)!==l)if(T=!0,a++,w){e.lastIndex=0;for(let x=e.exec(C);x!==null;x=e.exec(C))c.push(o?`${o}:${x[0]}`:x[0]),x[0].length===0&&e.lastIndex++}else i?c.push(o?`${o}:${n+1}:${C}`:`${n+1}:${C}`):c.push(o?`${o}:${C}`:C)}return{output:c.length>0?`${c.join(`
12
- `)}
13
- `:"",matched:T}}let P=[],I=0,R=new Set,M=[];for(let c=0;c<m&&!($>0&&I>=$);c++)e.lastIndex=0,e.test(y[c])!==l&&(M.push(c),I++);for(let c of M){for(let a=Math.max(0,c-h);a<c;a++)if(!R.has(a)){R.add(a);let n=y[a];i&&(n=`${a+1}-${n}`),o&&(n=`${o}-${n}`),P.push(n)}if(!R.has(c)){R.add(c);let a=y[c];if(w){e.lastIndex=0;for(let n=e.exec(a);n!==null;n=e.exec(a))P.push(o?`${o}:${n[0]}`:n[0]),n[0].length===0&&e.lastIndex++}else{let n=a;i&&(n=`${c+1}:${n}`),o&&(n=`${o}:${n}`),P.push(n)}}let T=Math.min(m-1,c+r);for(let a=c+1;a<=T;a++)if(!R.has(a)){R.add(a);let n=y[a];i&&(n=`${a+1}-${n}`),o&&(n=`${o}-${n}`),P.push(n)}}return{output:P.length>0?`${P.join(`
14
- `)}
15
- `:"",matched:I>0}}async function J(s,e,l,i){let f=l.fs.resolvePath(l.cwd,s);try{if(!(await l.fs.stat(f)).isDirectory){let h=s.split("/").pop()||"";if(e){let r=e.replace(/^\//,"");N(h,r,{stripQuotes:!0})&&i.push(s)}return}let w=await l.fs.readdir(f);for(let h of w){let r=s==="."?h:`${s}/${h}`,$=l.fs.resolvePath(l.cwd,r);if((await l.fs.stat($)).isDirectory)await J(r,e,l,i);else if(e){let d=e.replace(/^\//,"");N(h,d,{stripQuotes:!0})&&i.push(r)}}}catch{}}async function te(s,e){let l=[],i=s.lastIndexOf("/"),f,o;if(i===-1?(f=e.cwd,o=s):(f=s.slice(0,i)||"/",o=s.slice(i+1)),s.includes("**")){let h=[],r=s.split("**"),$=r[0].replace(/\/$/,"")||".",y=r[1]||"";return await J($,y,e,h),h.map(d=>({path:d}))}let w=e.fs.resolvePath(e.cwd,f);try{if(e.fs.readdirWithFileTypes){let h=await e.fs.readdirWithFileTypes(w);for(let r of h)if(N(r.name,o,{stripQuotes:!0})){let $=i===-1?r.name:`${f}/${r.name}`;l.push({path:$,isFile:r.isFile})}}else{let h=await e.fs.readdir(w);for(let r of h)if(N(r,o,{stripQuotes:!0})){let $=i===-1?r:`${f}/${r}`;l.push({path:$})}}}catch{}return l.sort((h,r)=>h.path.localeCompare(r.path))}async function Q(s,e,l=[],i=[],f=[],o){let w=e.fs.resolvePath(e.cwd,s),h=[];try{let r,$;if(o!==void 0)r=o,$=!o;else{let d=await e.fs.stat(w);r=d.isFile,$=d.isDirectory}if(r){let d=s.split("/").pop()||s;return i.length>0&&i.some(m=>N(d,m,{stripQuotes:!0}))?[]:l.length>0&&!l.some(m=>N(d,m,{stripQuotes:!0}))?[]:[{path:s,isFile:!0}]}if(!$)return[];let y=s.split("/").pop()||s;if(f.length>0&&f.some(d=>N(y,d,{stripQuotes:!0})))return[];if(e.fs.readdirWithFileTypes){let d=await e.fs.readdirWithFileTypes(w);for(let m of d){if(m.name.startsWith("."))continue;let P=s==="."?m.name:`${s}/${m.name}`,I=await Q(P,e,l,i,f,m.isFile);h.push(...I)}}else{let d=await e.fs.readdir(w);for(let m of d){if(m.startsWith("."))continue;let P=s==="."?m:`${s}/${m}`,I=await Q(P,e,l,i,f);h.push(...I)}}}catch{}return h}var re={name:"fgrep",async execute(s,e){return z.execute(["-F",...s],e)}},le={name:"egrep",async execute(s,e){return z.execute(["-E",...s],e)}};export{le as egrepCommand,re as fgrepCommand,z as grepCommand};
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env node
2
- import{a as f}from"./chunk-TA7RUHGQ.js";import{a as l,b as u}from"./chunk-GTNBSMZR.js";import"./chunk-KGOUQS5A.js";var g={name:"base64",summary:"base64 encode/decode data and print to standard output",usage:"base64 [OPTION]... [FILE]",options:["-d, --decode decode data","-w, --wrap=COLS wrap encoded lines after COLS character (default 76, 0 to disable)"," --help display this help and exit"]},m={decode:{short:"d",long:"decode",type:"boolean"},wrap:{short:"w",long:"wrap",type:"number",default:76}};async function p(o,r,n){if(r.length===0||r.length===1&&r[0]==="-")return{ok:!0,data:new TextEncoder().encode(o.stdin)};let s=[];for(let e of r){if(e==="-"){s.push(new TextEncoder().encode(o.stdin));continue}try{let t=o.fs.resolvePath(o.cwd,e),a=await o.fs.readFileBuffer(t);s.push(a)}catch{return{ok:!1,error:{stdout:"",stderr:`${n}: ${e}: No such file or directory
3
- `,exitCode:1}}}}let c=s.reduce((e,t)=>e+t.length,0),i=new Uint8Array(c),d=0;for(let e of s)i.set(e,d),d+=e.length;return{ok:!0,data:i}}var x={name:"base64",async execute(o,r){if(u(o))return l(g);let n=f("base64",o,m);if(!n.ok)return n.error;let s=n.result.flags.decode,c=n.result.flags.wrap,i=n.result.positional;try{if(s){let t=await p(r,i,"base64");if(!t.ok)return t.error;let h=new TextDecoder().decode(t.data).replace(/\s/g,""),w=Uint8Array.from(atob(h),b=>b.charCodeAt(0));return{stdout:new TextDecoder().decode(w),stderr:"",exitCode:0}}let d=await p(r,i,"base64");if(!d.ok)return d.error;let e=btoa(String.fromCharCode(...d.data));if(c>0){let t=[];for(let a=0;a<e.length;a+=c)t.push(e.slice(a,a+c));e=t.join(`
4
- `)+(e.length>0?`
5
- `:"")}return{stdout:e,stderr:"",exitCode:0}}catch{return{stdout:"",stderr:`base64: invalid input
6
- `,exitCode:1}}}};export{x as base64Command};
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env node
2
- import{a as N}from"./chunk-26Q3PZQ6.js";import{a as j,b as Z,c as q}from"./chunk-GTNBSMZR.js";import"./chunk-KGOUQS5A.js";var Y={name:"grep",summary:"print lines that match patterns",usage:"grep [OPTION]... PATTERN [FILE]...",options:["-E, --extended-regexp PATTERN is an extended regular expression","-P, --perl-regexp PATTERN is a Perl regular expression","-F, --fixed-strings PATTERN is a set of newline-separated strings","-i, --ignore-case ignore case distinctions","-v, --invert-match select non-matching lines","-w, --word-regexp match only whole words","-x, --line-regexp match only whole lines","-c, --count print only a count of matching lines","-l, --files-with-matches print only names of files with matches","-L, --files-without-match print names of files with no matches","-m NUM, --max-count=NUM stop after NUM matches","-n, --line-number print line number with output lines","-h, --no-filename suppress the file name prefix on output","-o, --only-matching show only nonempty parts of lines that match","-q, --quiet, --silent suppress all normal output","-r, -R, --recursive search directories recursively","-A NUM print NUM lines of trailing context","-B NUM print NUM lines of leading context","-C NUM print NUM lines of context","-e PATTERN use PATTERN for matching"," --include=GLOB search only files matching GLOB"," --exclude=GLOB skip files matching GLOB"," --exclude-dir=DIR skip directories matching DIR"," --help display this help and exit"]},z={name:"grep",async execute(s,e){if(Z(s))return j(Y);let l=!1,i=!1,f=!1,o=!1,w=!1,h=!1,r=!1,$=!1,y=!1,d=!1,m=!1,P=!1,I=!1,R=!1,M=!1,c=0,T=0,a=0,n=[],C=[],S=[],x=null,O=[];for(let p=0;p<s.length;p++){let u=s[p];if(u.startsWith("-")&&u!=="-"){if(u==="-e"&&p+1<s.length){x=s[++p];continue}if(u.startsWith("--include=")){n.push(u.slice(10));continue}if(u.startsWith("--exclude=")){C.push(u.slice(10));continue}if(u.startsWith("--exclude-dir=")){S.push(u.slice(14));continue}if(u.startsWith("--max-count=")){c=parseInt(u.slice(12),10);continue}let A=u.match(/^-m(\d+)$/);if(A){c=parseInt(A[1],10);continue}if(u==="-m"&&p+1<s.length){c=parseInt(s[++p],10);continue}let g=u.match(/^-([ABC])(\d+)$/);if(g){let t=parseInt(g[2],10);g[1]==="A"?a=t:g[1]==="B"?T=t:g[1]==="C"&&(T=t,a=t);continue}if((u==="-A"||u==="-B"||u==="-C")&&p+1<s.length){let t=parseInt(s[++p],10);u==="-A"?a=t:u==="-B"?T=t:(T=t,a=t);continue}let F=u.startsWith("--")?[u]:u.slice(1).split("");for(let t of F)if(t==="i"||t==="--ignore-case")l=!0;else if(t==="n"||t==="--line-number")i=!0;else if(t==="v"||t==="--invert-match")f=!0;else if(t==="c"||t==="--count")o=!0;else if(t==="l"||t==="--files-with-matches")w=!0;else if(t==="L"||t==="--files-without-match")h=!0;else if(t==="r"||t==="R"||t==="--recursive")r=!0;else if(t==="w"||t==="--word-regexp")$=!0;else if(t==="x"||t==="--line-regexp")y=!0;else if(t==="E"||t==="--extended-regexp")d=!0;else if(t==="P"||t==="--perl-regexp")m=!0;else if(t==="F"||t==="--fixed-strings")P=!0;else if(t==="o"||t==="--only-matching")I=!0;else if(t==="h"||t==="--no-filename")R=!0;else if(t==="q"||t==="--quiet"||t==="--silent")M=!0;else{if(t.startsWith("--"))return q("grep",t);if(t.length===1)return q("grep",`-${t}`)}}else x===null?x=u:O.push(u)}if(x===null)return{stdout:"",stderr:`grep: missing pattern
3
- `,exitCode:2};let W;P?W=x.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"):d||m?W=x:W=ee(x),$&&(W=`\\b${W}\\b`),y&&(W=`^${W}$`);let U;try{U=new RegExp(W,l?"gi":"g")}catch{return{stdout:"",stderr:`grep: invalid regular expression: ${x}
4
- `,exitCode:2}}if(O.length===0&&e.stdin){let p=_(e.stdin,U,f,i,o,"",I,T,a,c);return M?{stdout:"",stderr:"",exitCode:p.matched?0:1}:{stdout:p.output,stderr:"",exitCode:p.matched?0:1}}if(O.length===0)return{stdout:"",stderr:`grep: no input files
5
- `,exitCode:2};let E="",G="",D=!1,H=!1,v=[];for(let p of O)if(p.includes("*")||p.includes("?")||p.includes("[")){let u=await te(p,e);if(r)for(let A of u){let g=await Q(A.path,e,n,C,S,A.isFile);v.push(...g)}else v.push(...u)}else if(r){let u=await Q(p,e,n,C,S);v.push(...u)}else v.push({path:p});let K=(v.length>1||r)&&!R,k=50;for(let p=0;p<v.length;p+=k){let u=v.slice(p,p+k),A=await Promise.all(u.map(async g=>{let F=g.path,t=F.split("/").pop()||F;if(C.length>0&&!r&&C.some(B=>N(t,B,{stripQuotes:!0}))||n.length>0&&!r&&!n.some(B=>N(t,B,{stripQuotes:!0})))return null;try{let B=e.fs.resolvePath(e.cwd,F),b=!1;if(g.isFile===void 0?b=(await e.fs.stat(B)).isDirectory:b=!g.isFile,b)return r?null:{error:`grep: ${F}: Is a directory
6
- `};let V=await e.fs.readFile(B),X=_(V,U,f,i,o,K?F:"",I,T,a,c);return{file:F,result:X}}catch{return{error:`grep: ${F}: No such file or directory
7
- `}}}));for(let g of A){if(g===null)continue;if("error"in g&&g.error){G+=g.error,g.error.includes("Is a directory")||(H=!0);continue}if(!("file"in g)||!g.result)continue;let{file:F,result:t}=g;if(t.matched){if(D=!0,M)return{stdout:"",stderr:"",exitCode:0};w?E+=`${F}
8
- `:h||(E+=t.output)}else h?E+=`${F}
9
- `:o&&!w&&(E+=t.output)}}let L;return H?L=2:h?L=E.length>0?0:1:L=D?0:1,M?{stdout:"",stderr:"",exitCode:L}:{stdout:E,stderr:G,exitCode:L}}};function ee(s){let e="",l=0;for(;l<s.length;){let i=s[l];if(i==="\\"&&l+1<s.length){let f=s[l+1];if(f==="|"||f==="("||f===")"){e+=f,l+=2;continue}else if(f==="{"||f==="}"){e+=`\\${f}`,l+=2;continue}}i==="+"||i==="?"||i==="|"||i==="("||i===")"||i==="{"||i==="}"?e+=`\\${i}`:e+=i,l++}return e}function _(s,e,l,i,f,o,w=!1,h=0,r=0,$=0){let y=s.split(`
10
- `),d=y.length,m=d>0&&y[d-1]===""?d-1:d;if(f){let c=0;for(let a=0;a<m;a++)e.lastIndex=0,e.test(y[a])!==l&&c++;return{output:`${o?`${o}:${c}`:String(c)}
11
- `,matched:c>0}}if(h===0&&r===0){let c=[],T=!1,a=0;for(let n=0;n<m&&!($>0&&a>=$);n++){let C=y[n];if(e.lastIndex=0,e.test(C)!==l)if(T=!0,a++,w){e.lastIndex=0;for(let x=e.exec(C);x!==null;x=e.exec(C))c.push(o?`${o}:${x[0]}`:x[0]),x[0].length===0&&e.lastIndex++}else i?c.push(o?`${o}:${n+1}:${C}`:`${n+1}:${C}`):c.push(o?`${o}:${C}`:C)}return{output:c.length>0?`${c.join(`
12
- `)}
13
- `:"",matched:T}}let P=[],I=0,R=new Set,M=[];for(let c=0;c<m&&!($>0&&I>=$);c++)e.lastIndex=0,e.test(y[c])!==l&&(M.push(c),I++);for(let c of M){for(let a=Math.max(0,c-h);a<c;a++)if(!R.has(a)){R.add(a);let n=y[a];i&&(n=`${a+1}-${n}`),o&&(n=`${o}-${n}`),P.push(n)}if(!R.has(c)){R.add(c);let a=y[c];if(w){e.lastIndex=0;for(let n=e.exec(a);n!==null;n=e.exec(a))P.push(o?`${o}:${n[0]}`:n[0]),n[0].length===0&&e.lastIndex++}else{let n=a;i&&(n=`${c+1}:${n}`),o&&(n=`${o}:${n}`),P.push(n)}}let T=Math.min(m-1,c+r);for(let a=c+1;a<=T;a++)if(!R.has(a)){R.add(a);let n=y[a];i&&(n=`${a+1}-${n}`),o&&(n=`${o}-${n}`),P.push(n)}}return{output:P.length>0?`${P.join(`
14
- `)}
15
- `:"",matched:I>0}}async function J(s,e,l,i){let f=l.fs.resolvePath(l.cwd,s);try{if(!(await l.fs.stat(f)).isDirectory){let h=s.split("/").pop()||"";if(e){let r=e.replace(/^\//,"");N(h,r,{stripQuotes:!0})&&i.push(s)}return}let w=await l.fs.readdir(f);for(let h of w){let r=s==="."?h:`${s}/${h}`,$=l.fs.resolvePath(l.cwd,r);if((await l.fs.stat($)).isDirectory)await J(r,e,l,i);else if(e){let d=e.replace(/^\//,"");N(h,d,{stripQuotes:!0})&&i.push(r)}}}catch{}}async function te(s,e){let l=[],i=s.lastIndexOf("/"),f,o;if(i===-1?(f=e.cwd,o=s):(f=s.slice(0,i)||"/",o=s.slice(i+1)),s.includes("**")){let h=[],r=s.split("**"),$=r[0].replace(/\/$/,"")||".",y=r[1]||"";return await J($,y,e,h),h.map(d=>({path:d}))}let w=e.fs.resolvePath(e.cwd,f);try{if(e.fs.readdirWithFileTypes){let h=await e.fs.readdirWithFileTypes(w);for(let r of h)if(N(r.name,o,{stripQuotes:!0})){let $=i===-1?r.name:`${f}/${r.name}`;l.push({path:$,isFile:r.isFile})}}else{let h=await e.fs.readdir(w);for(let r of h)if(N(r,o,{stripQuotes:!0})){let $=i===-1?r:`${f}/${r}`;l.push({path:$})}}}catch{}return l.sort((h,r)=>h.path.localeCompare(r.path))}async function Q(s,e,l=[],i=[],f=[],o){let w=e.fs.resolvePath(e.cwd,s),h=[];try{let r,$;if(o!==void 0)r=o,$=!o;else{let d=await e.fs.stat(w);r=d.isFile,$=d.isDirectory}if(r){let d=s.split("/").pop()||s;return i.length>0&&i.some(m=>N(d,m,{stripQuotes:!0}))?[]:l.length>0&&!l.some(m=>N(d,m,{stripQuotes:!0}))?[]:[{path:s,isFile:!0}]}if(!$)return[];let y=s.split("/").pop()||s;if(f.length>0&&f.some(d=>N(y,d,{stripQuotes:!0})))return[];if(e.fs.readdirWithFileTypes){let d=await e.fs.readdirWithFileTypes(w);for(let m of d){if(m.name.startsWith("."))continue;let P=s==="."?m.name:`${s}/${m.name}`,I=await Q(P,e,l,i,f,m.isFile);h.push(...I)}}else{let d=await e.fs.readdir(w);for(let m of d){if(m.startsWith("."))continue;let P=s==="."?m:`${s}/${m}`,I=await Q(P,e,l,i,f);h.push(...I)}}}catch{}return h}var re={name:"fgrep",async execute(s,e){return z.execute(["-F",...s],e)}},le={name:"egrep",async execute(s,e){return z.execute(["-E",...s],e)}};export{le as egrepCommand,re as fgrepCommand,z as grepCommand};