Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e55f053efb | ||
|
|
7ec89551cc | ||
|
|
2c6236135c | ||
|
|
47fe0fbc0e | ||
|
|
31439db2f8 | ||
|
|
64f3e2b320 | ||
|
|
c86c24ed9b | ||
|
|
3ca85c3bfb |
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "mattpocock-skills"]
|
||||||
|
path = mattpocock-skills
|
||||||
|
url = ssh://git@git.grosinger.net:22322/tgrosinger/mattpocock-skills.git
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/code-review
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/codebase-design
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/diagnosing-bugs
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/domain-modeling
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/grill-with-docs
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/productivity/grilling
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/productivity/handoff
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/implement
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/improve-codebase-architecture
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/prototype
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/research
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/resolving-merge-conflicts
|
||||||
|
Before Width: | Height: | Size: 420 B After Width: | Height: | Size: 420 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/tdd
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/productivity/teach
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/productivity/to-questionnaire
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/to-spec
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/to-tickets
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/productivity/wait-what
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/wayfinder
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/engineering/wizard
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mattpocock-skills/skills/productivity/writing-for-agents
|
||||||
Executable
+27
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Source: https://github.com/mattpocock/skills
|
||||||
|
|
||||||
|
INPUT=$(cat)
|
||||||
|
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')
|
||||||
|
|
||||||
|
DANGEROUS_PATTERNS=(
|
||||||
|
"git push"
|
||||||
|
"git reset --hard"
|
||||||
|
"git clean -fd"
|
||||||
|
"git clean -f"
|
||||||
|
"git branch -D"
|
||||||
|
"git checkout \."
|
||||||
|
"git restore \."
|
||||||
|
"push --force"
|
||||||
|
"reset --hard"
|
||||||
|
)
|
||||||
|
|
||||||
|
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
|
||||||
|
if echo "$COMMAND" | grep -qE "$pattern"; then
|
||||||
|
echo "BLOCKED: '$COMMAND' matches dangerous pattern '$pattern'. The user has prevented you from doing this." >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
||||||
Executable
+98
@@ -0,0 +1,98 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Blocks Bash commands that delete or destroy files.
|
||||||
|
# Companion to CLAUDE.md's "never delete files" rule.
|
||||||
|
|
||||||
|
block() {
|
||||||
|
printf 'BLOCKED: %s\n' "$1" >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
command -v jq >/dev/null 2>&1 || block "jq is required to validate Bash commands."
|
||||||
|
command -v realpath >/dev/null 2>&1 || block "realpath is required to validate deletion paths."
|
||||||
|
command -v stat >/dev/null 2>&1 || block "stat is required to validate the temporary directory."
|
||||||
|
|
||||||
|
INPUT=$(cat) || block "could not read hook input."
|
||||||
|
COMMAND=$(printf '%s' "$INPUT" | jq -er '.tool_input.command | select(type == "string")') ||
|
||||||
|
block "hook input does not contain a valid tool_input.command string."
|
||||||
|
|
||||||
|
# Do not trust TMPDIR: when it is unset, `$TMPDIR/path` expands to `/path`.
|
||||||
|
# This fixed per-user directory is the only place where deletion is permitted.
|
||||||
|
TMP_ROOT="/tmp/claude-$(id -u)"
|
||||||
|
|
||||||
|
# True only for one command in one of these exact forms:
|
||||||
|
# rm -- /tmp/claude-UID/path [...]
|
||||||
|
# rm -f|-r|-rf|-fr -- /tmp/claude-UID/path [...]
|
||||||
|
#
|
||||||
|
# Paths are deliberately restricted to an unquoted, expansion-free character
|
||||||
|
# set. The filesystem checks reject an escaping canonical path and any symlink
|
||||||
|
# that already exists in the path. This is defense against accidental deletion,
|
||||||
|
# not a race-free security boundary against a process changing paths concurrently.
|
||||||
|
confined_to_tmp() {
|
||||||
|
local cmd="$1" option_part path_part path canonical component partial mode uid
|
||||||
|
local -a paths components
|
||||||
|
|
||||||
|
uid=$(id -u) || return 1
|
||||||
|
[[ -d "$TMP_ROOT" && ! -L "$TMP_ROOT" ]] || return 1
|
||||||
|
[[ "$(realpath -e -- "$TMP_ROOT" 2>/dev/null)" == "$TMP_ROOT" ]] || return 1
|
||||||
|
[[ "$(stat -c '%u' -- "$TMP_ROOT" 2>/dev/null)" == "$uid" ]] || return 1
|
||||||
|
mode=$(stat -c '%a' -- "$TMP_ROOT" 2>/dev/null) || return 1
|
||||||
|
(( (8#$mode & 0022) == 0 )) || return 1
|
||||||
|
|
||||||
|
if [[ "$cmd" =~ ^rm\ (--|-f\ --|-r\ --|-rf\ --|-fr\ --)\ (/tmp/claude-[0-9]+/[A-Za-z0-9._/+,=:@%-]+(\ /tmp/claude-[0-9]+/[A-Za-z0-9._/+,=:@%-]+)*)$ ]]; then
|
||||||
|
option_part="${BASH_REMATCH[1]}"
|
||||||
|
path_part="${BASH_REMATCH[2]}"
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The regex excludes shell syntax and whitespace within paths, so this split
|
||||||
|
# does not attempt to interpret arbitrary Bash source.
|
||||||
|
read -r -a paths <<< "$path_part"
|
||||||
|
((${#paths[@]} > 0)) || return 1
|
||||||
|
|
||||||
|
for path in "${paths[@]}"; do
|
||||||
|
[[ "$path" == "$TMP_ROOT"/?* ]] || return 1
|
||||||
|
[[ "$path" != */./* && "$path" != */../* && "$path" != */. && "$path" != */.. ]] || return 1
|
||||||
|
|
||||||
|
canonical=$(realpath -m -- "$path" 2>/dev/null) || return 1
|
||||||
|
[[ "$canonical" == "$TMP_ROOT"/?* ]] || return 1
|
||||||
|
|
||||||
|
# realpath catches symlink escapes. Reject in-tree symlinks too, since rm
|
||||||
|
# must not traverse a link whose target happens to currently be in the tree.
|
||||||
|
partial=""
|
||||||
|
IFS='/' read -r -a components <<< "$path"
|
||||||
|
for component in "${components[@]}"; do
|
||||||
|
[[ -n "$component" ]] || continue
|
||||||
|
partial="$partial/$component"
|
||||||
|
[[ ! -L "$partial" ]] || return 1
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# Keep the variable used so shellcheck documents that only allowlisted option
|
||||||
|
# spellings can reach this point.
|
||||||
|
[[ -n "$option_part" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
confined_to_tmp "$COMMAND" && exit 0
|
||||||
|
|
||||||
|
# These patterns are a backstop for ordinary Bash spellings, not a parser.
|
||||||
|
# Include quotes and backslashes between letters to catch forms such as r""m
|
||||||
|
# and r\m that Bash resolves to rm.
|
||||||
|
DANGEROUS_PATTERNS=(
|
||||||
|
'\br["'"'"'\\]*m\b'
|
||||||
|
'\bu["'"'"'\\]*n["'"'"'\\]*l["'"'"'\\]*i["'"'"'\\]*n["'"'"'\\]*k\b'
|
||||||
|
'\br["'"'"'\\]*m["'"'"'\\]*d["'"'"'\\]*i["'"'"'\\]*r\b'
|
||||||
|
'\bshred\b'
|
||||||
|
'\btruncate\b'
|
||||||
|
'\bfind\b.*-delete\b'
|
||||||
|
'\btrash\b'
|
||||||
|
)
|
||||||
|
|
||||||
|
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
|
||||||
|
if printf '%s\n' "$COMMAND" | grep -qE "$pattern"; then
|
||||||
|
block "'$COMMAND' is a deletion command. Only literal 'rm [-f|-r|-rf|-fr] -- $TMP_ROOT/path' commands without variables, quotes, globs, shell operators, or symlinks are allowed."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -18,9 +18,6 @@
|
|||||||
"Bash(ssh *)",
|
"Bash(ssh *)",
|
||||||
"Bash(ssh)",
|
"Bash(ssh)",
|
||||||
"Bash(scp *)",
|
"Bash(scp *)",
|
||||||
"Bash(rm:*)",
|
|
||||||
"Bash(unlink:*)",
|
|
||||||
"Bash(rmdir:*)",
|
|
||||||
"Bash(shred:*)",
|
"Bash(shred:*)",
|
||||||
"Bash(truncate:*)",
|
"Bash(truncate:*)",
|
||||||
"Bash(trash:*)",
|
"Bash(trash:*)",
|
||||||
@@ -33,7 +30,7 @@
|
|||||||
],
|
],
|
||||||
"defaultMode": "auto"
|
"defaultMode": "auto"
|
||||||
},
|
},
|
||||||
"model": "opus[1m]",
|
"model": "claude-opus-4-8",
|
||||||
"disableClaudeAiConnectors": true,
|
"disableClaudeAiConnectors": true,
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"PostToolUse": [
|
"PostToolUse": [
|
||||||
@@ -146,7 +143,7 @@
|
|||||||
"Thinking"
|
"Thinking"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"effortLevel": "high",
|
"effortLevel": "xhigh",
|
||||||
"tui": "fullscreen",
|
"tui": "fullscreen",
|
||||||
"voice": {
|
"voice": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
|
|||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../.agents/skills
|
||||||
@@ -4,6 +4,8 @@ workspaces = true
|
|||||||
keymap_mode = "auto"
|
keymap_mode = "auto"
|
||||||
enter_accept = true
|
enter_accept = true
|
||||||
|
|
||||||
|
sync_address = "https://atuin.i.grosinger.net"
|
||||||
|
|
||||||
history_filter = [
|
history_filter = [
|
||||||
"^cd$",
|
"^cd$",
|
||||||
"^lg$",
|
"^lg$",
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
# Interactive sessions get exact versions from `mise activate` below.
|
# Interactive sessions get exact versions from `mise activate` below.
|
||||||
fish_add_path --global ~/.local/bin ~/.local/share/mise/shims ~/go/bin
|
fish_add_path --global ~/.local/bin ~/.local/share/mise/shims ~/go/bin
|
||||||
|
|
||||||
|
if test -d ~/code/yt-dlp
|
||||||
|
fish_add_path --global ~/code/yt-dlp
|
||||||
|
end
|
||||||
|
|
||||||
if status is-interactive
|
if status is-interactive
|
||||||
# Commands to run in interactive sessions can go here
|
# Commands to run in interactive sessions can go here
|
||||||
|
|
||||||
|
|||||||
@@ -21,3 +21,4 @@ pnpm = "latest"
|
|||||||
"github:Satty-org/Satty" = "0.20.1"
|
"github:Satty-org/Satty" = "0.20.1"
|
||||||
"github:F1bonacc1/process-compose" = "latest"
|
"github:F1bonacc1/process-compose" = "latest"
|
||||||
"npm:@earendil-works/pi-coding-agent" = "latest"
|
"npm:@earendil-works/pi-coding-agent" = "latest"
|
||||||
|
uv = "latest"
|
||||||
|
|||||||
@@ -90,9 +90,6 @@
|
|||||||
[status]
|
[status]
|
||||||
submoduleSummary = true
|
submoduleSummary = true
|
||||||
|
|
||||||
[url "ssh://git@gitlab.i.extrahop.com/"]
|
|
||||||
insteadOf = https://gitlab.i.extrahop.com/
|
|
||||||
|
|
||||||
[merge]
|
[merge]
|
||||||
conflictstyle = zdiff3
|
conflictstyle = zdiff3
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
#/bin/bash
|
|
||||||
|
|
||||||
podman run --rm -i \
|
|
||||||
-v ${HOME}/Music:/downloads:z \
|
|
||||||
--userns keep-id:uid=1000,gid=1000 \
|
|
||||||
--entrypoint spotdl \
|
|
||||||
yt-dlp:latest $@
|
|
||||||
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#/bin/bash
|
|
||||||
|
|
||||||
podman run --rm \
|
|
||||||
-v ${HOME}/Videos/youtube:/downloads:z \
|
|
||||||
--userns keep-id:uid=1000,gid=1000 \
|
|
||||||
yt-dlp:latest -S 'res:1080' --extractor-args "youtube:player-client=web_embedded" $@
|
|
||||||
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#/bin/bash
|
|
||||||
|
|
||||||
podman run --rm \
|
|
||||||
-v ${HOME}/Videos/youtube:/downloads:z \
|
|
||||||
--userns keep-id:uid=1000,gid=1000 \
|
|
||||||
yt-dlp:latest --embed-metadata -o "%(playlist)s/%(playlist_index)s - %(title)s.%(ext)s" -S 'res:1080' $@
|
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"lastChangelogVersion": "0.79.8",
|
"lastChangelogVersion": "0.83.0",
|
||||||
"theme": "catppuccin-latte",
|
"theme": "catppuccin-latte",
|
||||||
"defaultProvider": "openai-codex",
|
"defaultProvider": "openai-codex",
|
||||||
"defaultModel": "gpt-5.5",
|
"defaultModel": "gpt-5.6-luna",
|
||||||
"defaultThinkingLevel": "high",
|
"defaultThinkingLevel": "high",
|
||||||
"skills": [
|
"skills": [
|
||||||
"~/.claude/skills"
|
"~/.claude/skills"
|
||||||
|
|||||||
Submodule
+1
Submodule mattpocock-skills added at 0bec6ef0f5
Reference in New Issue
Block a user