srsh 0.7.1 → 1.0.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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +18 -14
  3. data/README.md +351 -134
  4. data/bin/srsh +53 -1473
  5. data/docs/assets/slut.txt +4 -0
  6. data/docs/assets/srsh-mark.svg +12 -0
  7. data/docs/css/style.css +696 -0
  8. data/docs/index.html +703 -0
  9. data/docs/js/app.js +203 -0
  10. data/examples/bridge.rsh +8 -0
  11. data/examples/calculator.rsh +253 -0
  12. data/examples/defer.rsh +14 -0
  13. data/examples/hot.rsh +14 -0
  14. data/examples/meta.rsh +20 -0
  15. data/examples/modules/text.rsh +6 -0
  16. data/examples/modules.rsh +6 -0
  17. data/examples/paste.rsh +15 -0
  18. data/examples/plugin.rb +8 -0
  19. data/examples/power.rsh +65 -0
  20. data/examples/tour.rsh +38 -0
  21. data/ext/srsh_native/extconf.rb +3 -0
  22. data/ext/srsh_native/srsh_native.c +48 -0
  23. data/language-docs/LANGUAGE.md +670 -0
  24. data/language-docs/MIGRATION.md +44 -0
  25. data/language-docs/SECURITY.md +44 -0
  26. data/lib/srsh/app.rb +261 -0
  27. data/lib/srsh/builtins.rb +492 -0
  28. data/lib/srsh/editor.rb +530 -0
  29. data/lib/srsh/errors.rb +23 -0
  30. data/lib/srsh/history.rb +74 -0
  31. data/lib/srsh/language/evaluator.rb +1175 -0
  32. data/lib/srsh/language/lexer.rb +316 -0
  33. data/lib/srsh/language/parser.rb +997 -0
  34. data/lib/srsh/language/token.rb +5 -0
  35. data/lib/srsh/language/values.rb +392 -0
  36. data/lib/srsh/paths.rb +29 -0
  37. data/lib/srsh/plugins.rb +59 -0
  38. data/lib/srsh/process_identity.rb +38 -0
  39. data/lib/srsh/security.rb +38 -0
  40. data/lib/srsh/shell/executor.rb +1182 -0
  41. data/lib/srsh/shell/job.rb +101 -0
  42. data/lib/srsh/shell/lexer.rb +114 -0
  43. data/lib/srsh/shell/terminal.rb +26 -0
  44. data/lib/srsh/state.rb +136 -0
  45. data/lib/srsh/theme.rb +108 -0
  46. data/lib/srsh/version.rb +1 -2
  47. data/lib/srsh.rb +15 -0
  48. metadata +59 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c0910382ad05f07b93041cfbecb7d3db98f24e23df1ecd5d23243aab35a7f63
4
- data.tar.gz: c39ce2184076112bb950035ea2f09939bef9f4105b2c207e6ec73ee152fc3c89
3
+ metadata.gz: 5b4ebcca8a9c5952dd9608cd8fe5dd311aae5445224896c4e190db2c7981a4dc
4
+ data.tar.gz: 17f76ba91a316ebd35dfdfaf5c260baf778348a73e4f930c8c61fb0de2222cc3
5
5
  SHA512:
6
- metadata.gz: ee7bd7e5ae91582ed612171eda2f3440d16d8d07988b465fd61470e094d80b0f766cfc6f248d2980f0371a0db228593a326934fe7f6c4367fb8e9b009213e26f
7
- data.tar.gz: 6195a9d026471e57b1b7b8f87970362261302d0e7f8b936a030ecc02bce7de2c56d3420d2e7cee0b7810f60acc32f5a171bd45acd1181ffc7d2469389f37ebd7
6
+ metadata.gz: 37f82634b0c88623c50d1aa3eee65d2b219ed317c87ea6e9abe42c904a9989aec5a0fd360715a33879a5dfc44ecf020611c5880b0a024868bb4f6627cabf95d0
7
+ data.tar.gz: 787a567cfed45fdd641874c8a0e9f43b919645ff5c882c5be0aac6bde2899a6cb4c89f2f5f032bfe0b1c2a274df4df66800542834937fe8d12dec0f3932db835
data/LICENSE CHANGED
@@ -1,17 +1,21 @@
1
- Copyright (C) 2025 RobertFlexx
1
+ MIT License
2
2
 
3
- This software is provided 'as-is', without any express or implied
4
- warranty. In no event will the authors be held liable for any damages
5
- arising from the use of this software.
3
+ Copyright (c) 2026 RobertFlexx
6
4
 
7
- Permission is granted to anyone to use this software for any purpose,
8
- including commercial applications, and to alter it and redistribute it
9
- freely, subject to the following restrictions:
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
10
11
 
11
- 1. The origin of this software must not be misrepresented; you must not
12
- claim that you wrote the original software. If you use this software
13
- in a product, an acknowledgment in the product documentation would be
14
- appreciated but is not required.
15
- 2. Altered source versions must be plainly marked as such, and must not be
16
- misrepresented as being the original software.
17
- 3. This notice may not be removed or altered from any source distribution.
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -1,235 +1,452 @@
1
- This is version 0.6.0, if things dont work, or work optimally. If you notice anything wrong, please consult me.
2
- (Fixed Control-C, fixed some bugs, added new features (check via help command)
3
- THIS IS A BETA RELEASE, IT MAY NOT WORK.
1
+ # srsh, Simple Ruby Shell
4
2
 
5
- The code itself is written by RobertFlexx, but the comments are written by ChatGPT.
3
+ `srsh` is a Unix shell written in Ruby. Its scripting language is **RSH**.
6
4
 
7
- ## Known Issues:
5
+ The basic idea is pretty simple: keep the parts of a normal shell that are already good, then stop making people switch languages when a script gets serious.
8
6
 
9
- * Flatpak chaining with 'and' doesn't work.
10
- * Running Shell Scripts might not always work. Sometimes it works, other times not so much.
7
+ ```rsh
8
+ printf 'c\na\nb\n' | sort
11
9
 
12
- ## Please Consult:
10
+ files := glob("src/**/*.rb")
11
+ |> reject(::p => contains(p, "/vendor/"))
12
+ |> sort
13
13
 
14
- * if you have any issues with this SRSh version, please post an issue.
14
+ ? files |> len > 20 => = "that's a lot of Ruby"
15
+ ```
16
+
17
+ `|` is still a Unix process pipe. `|>` is an RSH value pipe. They look related because they *are* related, but they move different things.
18
+
19
+ This tree reports **1.0.0**. It is the unreleased 1.0 line; the older 1.1/1.2 numbers were development snapshots and were a dumb way to version something that had not shipped yet.
20
+
21
+ ## What SRSH is trying to be
22
+
23
+ Bash is fantastic at launching programs. It gets a lot less fun when you need nested data, workers, reusable modules, objects, error handling, higher-order functions, or a pile of state that has to remain understandable next month.
15
24
 
16
- ## How to Install:
25
+ RSH is meant to cover that gap without turning the shell into a foreign environment:
17
26
 
18
- ### Clone the repository
27
+ ```rsh
28
+ branch := $(git branch --show-current)
19
29
 
20
- ```console
21
- git clone https://github.com/RobertFlexx/RSH
30
+ fn changed(path) => cmd("git", "diff", "--quiet", "--", path).result().status != 0
31
+
32
+ dirty := glob("src/**/*") |> filter(changed)
33
+ = "#{branch}: #{dirty |> len} changed files"
22
34
  ```
23
35
 
24
- ### Change the directory to where the Ruby Script is located
36
+ It is **not a Bash parser**. Existing Bash scripts still belong to Bash. The goal is that new automation can start as a shell one-liner and grow into a proper RSH program without a rewrite.
37
+
38
+ ## Build and run
25
39
 
26
- ```console
27
- cd RSH
40
+ Ruby 3.2+ is required.
41
+
42
+ ```sh
43
+ make test
44
+ ./bin/srsh
28
45
  ```
29
46
 
30
- ### And finally run it
47
+ The shell is fully usable as Ruby-only code. There is a tiny optional C extension for hot lexer work and Linux process naming:
31
48
 
32
- ```console
33
- ./rsh
49
+ ```sh
50
+ make native
51
+ ./bin/srsh
34
52
  ```
35
53
 
36
- ---
54
+ YJIT is enabled when the running Ruby supports it. Set `SRSH_YJIT=0` if you want it off.
55
+
56
+ Install somewhere else with:
37
57
 
38
- ## Requirements
58
+ ```sh
59
+ make PREFIX="$HOME/.local" install
60
+ ```
39
61
 
40
- * Ruby installed (2.7+ is recommended; newer is better).
41
- * A POSIX-ish terminal (Linux, *BSD, macOS Terminal, iTerm2, etc).
42
- * `./rsh` needs the executable bit set:
62
+ ## The syntax has a reason
43
63
 
44
- ```console
45
- chmod +x rsh
46
- ```
64
+ RSH has some odd-looking syntax, but the goal is not to win a weird-language contest.
47
65
 
48
- If `./rsh` complains or behaves oddly, **run it directly in the repo first** before messing with symlinks or PATH.
66
+ There are a few boundaries you hit constantly in shell programming, and RSH gives each one a visible shape:
49
67
 
50
- ---
68
+ ```text
69
+ command | command bytes/processes move between Unix programs
70
+ value |> function RSH values move through functions
71
+ $(command) process output crosses into the value layer
72
+ name := value local RSH binding
73
+ $NAME := value exported process environment
74
+ ::x => expression tiny callable value
75
+ bridge ... from ... RSH crosses into a native C ABI
76
+ ```
51
77
 
52
- ## Basic Usage
78
+ That makes parsing less ambiguous around arbitrary Unix command names, and it lets hot scripts stay short without turning maintained code into punctuation soup.
53
79
 
54
- Once you’re in the repo:
80
+ Readable forms exist too:
55
81
 
56
- ```console
57
- ./rsh
82
+ ```rsh
83
+ fn deploy(files, dry := no)
84
+ if dry
85
+ = "would deploy #{files |> len} files"
86
+ else
87
+ each files -> path
88
+ emit path
89
+ end
90
+ end
91
+ end
58
92
  ```
59
93
 
60
- Inside `srsh` / `rsh` you can:
94
+ The short forms lower to the same AST:
61
95
 
62
- * Use normal commands (`ls`, `cat`, `grep`, etc.).
63
- * Use built-ins:
96
+ ```rsh
97
+ :: twice(x) => x * 2
98
+ ? ready => emit "go"
99
+ @ jobs -> job => = job.name
100
+ ```
64
101
 
65
- * `help` show builtin help with all srsh-specific commands.
66
- * `systemfetch` – prints system info with nice bars.
67
- * `hist` – view shell history.
68
- * `clearhist` – clear history (memory + file).
69
- * `alias` / `unalias` – manage aliases.
70
- * Enjoy:
102
+ Use whichever one fits the size of the job.
71
103
 
72
- * **Autosuggestions** (ghost text from history).
73
- * **Smart Tab completion**:
104
+ ## The REPL is actually an RSH REPL
74
105
 
75
- * Completes commands, files, dirs.
76
- * `cd` → only directories.
77
- * `cat` → only files.
106
+ Bindings, expressions and blocks work directly at the shell prompt:
78
107
 
79
- ---
108
+ ```text
109
+ > x := 21
110
+ > = x * 2
111
+ 42
80
112
 
81
- ## Adding `rsh` / `srsh` to your PATH
113
+ > fn triple(n)
114
+ ... return n * 3
115
+ ... end
116
+ > = triple(10)
117
+ 30
118
+ ```
82
119
 
83
- So you don’t have to always `cd` into the repo and run `./rsh`, you can either:
120
+ Multiline list/map/call expressions also continue properly:
84
121
 
85
- 1. Add the repo directory to your `PATH`, or
86
- 2. Symlink the script into a directory that’s already on your `PATH`.
122
+ ```text
123
+ > jobs := [
124
+ ... fetch("a"),
125
+ ... fetch("b")
126
+ ... ]
127
+ ```
128
+
129
+ That same completeness logic is used for manually entered continuations. For an actual terminal paste, SRSH enables bracketed-paste mode and captures the whole clipboard payload before parsing any of it. Multi-line pastes get a small preview; press Enter once to run the whole program or Ctrl-C to throw it away. Embedded newlines never become a queue of accidental commands.
130
+
131
+ The editor keeps the old SRSH behavior too: prefix history prediction, Right Arrow to accept it, UTF-8 cursor movement, history navigation, and first-Tab/second-Tab completion.
132
+
133
+ ## Shell side
134
+
135
+ Normal Unix muscle memory is supposed to work:
136
+
137
+ ```sh
138
+ cat *.log | grep ERROR | sort -u
139
+ make -j8 && put "built"
140
+ long_job &
141
+ jobs
142
+ fg %1
143
+ ```
144
+
145
+ Implemented shell features include:
146
+
147
+ - `fork`/`exec` pipelines and process groups
148
+ - `|`, `&&`, `||`, `;`, background `&`
149
+ - `<`, `>`, `>>`, `2>`, `2>>`
150
+ - `jobs`, `fg`, `bg`
151
+ - command substitution with nested `$(...)`
152
+ - aliases
153
+ - `$VAR`, `${VAR}`, `$?`, `$!`, positional arguments
154
+ - pathname globbing (`*`, `?`, `[...]`, and recursive `**` where Ruby's glob supports it)
155
+ - `~` expansion
156
+ - command lookup caching
157
+ - `cd`, `pwd`, `ls`, `printf`, `export`, `read`, `source`, `which`/`type`
158
+ - `pushd`, `popd`, `dirs`, `umask`, `kill`
159
+ - `option pipefail`, `option nounset`, `option noclobber`
160
+ - `option strict yes` as a shortcut for `pipefail + nounset`
161
+
162
+ No-match globs stay literal, which is a much less surprising default for an interactive shell.
163
+
164
+ ## Values and functional scripting
165
+
166
+ RSH has integers, floats, strings, booleans, `void`, lists, maps, ranges, lambdas, code values, tasks, prototypes, namespaces, native handles and structured commands.
167
+
168
+ ```rsh
169
+ users := json(readfile("users.json"))
170
+
171
+ enabled := users
172
+ |> filter(::u => u?.enabled ?? no)
173
+ |> sort(::u => lower(u.name))
174
+
175
+ = enabled |> map(::u => u.name)
176
+ ```
87
177
 
88
- > ⚠️ There is a *system* command called `rsh` on some systems.
89
- > To avoid conflict, using the name `srsh` for the installed command is usually safer.
178
+ The usual functional operations are built in:
90
179
 
91
- ### Option 1 — Add the repo directory to PATH (Linux & macOS, bash/zsh)
180
+ ```text
181
+ map filter reject fold find any all count sum
182
+ sort uniq flat zip enumerate take drop chunk group
183
+ each tap partial compose
184
+ ```
92
185
 
93
- Assuming the repo is at `~/RSH`:
186
+ Named functions are first-class too:
94
187
 
95
- ```console
96
- chmod +x ~/RSH/rsh
188
+ ```rsh
189
+ fn square(x) => x * x
190
+ = 1 .. 10 |> map(square) |> sum
97
191
  ```
98
192
 
99
- #### For `bash` (Linux, older macOS)
193
+ ## Objects without a ceremony tax
194
+
195
+ RSH uses prototypes plus traits. There is no class-inheritance maze to climb through just to hold some state.
196
+
197
+ ```rsh
198
+ trait Named
199
+ fn label() => "#{self.name}: #{self.value}"
200
+ end
100
201
 
101
- Add this line to `~/.bashrc` (or `~/.bash_profile` on macOS):
202
+ proto Counter(name, start := 0) with Named
203
+ slot name := name
204
+ slot value := start
102
205
 
103
- ```bash
104
- export PATH="$HOME/RSH:$PATH"
206
+ fn inc(by := 1)
207
+ self.value += by
208
+ return self
209
+ end
210
+ end
211
+
212
+ hits := Counter("hits")
213
+ hits.inc(3)
214
+ = hits.label()
105
215
  ```
106
216
 
107
- Then reload:
217
+ Object slot updates are synchronized, so objects can be an explicit shared-state tool between tasks.
218
+
219
+ ## Concurrency
108
220
 
109
- ```console
110
- source ~/.bashrc
221
+ Async RSH functions return task values immediately:
222
+
223
+ ```rsh
224
+ task fetch(url)
225
+ return cmd("curl", "-fsS", url).check().out
226
+ end
227
+
228
+ jobs := urls |> map(fetch)
229
+ pages := await_all(jobs)
111
230
  ```
112
231
 
113
- #### For `zsh` (default on modern macOS)
232
+ You can spawn a lambda directly:
233
+
234
+ ```rsh
235
+ job := &:: => expensive_io()
236
+ = job.await(2.0)
237
+ ```
114
238
 
115
- Add this line to `~/.zshrc`:
239
+ Shared mutation is explicit:
116
240
 
117
- ```zsh
118
- export PATH="$HOME/RSH:$PATH"
241
+ ```rsh
242
+ hits := atom(0)
243
+ workers := 0 ..< 32 |> map(::i => &:: => hits.swap(::n => n + 1))
244
+ await_all(workers)
245
+ = hits.get()
119
246
  ```
120
247
 
121
- Reload:
248
+ There are channels too:
122
249
 
123
- ```console
124
- source ~/.zshrc
250
+ ```rsh
251
+ queue := chan(8)
252
+ queue.send("hello")
253
+ = queue.recv(1)
254
+ queue.close()
125
255
  ```
126
256
 
127
- Now you can just run:
257
+ `parallel()` is a Ruby thread pool, which is great for I/O and subprocess waits. On CRuby the GVL still exists; SRSH does not pretend otherwise. `pmap()` uses Unix fork workers when you actually want CPU parallelism.
128
258
 
129
- ```console
130
- rsh
131
- # or if you prefer to rename it:
132
- srsh
259
+ `race()` cancels losing task handles. A failing `await_all()` cancels still-running siblings before propagating the error.
260
+
261
+ ## Modules, namespaces and cleanup
262
+
263
+ Namespaces can live in the same file:
264
+
265
+ ```rsh
266
+ space mathx
267
+ bias := 10
268
+ fn bump(x) => x + bias
269
+ end
270
+
271
+ = mathx.bump(5)
133
272
  ```
134
273
 
135
- ---
274
+ Or load a file as a namespace:
136
275
 
137
- ### Option 2 — Symlink into `/usr/local/bin` (Linux & macOS)
276
+ ```rsh
277
+ use "./lib/http.rsh" as http
278
+ = http.get("https://example.com")
279
+ ```
280
+
281
+ Module paths are resolved relative to the importing script when possible, and import cycles are rejected.
138
282
 
139
- This keeps your PATH clean and gives you a nice command name.
283
+ Cleanup is LIFO and tied to the current execution scope:
140
284
 
141
- From the repo directory:
285
+ ```rsh
286
+ fn build()
287
+ tmp := "/tmp/my-build.lock"
288
+ writefile(tmp, "busy")
289
+ defer rmfile(tmp)
142
290
 
143
- ```console
144
- chmod +x rsh
145
- sudo ln -s "$(pwd)/rsh" /usr/local/bin/srsh
291
+ # return, error, whatever; the cleanup still runs
292
+ return compile()
293
+ end
146
294
  ```
147
295
 
148
- Now you can just type:
296
+ There is a block form when cleanup takes more than one statement:
149
297
 
150
- ```console
151
- srsh
298
+ ```rsh
299
+ defer
300
+ close_stuff()
301
+ emit "cleaned up"
302
+ end
152
303
  ```
153
304
 
154
- from anywhere.
305
+ ## Structured process values
155
306
 
156
- If you really, really want to override the system `rsh` (not recommended):
307
+ Shell strings are convenient. They are not always what you want for untrusted filenames or arguments.
157
308
 
158
- ```console
159
- sudo ln -s "$(pwd)/rsh" /usr/local/bin/rsh
309
+ ```rsh
310
+ result := cmd("git", "rev-parse", "--verify", ref).check()
311
+ sha := result.out.trim()
160
312
  ```
161
313
 
162
- ---
314
+ `cmd()` keeps argv as argv. It does not feed your data back through shell parsing.
163
315
 
164
- ### *BSD: Adding to PATH
316
+ Available methods include `.argv()`, `.run()`, `.result()`, `.capture()`, `.check()` and `.task()`.
165
317
 
166
- On *BSD, the default shell might be `sh`, `ksh`, `csh`, or `tcsh`. Same idea, different config files.
318
+ ## C interop: `bridge`
167
319
 
168
- Assuming repo at `~/RSH`:
320
+ This is the native boundary:
169
321
 
170
- ```console
171
- chmod +x ~/RSH/rsh
322
+ ```rsh
323
+ bridge c from "@self"
324
+ strlen(cstr) -> usize
325
+ end
326
+
327
+ = c.strlen("hello")
172
328
  ```
173
329
 
174
- #### For `sh` / `ksh` / `ash` / `dash` style shells
330
+ Or load a specific shared library:
175
331
 
176
- Add to `~/.profile`:
332
+ ```rsh
333
+ bridge math from "libm.so.6"
334
+ cos(f64) -> f64
335
+ pow(f64, f64) -> f64
336
+ end
177
337
 
178
- ```sh
179
- export PATH="$HOME/RSH:$PATH"
338
+ = math.cos(0.0)
180
339
  ```
181
340
 
182
- Then either log out and back in, or:
341
+ For output buffers/pointer APIs:
183
342
 
184
- ```console
185
- . ~/.profile
343
+ ```rsh
344
+ bridge libc from "libc.so.6"
345
+ gethostname(ptr, usize) -> i32
346
+ end
347
+
348
+ buf := cbuf(256)
349
+ libc.gethostname(buf, buf.size())
350
+ = buf.string()
351
+ ```
352
+
353
+ Supported ABI names are:
354
+
355
+ ```text
356
+ void bool
357
+ i8 u8 i16 u16 i32 u32 i64 u64
358
+ isize usize
359
+ f32 f64
360
+ cstr ptr
186
361
  ```
187
362
 
188
- #### For `csh` / `tcsh`
363
+ `@self` means the current process' symbol table. Bridges resolve their symbols once when declared, so calls do not repeatedly search the library.
364
+
365
+ This is real FFI. A wrong C signature can crash the SRSH process, because C does not care about your feelings. See `docs/SECURITY.md` before feeding native pointers to random libraries.
366
+
367
+ ## Errors and strict scripts
368
+
369
+ ```rsh
370
+ try
371
+ cfg := json(readfile("config.json"))
372
+ catch err
373
+ = "config failed: #{err.message}"
374
+ cfg := %[]
375
+ finally
376
+ audit("config attempted")
377
+ end
378
+ ```
189
379
 
190
- Edit `~/.cshrc` (or `~/.tcshrc`) and add:
380
+ For value pipelines:
191
381
 
192
- ```csh
193
- set path = ( $HOME/RSH $path )
382
+ ```rsh
383
+ result := attempt(:: => risky())
384
+ ? !result.ok => = result.error.message
194
385
  ```
195
386
 
196
- Reload it:
387
+ For shell-side stricter behavior:
197
388
 
198
- ```console
199
- source ~/.cshrc
389
+ ```rsh
390
+ option strict yes
391
+ option noclobber yes
200
392
  ```
201
393
 
202
- Now you should be able to run:
394
+ `strict` currently means `nounset + pipefail`; it does **not** try to clone all of Bash's `set -e` edge cases.
203
395
 
204
- ```console
205
- rsh
206
- # or rename / symlink it as srsh if you want:
207
- srsh
396
+ ## Metascripting
397
+
398
+ RSH code can be a value instead of a string you hope parses later:
399
+
400
+ ```rsh
401
+ code cleanup
402
+ @ glob("tmp/*.log") -> file
403
+ rm $file
404
+ .@
405
+ end
406
+
407
+ ? dry => = sourceof(cleanup)
408
+ ? !dry => run(cleanup)
208
409
  ```
209
410
 
210
- ---
411
+ The reflective toolbox includes `code()`, `run()`, `eval()`, `sourceof()`, `valid()`, `locals()`, `fns()`, `protos()` and `traits()`.
412
+
413
+ ## Ruby plugins
211
414
 
212
- ## Tips / Notes
415
+ Ruby is still part of the point. A Ruby plugin can register builtins, hooks and themes through the SRSH API. Plugins are trusted code and are permission-checked before auto-loading.
213
416
 
214
- * If the command **isn’t found** after editing PATH:
417
+ RSH plugins are supported too if you want to stay entirely in the language.
215
418
 
216
- * Check which shell you’re actually using:
419
+ ## Process identity
217
420
 
218
- ```console
219
- echo $SHELL
220
- ```
221
- * Make sure you edited the correct rc file for that shell.
222
- * Print your PATH to confirm:
421
+ SRSH sets `$SHELL`, argv0, and the Linux process name to `srsh`. That keeps process-oriented tools from calling your active shell `ruby` just because Ruby is the engine.
422
+
423
+ The executable behind the process is still Ruby. That is intentional, not something SRSH tries to disguise.
424
+
425
+ ## Repo layout
426
+
427
+ ```text
428
+ bin/srsh
429
+ lib/srsh/
430
+ app.rb
431
+ editor.rb
432
+ builtins.rb
433
+ history.rb
434
+ plugins.rb
435
+ process_identity.rb
436
+ state.rb
437
+ theme.rb
438
+ language/
439
+ shell/
440
+ ext/srsh_native/ optional accelerator
441
+ examples/
442
+ docs/
443
+ test/
444
+ ```
223
445
 
224
- ```console
225
- echo "$PATH"
226
- ```
227
- * If things feel off, run it directly from the repo with:
446
+ The code is split by job, not by architectural cosplay. If a file gets big because the job is big, it gets split when that actually makes it easier to work on.
228
447
 
229
- ```console
230
- ./rsh
231
- ```
448
+ ## Current status
232
449
 
233
- to see if the issue is PATH-related or shell-related.
450
+ The project is still unreleased. `1.0.0` means “the 1.0 tree,” not “independently audited and incapable of bugs.” A shell has too much surface area for that kind of claim.
234
451
 
235
- And as i say : if anything looks cursed, **consult me and/or open an issue** :D
452
+ Run the tests, beat on it, and report the ugly cases. Those are usually more useful than another feature bullet.