just-bash 2.4.3 → 2.5.0

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 (86) 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-X4WRNADE.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-WDHYDUUD.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-ALK3CYAN.js +29 -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/sqlite3-THMDBIGF.js +36 -0
  18. package/dist/bin/chunks/tar-C27YYUAS.js +63 -0
  19. package/dist/bin/{shell/chunks/uniq-DKS7RIAE.js → chunks/uniq-IXHB2FVS.js} +1 -1
  20. package/dist/bin/chunks/{wc-4LMTC3QD.js → wc-QSBRKIF5.js} +1 -1
  21. package/dist/bin/chunks/{xan-WNN2ZOAX.js → xan-6K2NGTHM.js} +1 -1
  22. package/dist/bin/just-bash.js +78 -78
  23. package/dist/bin/shell/chunks/base64-O7TCK5TL.js +6 -0
  24. package/dist/bin/{chunks/cat-ZEMMQGY5.js → shell/chunks/cat-AJXZOSPN.js} +1 -1
  25. package/dist/bin/shell/chunks/{chunk-45SNFRCY.js → chunk-5WFYIUU2.js} +2 -2
  26. package/dist/bin/shell/chunks/chunk-X4WRNADE.js +17 -0
  27. package/dist/bin/{chunks/chunk-GX4MPCG6.js → shell/chunks/chunk-Y5QKO4KO.js} +5 -5
  28. package/dist/bin/shell/chunks/{cut-WWPJ2PYT.js → cut-IHF6BEOO.js} +1 -1
  29. package/dist/bin/shell/chunks/grep-WDHYDUUD.js +9 -0
  30. package/dist/bin/{chunks/gzip-MNCJB6OR.js → shell/chunks/gzip-YXK3WZQL.js} +22 -22
  31. package/dist/bin/{chunks/jq-XH2PXRWE.js → shell/chunks/jq-XXZPU5CA.js} +1 -1
  32. package/dist/bin/shell/chunks/{md5sum-VGXAOUBA.js → md5sum-2VAAFCTS.js} +1 -1
  33. package/dist/bin/shell/chunks/rg-ALK3CYAN.js +29 -0
  34. package/dist/bin/shell/chunks/{sha1sum-BIUH233Z.js → sha1sum-67P4ME4N.js} +1 -1
  35. package/dist/bin/{chunks/sha256sum-SUIK2MT2.js → shell/chunks/sha256sum-MV3WQ4QF.js} +1 -1
  36. package/dist/bin/{chunks/sort-C3F6LCNY.js → shell/chunks/sort-KUHOCH5S.js} +1 -1
  37. package/dist/bin/shell/chunks/sqlite3-THMDBIGF.js +36 -0
  38. package/dist/bin/shell/chunks/tar-C27YYUAS.js +63 -0
  39. package/dist/bin/{chunks/uniq-DKS7RIAE.js → shell/chunks/uniq-IXHB2FVS.js} +1 -1
  40. package/dist/bin/shell/chunks/{wc-4LMTC3QD.js → wc-QSBRKIF5.js} +1 -1
  41. package/dist/bin/shell/chunks/{xan-WNN2ZOAX.js → xan-6K2NGTHM.js} +1 -1
  42. package/dist/bin/shell/shell.js +100 -100
  43. package/dist/bundle/browser.js +542 -506
  44. package/dist/bundle/chunks/base64-3BME25ON.js +5 -0
  45. package/dist/bundle/chunks/{cat-W5XITXDC.js → cat-MV4K6AUA.js} +1 -1
  46. package/dist/bundle/chunks/{chunk-4ACWXGKW.js → chunk-7L36YK2X.js} +2 -2
  47. package/dist/bundle/chunks/chunk-7VH6U2UX.js +16 -0
  48. package/dist/bundle/chunks/{chunk-46TSKXFW.js → chunk-GFLIVSUW.js} +5 -5
  49. package/dist/bundle/chunks/{cut-KKAAQJVD.js → cut-NVKWEAZF.js} +1 -1
  50. package/dist/bundle/chunks/grep-QVR5G7SC.js +8 -0
  51. package/dist/bundle/chunks/{gzip-7QAS5P2Y.js → gzip-L3NDJG3F.js} +22 -22
  52. package/dist/bundle/chunks/{jq-AAWVUTC4.js → jq-3YU5HRKE.js} +1 -1
  53. package/dist/bundle/chunks/{md5sum-LJHKXLVT.js → md5sum-KLHZSRUA.js} +1 -1
  54. package/dist/bundle/chunks/rg-43HLKW4V.js +28 -0
  55. package/dist/bundle/chunks/{sha1sum-NRUZZ4Q6.js → sha1sum-WKWTIZGQ.js} +1 -1
  56. package/dist/bundle/chunks/{sha256sum-5ZGJ4NJL.js → sha256sum-IUVNMBTA.js} +1 -1
  57. package/dist/bundle/chunks/{sort-JHO22QVO.js → sort-EJUT5LXD.js} +1 -1
  58. package/dist/bundle/chunks/sqlite3-5QVZOGER.js +35 -0
  59. package/dist/bundle/chunks/tar-QWBXMF7K.js +62 -0
  60. package/dist/bundle/chunks/{uniq-SEKCFR7B.js → uniq-47QVBRNC.js} +1 -1
  61. package/dist/bundle/chunks/{wc-52FZ4QGS.js → wc-DFQKWSIZ.js} +1 -1
  62. package/dist/bundle/chunks/{xan-ZHXYF6B4.js → xan-2R2APJJ4.js} +1 -1
  63. package/dist/bundle/index.js +119 -119
  64. package/dist/commands/registry.d.ts +1 -1
  65. package/dist/commands/rg/file-types.d.ts +23 -0
  66. package/dist/commands/rg/gitignore.d.ts +69 -0
  67. package/dist/commands/rg/rg-options.d.ts +47 -0
  68. package/dist/commands/rg/rg-parser.d.ts +20 -0
  69. package/dist/commands/rg/rg-search.d.ts +15 -0
  70. package/dist/commands/rg/rg.d.ts +12 -0
  71. package/dist/commands/search-engine/index.d.ts +10 -0
  72. package/dist/commands/search-engine/matcher.d.ts +57 -0
  73. package/dist/commands/search-engine/regex.d.ts +17 -0
  74. package/dist/commands/tar/archive.d.ts +107 -0
  75. package/dist/commands/tar/tar.d.ts +8 -0
  76. package/dist/index.d.ts +1 -0
  77. package/package.json +11 -5
  78. package/dist/bin/chunks/base64-RJX7MYGG.js +0 -6
  79. package/dist/bin/chunks/grep-U2RCKOEG.js +0 -15
  80. package/dist/bin/chunks/sqlite3-PZRKN3TT.js +0 -37
  81. package/dist/bin/shell/chunks/base64-RJX7MYGG.js +0 -6
  82. package/dist/bin/shell/chunks/grep-U2RCKOEG.js +0 -15
  83. package/dist/bin/shell/chunks/sqlite3-PZRKN3TT.js +0 -37
  84. package/dist/bundle/chunks/base64-F5R4G5EG.js +0 -5
  85. package/dist/bundle/chunks/grep-CTJRP2G3.js +0 -14
  86. package/dist/bundle/chunks/sqlite3-CX5D36A5.js +0 -36
@@ -1,6 +1,6 @@
1
1
  import type { Command } from "../types.js";
2
2
  /** All available built-in command names (excludes network commands) */
3
- export type CommandName = "echo" | "cat" | "printf" | "ls" | "mkdir" | "touch" | "rm" | "cp" | "mv" | "ln" | "chmod" | "pwd" | "readlink" | "head" | "tail" | "wc" | "stat" | "grep" | "fgrep" | "egrep" | "sed" | "awk" | "sort" | "uniq" | "comm" | "cut" | "paste" | "tr" | "rev" | "nl" | "fold" | "expand" | "unexpand" | "strings" | "split" | "column" | "join" | "tee" | "find" | "basename" | "dirname" | "tree" | "du" | "env" | "printenv" | "alias" | "unalias" | "history" | "xargs" | "true" | "false" | "clear" | "bash" | "sh" | "jq" | "base64" | "diff" | "date" | "sleep" | "timeout" | "seq" | "expr" | "md5sum" | "sha1sum" | "sha256sum" | "file" | "html-to-markdown" | "help" | "which" | "tac" | "hostname" | "od" | "gzip" | "gunzip" | "zcat" | "yq" | "xan" | "sqlite3";
3
+ export type CommandName = "echo" | "cat" | "printf" | "ls" | "mkdir" | "touch" | "rm" | "cp" | "mv" | "ln" | "chmod" | "pwd" | "readlink" | "head" | "tail" | "wc" | "stat" | "grep" | "fgrep" | "egrep" | "rg" | "sed" | "awk" | "sort" | "uniq" | "comm" | "cut" | "paste" | "tr" | "rev" | "nl" | "fold" | "expand" | "unexpand" | "strings" | "split" | "column" | "join" | "tee" | "find" | "basename" | "dirname" | "tree" | "du" | "env" | "printenv" | "alias" | "unalias" | "history" | "xargs" | "true" | "false" | "clear" | "bash" | "sh" | "jq" | "base64" | "diff" | "date" | "sleep" | "timeout" | "seq" | "expr" | "md5sum" | "sha1sum" | "sha256sum" | "file" | "html-to-markdown" | "help" | "which" | "tac" | "hostname" | "od" | "gzip" | "gunzip" | "zcat" | "tar" | "yq" | "xan" | "sqlite3";
4
4
  /** Network command names (only available when network is configured) */
5
5
  export type NetworkCommandName = "curl";
6
6
  /** All command names including network commands */
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Built-in file type definitions for rg
3
+ *
4
+ * Maps type names to file extensions and glob patterns.
5
+ * Based on ripgrep's default type definitions.
6
+ */
7
+ export interface FileType {
8
+ extensions: string[];
9
+ globs: string[];
10
+ }
11
+ /**
12
+ * Built-in file type definitions
13
+ * Use `rg --type-list` to see all types in real ripgrep
14
+ */
15
+ export declare const FILE_TYPES: Record<string, FileType>;
16
+ /**
17
+ * Check if a filename matches any of the specified types
18
+ */
19
+ export declare function matchesType(filename: string, types: string[]): boolean;
20
+ /**
21
+ * Format type list for --type-list output
22
+ */
23
+ export declare function formatTypeList(): string;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * .gitignore parser for rg
3
+ *
4
+ * Handles:
5
+ * - Simple patterns (*.log, node_modules/)
6
+ * - Negation patterns (!important.log)
7
+ * - Directory-only patterns (build/)
8
+ * - Rooted patterns (/root-only)
9
+ * - Double-star patterns (for matching across directories)
10
+ */
11
+ import type { IFileSystem } from "../../fs/interface.js";
12
+ export declare class GitignoreParser {
13
+ private patterns;
14
+ private basePath;
15
+ constructor(basePath?: string);
16
+ /**
17
+ * Parse .gitignore content and add patterns
18
+ */
19
+ parse(content: string): void;
20
+ /**
21
+ * Convert a gitignore pattern to a regex
22
+ */
23
+ private patternToRegex;
24
+ /**
25
+ * Check if a path should be ignored
26
+ *
27
+ * @param relativePath Path relative to the gitignore location
28
+ * @param isDirectory Whether the path is a directory
29
+ * @returns true if the path should be ignored
30
+ */
31
+ matches(relativePath: string, isDirectory: boolean): boolean;
32
+ /**
33
+ * Get the base path for this gitignore
34
+ */
35
+ getBasePath(): string;
36
+ }
37
+ /**
38
+ * Hierarchical gitignore manager
39
+ *
40
+ * Loads .gitignore and .ignore files from the root down to the current directory,
41
+ * applying patterns in order (child patterns override parent patterns).
42
+ */
43
+ export declare class GitignoreManager {
44
+ private parsers;
45
+ private fs;
46
+ private rootPath;
47
+ constructor(fs: IFileSystem, rootPath: string);
48
+ /**
49
+ * Load all .gitignore and .ignore files from root to the specified path
50
+ */
51
+ load(targetPath: string): Promise<void>;
52
+ /**
53
+ * Check if a path should be ignored
54
+ *
55
+ * @param absolutePath Absolute path to check
56
+ * @param isDirectory Whether the path is a directory
57
+ * @returns true if the path should be ignored
58
+ */
59
+ matches(absolutePath: string, isDirectory: boolean): boolean;
60
+ /**
61
+ * Quick check for common ignored directories
62
+ * Used for early pruning during traversal
63
+ */
64
+ static isCommonIgnored(name: string): boolean;
65
+ }
66
+ /**
67
+ * Load gitignore files for a search starting at the given path
68
+ */
69
+ export declare function loadGitignores(fs: IFileSystem, startPath: string): Promise<GitignoreManager>;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * RgOptions interface and default values
3
+ */
4
+ export interface RgOptions {
5
+ ignoreCase: boolean;
6
+ caseSensitive: boolean;
7
+ smartCase: boolean;
8
+ fixedStrings: boolean;
9
+ wordRegexp: boolean;
10
+ lineRegexp: boolean;
11
+ invertMatch: boolean;
12
+ multiline: boolean;
13
+ patterns: string[];
14
+ patternFiles: string[];
15
+ count: boolean;
16
+ countMatches: boolean;
17
+ filesWithMatches: boolean;
18
+ filesWithoutMatch: boolean;
19
+ onlyMatching: boolean;
20
+ maxCount: number;
21
+ lineNumber: boolean;
22
+ noFilename: boolean;
23
+ nullSeparator: boolean;
24
+ byteOffset: boolean;
25
+ column: boolean;
26
+ vimgrep: boolean;
27
+ replace: string | null;
28
+ afterContext: number;
29
+ beforeContext: number;
30
+ contextSeparator: string;
31
+ quiet: boolean;
32
+ heading: boolean;
33
+ passthru: boolean;
34
+ includeZero: boolean;
35
+ sort: "path" | "none";
36
+ json: boolean;
37
+ globs: string[];
38
+ types: string[];
39
+ typesNot: string[];
40
+ hidden: boolean;
41
+ noIgnore: boolean;
42
+ maxDepth: number;
43
+ followSymlinks: boolean;
44
+ searchZip: boolean;
45
+ searchBinary: boolean;
46
+ }
47
+ export declare function createDefaultOptions(): RgOptions;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Argument parsing for rg command - Declarative approach
3
+ */
4
+ import type { ExecResult } from "../../types.js";
5
+ import { type RgOptions } from "./rg-options.js";
6
+ export interface ParseResult {
7
+ success: true;
8
+ options: RgOptions;
9
+ paths: string[];
10
+ explicitLineNumbers: boolean;
11
+ }
12
+ export interface ParseError {
13
+ success: false;
14
+ error: ExecResult;
15
+ }
16
+ export type ParseArgsResult = ParseResult | ParseError;
17
+ /**
18
+ * Parse rg command arguments
19
+ */
20
+ export declare function parseArgs(args: string[]): ParseArgsResult;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Core search logic for rg command
3
+ */
4
+ import type { CommandContext, ExecResult } from "../../types.js";
5
+ import type { RgOptions } from "./rg-options.js";
6
+ export interface SearchContext {
7
+ ctx: CommandContext;
8
+ options: RgOptions;
9
+ paths: string[];
10
+ explicitLineNumbers: boolean;
11
+ }
12
+ /**
13
+ * Execute the search with parsed options
14
+ */
15
+ export declare function executeSearch(searchCtx: SearchContext): Promise<ExecResult>;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * rg - ripgrep-like recursive search
3
+ *
4
+ * Fast recursive search with smart defaults:
5
+ * - Recursive by default (unlike grep)
6
+ * - Respects .gitignore
7
+ * - Skips hidden files by default
8
+ * - Skips binary files by default
9
+ * - Smart case sensitivity (case-insensitive unless pattern has uppercase)
10
+ */
11
+ import type { Command } from "../../types.js";
12
+ export declare const rgCommand: Command;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Shared search engine for grep and rg commands
3
+ *
4
+ * Provides core text searching functionality:
5
+ * - Line-by-line content matching
6
+ * - Context lines (before/after)
7
+ * - Regex building for different modes (basic, extended, fixed, perl)
8
+ */
9
+ export { type SearchOptions, type SearchResult, searchContent, } from "./matcher.js";
10
+ export { buildRegex, type RegexMode, type RegexOptions } from "./regex.js";
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Core content matching logic for search commands
3
+ */
4
+ export interface SearchOptions {
5
+ /** Select non-matching lines */
6
+ invertMatch?: boolean;
7
+ /** Print line number with output lines */
8
+ showLineNumbers?: boolean;
9
+ /** Print only a count of matching lines */
10
+ countOnly?: boolean;
11
+ /** Count individual matches instead of lines (--count-matches) */
12
+ countMatches?: boolean;
13
+ /** Filename prefix for output (empty string for no prefix) */
14
+ filename?: string;
15
+ /** Show only the matching parts of lines */
16
+ onlyMatching?: boolean;
17
+ /** Print NUM lines of leading context */
18
+ beforeContext?: number;
19
+ /** Print NUM lines of trailing context */
20
+ afterContext?: number;
21
+ /** Stop after NUM matches (0 = unlimited) */
22
+ maxCount?: number;
23
+ /** Separator between context groups (default: --) */
24
+ contextSeparator?: string;
25
+ /** Show column number of first match */
26
+ showColumn?: boolean;
27
+ /** Output each match separately (vimgrep format) */
28
+ vimgrep?: boolean;
29
+ /** Show byte offset of each match */
30
+ showByteOffset?: boolean;
31
+ /** Replace matched text with this string */
32
+ replace?: string | null;
33
+ /** Print all lines (matches use :, non-matches use -) */
34
+ passthru?: boolean;
35
+ /** Enable multiline matching (patterns can span lines) */
36
+ multiline?: boolean;
37
+ }
38
+ export interface SearchResult {
39
+ /** The formatted output string */
40
+ output: string;
41
+ /** Whether any matches were found */
42
+ matched: boolean;
43
+ /** Number of matches found */
44
+ matchCount: number;
45
+ }
46
+ /**
47
+ * Search content for regex matches and format output
48
+ *
49
+ * Handles:
50
+ * - Count only mode (-c)
51
+ * - Line numbers (-n)
52
+ * - Invert match (-v)
53
+ * - Only matching (-o)
54
+ * - Context lines (-A, -B, -C)
55
+ * - Max count (-m)
56
+ */
57
+ export declare function searchContent(content: string, regex: RegExp, options?: SearchOptions): SearchResult;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Regex building utilities for search commands
3
+ */
4
+ export type RegexMode = "basic" | "extended" | "fixed" | "perl";
5
+ export interface RegexOptions {
6
+ mode: RegexMode;
7
+ ignoreCase?: boolean;
8
+ wholeWord?: boolean;
9
+ lineRegexp?: boolean;
10
+ multiline?: boolean;
11
+ /** Makes . match newlines in multiline mode (ripgrep --multiline-dotall) */
12
+ multilineDotall?: boolean;
13
+ }
14
+ /**
15
+ * Build a JavaScript RegExp from a pattern with the specified mode
16
+ */
17
+ export declare function buildRegex(pattern: string, options: RegexOptions): RegExp;
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Tar archive utilities using modern-tar
3
+ *
4
+ * Provides helpers for creating and extracting tar archives
5
+ * with optional gzip, bzip2, and xz compression.
6
+ */
7
+ import { type ParsedTarEntryWithData, type TarEntry, type TarHeader } from "modern-tar";
8
+ export type { TarEntry, TarHeader, ParsedTarEntryWithData };
9
+ /**
10
+ * Entry for creating a tar archive
11
+ */
12
+ export interface TarCreateEntry {
13
+ name: string;
14
+ content?: Uint8Array | string;
15
+ mode?: number;
16
+ mtime?: Date;
17
+ isDirectory?: boolean;
18
+ isSymlink?: boolean;
19
+ linkTarget?: string;
20
+ uid?: number;
21
+ gid?: number;
22
+ }
23
+ /**
24
+ * Create a tar archive from entries
25
+ */
26
+ export declare function createArchive(entries: TarCreateEntry[]): Promise<Uint8Array>;
27
+ /**
28
+ * Create a gzip-compressed tar archive from entries
29
+ */
30
+ export declare function createCompressedArchive(entries: TarCreateEntry[]): Promise<Uint8Array>;
31
+ /**
32
+ * Parsed tar entry for extraction
33
+ */
34
+ export interface ParsedEntry {
35
+ name: string;
36
+ mode: number;
37
+ uid: number;
38
+ gid: number;
39
+ size: number;
40
+ mtime: Date;
41
+ type: "file" | "directory" | "symlink" | "hardlink" | "other";
42
+ linkTarget?: string;
43
+ content: Uint8Array;
44
+ }
45
+ /**
46
+ * Parse a tar archive and return entries
47
+ */
48
+ export declare function parseArchive(data: Uint8Array): Promise<{
49
+ entries: ParsedEntry[];
50
+ error?: string;
51
+ }>;
52
+ /**
53
+ * Parse a gzip-compressed tar archive
54
+ */
55
+ export declare function parseCompressedArchive(data: Uint8Array): Promise<{
56
+ entries: ParsedEntry[];
57
+ error?: string;
58
+ }>;
59
+ /**
60
+ * Check if data is gzip compressed (magic bytes 0x1f 0x8b)
61
+ */
62
+ export declare function isGzipCompressed(data: Uint8Array): boolean;
63
+ /**
64
+ * Check if data is bzip2 compressed (magic bytes "BZh")
65
+ */
66
+ export declare function isBzip2Compressed(data: Uint8Array): boolean;
67
+ /**
68
+ * Check if data is xz compressed (magic bytes 0xFD 0x37 0x7A 0x58 0x5A 0x00)
69
+ */
70
+ export declare function isXzCompressed(data: Uint8Array): boolean;
71
+ /**
72
+ * Create a bzip2-compressed tar archive from entries
73
+ */
74
+ export declare function createBzip2CompressedArchive(entries: TarCreateEntry[]): Promise<Uint8Array>;
75
+ /**
76
+ * Create an xz-compressed tar archive from entries
77
+ */
78
+ export declare function createXzCompressedArchive(entries: TarCreateEntry[]): Promise<Uint8Array>;
79
+ /**
80
+ * Parse a bzip2-compressed tar archive
81
+ */
82
+ export declare function parseBzip2CompressedArchive(data: Uint8Array): Promise<{
83
+ entries: ParsedEntry[];
84
+ error?: string;
85
+ }>;
86
+ /**
87
+ * Parse an xz-compressed tar archive
88
+ */
89
+ export declare function parseXzCompressedArchive(data: Uint8Array): Promise<{
90
+ entries: ParsedEntry[];
91
+ error?: string;
92
+ }>;
93
+ /**
94
+ * Check if data is zstd compressed (magic number 0x28 0xB5 0x2F 0xFD)
95
+ */
96
+ export declare function isZstdCompressed(data: Uint8Array): boolean;
97
+ /**
98
+ * Create a zstd-compressed tar archive from entries
99
+ */
100
+ export declare function createZstdCompressedArchive(entries: TarCreateEntry[]): Promise<Uint8Array>;
101
+ /**
102
+ * Parse a zstd-compressed tar archive
103
+ */
104
+ export declare function parseZstdCompressedArchive(data: Uint8Array): Promise<{
105
+ entries: ParsedEntry[];
106
+ error?: string;
107
+ }>;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * tar - manipulate tape archives
3
+ *
4
+ * Supports creating, extracting, and listing tar archives
5
+ * with optional gzip, bzip2, and xz compression.
6
+ */
7
+ import type { Command } from "../../types.js";
8
+ export declare const tarCommand: Command;
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.3",
3
+ "version": "2.5.0",
4
4
  "description": "A simulated bash environment with virtual filesystem",
5
5
  "repository": {
6
6
  "type": "git",
@@ -64,11 +64,14 @@
64
64
  "vitest": "^4.0.16"
65
65
  },
66
66
  "dependencies": {
67
+ "@mongodb-js/zstd": "^7.0.0",
68
+ "compressjs": "^1.0.3",
67
69
  "diff": "^8.0.2",
68
70
  "fast-xml-parser": "^5.3.3",
69
71
  "file-type": "^21.2.0",
70
72
  "ini": "^6.0.0",
71
73
  "minimatch": "^10.1.1",
74
+ "modern-tar": "^0.7.3",
72
75
  "papaparse": "^5.5.3",
73
76
  "smol-toml": "^1.6.0",
74
77
  "sprintf-js": "^1.1.3",
@@ -76,14 +79,17 @@
76
79
  "turndown": "^7.2.2",
77
80
  "yaml": "^2.8.2"
78
81
  },
82
+ "optionalDependencies": {
83
+ "node-liblzma": "^2.0.3"
84
+ },
79
85
  "packageManager": "pnpm@8.15.9+sha512.499434c9d8fdd1a2794ebf4552b3b25c0a633abcee5bb15e7b5de90f32f47b513aca98cd5cfd001c31f0db454bc3804edccd578501e4ca293a6816166bbd9f81",
80
86
  "scripts": {
81
87
  "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
88
  "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",
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'",
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'",
89
+ "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",
90
+ "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",
91
+ "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",
92
+ "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
93
  "validate": "pnpm lint && pnpm knip && pnpm typecheck && pnpm build && pnpm test:run && pnpm test:dist",
88
94
  "typecheck": "tsc --noEmit",
89
95
  "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};