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.
- package/README.md +42 -4
- package/dist/AGENTS.md +2 -2
- package/dist/bin/chunks/base64-O7TCK5TL.js +6 -0
- package/dist/bin/{shell/chunks/cat-ZEMMQGY5.js → chunks/cat-AJXZOSPN.js} +1 -1
- package/dist/bin/chunks/{chunk-45SNFRCY.js → chunk-5WFYIUU2.js} +2 -2
- package/dist/bin/chunks/chunk-CTLU5QUH.js +17 -0
- package/dist/bin/{shell/chunks/chunk-GX4MPCG6.js → chunks/chunk-Y5QKO4KO.js} +5 -5
- package/dist/bin/chunks/{cut-WWPJ2PYT.js → cut-IHF6BEOO.js} +1 -1
- package/dist/bin/chunks/grep-QCXXYC54.js +9 -0
- package/dist/bin/{shell/chunks/gzip-MNCJB6OR.js → chunks/gzip-YXK3WZQL.js} +22 -22
- package/dist/bin/{shell/chunks/jq-XH2PXRWE.js → chunks/jq-XXZPU5CA.js} +1 -1
- package/dist/bin/chunks/{md5sum-VGXAOUBA.js → md5sum-2VAAFCTS.js} +1 -1
- package/dist/bin/chunks/rg-GVIT6FTE.js +33 -0
- package/dist/bin/chunks/{sha1sum-BIUH233Z.js → sha1sum-67P4ME4N.js} +1 -1
- package/dist/bin/{shell/chunks/sha256sum-SUIK2MT2.js → chunks/sha256sum-MV3WQ4QF.js} +1 -1
- package/dist/bin/{shell/chunks/sort-C3F6LCNY.js → chunks/sort-KUHOCH5S.js} +1 -1
- package/dist/bin/chunks/tar-C27YYUAS.js +63 -0
- package/dist/bin/{shell/chunks/uniq-DKS7RIAE.js → chunks/uniq-IXHB2FVS.js} +1 -1
- package/dist/bin/chunks/{wc-4LMTC3QD.js → wc-QSBRKIF5.js} +1 -1
- package/dist/bin/chunks/{xan-WNN2ZOAX.js → xan-6K2NGTHM.js} +1 -1
- package/dist/bin/just-bash.js +78 -78
- package/dist/bin/shell/chunks/base64-O7TCK5TL.js +6 -0
- package/dist/bin/{chunks/cat-ZEMMQGY5.js → shell/chunks/cat-AJXZOSPN.js} +1 -1
- package/dist/bin/shell/chunks/{chunk-45SNFRCY.js → chunk-5WFYIUU2.js} +2 -2
- package/dist/bin/shell/chunks/chunk-CTLU5QUH.js +17 -0
- package/dist/bin/{chunks/chunk-GX4MPCG6.js → shell/chunks/chunk-Y5QKO4KO.js} +5 -5
- package/dist/bin/shell/chunks/{cut-WWPJ2PYT.js → cut-IHF6BEOO.js} +1 -1
- package/dist/bin/shell/chunks/grep-QCXXYC54.js +9 -0
- package/dist/bin/{chunks/gzip-MNCJB6OR.js → shell/chunks/gzip-YXK3WZQL.js} +22 -22
- package/dist/bin/{chunks/jq-XH2PXRWE.js → shell/chunks/jq-XXZPU5CA.js} +1 -1
- package/dist/bin/shell/chunks/{md5sum-VGXAOUBA.js → md5sum-2VAAFCTS.js} +1 -1
- package/dist/bin/shell/chunks/rg-GVIT6FTE.js +33 -0
- package/dist/bin/shell/chunks/{sha1sum-BIUH233Z.js → sha1sum-67P4ME4N.js} +1 -1
- package/dist/bin/{chunks/sha256sum-SUIK2MT2.js → shell/chunks/sha256sum-MV3WQ4QF.js} +1 -1
- package/dist/bin/{chunks/sort-C3F6LCNY.js → shell/chunks/sort-KUHOCH5S.js} +1 -1
- package/dist/bin/shell/chunks/tar-C27YYUAS.js +63 -0
- package/dist/bin/{chunks/uniq-DKS7RIAE.js → shell/chunks/uniq-IXHB2FVS.js} +1 -1
- package/dist/bin/shell/chunks/{wc-4LMTC3QD.js → wc-QSBRKIF5.js} +1 -1
- package/dist/bin/shell/chunks/{xan-WNN2ZOAX.js → xan-6K2NGTHM.js} +1 -1
- package/dist/bin/shell/shell.js +100 -100
- package/dist/bundle/browser.js +557 -517
- package/dist/bundle/chunks/base64-3BME25ON.js +5 -0
- package/dist/bundle/chunks/{cat-W5XITXDC.js → cat-MV4K6AUA.js} +1 -1
- package/dist/bundle/chunks/{chunk-4ACWXGKW.js → chunk-7L36YK2X.js} +2 -2
- package/dist/bundle/chunks/{chunk-46TSKXFW.js → chunk-GFLIVSUW.js} +5 -5
- package/dist/bundle/chunks/chunk-OHJS5H37.js +16 -0
- package/dist/bundle/chunks/{cut-KKAAQJVD.js → cut-NVKWEAZF.js} +1 -1
- package/dist/bundle/chunks/grep-TUWLGQC2.js +8 -0
- package/dist/bundle/chunks/{gzip-7QAS5P2Y.js → gzip-L3NDJG3F.js} +22 -22
- package/dist/bundle/chunks/{jq-AAWVUTC4.js → jq-3YU5HRKE.js} +1 -1
- package/dist/bundle/chunks/{md5sum-LJHKXLVT.js → md5sum-KLHZSRUA.js} +1 -1
- package/dist/bundle/chunks/rg-KTCMPGU6.js +32 -0
- package/dist/bundle/chunks/{sha1sum-NRUZZ4Q6.js → sha1sum-WKWTIZGQ.js} +1 -1
- package/dist/bundle/chunks/{sha256sum-5ZGJ4NJL.js → sha256sum-IUVNMBTA.js} +1 -1
- package/dist/bundle/chunks/{sort-JHO22QVO.js → sort-EJUT5LXD.js} +1 -1
- package/dist/bundle/chunks/tar-QWBXMF7K.js +62 -0
- package/dist/bundle/chunks/{uniq-SEKCFR7B.js → uniq-47QVBRNC.js} +1 -1
- package/dist/bundle/chunks/{wc-52FZ4QGS.js → wc-DFQKWSIZ.js} +1 -1
- package/dist/bundle/chunks/{xan-ZHXYF6B4.js → xan-2R2APJJ4.js} +1 -1
- package/dist/bundle/index.js +119 -119
- package/dist/commands/registry.d.ts +1 -1
- package/dist/commands/rg/file-types.d.ts +49 -0
- package/dist/commands/rg/gitignore.d.ts +98 -0
- package/dist/commands/rg/rg-options.d.ts +61 -0
- package/dist/commands/rg/rg-parser.d.ts +20 -0
- package/dist/commands/rg/rg-search.d.ts +15 -0
- package/dist/commands/rg/rg.d.ts +12 -0
- package/dist/commands/search-engine/index.d.ts +10 -0
- package/dist/commands/search-engine/matcher.d.ts +57 -0
- package/dist/commands/search-engine/regex.d.ts +27 -0
- package/dist/commands/tar/archive.d.ts +107 -0
- package/dist/commands/tar/tar.d.ts +8 -0
- package/dist/fs/in-memory-fs/in-memory-fs.d.ts +51 -0
- package/dist/fs/in-memory-fs/index.d.ts +1 -0
- package/dist/fs/init.d.ts +12 -0
- package/dist/fs/interface.d.ts +203 -0
- package/dist/fs/mountable-fs/index.d.ts +1 -0
- package/dist/fs/mountable-fs/mountable-fs.d.ts +108 -0
- package/dist/fs/overlay-fs/index.d.ts +1 -0
- package/dist/fs/overlay-fs/overlay-fs.d.ts +107 -0
- package/dist/fs/read-write-fs/index.d.ts +1 -0
- package/dist/fs/read-write-fs/read-write-fs.d.ts +47 -0
- package/dist/fs/utils.d.ts +17 -0
- package/dist/index.d.ts +1 -0
- package/package.json +12 -7
- package/dist/bin/chunks/base64-RJX7MYGG.js +0 -6
- package/dist/bin/chunks/grep-U2RCKOEG.js +0 -15
- package/dist/bin/shell/chunks/base64-RJX7MYGG.js +0 -6
- package/dist/bin/shell/chunks/grep-U2RCKOEG.js +0 -15
- package/dist/bundle/chunks/base64-F5R4G5EG.js +0 -5
- 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.
|
|
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/
|
|
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};
|