- Replace 6 compound Likert questions with 12 atomic ones grouped by dimension (syntax, expressiveness, data/IO, errors, overall); drop free-form question. Responses now stored as ints, not strings. - Back-compat layer maps legacy keys to new dimensions so existing results still render. - Parallelize run-all with ThreadPoolExecutor (configurable workers) and add a thread-safe min-request-interval rate limiter to the Anthropic provider. - Add new tasks: path_normalizer, todo_manager, currency_converter, locale_weather_url, network_info_parser, url_normalizer.
98 lines
2.2 KiB
TOML
98 lines
2.2 KiB
TOML
name = "path_normalizer"
|
|
category = "environment"
|
|
mode = "convert"
|
|
description = """
|
|
Read file paths from stdin, one per line. Normalize each path:
|
|
1. Replace a leading "~" with the value of $HOME.
|
|
2. Remove trailing slashes (except for root "/").
|
|
3. Collapse consecutive slashes into one.
|
|
4. Resolve "." components (remove them).
|
|
5. Resolve ".." components (go up one directory level).
|
|
Output the cleaned path, one per line.
|
|
Skip empty lines.
|
|
"""
|
|
|
|
bash_source = '''
|
|
#!/bin/bash
|
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
[[ -z "$line" ]] && continue
|
|
|
|
# Expand tilde
|
|
path=$(echo "$line" | sed "s:^~:$HOME:")
|
|
|
|
# Collapse multiple slashes
|
|
path=$(echo "$path" | sed 's:/\\+:/:g')
|
|
|
|
# Remove trailing slash (but keep root)
|
|
path=$(echo "$path" | sed 's:/$::')
|
|
[[ -z "$path" ]] && path="/"
|
|
|
|
# Resolve . and .. components
|
|
IFS='/' read -ra parts <<< "$path"
|
|
result=()
|
|
absolute=""
|
|
if [[ "$path" == /* ]]; then
|
|
absolute="/"
|
|
fi
|
|
|
|
for part in "${parts[@]}"; do
|
|
if [[ "$part" == "." || "$part" == "" ]]; then
|
|
continue
|
|
elif [[ "$part" == ".." ]]; then
|
|
if [[ ${#result[@]} -gt 0 && "${result[-1]}" != ".." ]]; then
|
|
unset 'result[${#result[@]}-1]'
|
|
elif [[ -z "$absolute" ]]; then
|
|
result+=("..")
|
|
fi
|
|
else
|
|
result+=("$part")
|
|
fi
|
|
done
|
|
|
|
if [[ -n "$absolute" ]]; then
|
|
final="/"
|
|
IFS='/'; final+="${result[*]}"
|
|
else
|
|
IFS='/'; final="${result[*]}"
|
|
fi
|
|
[[ -z "$final" ]] && final="/"
|
|
|
|
echo "$final"
|
|
done
|
|
'''
|
|
|
|
[[test_cases]]
|
|
description = "Tilde expansion and trailing slashes"
|
|
stdin = """~/Documents/
|
|
~/projects/code
|
|
/var/log/"""
|
|
expected_stdout = """/Users/testuser/Documents
|
|
/Users/testuser/projects/code
|
|
/var/log"""
|
|
env = { "HOME" = "/Users/testuser" }
|
|
|
|
[[test_cases]]
|
|
description = "Resolving . and .. components"
|
|
stdin = """/usr/local/./bin
|
|
/home/user/../shared/docs
|
|
/a/b/c/../../d"""
|
|
expected_stdout = """/usr/local/bin
|
|
/home/shared/docs
|
|
/a/d"""
|
|
|
|
[[test_cases]]
|
|
description = "Collapsing multiple slashes"
|
|
stdin = """/usr//local///bin
|
|
/var/log//syslog"""
|
|
expected_stdout = """/usr/local/bin
|
|
/var/log/syslog"""
|
|
|
|
[[test_cases]]
|
|
description = "Root and relative paths"
|
|
stdin = """/
|
|
./config/settings
|
|
../parent/child"""
|
|
expected_stdout = """/
|
|
config/settings
|
|
../parent/child"""
|