Skip to content

Commit e2ea375

Browse files
chaliyclaude
andauthored
chore: pre-release maintenance — fix fuzz crash, update docs (#272)
## Summary - **Fix arithmetic_fuzz crash**: Reduce `MAX_ARITHMETIC_DEPTH` from 200 to 50, preventing stack overflow on deeply nested/malformed arithmetic expressions. Fuzz CI has been red for 6+ consecutive days due to this. - **Fix threat ID mismatch**: Code comments cited `TM-DOS-025` (regex backtracking) instead of `TM-DOS-026` (arithmetic recursion). - **Fix ASan nightly flake**: Relax `threat_cpu_exhaustion_timeout` assertion from 5s to 15s — ASan overhead (~10x) caused the timing assertion to fail in nightly CI. - **Update documentation**: README builtin count (85 → 100+), compatibility scorecard (12 builtins moved from "Not Implemented" to "Recently Added"), CHANGELOG (40+ unreleased entries since v0.1.6), implementation status spec (builtin count 100 → 109, cleaned stale strikethrough entries). ## Maintenance Checklist | Section | Status | Notes | |---------|--------|-------| | 1. Dependencies | Pass | `cargo update` (up to date), `cargo audit` (clean), `cargo deny` (clean) | | 2. Security | Pass | Threat model reviewed, TM-DOS-026 depth reduced, security tests pass | | 3. Tests | Pass | All tests pass, 899/899 bash compat | | 4. Documentation | Fixed | README, compatibility, CHANGELOG, threat model docs updated | | 5. Examples | Pass | All 15 examples compile and run | | 6. Specs | Fixed | 009-implementation-status updated, stale entries cleaned | | 7. Code Quality | Pass | `cargo fmt --check` and `cargo clippy` clean | | 8. Agent Config | Pass | AGENTS.md verified current | | 9. Nightly CI | Fixed | Fuzz crash fixed (depth limit); ASan timeout flake fixed (15s bound) | ## Test plan - [x] `cargo fmt --check` — clean - [x] `cargo clippy --all-targets --all-features -- -D warnings` — clean - [x] `cargo test --all-features` — all pass - [x] `cargo test --test threat_model_tests` — 93 pass - [x] `just check-bash-compat` — 899/899 match - [x] All 15 examples compile and run - [x] `cargo doc --all-features` — no warnings --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 2cb9ba1 commit e2ea375

File tree

8 files changed

+112
-43
lines changed

8 files changed

+112
-43
lines changed

CHANGELOG.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,66 @@
11
# Changelog
22

3+
## [Unreleased]
4+
5+
### Highlights
6+
7+
- 20+ new builtins: `declare`/`typeset`, `let`, `getopts`, `trap`, `caller`, `shopt`, `pushd`/`popd`/`dirs`, `seq`, `tac`, `rev`, `yes`, `expr`, `mktemp`, `realpath`, and more
8+
- Glob options: `dotglob`, `nocaseglob`, `failglob`, `noglob`, `globstar`
9+
- Shell flags: `bash -e/-x/-u/-f/-o`, `set -x` xtrace debugging
10+
- `select` construct, `case ;;&` fallthrough, `FUNCNAME` variable
11+
- Nameref variables (`declare -n`), case conversion (`declare -l/-u`)
12+
- 10+ bug fixes for quoting, arrays, globs, and redirections
13+
14+
### What's Changed
15+
16+
* feat(interpreter): implement bash/sh -e/-x/-u/-f/-o flags ([#270](https://github.com/everruns/bashkit/pull/270))
17+
* chore(eval): run 2026-02-25 evals across 4 models ([#271](https://github.com/everruns/bashkit/pull/271))
18+
* feat(interpreter): implement glob options (dotglob, nocaseglob, failglob, noglob, globstar) ([#269](https://github.com/everruns/bashkit/pull/269))
19+
* feat(builtins): implement pushd, popd, dirs ([#268](https://github.com/everruns/bashkit/pull/268))
20+
* feat(builtins): implement file comparison test operators ([#267](https://github.com/everruns/bashkit/pull/267))
21+
* feat(builtins): implement expr builtin ([#266](https://github.com/everruns/bashkit/pull/266))
22+
* feat(builtins): implement yes and realpath builtins ([#265](https://github.com/everruns/bashkit/pull/265))
23+
* feat(interpreter): implement caller builtin ([#264](https://github.com/everruns/bashkit/pull/264))
24+
* feat(builtins): implement printf %q shell quoting ([#263](https://github.com/everruns/bashkit/pull/263))
25+
* feat(builtins): implement tac and rev builtins ([#262](https://github.com/everruns/bashkit/pull/262))
26+
* feat(builtins): implement seq builtin ([#261](https://github.com/everruns/bashkit/pull/261))
27+
* chore(deps): bump pyo3 to 0.28.2 and pyo3-async-runtimes to 0.28 ([#260](https://github.com/everruns/bashkit/pull/260))
28+
* feat(builtins): implement mktemp builtin ([#259](https://github.com/everruns/bashkit/pull/259))
29+
* feat(interpreter): implement trap -p flag and sorted trap listing ([#258](https://github.com/everruns/bashkit/pull/258))
30+
* feat(builtins): implement set -o / set +o option display ([#257](https://github.com/everruns/bashkit/pull/257))
31+
* feat(interpreter): implement declare -l/-u case conversion attributes ([#256](https://github.com/everruns/bashkit/pull/256))
32+
* feat(interpreter): implement declare -n nameref variables ([#255](https://github.com/everruns/bashkit/pull/255))
33+
* feat(builtins): implement shopt builtin with nullglob enforcement ([#254](https://github.com/everruns/bashkit/pull/254))
34+
* feat(interpreter): implement set -x xtrace debugging ([#253](https://github.com/everruns/bashkit/pull/253))
35+
* feat(bash): auto-populate shell variables (PWD, HOME, USER, etc.) ([#252](https://github.com/everruns/bashkit/pull/252))
36+
* feat(bash): implement select construct ([#251](https://github.com/everruns/bashkit/pull/251))
37+
* feat(bash): implement let builtin and fix declare -i arithmetic ([#250](https://github.com/everruns/bashkit/pull/250))
38+
* feat(bash): case ;& and ;;& fallthrough/continue-matching ([#249](https://github.com/everruns/bashkit/pull/249))
39+
* feat(bash): implement FUNCNAME special variable ([#248](https://github.com/everruns/bashkit/pull/248))
40+
* fix(bash): backslash-newline line continuation in double quotes ([#247](https://github.com/everruns/bashkit/pull/247))
41+
* fix(bash): nested double quotes inside $() in double-quoted strings ([#246](https://github.com/everruns/bashkit/pull/246))
42+
* fix(bash): input redirections on compound commands ([#245](https://github.com/everruns/bashkit/pull/245))
43+
* fix(bash): glob pattern matching in [[ == ]] and [[ != ]] ([#244](https://github.com/everruns/bashkit/pull/244))
44+
* fix(bash): negative array indexing ${arr[-1]} ([#243](https://github.com/everruns/bashkit/pull/243))
45+
* fix(bash): BASH_REMATCH not populated when regex starts with parens ([#242](https://github.com/everruns/bashkit/pull/242))
46+
* feat(bash): arithmetic exponentiation, base literals, mapfile ([#241](https://github.com/everruns/bashkit/pull/241))
47+
* feat: grep binary detection, awk %.6g and sorted for-in ([#240](https://github.com/everruns/bashkit/pull/240))
48+
* feat: bash compatibility — compound arrays, grep -f, awk getline, jq env/input ([#238](https://github.com/everruns/bashkit/pull/238))
49+
* feat: string ops, read -r, heredoc tests ([#237](https://github.com/everruns/bashkit/pull/237))
50+
* feat: associative arrays, chown/kill builtins, array slicing tests ([#236](https://github.com/everruns/bashkit/pull/236))
51+
* feat: cat -v, sort -m, brace/date/lexer fixes ([#234](https://github.com/everruns/bashkit/pull/234))
52+
* feat: type/which/declare/ln builtins, errexit, nounset fix, sort -z, cut -z ([#233](https://github.com/everruns/bashkit/pull/233))
53+
* feat: paste, command, getopts, nounset, [[ =~ ]], glob **, backtick subst ([#232](https://github.com/everruns/bashkit/pull/232))
54+
* feat(date): add -R, -I flags and %N format ([#231](https://github.com/everruns/bashkit/pull/231))
55+
* fix(lexer): handle backslash-escaped metacharacters ([#230](https://github.com/everruns/bashkit/pull/230))
56+
* feat(grep): add --include/--exclude glob patterns ([#229](https://github.com/everruns/bashkit/pull/229))
57+
* feat(sort,uniq,cut,tr): add sort/uniq/cut/tr missing options ([#228](https://github.com/everruns/bashkit/pull/228))
58+
* feat(sed): grouped commands, branching, Q quit, step/zero addresses ([#227](https://github.com/everruns/bashkit/pull/227))
59+
* chore(deps): upgrade monty to latest main (87f8f31) ([#226](https://github.com/everruns/bashkit/pull/226))
60+
* fix(ci): repair nightly CI and add fuzz compile guard ([#225](https://github.com/everruns/bashkit/pull/225))
61+
62+
**Full Changelog**: https://github.com/everruns/bashkit/compare/v0.1.6...HEAD
63+
364
## [0.1.6] - 2026-02-20
465

566
### Highlights

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,23 @@ async fn main() -> anyhow::Result<()> {
4343
</a>
4444
</div>
4545

46-
## Built-in Commands (85)
46+
## Built-in Commands (100+)
4747

4848
| Category | Commands |
4949
|----------|----------|
5050
| Core | `echo`, `printf`, `cat`, `nl`, `read` |
51-
| Navigation | `cd`, `pwd`, `ls`, `find` |
51+
| Navigation | `cd`, `pwd`, `ls`, `find`, `pushd`, `popd`, `dirs` |
5252
| Flow control | `true`, `false`, `exit`, `return`, `break`, `continue`, `test`, `[` |
53-
| Variables | `export`, `set`, `unset`, `local`, `shift`, `source`, `.`, `eval`, `readonly`, `times` |
54-
| Text processing | `grep`, `sed`, `awk`, `jq`, `head`, `tail`, `sort`, `uniq`, `cut`, `tr`, `wc`, `paste`, `column`, `diff`, `comm`, `strings` |
55-
| File operations | `mkdir`, `rm`, `cp`, `mv`, `touch`, `chmod`, `rmdir` |
53+
| Variables | `export`, `set`, `unset`, `local`, `shift`, `source`, `.`, `eval`, `readonly`, `times`, `declare`, `typeset`, `let` |
54+
| Shell | `bash`, `sh` (virtual re-invocation), `:`, `trap`, `caller`, `getopts`, `shopt` |
55+
| Text processing | `grep`, `sed`, `awk`, `jq`, `head`, `tail`, `sort`, `uniq`, `cut`, `tr`, `wc`, `paste`, `column`, `diff`, `comm`, `strings`, `tac`, `rev`, `seq`, `expr` |
56+
| File operations | `mkdir`, `mktemp`, `rm`, `cp`, `mv`, `touch`, `chmod`, `chown`, `ln`, `rmdir`, `realpath` |
5657
| File inspection | `file`, `stat`, `less` |
5758
| Archives | `tar`, `gzip`, `gunzip` |
5859
| Byte tools | `od`, `xxd`, `hexdump` |
59-
| Utilities | `sleep`, `date`, `basename`, `dirname`, `timeout`, `wait`, `watch` |
60+
| Utilities | `sleep`, `date`, `basename`, `dirname`, `timeout`, `wait`, `watch`, `yes`, `kill` |
6061
| Disk | `df`, `du` |
6162
| Pipeline | `xargs`, `tee` |
62-
| Shell | `bash`, `sh` (virtual re-invocation), `:` |
6363
| System info | `whoami`, `hostname`, `uname`, `id`, `env`, `printenv`, `history` |
6464
| Network | `curl`, `wget` (requires allowlist) |
6565
| Experimental | `python`, `python3` (requires `python` feature), `git` (requires `git` feature) |

crates/bashkit/docs/compatibility.md

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -125,22 +125,37 @@ for sandbox security reasons. See the compliance spec for details.
125125
| `xxd` | `-l`, `-s`, `-c`, `-g`, `-p` | Hex dump |
126126
| `hexdump` | `-C`, `-n`, `-s` | Display file in hex+ASCII |
127127

128+
### Recently Added
129+
130+
| Builtin | Flags / Arguments | Notes |
131+
|---------|-------------------|-------|
132+
| `ln` | `-s`, `-f` | Create links |
133+
| `chown` | `OWNER[:GROUP] FILE` | Change ownership (virtual) |
134+
| `kill` | `-SIGNAL PID` | Send signals (virtual) |
135+
| `trap` | `COMMAND SIGNAL...`, `-p`, `-l` | Signal/event handlers |
136+
| `type` | `NAME...` | Describe command type |
137+
| `which` | `NAME...` | Locate a command |
138+
| `command` | `-v`, `NAME...` | Run or identify commands |
139+
| `hash` | (none) | No-op in sandboxed env |
140+
| `declare`/`typeset` | `-i`, `-r`, `-x`, `-a`, `-p`, `-n`, `-l`, `-u` | Variable attributes |
141+
| `let` | `EXPR...` | Evaluate arithmetic |
142+
| `getopts` | `OPTSTRING NAME` | Parse positional parameters |
143+
| `caller` | `[FRAME]` | Display call stack frame |
144+
| `shopt` | `-s`, `-u`, `-q` | Shell options |
145+
| `seq` | `[FIRST [INCR]] LAST` | Print number sequence |
146+
| `tac` | (none) | Reverse file lines |
147+
| `rev` | (none) | Reverse characters per line |
148+
| `yes` | `[STRING]` | Output repeated string |
149+
| `expr` | `EXPRESSION` | Evaluate expressions |
150+
| `mktemp` | `-d`, `-p`, `-t` | Create temporary files |
151+
| `realpath` | `PATH` | Resolve path |
152+
| `pushd`/`popd`/`dirs` | standard flags | Directory stack |
153+
128154
### Not Implemented
129155

130156
| Builtin | Priority | Status |
131157
|---------|----------|--------|
132-
| `ln` | Low | - |
133-
| `chown` | Low | - |
134-
| `kill` | Low | - |
135158
| `exec` | N/A | Security: intentionally excluded |
136-
| `trap` | N/A | Security: intentionally excluded |
137-
| `type` | Low | - |
138-
| `which` | Low | - |
139-
| `command` | Medium | POSIX utility |
140-
| `hash` | Low | - |
141-
| `declare` | Low | Bash extension |
142-
| `typeset` | Low | Bash extension |
143-
| `getopts` | Medium | POSIX utility |
144159

145160
---
146161

crates/bashkit/docs/threat-model.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ through configurable limits.
3232
| Recursion (TM-DOS-020) | `f() { f; }; f` | `max_function_depth` | [`limits.rs`][limits] |
3333
| Parser depth (TM-DOS-022) | `(((((...))))))` nesting | `max_ast_depth` + hard cap (100) | [`parser/mod.rs`][parser] |
3434
| Command sub depth (TM-DOS-021) | `$($($($())))` nesting | Inherited depth/fuel from parent | [`parser/mod.rs`][parser] |
35-
| Arithmetic depth (TM-DOS-026) | `$(((((...))))))` | `MAX_ARITHMETIC_DEPTH` (200) | [`interpreter/mod.rs`][interp] |
35+
| Arithmetic depth (TM-DOS-026) | `$(((((...))))))` | `MAX_ARITHMETIC_DEPTH` (50) | [`interpreter/mod.rs`][interp] |
3636
| Parser attack (TM-DOS-024) | Malformed input | `parser_timeout` | [`limits.rs`][limits] |
3737
| Filesystem bomb (TM-DOS-007) | Zip bomb extraction | `FsLimits` | [`fs/limits.rs`][fslimits] |
3838
| Many files (TM-DOS-006) | Create 1M files | `max_file_count` | [`fs/limits.rs`][fslimits] |
@@ -308,7 +308,7 @@ attacks:
308308
This prevents attackers from bypassing depth limits through nested substitutions.
309309

310310
4. **Arithmetic depth limit** (TM-DOS-026): The arithmetic evaluator (`$((expr))`)
311-
has its own depth limit (`MAX_ARITHMETIC_DEPTH = 200`) to prevent stack overflow
311+
has its own depth limit (`MAX_ARITHMETIC_DEPTH = 50`) to prevent stack overflow
312312
from deeply nested parenthesized expressions.
313313

314314
5. **Parser fuel** (`max_parser_operations`, default 100K): Independent of depth,

crates/bashkit/src/interpreter/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5421,9 +5421,9 @@ impl Interpreter {
54215421
}
54225422

54235423
/// Maximum recursion depth for arithmetic expression evaluation.
5424-
/// THREAT[TM-DOS-025]: Prevents stack overflow via deeply nested arithmetic like
5424+
/// THREAT[TM-DOS-026]: Prevents stack overflow via deeply nested arithmetic like
54255425
/// $(((((((...)))))))
5426-
const MAX_ARITHMETIC_DEPTH: usize = 200;
5426+
const MAX_ARITHMETIC_DEPTH: usize = 50;
54275427

54285428
/// Evaluate arithmetic with assignment support (e.g. `X = X + 1`).
54295429
/// Assignment must be handled before variable expansion so the LHS
@@ -5578,7 +5578,7 @@ impl Interpreter {
55785578
// First expand any variables in the expression
55795579
let expanded = self.expand_arithmetic_vars(expr);
55805580

5581-
// Parse and evaluate with depth tracking (TM-DOS-025)
5581+
// Parse and evaluate with depth tracking (TM-DOS-026)
55825582
self.parse_arithmetic_impl(&expanded, 0)
55835583
}
55845584

@@ -5658,7 +5658,7 @@ impl Interpreter {
56585658
}
56595659

56605660
/// Parse and evaluate a simple arithmetic expression with depth tracking.
5661-
/// THREAT[TM-DOS-025]: `arith_depth` prevents stack overflow from deeply nested expressions.
5661+
/// THREAT[TM-DOS-026]: `arith_depth` prevents stack overflow from deeply nested expressions.
56625662
fn parse_arithmetic_impl(&self, expr: &str, arith_depth: usize) -> i64 {
56635663
let expr = expr.trim();
56645664

@@ -5671,7 +5671,7 @@ impl Interpreter {
56715671
return 0;
56725672
}
56735673

5674-
// THREAT[TM-DOS-025]: Bail out if arithmetic nesting is too deep
5674+
// THREAT[TM-DOS-026]: Bail out if arithmetic nesting is too deep
56755675
if arith_depth >= Self::MAX_ARITHMETIC_DEPTH {
56765676
return 0;
56775677
}

crates/bashkit/tests/threat_model_tests.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,9 @@ mod resource_exhaustion {
157157
.await;
158158
let elapsed = start.elapsed();
159159

160-
// Should complete quickly due to either timeout or loop limit
161-
assert!(elapsed < Duration::from_secs(5));
160+
// Should complete quickly due to either timeout or loop limit.
161+
// Under ASan the overhead can be ~10x, so use a generous bound.
162+
assert!(elapsed < Duration::from_secs(15));
162163
}
163164
}
164165

specs/006-threat-model.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ runaway scripts without permanently breaking the session.
191191
| TM-DOS-020 | Function recursion | `f() { f; }; f` | Depth limit (100) | **MITIGATED** |
192192
| TM-DOS-021 | Command sub nesting | `$($($($())))` | Child parsers inherit remaining depth budget + fuel from parent | **MITIGATED** |
193193
| TM-DOS-022 | Parser recursion | Deeply nested `(((())))` | `max_ast_depth` limit (100) + `HARD_MAX_AST_DEPTH` cap (100) | **MITIGATED** |
194-
| TM-DOS-026 | Arithmetic recursion | `$(((((((...)))))))` deeply nested parens | `MAX_ARITHMETIC_DEPTH` limit (200) | **MITIGATED** |
194+
| TM-DOS-026 | Arithmetic recursion | `$(((((((...)))))))` deeply nested parens | `MAX_ARITHMETIC_DEPTH` limit (50) | **MITIGATED** |
195195

196196
**Current Risk**: LOW - Both execution and parser protected
197197

@@ -201,7 +201,7 @@ max_function_depth: 100, // Runtime recursion (TM-DOS-020, TM-DOS-021)
201201
max_ast_depth: 100, // Parser recursion (TM-DOS-022)
202202
// TM-DOS-021: Child parsers in command/process substitution inherit remaining
203203
// depth budget and fuel from parent parser (parser/mod.rs lines 1553, 1670)
204-
// TM-DOS-026: Arithmetic evaluator tracks recursion depth, capped at 200
204+
// TM-DOS-026: Arithmetic evaluator tracks recursion depth, capped at 50
205205
// (interpreter/mod.rs MAX_ARITHMETIC_DEPTH)
206206
```
207207

@@ -850,7 +850,7 @@ This section maps former vulnerability IDs to the new threat ID scheme and track
850850
| V4 | TM-DOS-022 | Parser recursion | **MITIGATED** via `max_ast_depth` |
851851
| V5 | TM-DOS-018 | Nested loop multiplication | **MITIGATED** via `max_total_loop_iterations` (1M) |
852852
| V6 | TM-DOS-021 | Command sub parser limit bypass | **MITIGATED** via inherited depth/fuel |
853-
| V7 | TM-DOS-026 | Arithmetic recursion overflow | **MITIGATED** via `MAX_ARITHMETIC_DEPTH` (200) |
853+
| V7 | TM-DOS-026 | Arithmetic recursion overflow | **MITIGATED** via `MAX_ARITHMETIC_DEPTH` (50) |
854854

855855
### Open (Medium Priority)
856856

@@ -881,7 +881,7 @@ This section maps former vulnerability IDs to the new threat ID scheme and track
881881
| Parser fuel (100K ops) | TM-DOS-024 | `limits.rs` | Yes |
882882
| AST depth limit (100) | TM-DOS-022 | `limits.rs` | Yes |
883883
| Child parser limit propagation | TM-DOS-021 | `parser/mod.rs` | Yes |
884-
| Arithmetic depth limit (200) | TM-DOS-026 | `interpreter/mod.rs` | Yes |
884+
| Arithmetic depth limit (50) | TM-DOS-026 | `interpreter/mod.rs` | Yes |
885885
| Builtin parser depth limit (100) | TM-DOS-027 | `builtins/awk.rs`, `builtins/jq.rs` | Yes |
886886
| Execution timeout (30s) | TM-DOS-023 | `limits.rs` | Yes |
887887
| Virtual filesystem | TM-ESC-001, TM-ESC-003 | `fs/memory.rs` | Yes |
@@ -927,7 +927,7 @@ ExecutionLimits::new()
927927
.max_input_bytes(10_000_000) // TM-DOS-001 (10MB)
928928
.max_ast_depth(100) // TM-DOS-022 (also inherited by child parsers: TM-DOS-021)
929929
.max_parser_operations(100_000) // TM-DOS-024 (also inherited by child parsers: TM-DOS-021)
930-
// Note: MAX_ARITHMETIC_DEPTH (200) is a compile-time constant in interpreter (TM-DOS-026)
930+
// Note: MAX_ARITHMETIC_DEPTH (50) is a compile-time constant in interpreter (TM-DOS-026)
931931
// Note: MAX_AWK_PARSER_DEPTH (100) is a compile-time constant in builtins/awk.rs (TM-DOS-027)
932932
// Note: MAX_JQ_JSON_DEPTH (100) is a compile-time constant in builtins/jq.rs (TM-DOS-027)
933933

specs/009-implementation-status.md

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -184,15 +184,6 @@ Features that may be added in the future (not intentionally excluded):
184184
| Feature | Priority | Notes |
185185
|---------|----------|-------|
186186
| Coprocesses `coproc` | Low | Rarely used |
187-
| ~~Extended globs `@()` `!()` `?()` `*()` `+()`~~ | ~~Medium~~ | Implemented: all five extglob operators |
188-
| ~~Associative arrays `declare -A`~~ | ~~Medium~~ | Implemented: key-value access, iteration, unset, `${!m[@]}` |
189-
| ~~`[[ =~ ]]` regex matching~~ | ~~Medium~~ | Implemented: `[[ ]]` conditionals with `=~` and BASH_REMATCH |
190-
| ~~`getopts`~~ | ~~Medium~~ | Implemented: POSIX option parsing |
191-
| ~~`command` builtin~~ | ~~Medium~~ | Implemented: `-v`, `-V`, bypass functions |
192-
| ~~`type`/`which` builtins~~ | ~~Medium~~ | Implemented: `-t`, `-a`, `-p` flags |
193-
| ~~`declare` builtin~~ | ~~Medium~~ | Implemented: `-i`, `-r`, `-x`, `-a`, `-p`, `-n`, `-l`, `-u` |
194-
| ~~`ln` builtin~~ | ~~Medium~~ | Implemented: symbolic links (`-s`, `-f`) |
195-
| ~~Directory stack `pushd`/`popd`/`dirs`~~ | ~~Low-Medium~~ | Implemented: push, pop, swap, clear, display |
196187
| `alias` | Low | Interactive feature |
197188
| History expansion | Out of scope | Interactive only |
198189

@@ -215,15 +206,16 @@ Features that may be added in the future (not intentionally excluded):
215206

216207
### Implemented
217208

218-
**97 core builtins + 3 feature-gated = 100 total**
209+
**106 core builtins + 3 feature-gated = 109 total**
219210

220211
`echo`, `printf`, `cat`, `nl`, `cd`, `pwd`, `true`, `false`, `exit`, `test`, `[`,
221212
`export`, `set`, `unset`, `local`, `source`, `.`, `read`, `shift`, `break`,
222213
`continue`, `return`, `grep`, `sed`, `awk`, `jq`, `sleep`, `head`, `tail`,
223-
`basename`, `dirname`, `mkdir`, `rm`, `cp`, `mv`, `touch`, `chmod`, `chown`, `ln`, `wc`,
214+
`basename`, `dirname`, `realpath`, `mkdir`, `mktemp`, `rm`, `cp`, `mv`, `touch`, `chmod`, `chown`, `ln`, `wc`,
224215
`sort`, `uniq`, `cut`, `tr`, `paste`, `column`, `diff`, `comm`, `date`,
225216
`wait`, `curl`, `wget`, `timeout`, `command`, `getopts`,
226217
`type`, `which`, `hash`, `declare`, `typeset`, `let`, `kill`, `shopt`,
218+
`trap`, `caller`, `seq`, `tac`, `rev`, `yes`, `expr`,
227219
`time` (keyword), `whoami`, `hostname`, `uname`, `id`, `ls`, `rmdir`, `find`, `xargs`, `tee`,
228220
`:` (colon), `eval`, `readonly`, `times`, `bash`, `sh`,
229221
`od`, `xxd`, `hexdump`, `strings`,

0 commit comments

Comments
 (0)