@objctp/opencode-shell-routines 1.2.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.
- package/LICENSE +21 -0
- package/README.md +114 -0
- package/agents/shell-architect.md +88 -0
- package/agents/shell-expert.md +60 -0
- package/commands/shell-audit.md +47 -0
- package/commands/shell-batch-exec.md +48 -0
- package/commands/shell-new.md +57 -0
- package/commands/shell-routines-setup.md +66 -0
- package/commands/shell-test-run.md +46 -0
- package/opencode.json +19 -0
- package/package.json +34 -0
- package/plugins/shell-hooks.ts +150 -0
- package/scripts/lib-batch.sh +297 -0
- package/scripts/lib-common.sh +332 -0
- package/skills/shell-batch-operations/SKILL.md +97 -0
- package/skills/shell-batch-operations/assets/batch-template.sh +124 -0
- package/skills/shell-batch-operations/examples/data-pipeline.sh +157 -0
- package/skills/shell-batch-operations/examples/file-batch.sh +140 -0
- package/skills/shell-batch-operations/references/decision-tree.md +53 -0
- package/skills/shell-best-practices/SKILL.md +313 -0
- package/skills/shell-best-practices/assets/library.sh +142 -0
- package/skills/shell-best-practices/assets/minimal.sh +54 -0
- package/skills/shell-best-practices/assets/posix.sh +180 -0
- package/skills/shell-best-practices/assets/standard.sh +203 -0
- package/skills/shell-best-practices/references/patterns.md +386 -0
- package/skills/shell-best-practices/references/security.md +195 -0
- package/skills/shell-debugging/SKILL.md +115 -0
- package/skills/shell-debugging/examples/debug-session.md +165 -0
- package/skills/shell-debugging/references/debugging-guide.md +336 -0
- package/skills/shell-profiling/SKILL.md +154 -0
- package/skills/shell-profiling/examples/profile-session.md +225 -0
- package/skills/shell-profiling/references/optimisation-patterns.md +373 -0
- package/skills/shell-profiling/references/profiling-tools.md +318 -0
- package/skills/shell-profiling/scripts/bench.sh +82 -0
- package/skills/shell-profiling/scripts/trace-aggregate.sh +34 -0
- package/skills/shell-review/SKILL.md +61 -0
- package/skills/shell-review/examples/sample-review.md +42 -0
- package/skills/shell-review/references/guidelines.md +48 -0
- package/skills/shell-review/references/review-template.md +56 -0
- package/skills/shell-security/SKILL.md +128 -0
- package/skills/shell-security/examples/dangerous-command-review.md +231 -0
- package/skills/shell-security/examples/secure-script-example.sh +317 -0
- package/skills/shell-security/references/dangerous-commands.md +561 -0
- package/skills/shell-security/references/security-patterns.md +30 -0
- package/skills/shell-security/references/sensitive-files.md +525 -0
- package/skills/shell-security/scripts/security-audit.sh +208 -0
- package/skills/shell-test/SKILL.md +237 -0
- package/skills/shell-test/examples/test-example.md +74 -0
- package/skills/shell-test/references/advanced-patterns.md +52 -0
- package/skills/shell-test/references/assertions.md +184 -0
- package/skills/shell-test/references/test-template.md +60 -0
- package/skills/shell-test/scripts/public-coverage.sh +93 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# Profiling Tools Reference
|
|
2
|
+
|
|
3
|
+
## Built-in Timing
|
|
4
|
+
|
|
5
|
+
### `time` (bash keyword)
|
|
6
|
+
|
|
7
|
+
Measures the elapsed, user, and system time for a pipeline or command.
|
|
8
|
+
|
|
9
|
+
**Syntax:**
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
time bash script.sh
|
|
13
|
+
time ( ./slow_section; ./another_section )
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Output fields:**
|
|
17
|
+
|
|
18
|
+
| Field | Meaning |
|
|
19
|
+
| ------- | ---------------------------------------- |
|
|
20
|
+
| real | Wall-clock elapsed time |
|
|
21
|
+
| user | CPU time spent in user mode |
|
|
22
|
+
| sys | CPU time spent in kernel mode |
|
|
23
|
+
|
|
24
|
+
**Caveats:**
|
|
25
|
+
|
|
26
|
+
- `time` is a bash reserved word, not an external command -- it works with pipelines and compound commands
|
|
27
|
+
- Output goes to stderr by default; redirect with `{ time cmd; } 2>timing.log`
|
|
28
|
+
- The output format varies between bash's built-in `time` and `/usr/bin/time`
|
|
29
|
+
|
|
30
|
+
### `/usr/bin/time`
|
|
31
|
+
|
|
32
|
+
External command providing detailed resource reporting beyond the bash built-in.
|
|
33
|
+
|
|
34
|
+
**Syntax:**
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Verbose output -- page faults, context switches, peak memory
|
|
38
|
+
/usr/bin/time -v bash script.sh
|
|
39
|
+
|
|
40
|
+
# Custom format
|
|
41
|
+
/usr/bin/time -f "Elapsed: %e s\nCPU: %P\nMax RSS: %M kB" bash script.sh
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Useful format specifiers:**
|
|
45
|
+
|
|
46
|
+
| Specifier | Meaning |
|
|
47
|
+
| --------- | -------------------------------- |
|
|
48
|
+
| `%e` | Elapsed real time (seconds) |
|
|
49
|
+
| `%U` | User mode CPU time (seconds) |
|
|
50
|
+
| `%S` | Kernel mode CPU time (seconds) |
|
|
51
|
+
| `%P` | CPU percentage |
|
|
52
|
+
| `%M` | Maximum resident set size (kB) |
|
|
53
|
+
| `%W` | Number of times swapped out |
|
|
54
|
+
| `%c` | Voluntary context switches |
|
|
55
|
+
| `%w` | Involuntary context switches |
|
|
56
|
+
|
|
57
|
+
**Platform:** Linux, macOS (GNU or BSD variant; format specifiers differ between them).
|
|
58
|
+
|
|
59
|
+
**GNU vs BSD differences:** On macOS, the BSD variant of `/usr/bin/time` uses `-l` for verbose output (equivalent to `-v` on GNU) and supports fewer format specifiers. For consistent cross-platform behaviour, install the GNU version via `brew install coreutils` and use `gtime`.
|
|
60
|
+
|
|
61
|
+
### `times` builtin
|
|
62
|
+
|
|
63
|
+
Reports cumulative user and system times for the current shell and its children.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# After running some commands
|
|
67
|
+
times
|
|
68
|
+
# Output:
|
|
69
|
+
# 0m0.012s 0m0.008s <- shell itself
|
|
70
|
+
# 0m0.345s 0m0.120s <- children
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Useful for measuring accumulated time across a script's lifetime. Less granular than `time`.
|
|
74
|
+
|
|
75
|
+
### `$SECONDS`
|
|
76
|
+
|
|
77
|
+
Integer variable that increments every second since shell start or since last assignment.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
SECONDS=0
|
|
81
|
+
run_expensive_operation
|
|
82
|
+
echo "Took $SECONDS seconds"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Precision:** Whole seconds only. Suitable for operations lasting more than a few seconds.
|
|
86
|
+
|
|
87
|
+
**Portability:** Bash-specific (not POSIX).
|
|
88
|
+
|
|
89
|
+
### `$EPOCHREALTIME`
|
|
90
|
+
|
|
91
|
+
Microsecond-precision timestamp (seconds.microseconds since epoch). Available in bash 5.0+.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
start=$EPOCHREALTIME
|
|
95
|
+
run_operation
|
|
96
|
+
end=$EPOCHREALTIME
|
|
97
|
+
# Compute elapsed microseconds
|
|
98
|
+
elapsed=$(( 10#${end%.*} * 1000000 + 10#${end#*.} - 10#${start%.*} * 1000000 - 10#${start#*.} ))
|
|
99
|
+
echo "Took ${elapsed} us ($(( elapsed / 1000 )) ms)"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Precision:** Microseconds. The best built-in option for sub-second measurement.
|
|
103
|
+
|
|
104
|
+
**Portability:** Bash 5.0+. Not available in bash 4.x. Use `date +%s.%N` as a fallback (requires spawning an external command).
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Xtrace Profiling
|
|
109
|
+
|
|
110
|
+
### PS4 with EPOCHREALTIME
|
|
111
|
+
|
|
112
|
+
Configure PS4 to include a timestamp in every xtrace line:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
PS4='+ ${EPOCHREALTIME} ${BASH_SOURCE}:${LINENO} ${FUNCNAME[0]:-main} '
|
|
116
|
+
set -x
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Output format:**
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
+ 1709654321.123456 script.sh:42 process_line + awk '{print $3}'
|
|
123
|
+
+ 1709654321.234567 script.sh:43 process_line + grep -c error
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Each line begins with the timestamp, source file, line number, and function name.
|
|
127
|
+
|
|
128
|
+
**Bash 4.x fallback** (no EPOCHREALTIME):
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
PS4='+ $(date +%s.%N) ${BASH_SOURCE}:${LINENO} ${FUNCNAME[0]:-main} '
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Warning: this spawns a `date` process per trace line, adding measurable overhead. Use only for coarse analysis.
|
|
135
|
+
|
|
136
|
+
### BASH_XTRACEFD
|
|
137
|
+
|
|
138
|
+
Redirect xtrace output to a separate file descriptor so it does not mix with stderr:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Open a file for trace output
|
|
142
|
+
exec 42>/tmp/script.trace.log
|
|
143
|
+
|
|
144
|
+
# Tell bash to write xtrace to fd 42
|
|
145
|
+
BASH_XTRACEFD=42
|
|
146
|
+
|
|
147
|
+
# Enable tracing (PS4 set above)
|
|
148
|
+
set -x
|
|
149
|
+
|
|
150
|
+
# ... script runs ...
|
|
151
|
+
|
|
152
|
+
# Disable and close
|
|
153
|
+
set +x
|
|
154
|
+
exec 42>&-
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Why this matters:** Without BASH_XTRACEFD, xtrace output goes to stderr alongside actual error messages, making both harder to read. A dedicated file keeps the trace clean for post-processing.
|
|
158
|
+
|
|
159
|
+
### Post-processing Trace Output
|
|
160
|
+
|
|
161
|
+
Compute per-line elapsed time from the EPOCHREALTIME stamps:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# Extract timestamp, file:line, function -- compute deltas
|
|
165
|
+
awk '
|
|
166
|
+
BEGIN { prev = 0 }
|
|
167
|
+
/^+/ {
|
|
168
|
+
ts = $2
|
|
169
|
+
delta = ts - prev
|
|
170
|
+
if (prev > 0) {
|
|
171
|
+
printf "%.6f s %s %s\n", delta, $3, $4
|
|
172
|
+
}
|
|
173
|
+
prev = ts
|
|
174
|
+
}
|
|
175
|
+
' /tmp/script.trace.log | sort -rn | head -20
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
This produces a ranked list of the slowest lines, e.g.:
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
0.451234 s script.sh:87 process_line
|
|
182
|
+
0.210876 s script.sh:45 extract_fields
|
|
183
|
+
0.002345 s script.sh:12 main
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Syscall and External Analysis
|
|
189
|
+
|
|
190
|
+
### `strace` (Linux)
|
|
191
|
+
|
|
192
|
+
Trace system calls made by a script and its child processes.
|
|
193
|
+
|
|
194
|
+
**Summary mode** -- aggregate counts and timing per syscall:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
strace -c -f bash script.sh
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Output shows calls, errors, and total time per syscall. Useful for spotting excessive `fork`, `execve`, `read`, `write`, or `stat` calls.
|
|
201
|
+
|
|
202
|
+
**Per-call timing:**
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
strace -T -f -e trace=read,write,open,close bash script.sh 2>&1 | grep '<'
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Each syscall line shows its duration in angle brackets: `<0.000012>`.
|
|
209
|
+
|
|
210
|
+
**Filter to specific syscalls:**
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
strace -c -e trace=file bash script.sh # file-related only
|
|
214
|
+
strace -c -e trace=process bash script.sh # fork/exec/clone only
|
|
215
|
+
strace -c -e trace=network bash script.sh # socket/connect only
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Platform:** Linux only.
|
|
219
|
+
|
|
220
|
+
### `ltrace`
|
|
221
|
+
|
|
222
|
+
Trace library calls (malloc, strcmp, fopen, etc.) in addition to syscalls:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
ltrace -c bash script.sh
|
|
226
|
+
ltrace -e malloc+free bash script.sh
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Useful when performance problems stem from library-level operations rather than raw syscalls.
|
|
230
|
+
|
|
231
|
+
**Platform:** Linux only.
|
|
232
|
+
|
|
233
|
+
### `perf` (Linux)
|
|
234
|
+
|
|
235
|
+
Hardware performance counters for CPU-bound analysis:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
perf stat bash script.sh
|
|
239
|
+
perf record -g bash script.sh
|
|
240
|
+
perf report
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Provides cache miss rates, branch mispredictions, and instruction-level profiling. Overkill for most shell scripts. Relevant when the shell invokes compiled programs doing heavy computation (e.g., image processing, numerical analysis, compression) and the bottleneck is suspected to be inside that compiled program rather than in the shell logic itself. For pure bash scripts, `strace -c` or xtrace profiling will identify bottlenecks more directly.
|
|
244
|
+
|
|
245
|
+
**Platform:** Linux only.
|
|
246
|
+
|
|
247
|
+
### macOS Alternatives
|
|
248
|
+
|
|
249
|
+
macOS does not provide `strace`. Use these alternatives:
|
|
250
|
+
|
|
251
|
+
| Tool | Purpose | Availability |
|
|
252
|
+
| ------------ | ------------------------------------------ | ------------------------- |
|
|
253
|
+
| `dtruss` | Syscall tracing (requires sudo) | macOS built-in |
|
|
254
|
+
| `sample` | Sampling profiler for a running process | Xcode command-line tools |
|
|
255
|
+
| `Instruments`| GUI profiler (Time, System Trace templates)| Xcode |
|
|
256
|
+
| `dtrace` | D scripting language for dynamic tracing | macOS (SIP may restrict) |
|
|
257
|
+
|
|
258
|
+
**dtruss example:**
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
sudo dtruss -c bash script.sh
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Benchmarking
|
|
267
|
+
|
|
268
|
+
### hyperfine
|
|
269
|
+
|
|
270
|
+
Statistical benchmarking tool that handles warm-up runs, outlier detection, and formatting.
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
# Compare two versions
|
|
274
|
+
hyperfine \
|
|
275
|
+
--warmup 3 \
|
|
276
|
+
--runs 10 \
|
|
277
|
+
'bash script_before.sh' \
|
|
278
|
+
'bash script_after.sh'
|
|
279
|
+
|
|
280
|
+
# Export results
|
|
281
|
+
hyperfine --export-markdown results.md 'bash script.sh'
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Key features:**
|
|
285
|
+
|
|
286
|
+
- Automatic warm-up runs (discard initial slow runs caused by caching)
|
|
287
|
+
- Statistical analysis (mean, median, standard deviation)
|
|
288
|
+
- Outlier detection
|
|
289
|
+
- Markdown/JSON/CSV export
|
|
290
|
+
|
|
291
|
+
**Install:**
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
# macOS
|
|
295
|
+
brew install hyperfine
|
|
296
|
+
|
|
297
|
+
# Linux
|
|
298
|
+
cargo install hyperfine
|
|
299
|
+
# or: apt install hyperfine (on Debian/Ubuntu)
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**Platform:** Cross-platform (Rust binary).
|
|
303
|
+
|
|
304
|
+
### Manual Iteration-based Benchmarking
|
|
305
|
+
|
|
306
|
+
When hyperfine is unavailable, use `scripts/bench.sh` — it handles warm-up runs and reports median, min, max, and spread:
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
scripts/bench.sh -r 10 -w 1 -- bash script.sh
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Statistical Considerations
|
|
313
|
+
|
|
314
|
+
- **Discard the first run.** Filesystem caches and interpreter loading inflate the initial measurement.
|
|
315
|
+
- **Prefer median over mean.** Outliers (background processes, I/O spikes) distort the mean; the median is more robust.
|
|
316
|
+
- **Run at least 5 iterations.** Fewer than 5 makes statistical analysis unreliable. 10--20 is ideal.
|
|
317
|
+
- **Control the environment.** Close other applications, disable cron jobs, and avoid running benchmarks on shared hardware.
|
|
318
|
+
- **Report the spread.** Alongside the median, report min/max or standard deviation so readers can assess consistency.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# bench.sh -- Manual benchmark harness for shell scripts
|
|
5
|
+
# Usage: bench.sh [-r runs] [-w warmup] [--] <command...>
|
|
6
|
+
# -r runs Number of measured runs (default: 10)
|
|
7
|
+
# -w warmup Number of warm-up runs to discard (default: 1)
|
|
8
|
+
# -- End option parsing; all following args form the command
|
|
9
|
+
#
|
|
10
|
+
# Example:
|
|
11
|
+
# bench.sh -r 15 -w 2 -- bash script.sh arg1 arg2
|
|
12
|
+
# bench.sh -- ./my-script
|
|
13
|
+
|
|
14
|
+
runs=10
|
|
15
|
+
warmup=1
|
|
16
|
+
cmd=()
|
|
17
|
+
|
|
18
|
+
while [[ $# -gt 0 ]]; do
|
|
19
|
+
case "$1" in
|
|
20
|
+
-r)
|
|
21
|
+
runs="${2:?Missing value for -r}"
|
|
22
|
+
shift 2
|
|
23
|
+
;;
|
|
24
|
+
-w)
|
|
25
|
+
warmup="${2:?Missing value for -w}"
|
|
26
|
+
shift 2
|
|
27
|
+
;;
|
|
28
|
+
--)
|
|
29
|
+
shift
|
|
30
|
+
cmd=("$@")
|
|
31
|
+
break
|
|
32
|
+
;;
|
|
33
|
+
*)
|
|
34
|
+
cmd=("$@")
|
|
35
|
+
break
|
|
36
|
+
;;
|
|
37
|
+
esac
|
|
38
|
+
done
|
|
39
|
+
|
|
40
|
+
if [[ ${#cmd[@]} -eq 0 ]]; then
|
|
41
|
+
echo "Usage: $0 [-r runs] [-w warmup] [--] <command...>" >&2
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# EPOCHREALTIME (Bash 5.0+) is required for microsecond timing
|
|
46
|
+
if [[ -z "${EPOCHREALTIME:-}" ]]; then
|
|
47
|
+
echo "Error: $0 requires Bash 5.0+ (EPOCHREALTIME) for sub-second timing. Current: $(bash --version | head -1)" >&2
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Warm-up runs (discarded)
|
|
52
|
+
for ((i = 1; i <= warmup; i++)); do
|
|
53
|
+
"${cmd[@]}" >/dev/null 2>&1 || true
|
|
54
|
+
done
|
|
55
|
+
|
|
56
|
+
# Measured runs
|
|
57
|
+
results=()
|
|
58
|
+
for ((i = 1; i <= runs; i++)); do
|
|
59
|
+
start=$EPOCHREALTIME
|
|
60
|
+
"${cmd[@]}" >/dev/null 2>&1 || true
|
|
61
|
+
end=$EPOCHREALTIME
|
|
62
|
+
elapsed=$((10#${end%.*} * 1000000 + 10#${end#*.} - 10#${start%.*} * 1000000 - 10#${start#*.}))
|
|
63
|
+
results+=("$elapsed")
|
|
64
|
+
done
|
|
65
|
+
|
|
66
|
+
# Compute statistics
|
|
67
|
+
mapfile -t sorted < <(printf '%s\n' "${results[@]}" | sort -n)
|
|
68
|
+
|
|
69
|
+
min=${sorted[0]}
|
|
70
|
+
max=${sorted[-1]}
|
|
71
|
+
mid=$((runs / 2))
|
|
72
|
+
median=${sorted[$mid]}
|
|
73
|
+
|
|
74
|
+
if [[ $((runs % 2)) -eq 0 ]]; then
|
|
75
|
+
median=$(((median + sorted[$((mid - 1))]) / 2))
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
echo "Runs: $runs (+ $warmup warm-up)"
|
|
79
|
+
echo "Median: $((median / 1000)) ms"
|
|
80
|
+
echo "Min: $((min / 1000)) ms"
|
|
81
|
+
echo "Max: $((max / 1000)) ms"
|
|
82
|
+
echo "Spread: $(((max - min) / 1000)) ms"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# trace-aggregate.sh -- Aggregate xtrace timestamps into cumulative per-line timings
|
|
5
|
+
# Usage: trace-aggregate.sh <trace-file> [top-n]
|
|
6
|
+
# Produces a ranked list of source locations by cumulative execution time.
|
|
7
|
+
#
|
|
8
|
+
# Expects trace files generated with:
|
|
9
|
+
# PS4='+ ${EPOCHREALTIME} ${BASH_SOURCE}:${LINENO} ${FUNCNAME[0]:-main} '
|
|
10
|
+
# BASH_XTRACEFD=N (redirected to the trace file)
|
|
11
|
+
|
|
12
|
+
trace_file="${1:?Usage: $0 <trace-file> [top-n]}"
|
|
13
|
+
top_n="${2:-20}"
|
|
14
|
+
|
|
15
|
+
if [[ ! -f "$trace_file" ]]; then
|
|
16
|
+
echo "Error: trace file not found: $trace_file" >&2
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
awk '
|
|
21
|
+
/^+/ {
|
|
22
|
+
ts = $2
|
|
23
|
+
if (prev > 0) {
|
|
24
|
+
delta = ts - prev
|
|
25
|
+
total[$3] += delta
|
|
26
|
+
count[$3]++
|
|
27
|
+
}
|
|
28
|
+
prev = ts
|
|
29
|
+
}
|
|
30
|
+
END {
|
|
31
|
+
for (loc in total)
|
|
32
|
+
printf "%.4f s %s (called %d times)\n", total[loc], loc, count[loc]
|
|
33
|
+
}
|
|
34
|
+
' "$trace_file" | sort -rn | head -n "$top_n"
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: shell-review
|
|
3
|
+
description: Review a working bash script for quality, correctness, standards compliance, and security, producing a structured report with severity-ranked findings and concrete fixes. Use when assessing a finished script ("review my script", "pre-merge review", "is this good bash?"). For runtime failures use shell-debugging; for deep security auditing use shell-security.
|
|
4
|
+
allowed-tools: Read, Grep, Glob, Bash
|
|
5
|
+
argument-hint: [file-or-diff]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Shell Review Skill
|
|
9
|
+
|
|
10
|
+
Produces a structured, actionable review of bash/shell scripts.
|
|
11
|
+
|
|
12
|
+
**Scope**: Quality assessment of working scripts — correctness, standards, security, and style.
|
|
13
|
+
|
|
14
|
+
## Target
|
|
15
|
+
|
|
16
|
+
**Target:** `$ARGUMENTS`
|
|
17
|
+
|
|
18
|
+
- If `$ARGUMENTS` is a file path, read that file
|
|
19
|
+
- If `$ARGUMENTS` is a unified diff, extract changed lines and review them in context of the surrounding code
|
|
20
|
+
- If `$ARGUMENTS` is not provided, ask for clarification
|
|
21
|
+
|
|
22
|
+
## Process
|
|
23
|
+
|
|
24
|
+
1. **Read the code** — understand the script's purpose before raising any issues
|
|
25
|
+
2. **Run diagnostics** — ShellCheck and `bash -n` run automatically via hooks; interpret their output, don't relay it verbatim
|
|
26
|
+
3. **Categorise findings** — critical (must fix), moderate (should fix), minor (nice to have); do not pad minor categories
|
|
27
|
+
4. **Be specific** — every issue needs a file, line, and concrete suggested fix
|
|
28
|
+
5. **Acknowledge strengths** — note what is done well; a review with no positives is usually incomplete
|
|
29
|
+
|
|
30
|
+
**Done when** every finding has a file, line, and concrete fix; each passes the *when-not-to-raise* filter in `guidelines.md`; strengths are noted; severity follows the definitions in `review-template.md`; and an Overall Assessment is given.
|
|
31
|
+
|
|
32
|
+
## Output
|
|
33
|
+
|
|
34
|
+
Use the template in `references/review-template.md` for the exact output format. Key sections:
|
|
35
|
+
|
|
36
|
+
- **Summary** — one sentence verdict
|
|
37
|
+
- **Strengths** — what's done well
|
|
38
|
+
- **Issues** — categorised as Critical / Moderate / Minor with file, line, issue, fix
|
|
39
|
+
- **Suggestions** — anything useful that doesn't fit the issues table
|
|
40
|
+
- **Security Notes** — only if genuine concerns exist
|
|
41
|
+
- **Overall Assessment** — Approve / Approve with minor changes / Request changes / Needs major rework
|
|
42
|
+
|
|
43
|
+
## Additional Resources
|
|
44
|
+
|
|
45
|
+
### Reference Files
|
|
46
|
+
|
|
47
|
+
- `references/review-template.md` — Exact output format with severity definitions
|
|
48
|
+
- `references/guidelines.md` — What to raise and what not to
|
|
49
|
+
|
|
50
|
+
Always read all references and examples before producing a review.
|
|
51
|
+
|
|
52
|
+
### Examples
|
|
53
|
+
|
|
54
|
+
- `examples/sample-review.md` — Complete review example demonstrating expected output
|
|
55
|
+
|
|
56
|
+
## Integration
|
|
57
|
+
|
|
58
|
+
- **`shell-security`** skill — Deep security auditing (destructive commands, credential exposure, system file risks)
|
|
59
|
+
- **`shell-expert`** agent — Technical depth for complex analysis
|
|
60
|
+
- **`shell-debugging`** skill — When the script has runtime failures, not quality issues
|
|
61
|
+
- **`/shell-audit`** command — Comprehensive quality audit
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Code Review: `auth.sh`
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
Adds a user authentication function with input validation and basic password handling; approve pending two moderate fixes.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## [+] Strengths
|
|
9
|
+
- `local` used correctly for all function-scoped variables
|
|
10
|
+
- Error messages consistently directed to stderr
|
|
11
|
+
- Exit codes follow conventions: 0 = success, 1 = error
|
|
12
|
+
|
|
13
|
+
## [!] Issues
|
|
14
|
+
|
|
15
|
+
### Moderate
|
|
16
|
+
|
|
17
|
+
| File | Line | Issue | Suggested Fix |
|
|
18
|
+
|------|------|-------|---------------|
|
|
19
|
+
| `auth.sh` | 24 | Username accepted without pattern validation — allows injection characters | Add `[[ "$username" =~ ^[a-zA-Z0-9_]+$ ]] \|\| return 1` |
|
|
20
|
+
| `auth.sh` | 31 | Missing shebang | Add `#!/usr/bin/env bash` as line 1 |
|
|
21
|
+
|
|
22
|
+
### Minor
|
|
23
|
+
|
|
24
|
+
| File | Line | Issue | Suggested Fix |
|
|
25
|
+
|------|------|-------|---------------|
|
|
26
|
+
| `auth.sh` | 18 | Single-letter variable `u` loses context at a glance | Rename to `username` |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## [*] Suggestions
|
|
31
|
+
- Add rate limiting or a lockout counter for repeated failed attempts
|
|
32
|
+
- Document the expected format and permissions of the password file in a comment
|
|
33
|
+
- Add an audit log entry on each authentication attempt (success and failure)
|
|
34
|
+
|
|
35
|
+
## [SEC] Security Notes
|
|
36
|
+
- `read -s` is used for password input — correct, prevents terminal echo
|
|
37
|
+
- Plain-text password comparison is high risk; consider delegating to PAM or hashing with `openssl dgst`
|
|
38
|
+
- Ensure the password file is owned by root with permissions 0600
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
**Overall Assessment:** `Request changes`
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Code Review Guidelines
|
|
2
|
+
|
|
3
|
+
## When Not to Raise an Issue
|
|
4
|
+
|
|
5
|
+
Do not raise issues for:
|
|
6
|
+
|
|
7
|
+
- **Style preferences** with no correctness or security implication
|
|
8
|
+
- **POSIX portability concerns** when the script explicitly targets bash only (shebang is `#!/usr/bin/env bash` or `#!/bin/bash`)
|
|
9
|
+
- **Performance micro-optimisations** in non-hot code paths
|
|
10
|
+
- **ShellCheck false positives** like `SC2148` (missing shebang) when a shebang is clearly present
|
|
11
|
+
|
|
12
|
+
## Review Quality Standards
|
|
13
|
+
|
|
14
|
+
### Be Specific
|
|
15
|
+
|
|
16
|
+
Every issue needs:
|
|
17
|
+
- **File** — which file has the issue
|
|
18
|
+
- **Line** — exact line number
|
|
19
|
+
- **Issue** — clear description of what's wrong
|
|
20
|
+
- **Suggested Fix** — concrete, actionable solution
|
|
21
|
+
|
|
22
|
+
Vague comments like "improve error handling" are not acceptable.
|
|
23
|
+
|
|
24
|
+
### Acknowledge Strengths
|
|
25
|
+
|
|
26
|
+
A review with no positives is usually incomplete. Note what is done well:
|
|
27
|
+
- Good error handling
|
|
28
|
+
- Clear variable naming
|
|
29
|
+
- Proper use of builtins
|
|
30
|
+
- Security-conscious design
|
|
31
|
+
- Good documentation
|
|
32
|
+
|
|
33
|
+
### Categorise Appropriately
|
|
34
|
+
|
|
35
|
+
Use the severity definitions in `review-template.md` (Critical / Moderate / Minor). Do not pad the minor category to appear thorough — an empty Minor section is fine.
|
|
36
|
+
|
|
37
|
+
## When POSIX Portability Must Be Raised
|
|
38
|
+
|
|
39
|
+
POSIX compliance is a **Critical** review dimension when the shebang is `#!/bin/sh`, `#!/usr/bin/env sh`, or `#!/usr/bin/dash`. On these scripts, bashisms will fail at runtime under dash (Ubuntu/Debian's `/bin/sh`).
|
|
40
|
+
|
|
41
|
+
Raise POSIX issues when:
|
|
42
|
+
- The shebang targets `sh` and the script uses bash-only features (`[[ ]]`, arrays, `${var,,}`, `<<<`, `source`, `function` keyword, etc.)
|
|
43
|
+
- `checkbashisms` reports findings on a `#!/bin/sh` script
|
|
44
|
+
|
|
45
|
+
Do not raise POSIX issues when:
|
|
46
|
+
- The shebang explicitly targets bash (`#!/usr/bin/env bash` or `#!/bin/bash`) — bashisms are expected and correct
|
|
47
|
+
|
|
48
|
+
Consult `shell-best-practices` for POSIX feature restrictions and shebang guidance.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Code Review Output Template
|
|
2
|
+
|
|
3
|
+
Use this format exactly. Omit any section that has no content rather than writing "None."
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Code Review: `[filename]`
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
[One sentence: what the script does and the overall verdict.]
|
|
11
|
+
|
|
12
|
+
## [+] Strengths
|
|
13
|
+
- [Specific thing done well, with line reference if helpful]
|
|
14
|
+
|
|
15
|
+
## [!] Issues
|
|
16
|
+
|
|
17
|
+
### Critical
|
|
18
|
+
*Issues that cause incorrect behaviour, security vulnerabilities, or data loss.*
|
|
19
|
+
|
|
20
|
+
| File | Line | Issue | Suggested Fix |
|
|
21
|
+
|------|------|-------|---------------|
|
|
22
|
+
| `file.sh` | 42 | Unquoted `$filename` in `rm` — word-splits on spaces | `rm -- "$filename"` |
|
|
23
|
+
|
|
24
|
+
### Moderate
|
|
25
|
+
*Issues that should be addressed before production use.*
|
|
26
|
+
|
|
27
|
+
| File | Line | Issue | Suggested Fix |
|
|
28
|
+
|------|------|-------|---------------|
|
|
29
|
+
| `file.sh` | 15 | No `trap` for temp file cleanup | Add `trap 'rm -f "$tmp"' EXIT` |
|
|
30
|
+
|
|
31
|
+
### Minor
|
|
32
|
+
*Low-priority improvements.*
|
|
33
|
+
|
|
34
|
+
| File | Line | Issue | Suggested Fix |
|
|
35
|
+
|------|------|-------|---------------|
|
|
36
|
+
| `file.sh` | 8 | `$i` — name gives no context | Rename to `$filename` or `$entry` |
|
|
37
|
+
|
|
38
|
+
## [*] Suggestions
|
|
39
|
+
[Anything useful that doesn't fit the issues table — architecture, testing gaps, missing documentation.]
|
|
40
|
+
|
|
41
|
+
## [SEC] Security Notes
|
|
42
|
+
[Only include if there are genuine security concerns. Do not write this section to appear thorough.]
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
**Overall Assessment:** `Approve` / `Approve with minor changes` / `Request changes` / `Needs major rework`
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
# Severity Definitions
|
|
51
|
+
|
|
52
|
+
| Level | Meaning |
|
|
53
|
+
|-------|---------|
|
|
54
|
+
| **Critical** | Data loss, security vulnerability, incorrect output, unhandled failure mode |
|
|
55
|
+
| **Moderate** | Likely to cause problems under real conditions; blocks production readiness |
|
|
56
|
+
| **Minor** | Code quality, readability, or convention — no functional impact |
|