safeword 0.12.2 → 0.13.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 (40) hide show
  1. package/dist/{check-3X75X2JL.js → check-X7NR4WAM.js} +5 -4
  2. package/dist/check-X7NR4WAM.js.map +1 -0
  3. package/dist/{chunk-O4LAXZK3.js → chunk-XLOXGDJG.js} +103 -41
  4. package/dist/chunk-XLOXGDJG.js.map +1 -0
  5. package/dist/cli.js +5 -5
  6. package/dist/{diff-6HFT7BLG.js → diff-3USPMFT2.js} +2 -2
  7. package/dist/{reset-XFXLQXOC.js → reset-CM3BNT5S.js} +2 -2
  8. package/dist/{setup-C6NF3YJ5.js → setup-4PQV6EV2.js} +4 -17
  9. package/dist/setup-4PQV6EV2.js.map +1 -0
  10. package/dist/{upgrade-C2I22FAB.js → upgrade-BIMRJENC.js} +12 -6
  11. package/dist/upgrade-BIMRJENC.js.map +1 -0
  12. package/package.json +2 -2
  13. package/templates/hooks/cursor/after-file-edit.ts +47 -0
  14. package/templates/hooks/cursor/stop.ts +73 -0
  15. package/templates/hooks/lib/lint.ts +49 -0
  16. package/templates/hooks/lib/quality.ts +30 -0
  17. package/templates/hooks/post-tool-lint.ts +33 -0
  18. package/templates/hooks/prompt-questions.ts +32 -0
  19. package/templates/hooks/prompt-timestamp.ts +30 -0
  20. package/templates/hooks/session-lint-check.ts +62 -0
  21. package/templates/hooks/session-verify-agents.ts +32 -0
  22. package/templates/hooks/session-version.ts +18 -0
  23. package/templates/hooks/stop-quality.ts +171 -0
  24. package/dist/check-3X75X2JL.js.map +0 -1
  25. package/dist/chunk-O4LAXZK3.js.map +0 -1
  26. package/dist/setup-C6NF3YJ5.js.map +0 -1
  27. package/dist/upgrade-C2I22FAB.js.map +0 -1
  28. package/templates/hooks/cursor/after-file-edit.sh +0 -58
  29. package/templates/hooks/cursor/stop.sh +0 -50
  30. package/templates/hooks/post-tool-lint.sh +0 -51
  31. package/templates/hooks/prompt-questions.sh +0 -27
  32. package/templates/hooks/prompt-timestamp.sh +0 -13
  33. package/templates/hooks/session-lint-check.sh +0 -42
  34. package/templates/hooks/session-verify-agents.sh +0 -31
  35. package/templates/hooks/session-version.sh +0 -17
  36. package/templates/hooks/stop-quality.sh +0 -91
  37. package/templates/lib/common.sh +0 -26
  38. package/templates/lib/jq-fallback.sh +0 -20
  39. /package/dist/{diff-6HFT7BLG.js.map → diff-3USPMFT2.js.map} +0 -0
  40. /package/dist/{reset-XFXLQXOC.js.map → reset-CM3BNT5S.js.map} +0 -0
@@ -1,27 +0,0 @@
1
- #!/bin/bash
2
- # Safeword: Question protocol guidance (UserPromptSubmit)
3
- # Reminds Claude to ask 1-5 clarifying questions for ambiguous tasks
4
-
5
- # Change to project directory if set
6
- [ -n "$CLAUDE_PROJECT_DIR" ] && cd "$CLAUDE_PROJECT_DIR" || true
7
-
8
- if [ ! -d ".safeword" ]; then
9
- exit 0
10
- fi
11
-
12
- # Read the user prompt from stdin
13
- input=$(cat)
14
-
15
- # Only trigger on substantial prompts (more than 20 chars)
16
- prompt_length=${#input}
17
- if [ "$prompt_length" -lt 20 ]; then
18
- exit 0
19
- fi
20
-
21
- # Output guidance
22
- cat << 'EOF'
23
- SAFEWORD Question Protocol: For ambiguous or complex requests, ask 1-5 clarifying questions before proceeding. Focus on:
24
- - Scope boundaries (what's included/excluded)
25
- - Technical constraints (frameworks, patterns, compatibility)
26
- - Success criteria (how will we know it's done)
27
- EOF
@@ -1,13 +0,0 @@
1
- #!/bin/bash
2
- # Safeword: Inject timestamp (UserPromptSubmit)
3
- # Outputs current timestamp for Claude's context awareness
4
- # Helps with accurate ticket timestamps and time-based reasoning
5
-
6
- # Natural language day/time in UTC
7
- natural=$(date -u +"%A, %B %d, %Y at %H:%M UTC")
8
- # ISO 8601 UTC
9
- iso=$(date -u +%Y-%m-%dT%H:%M:%SZ)
10
- # Local timezone
11
- local_time=$(date +"%H:%M %Z")
12
-
13
- echo "Current time: $natural ($iso) | Local: $local_time"
@@ -1,42 +0,0 @@
1
- #!/bin/bash
2
- # Safeword: Lint configuration sync check (SessionStart)
3
- # Warns if ESLint or Prettier configs are missing or out of sync
4
-
5
- # Change to project directory if set
6
- [ -n "$CLAUDE_PROJECT_DIR" ] && cd "$CLAUDE_PROJECT_DIR" || true
7
-
8
- if [ ! -d ".safeword" ]; then
9
- exit 0
10
- fi
11
-
12
- warnings=()
13
-
14
- # Check for ESLint config
15
- if [ ! -f "eslint.config.mjs" ] && [ ! -f "eslint.config.js" ] && [ ! -f ".eslintrc.json" ] && [ ! -f ".eslintrc.js" ]; then
16
- warnings+=("ESLint config not found - run 'npm run lint' may fail")
17
- fi
18
-
19
- # Check for Prettier config
20
- if [ ! -f ".prettierrc" ] && [ ! -f ".prettierrc.json" ] && [ ! -f "prettier.config.js" ]; then
21
- warnings+=("Prettier config not found - formatting may be inconsistent")
22
- fi
23
-
24
- # Check for required dependencies
25
- if [ -f "package.json" ]; then
26
- if ! grep -q '"eslint"' package.json 2>/dev/null; then
27
- warnings+=("ESLint not in package.json - run 'npm install -D eslint'")
28
- fi
29
- if ! grep -q '"prettier"' package.json 2>/dev/null; then
30
- warnings+=("Prettier not in package.json - run 'npm install -D prettier'")
31
- fi
32
- fi
33
-
34
- # Output warnings if any
35
- if [ ${#warnings[@]} -gt 0 ]; then
36
- echo "SAFEWORD Lint Check:"
37
- for warning in "${warnings[@]}"; do
38
- echo " ⚠️ $warning"
39
- done
40
- fi
41
-
42
- exit 0
@@ -1,31 +0,0 @@
1
- #!/bin/bash
2
- # Safeword: Verify AGENTS.md link (SessionStart)
3
- # Self-heals by restoring the link if removed
4
-
5
- # shellcheck disable=SC2016 # Backticks are literal markdown, not command substitution
6
- LINK='**⚠️ ALWAYS READ FIRST:** `.safeword/SAFEWORD.md`'
7
-
8
- # Change to project directory if set
9
- [ -n "$CLAUDE_PROJECT_DIR" ] && cd "$CLAUDE_PROJECT_DIR" || true
10
-
11
- if [ ! -d ".safeword" ]; then
12
- # Not a safeword project, skip silently
13
- exit 0
14
- fi
15
-
16
- if [ ! -f "AGENTS.md" ]; then
17
- # AGENTS.md doesn't exist, create it
18
- echo "$LINK" > AGENTS.md
19
- echo "SAFEWORD: Created AGENTS.md with safeword link"
20
- exit 0
21
- fi
22
-
23
- # Check if link is present
24
- if ! grep -q ".safeword/SAFEWORD.md" AGENTS.md; then
25
- # Link missing, prepend it
26
- CONTENT=$(cat AGENTS.md)
27
- echo -e "$LINK\n\n$CONTENT" > AGENTS.md
28
- echo "SAFEWORD: Restored AGENTS.md link (was removed)"
29
- fi
30
-
31
- exit 0
@@ -1,17 +0,0 @@
1
- #!/bin/bash
2
- # Safeword: Display version on session start (SessionStart)
3
- # Shows current safeword version and confirms hooks are active
4
-
5
- # Change to project directory if set
6
- [ -n "$CLAUDE_PROJECT_DIR" ] && cd "$CLAUDE_PROJECT_DIR" || true
7
-
8
- if [ ! -d ".safeword" ]; then
9
- exit 0
10
- fi
11
-
12
- VERSION="unknown"
13
- if [ -f ".safeword/version" ]; then
14
- VERSION=$(cat .safeword/version)
15
- fi
16
-
17
- echo "SAFE WORD Claude Config v${VERSION} installed - auto-linting and quality review active"
@@ -1,91 +0,0 @@
1
- #!/bin/bash
2
- # Auto Quality Review Stop Hook
3
- # Triggers quality review when changes are proposed or made
4
- # Only runs for projects with .safeword/ directory
5
- # Looks for {"proposedChanges": ..., "madeChanges": ...} JSON blob
6
-
7
- # Change to project directory if set
8
- [ -n "$CLAUDE_PROJECT_DIR" ] && cd "$CLAUDE_PROJECT_DIR" || true
9
-
10
- # Check for .safeword directory
11
- if [ ! -d ".safeword" ]; then
12
- exit 0
13
- fi
14
-
15
- # Read hook input from stdin
16
- input=$(cat)
17
-
18
- # Require jq for JSON parsing
19
- if ! command -v jq &> /dev/null; then
20
- exit 0
21
- fi
22
-
23
- # Get transcript path
24
- transcript_path=$(echo "$input" | jq -r '.transcript_path // empty' 2>/dev/null)
25
-
26
- if [ -z "$transcript_path" ] || [ ! -f "$transcript_path" ]; then
27
- exit 0
28
- fi
29
-
30
- # Extract last assistant message from transcript
31
- # Transcript is JSONL format - each line is a message
32
- last_assistant_msg=$(grep '"role":"assistant"' "$transcript_path" | tail -1)
33
-
34
- if [ -z "$last_assistant_msg" ]; then
35
- exit 0
36
- fi
37
-
38
- # Extract the text content from the message
39
- msg_text=$(echo "$last_assistant_msg" | jq -r '.message.content[]? | select(.type == "text") | .text' 2>/dev/null)
40
-
41
- if [ -z "$msg_text" ]; then
42
- exit 0
43
- fi
44
-
45
- # Extract JSON blob containing our required fields (order-independent)
46
- # Strategy: Use jq to find and validate the response summary object
47
- # Look for object with exactly our three boolean fields anywhere in the text
48
- json_blob=$(echo "$msg_text" | grep -oE '\{[^}]+\}' | while IFS= read -r candidate; do
49
- if echo "$candidate" | jq -e '
50
- type == "object" and
51
- (.proposedChanges | type) == "boolean" and
52
- (.madeChanges | type) == "boolean" and
53
- (.askedQuestion | type) == "boolean"
54
- ' >/dev/null 2>&1; then
55
- echo "$candidate"
56
- fi
57
- done | tail -1)
58
-
59
- if [ -z "$json_blob" ]; then
60
- # No valid JSON blob found - remind about required format
61
- echo "SAFEWORD: Response missing required JSON summary. Add to end of response:" >&2
62
- echo '{"proposedChanges": boolean, "madeChanges": boolean, "askedQuestion": boolean}' >&2
63
- exit 2
64
- fi
65
-
66
- # Parse the boolean values (already validated, safe to extract)
67
- proposed_changes=$(echo "$json_blob" | jq -r '.proposedChanges')
68
- made_changes=$(echo "$json_blob" | jq -r '.madeChanges')
69
- asked_question=$(echo "$json_blob" | jq -r '.askedQuestion')
70
-
71
- # If asked a question, don't trigger review (waiting for user input)
72
- if [ "$asked_question" = "true" ]; then
73
- exit 0
74
- fi
75
-
76
- # If either proposed or made changes, trigger quality review
77
- if [ "$proposed_changes" = "true" ] || [ "$made_changes" = "true" ]; then
78
- echo "SAFEWORD Quality Review:" >&2
79
- echo "" >&2
80
- echo "Double check and critique your work again just in case." >&2
81
- echo "Assume you've never seen it before." >&2
82
- echo "" >&2
83
- echo "- Is it correct?" >&2
84
- echo "- Is it elegant?" >&2
85
- echo "- Does it follow latest docs/best practices?" >&2
86
- echo "- Ask me any non-obvious questions." >&2
87
- echo "- Avoid bloat." >&2
88
- exit 2
89
- fi
90
-
91
- exit 0
@@ -1,26 +0,0 @@
1
- #!/bin/bash
2
- # Safeword common utilities for hook scripts
3
-
4
- # Output JSON response for Claude Code hooks
5
- # Usage: json_response '{"key": "value"}'
6
- json_response() {
7
- echo "$1"
8
- }
9
-
10
- # Check if running in a safeword project
11
- is_safeword_project() {
12
- [ -d ".safeword" ]
13
- }
14
-
15
- # Get project root (directory containing .safeword)
16
- get_project_root() {
17
- local dir="$PWD"
18
- while [ "$dir" != "/" ]; do
19
- if [ -d "$dir/.safeword" ]; then
20
- echo "$dir"
21
- return 0
22
- fi
23
- dir=$(dirname "$dir")
24
- done
25
- return 1
26
- }
@@ -1,20 +0,0 @@
1
- #!/bin/bash
2
- # Fallback JSON output when jq is not available
3
- # Uses printf for safe JSON string escaping
4
-
5
- # Escape a string for JSON output
6
- json_escape() {
7
- local str="$1"
8
- str="${str//\\/\\\\}"
9
- str="${str//\"/\\\"}"
10
- str="${str//$'\n'/\\n}"
11
- str="${str//$'\t'/\\t}"
12
- echo "$str"
13
- }
14
-
15
- # Output a simple JSON object with one key-value pair
16
- json_kv() {
17
- local key="$1"
18
- local value="$2"
19
- printf '{"proposedChanges": false, "madeChanges": false, "askedQuestion": false, "%s": "%s"}\n' "$key" "$(json_escape "$value")"
20
- }