safeword 0.2.3 → 0.2.4

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 (235) hide show
  1. package/.claude/commands/arch-review.md +32 -0
  2. package/.claude/commands/lint.md +6 -0
  3. package/.claude/commands/quality-review.md +13 -0
  4. package/.claude/commands/setup-linting.md +6 -0
  5. package/.claude/hooks/auto-lint.sh +6 -0
  6. package/.claude/hooks/auto-quality-review.sh +170 -0
  7. package/.claude/hooks/check-linting-sync.sh +17 -0
  8. package/.claude/hooks/inject-timestamp.sh +6 -0
  9. package/.claude/hooks/question-protocol.sh +12 -0
  10. package/.claude/hooks/run-linters.sh +8 -0
  11. package/.claude/hooks/run-quality-review.sh +76 -0
  12. package/.claude/hooks/version-check.sh +10 -0
  13. package/.claude/mcp/README.md +96 -0
  14. package/.claude/mcp/arcade.sample.json +9 -0
  15. package/.claude/mcp/context7.sample.json +7 -0
  16. package/.claude/mcp/playwright.sample.json +7 -0
  17. package/.claude/settings.json +62 -0
  18. package/.claude/skills/quality-reviewer/SKILL.md +190 -0
  19. package/.claude/skills/safeword-quality-reviewer/SKILL.md +13 -0
  20. package/.env.arcade.example +4 -0
  21. package/.env.example +11 -0
  22. package/.gitmodules +4 -0
  23. package/.safeword/SAFEWORD.md +33 -0
  24. package/.safeword/eslint/eslint-base.mjs +101 -0
  25. package/.safeword/guides/architecture-guide.md +404 -0
  26. package/.safeword/guides/code-philosophy.md +174 -0
  27. package/.safeword/guides/context-files-guide.md +405 -0
  28. package/.safeword/guides/data-architecture-guide.md +183 -0
  29. package/.safeword/guides/design-doc-guide.md +165 -0
  30. package/.safeword/guides/learning-extraction.md +515 -0
  31. package/.safeword/guides/llm-instruction-design.md +239 -0
  32. package/.safeword/guides/llm-prompting.md +95 -0
  33. package/.safeword/guides/tdd-best-practices.md +570 -0
  34. package/.safeword/guides/test-definitions-guide.md +243 -0
  35. package/.safeword/guides/testing-methodology.md +573 -0
  36. package/.safeword/guides/user-story-guide.md +237 -0
  37. package/.safeword/guides/zombie-process-cleanup.md +214 -0
  38. package/{templates → .safeword}/hooks/agents-md-check.sh +0 -0
  39. package/{templates → .safeword}/hooks/post-tool.sh +0 -0
  40. package/{templates → .safeword}/hooks/pre-commit.sh +0 -0
  41. package/.safeword/planning/002-user-story-quality-evaluation.md +1840 -0
  42. package/.safeword/planning/003-langsmith-eval-setup-prompt.md +363 -0
  43. package/.safeword/planning/004-llm-eval-test-cases.md +3226 -0
  44. package/.safeword/planning/005-architecture-enforcement-system.md +169 -0
  45. package/.safeword/planning/006-reactive-fix-prevention-research.md +135 -0
  46. package/.safeword/planning/011-cli-ux-vision.md +330 -0
  47. package/.safeword/planning/012-project-structure-cleanup.md +154 -0
  48. package/.safeword/planning/README.md +39 -0
  49. package/.safeword/planning/automation-plan-v2.md +1225 -0
  50. package/.safeword/planning/automation-plan-v3.md +1291 -0
  51. package/.safeword/planning/automation-plan.md +3058 -0
  52. package/.safeword/planning/design/005-cli-implementation.md +343 -0
  53. package/.safeword/planning/design/013-cli-self-contained-templates.md +596 -0
  54. package/.safeword/planning/design/013a-eslint-plugin-suite.md +256 -0
  55. package/.safeword/planning/design/013b-implementation-snippets.md +385 -0
  56. package/.safeword/planning/design/013c-config-isolation-strategy.md +242 -0
  57. package/.safeword/planning/design/code-philosophy-improvements.md +60 -0
  58. package/.safeword/planning/mcp-analysis.md +545 -0
  59. package/.safeword/planning/phase2-subagents-vs-skills-analysis.md +451 -0
  60. package/.safeword/planning/settings-improvements.md +970 -0
  61. package/.safeword/planning/test-definitions/005-cli-implementation.md +1301 -0
  62. package/.safeword/planning/test-definitions/cli-self-contained-templates.md +205 -0
  63. package/.safeword/planning/user-stories/001-guides-review-user-stories.md +1381 -0
  64. package/.safeword/planning/user-stories/003-reactive-fix-prevention.md +132 -0
  65. package/.safeword/planning/user-stories/004-technical-constraints.md +86 -0
  66. package/.safeword/planning/user-stories/005-cli-implementation.md +311 -0
  67. package/.safeword/planning/user-stories/cli-self-contained-templates.md +172 -0
  68. package/.safeword/planning/versioned-distribution.md +740 -0
  69. package/.safeword/prompts/arch-review.md +43 -0
  70. package/.safeword/prompts/quality-review.md +11 -0
  71. package/.safeword/scripts/arch-review.sh +235 -0
  72. package/.safeword/scripts/check-linting-sync.sh +58 -0
  73. package/.safeword/scripts/setup-linting.sh +559 -0
  74. package/.safeword/templates/architecture-template.md +136 -0
  75. package/.safeword/templates/ci/architecture-check.yml +79 -0
  76. package/.safeword/templates/design-doc-template.md +127 -0
  77. package/.safeword/templates/test-definitions-feature.md +100 -0
  78. package/.safeword/templates/ticket-template.md +74 -0
  79. package/.safeword/templates/user-stories-template.md +82 -0
  80. package/.safeword/tickets/001-guides-review-user-stories.md +83 -0
  81. package/.safeword/tickets/002-architecture-enforcement.md +211 -0
  82. package/.safeword/tickets/003-reactive-fix-prevention.md +57 -0
  83. package/.safeword/tickets/004-technical-constraints-in-user-stories.md +39 -0
  84. package/.safeword/tickets/005-cli-implementation.md +248 -0
  85. package/.safeword/tickets/006-flesh-out-skills.md +43 -0
  86. package/.safeword/tickets/007-flesh-out-questioning.md +44 -0
  87. package/.safeword/tickets/008-upgrade-questioning.md +58 -0
  88. package/.safeword/tickets/009-naming-conventions.md +41 -0
  89. package/.safeword/tickets/010-safeword-md-cleanup.md +34 -0
  90. package/.safeword/tickets/011-cursor-setup.md +86 -0
  91. package/.safeword/tickets/README.md +73 -0
  92. package/.safeword/version +1 -0
  93. package/AGENTS.md +59 -0
  94. package/CLAUDE.md +12 -0
  95. package/README.md +347 -0
  96. package/docs/001-cli-implementation-plan.md +856 -0
  97. package/docs/elite-dx-implementation-plan.md +1034 -0
  98. package/framework/README.md +131 -0
  99. package/framework/mcp/README.md +96 -0
  100. package/framework/mcp/arcade.sample.json +8 -0
  101. package/framework/mcp/context7.sample.json +6 -0
  102. package/framework/mcp/playwright.sample.json +6 -0
  103. package/framework/scripts/arch-review.sh +235 -0
  104. package/framework/scripts/check-linting-sync.sh +58 -0
  105. package/framework/scripts/load-env.sh +49 -0
  106. package/framework/scripts/setup-claude.sh +223 -0
  107. package/framework/scripts/setup-linting.sh +559 -0
  108. package/framework/scripts/setup-quality.sh +477 -0
  109. package/framework/scripts/setup-safeword.sh +550 -0
  110. package/framework/templates/ci/architecture-check.yml +78 -0
  111. package/learnings/ai-sdk-v5-breaking-changes.md +178 -0
  112. package/learnings/e2e-test-zombie-processes.md +231 -0
  113. package/learnings/milkdown-crepe-editor-property.md +96 -0
  114. package/learnings/prosemirror-fragment-traversal.md +119 -0
  115. package/package.json +19 -43
  116. package/packages/cli/AGENTS.md +1 -0
  117. package/packages/cli/ARCHITECTURE.md +279 -0
  118. package/packages/cli/package.json +51 -0
  119. package/packages/cli/src/cli.ts +63 -0
  120. package/packages/cli/src/commands/check.ts +166 -0
  121. package/packages/cli/src/commands/diff.ts +209 -0
  122. package/packages/cli/src/commands/reset.ts +190 -0
  123. package/packages/cli/src/commands/setup.ts +325 -0
  124. package/packages/cli/src/commands/upgrade.ts +163 -0
  125. package/packages/cli/src/index.ts +3 -0
  126. package/packages/cli/src/templates/config.ts +58 -0
  127. package/packages/cli/src/templates/content.ts +18 -0
  128. package/packages/cli/src/templates/index.ts +12 -0
  129. package/packages/cli/src/utils/agents-md.ts +66 -0
  130. package/packages/cli/src/utils/fs.ts +179 -0
  131. package/packages/cli/src/utils/git.ts +124 -0
  132. package/packages/cli/src/utils/hooks.ts +29 -0
  133. package/packages/cli/src/utils/output.ts +60 -0
  134. package/packages/cli/src/utils/project-detector.test.ts +185 -0
  135. package/packages/cli/src/utils/project-detector.ts +44 -0
  136. package/packages/cli/src/utils/version.ts +28 -0
  137. package/packages/cli/src/version.ts +6 -0
  138. package/packages/cli/templates/SAFEWORD.md +776 -0
  139. package/packages/cli/templates/doc-templates/architecture-template.md +136 -0
  140. package/packages/cli/templates/doc-templates/design-doc-template.md +134 -0
  141. package/packages/cli/templates/doc-templates/test-definitions-feature.md +131 -0
  142. package/packages/cli/templates/doc-templates/ticket-template.md +82 -0
  143. package/packages/cli/templates/doc-templates/user-stories-template.md +92 -0
  144. package/packages/cli/templates/guides/architecture-guide.md +423 -0
  145. package/packages/cli/templates/guides/code-philosophy.md +195 -0
  146. package/packages/cli/templates/guides/context-files-guide.md +457 -0
  147. package/packages/cli/templates/guides/data-architecture-guide.md +200 -0
  148. package/packages/cli/templates/guides/design-doc-guide.md +171 -0
  149. package/packages/cli/templates/guides/learning-extraction.md +552 -0
  150. package/packages/cli/templates/guides/llm-instruction-design.md +248 -0
  151. package/packages/cli/templates/guides/llm-prompting.md +102 -0
  152. package/packages/cli/templates/guides/tdd-best-practices.md +615 -0
  153. package/packages/cli/templates/guides/test-definitions-guide.md +334 -0
  154. package/packages/cli/templates/guides/testing-methodology.md +618 -0
  155. package/packages/cli/templates/guides/user-story-guide.md +256 -0
  156. package/packages/cli/templates/guides/zombie-process-cleanup.md +219 -0
  157. package/packages/cli/templates/hooks/agents-md-check.sh +27 -0
  158. package/packages/cli/templates/hooks/post-tool.sh +4 -0
  159. package/packages/cli/templates/hooks/pre-commit.sh +10 -0
  160. package/packages/cli/templates/prompts/arch-review.md +43 -0
  161. package/packages/cli/templates/prompts/quality-review.md +10 -0
  162. package/packages/cli/templates/skills/safeword-quality-reviewer/SKILL.md +207 -0
  163. package/packages/cli/tests/commands/check.test.ts +129 -0
  164. package/packages/cli/tests/commands/cli.test.ts +89 -0
  165. package/packages/cli/tests/commands/diff.test.ts +115 -0
  166. package/packages/cli/tests/commands/reset.test.ts +310 -0
  167. package/packages/cli/tests/commands/self-healing.test.ts +170 -0
  168. package/packages/cli/tests/commands/setup-blocking.test.ts +71 -0
  169. package/packages/cli/tests/commands/setup-core.test.ts +135 -0
  170. package/packages/cli/tests/commands/setup-git.test.ts +139 -0
  171. package/packages/cli/tests/commands/setup-hooks.test.ts +334 -0
  172. package/packages/cli/tests/commands/setup-linting.test.ts +189 -0
  173. package/packages/cli/tests/commands/setup-noninteractive.test.ts +80 -0
  174. package/packages/cli/tests/commands/setup-templates.test.ts +181 -0
  175. package/packages/cli/tests/commands/upgrade.test.ts +215 -0
  176. package/packages/cli/tests/helpers.ts +243 -0
  177. package/packages/cli/tests/npm-package.test.ts +83 -0
  178. package/packages/cli/tests/technical-constraints.test.ts +96 -0
  179. package/packages/cli/tsconfig.json +25 -0
  180. package/packages/cli/tsup.config.ts +11 -0
  181. package/packages/cli/vitest.config.ts +23 -0
  182. package/promptfoo.yaml +3270 -0
  183. package/dist/check-3NGQ4NR5.js +0 -129
  184. package/dist/check-3NGQ4NR5.js.map +0 -1
  185. package/dist/chunk-2XWIUEQK.js +0 -190
  186. package/dist/chunk-2XWIUEQK.js.map +0 -1
  187. package/dist/chunk-GZRQL3SX.js +0 -146
  188. package/dist/chunk-GZRQL3SX.js.map +0 -1
  189. package/dist/chunk-ORQHKDT2.js +0 -10
  190. package/dist/chunk-ORQHKDT2.js.map +0 -1
  191. package/dist/chunk-W66Z3C5H.js +0 -21
  192. package/dist/chunk-W66Z3C5H.js.map +0 -1
  193. package/dist/cli.d.ts +0 -1
  194. package/dist/cli.js +0 -34
  195. package/dist/cli.js.map +0 -1
  196. package/dist/diff-Y6QTAW4O.js +0 -166
  197. package/dist/diff-Y6QTAW4O.js.map +0 -1
  198. package/dist/index.d.ts +0 -11
  199. package/dist/index.js +0 -7
  200. package/dist/index.js.map +0 -1
  201. package/dist/reset-3ACTIYYE.js +0 -143
  202. package/dist/reset-3ACTIYYE.js.map +0 -1
  203. package/dist/setup-RR4M334C.js +0 -266
  204. package/dist/setup-RR4M334C.js.map +0 -1
  205. package/dist/upgrade-6AR3DHUV.js +0 -134
  206. package/dist/upgrade-6AR3DHUV.js.map +0 -1
  207. /package/{templates → framework}/SAFEWORD.md +0 -0
  208. /package/{templates → framework}/guides/architecture-guide.md +0 -0
  209. /package/{templates → framework}/guides/code-philosophy.md +0 -0
  210. /package/{templates → framework}/guides/context-files-guide.md +0 -0
  211. /package/{templates → framework}/guides/data-architecture-guide.md +0 -0
  212. /package/{templates → framework}/guides/design-doc-guide.md +0 -0
  213. /package/{templates → framework}/guides/learning-extraction.md +0 -0
  214. /package/{templates → framework}/guides/llm-instruction-design.md +0 -0
  215. /package/{templates → framework}/guides/llm-prompting.md +0 -0
  216. /package/{templates → framework}/guides/tdd-best-practices.md +0 -0
  217. /package/{templates → framework}/guides/test-definitions-guide.md +0 -0
  218. /package/{templates → framework}/guides/testing-methodology.md +0 -0
  219. /package/{templates → framework}/guides/user-story-guide.md +0 -0
  220. /package/{templates → framework}/guides/zombie-process-cleanup.md +0 -0
  221. /package/{templates → framework}/prompts/arch-review.md +0 -0
  222. /package/{templates → framework}/prompts/quality-review.md +0 -0
  223. /package/{templates/skills/safeword-quality-reviewer → framework/skills/quality-reviewer}/SKILL.md +0 -0
  224. /package/{templates/doc-templates → framework/templates}/architecture-template.md +0 -0
  225. /package/{templates/doc-templates → framework/templates}/design-doc-template.md +0 -0
  226. /package/{templates/doc-templates → framework/templates}/test-definitions-feature.md +0 -0
  227. /package/{templates/doc-templates → framework/templates}/ticket-template.md +0 -0
  228. /package/{templates/doc-templates → framework/templates}/user-stories-template.md +0 -0
  229. /package/{templates → packages/cli/templates}/commands/arch-review.md +0 -0
  230. /package/{templates → packages/cli/templates}/commands/lint.md +0 -0
  231. /package/{templates → packages/cli/templates}/commands/quality-review.md +0 -0
  232. /package/{templates → packages/cli/templates}/hooks/inject-timestamp.sh +0 -0
  233. /package/{templates → packages/cli/templates}/lib/common.sh +0 -0
  234. /package/{templates → packages/cli/templates}/lib/jq-fallback.sh +0 -0
  235. /package/{templates → packages/cli/templates}/markdownlint.jsonc +0 -0
@@ -0,0 +1,32 @@
1
+ Run an architecture review on staged or recent changes.
2
+
3
+ ## Steps:
4
+
5
+ 1. Get changed files:
6
+ ```bash
7
+ git diff --cached --name-only --diff-filter=ACM 2>/dev/null || git diff HEAD~1 --name-only
8
+ ```
9
+
10
+ 2. Read the project's `ARCHITECTURE.md` if it exists
11
+
12
+ 3. Read the changed files
13
+
14
+ 4. Review for these issues:
15
+ - **Misplaced logic** - Business rules in wrong layer?
16
+ - **God module** - Too many responsibilities (>10 dependents or >500 lines)?
17
+ - **Leaky abstraction** - Implementation details exposed to callers?
18
+ - **Tight coupling** - Changes would cascade unnecessarily?
19
+ - **Boundary violation** - Import from disallowed layer?
20
+
21
+ 5. Return verdict:
22
+ ```json
23
+ {
24
+ "issues": [],
25
+ "verdict": "clean | minor | refactor_needed"
26
+ }
27
+ ```
28
+
29
+ Verdicts:
30
+ - **clean**: No architectural issues
31
+ - **minor**: Small issues, doesn't block commit
32
+ - **refactor_needed**: Address before committing
@@ -0,0 +1,6 @@
1
+ Run linting on all project files.
2
+
3
+ Execute:
4
+ ```bash
5
+ bash .claude/hooks/run-linters.sh .
6
+ ```
@@ -0,0 +1,13 @@
1
+ Trigger a quality review to double-check your work.
2
+
3
+ Execute:
4
+ ```bash
5
+ bash .claude/hooks/run-quality-review.sh
6
+ ```
7
+
8
+ This will prompt you to:
9
+ - Verify correctness
10
+ - Check elegance
11
+ - Validate against latest docs and best practices
12
+ - Consider asking clarifying questions
13
+ - Think deeply and avoid bloat
@@ -0,0 +1,6 @@
1
+ Re-run SAFEWORD linting setup (auto-detects frameworks, regenerates base config).
2
+
3
+ Execute:
4
+ ```bash
5
+ bash .safeword/scripts/setup-linting.sh
6
+ ```
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+ # PostToolUse hook - auto-lint changed files
3
+ input=$(cat)
4
+ file_path=$(echo "$input" | jq -r '.tool_input.file_path // .tool_input.notebook_path // empty')
5
+ [ -n "$file_path" ] && [ -f "$file_path" ] && "$CLAUDE_PROJECT_DIR/.claude/hooks/run-linters.sh" "$file_path"
6
+ exit 0
@@ -0,0 +1,170 @@
1
+ #!/bin/bash
2
+ # Generated by setup-quality.sh v1.0.0
3
+ # To upgrade: Re-run setup script in this project
4
+ #
5
+ # Auto Quality Review Stop Hook
6
+ # Triggers quality review when changes are proposed or made
7
+ # Only runs for projects with SAFEWORD.md or CLAUDE.md (searches upward)
8
+ # Looks for {"proposedChanges": ..., "madeChanges": ...} JSON blob
9
+
10
+ # Debug logging (persistent across reboots, user-specific)
11
+ DEBUG_DIR="$HOME/.cache/claude-hooks"
12
+ mkdir -p "$DEBUG_DIR" 2>/dev/null || DEBUG_DIR="/tmp"
13
+ DEBUG_LOG="$DEBUG_DIR/auto-quality-review-debug.log"
14
+ echo "=== Hook triggered at $(date) ===" >> "$DEBUG_LOG"
15
+ echo "PWD: $PWD" >> "$DEBUG_LOG"
16
+
17
+ # Read hook input from stdin
18
+ input=$(cat)
19
+ echo "Input: $input" >> "$DEBUG_LOG"
20
+
21
+ # Check for project-level SAFEWORD.md or CLAUDE.md
22
+ # Search upward from current directory (supports monorepos)
23
+ current_dir="$PWD"
24
+ echo "Searching for SAFEWORD.md or CLAUDE.md..." >> "$DEBUG_LOG"
25
+ while true; do
26
+ if [ -f "$current_dir/SAFEWORD.md" ] || [ -f "$current_dir/CLAUDE.md" ]; then
27
+ echo "Found context file in: $current_dir" >> "$DEBUG_LOG"
28
+ break # Found context file
29
+ fi
30
+
31
+ # Reached root without finding context file
32
+ if [ "$current_dir" = "/" ]; then
33
+ echo "No SAFEWORD.md or CLAUDE.md found, exiting" >> "$DEBUG_LOG"
34
+ exit 0
35
+ fi
36
+
37
+ current_dir=$(dirname "$current_dir")
38
+ done
39
+
40
+ # Read project config (defaults: enabled=true, ask_questions=true)
41
+ config_file="$current_dir/.auto-quality-review.config"
42
+ enabled=true
43
+ ask_questions=true
44
+
45
+ if [ -f "$config_file" ]; then
46
+ while IFS='=' read -r key value; do
47
+ # Skip empty lines and comments
48
+ [[ -z "$key" || "$key" =~ ^# ]] && continue
49
+ # Trim whitespace
50
+ key=$(echo "$key" | xargs)
51
+ value=$(echo "$value" | xargs)
52
+
53
+ case "$key" in
54
+ enabled)
55
+ enabled="$value"
56
+ ;;
57
+ ask_questions)
58
+ ask_questions="$value"
59
+ ;;
60
+ esac
61
+ done < "$config_file"
62
+ fi
63
+
64
+ # Exit if disabled for this project
65
+ echo "Config: enabled=$enabled, ask_questions=$ask_questions" >> "$DEBUG_LOG"
66
+ if [ "$enabled" != "true" ]; then
67
+ echo "Hook disabled for this project, exiting" >> "$DEBUG_LOG"
68
+ exit 0
69
+ fi
70
+
71
+ # Get transcript path
72
+ if ! transcript_path=$(echo "$input" | jq -r '.transcript_path // empty' 2>/dev/null); then
73
+ echo "ERROR: jq failed to extract transcript_path from hook input." >&2
74
+ echo "ERROR: jq failed to parse input" >> "$DEBUG_LOG"
75
+ exit 2
76
+ fi
77
+
78
+ echo "Transcript path: $transcript_path" >> "$DEBUG_LOG"
79
+ if [ -z "$transcript_path" ] || [ ! -f "$transcript_path" ]; then
80
+ echo "No transcript or file doesn't exist, exiting" >> "$DEBUG_LOG"
81
+ exit 0
82
+ fi
83
+
84
+ # Extract last assistant message from transcript
85
+ # Transcript is JSONL format - each line is a message
86
+ last_assistant_msg=$(grep '"role":"assistant"' "$transcript_path" | tail -1)
87
+
88
+ echo "Last assistant message length: ${#last_assistant_msg}" >> "$DEBUG_LOG"
89
+ if [ -z "$last_assistant_msg" ]; then
90
+ # Normal case: No assistant messages yet
91
+ echo "No assistant messages found, exiting" >> "$DEBUG_LOG"
92
+ exit 0
93
+ fi
94
+
95
+ # Extract the text content from the message
96
+ # Looking for the final JSON blob: {"proposedChanges": ..., "madeChanges": ...}
97
+ if ! msg_text=$(echo "$last_assistant_msg" | jq -r '.message.content[]? | select(.type == "text") | .text' 2>/dev/null); then
98
+ echo "ERROR: jq failed to parse assistant message structure. Transcript format may have changed." >&2
99
+ echo "DEBUG: Message structure: $(echo "$last_assistant_msg" | jq -r '.message.content[].type' 2>/dev/null)" >> "$DEBUG_LOG"
100
+ exit 2
101
+ fi
102
+
103
+ if [ -z "$msg_text" ]; then
104
+ # Normal case: Message has no text content
105
+ exit 0
106
+ fi
107
+
108
+ # Extract the JSON blob from the end of the message
109
+ # Pattern: {"proposedChanges": boolean, "madeChanges": boolean, "askedQuestion": boolean}
110
+ json_blob=$(echo "$msg_text" | grep -oE '\{"proposedChanges":\s*(true|false)\s*,\s*"madeChanges":\s*(true|false)\s*,\s*"askedQuestion":\s*(true|false)\s*\}' | tail -1)
111
+
112
+ echo "JSON blob: $json_blob" >> "$DEBUG_LOG"
113
+ if [ -z "$json_blob" ]; then
114
+ # Check if this looks like a substantive response (>100 chars)
115
+ # If so, remind agent to include JSON payload
116
+ msg_length=${#msg_text}
117
+ echo "No JSON blob found, message length: $msg_length" >> "$DEBUG_LOG"
118
+
119
+ if [ "$msg_length" -gt 100 ]; then
120
+ echo "Substantive response without JSON payload, sending reminder" >> "$DEBUG_LOG"
121
+ echo "Missing required JSON response format. Please include: {\"proposedChanges\": bool, \"madeChanges\": bool, \"askedQuestion\": bool}" >&2
122
+ exit 2
123
+ fi
124
+
125
+ # Short message without JSON is fine (acknowledgments, etc)
126
+ echo "Short message without JSON, exiting" >> "$DEBUG_LOG"
127
+ exit 0
128
+ fi
129
+
130
+ # Parse the boolean values
131
+ if ! proposed_changes=$(echo "$json_blob" | jq -r '.proposedChanges // false' 2>/dev/null); then
132
+ echo "ERROR: jq failed to parse proposedChanges field from JSON blob." >&2
133
+ exit 2
134
+ fi
135
+
136
+ if ! made_changes=$(echo "$json_blob" | jq -r '.madeChanges // false' 2>/dev/null); then
137
+ echo "ERROR: jq failed to parse madeChanges field from JSON blob." >&2
138
+ exit 2
139
+ fi
140
+
141
+ if ! asked_question=$(echo "$json_blob" | jq -r '.askedQuestion // false' 2>/dev/null); then
142
+ echo "ERROR: jq failed to parse askedQuestion field from JSON blob." >&2
143
+ exit 2
144
+ fi
145
+
146
+ # If asked question, skip quality review (waiting for user response)
147
+ echo "proposedChanges=$proposed_changes, madeChanges=$made_changes, askedQuestion=$asked_question" >> "$DEBUG_LOG"
148
+ if [ "$asked_question" = "true" ]; then
149
+ echo "Agent asked question, skipping quality review" >> "$DEBUG_LOG"
150
+ exit 0
151
+ fi
152
+
153
+ # If either proposed or made changes, trigger quality review
154
+ if [ "$proposed_changes" = "true" ] || [ "$made_changes" = "true" ]; then
155
+ # Block and request quality review
156
+ echo "TRIGGERING QUALITY REVIEW" >> "$DEBUG_LOG"
157
+
158
+ # Find the shared quality review script (same directory as this hook)
159
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
160
+
161
+ # Call shared quality review script
162
+ if [ "$ask_questions" = "true" ]; then
163
+ exec "$SCRIPT_DIR/run-quality-review.sh"
164
+ else
165
+ exec "$SCRIPT_DIR/run-quality-review.sh" --no-questions
166
+ fi
167
+ fi
168
+
169
+ # No changes proposed or made - allow continuation
170
+ exit 0
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+ # SessionStart hook - reminds user to re-run setup if frameworks changed
3
+ [ ! -f ".safeword/eslint/eslint-base.mjs" ] || [ ! -f "package.json" ] && exit 0
4
+ DEPS=$(jq -r '(.dependencies//{}),(.devDependencies//{}) | keys[]' package.json 2>/dev/null || grep -oE '"[^"]+":' package.json | tr -d '":')
5
+ HAS_TS=false; HAS_REACT=false; HAS_ASTRO=false
6
+ { [ -f "tsconfig.json" ] || echo "$DEPS" | grep -qx "typescript"; } && HAS_TS=true
7
+ echo "$DEPS" | grep -qx "react" && HAS_REACT=true
8
+ echo "$DEPS" | grep -qx "astro" && HAS_ASTRO=true
9
+ CFG_TS=$(grep -q "typescript-eslint" .safeword/eslint/eslint-base.mjs && echo true || echo false)
10
+ CFG_REACT=$(grep -q "@eslint-react" .safeword/eslint/eslint-base.mjs && echo true || echo false)
11
+ CFG_ASTRO=$(grep -q "eslint-plugin-astro" .safeword/eslint/eslint-base.mjs && echo true || echo false)
12
+ MSG=""
13
+ [ "$HAS_TS" != "$CFG_TS" ] && MSG+="TypeScript "
14
+ [ "$HAS_REACT" != "$CFG_REACT" ] && MSG+="React "
15
+ [ "$HAS_ASTRO" != "$CFG_ASTRO" ] && MSG+="Astro "
16
+ [ -n "$MSG" ] && echo "⚠️ ESLint config out of sync (${MSG% }changed). Run: bash .safeword/scripts/setup-linting.sh"
17
+ exit 0
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+ # Inject Timestamp - Notification Hook
3
+ # Outputs current Unix timestamp at session start for Claude's context awareness
4
+ # Helps with accurate ticket timestamps and time-based reasoning
5
+
6
+ echo "Current time: $(date +%s) ($(date -u +%Y-%m-%dT%H:%M:%SZ))"
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env bash
2
+ # Pre-hook: Question-asking protocol
3
+ # Triggers on UserPromptSubmit (20+ chars) to guide clarifying questions
4
+
5
+ cat <<'EOF'
6
+ {
7
+ "hookSpecificOutput": {
8
+ "hookEventName": "UserPromptSubmit",
9
+ "additionalContext": "<question-protocol>Research first. Ask 1-3 questions ONLY about what to build (not how) that only user knows. Skip searchable things. Unsure? Ask.</question-protocol>"
10
+ }
11
+ }
12
+ EOF
@@ -0,0 +1,8 @@
1
+ #!/bin/bash
2
+ # Shared Linting Script - runs Prettier + ESLint on files
3
+ if [ -n "$CLAUDE_PROJECT_DIR" ]; then cd "$CLAUDE_PROJECT_DIR" || exit 1; fi
4
+ for target in "$@"; do
5
+ [ -e "$target" ] || continue
6
+ npx prettier --write "$target" 2>&1 || true
7
+ npx eslint --fix "$target" 2>&1 || true
8
+ done
@@ -0,0 +1,76 @@
1
+ #!/bin/bash
2
+ # Generated by setup-quality.sh v1.0.0
3
+ # To upgrade: Re-run setup script in this project
4
+ #
5
+ # Shared Quality Review Script
6
+ #
7
+ # Prompts for a quality review with configurable questions.
8
+ # Used by both Stop hooks and manual /quality-review command.
9
+ #
10
+ # Usage:
11
+ # run-quality-review.sh # With questions enabled
12
+ # run-quality-review.sh --no-questions # Without "ask me" prompt
13
+ #
14
+ # Environment variables:
15
+ # CLAUDE_PROJECT_DIR - Project root (for finding config and prompts)
16
+
17
+ # Default: ask questions enabled
18
+ ask_questions=true
19
+
20
+ # Parse command line arguments
21
+ for arg in "$@"; do
22
+ case "$arg" in
23
+ --no-questions)
24
+ ask_questions=false
25
+ ;;
26
+ esac
27
+ done
28
+
29
+ # Try to read project config if CLAUDE_PROJECT_DIR is set
30
+ if [ -n "$CLAUDE_PROJECT_DIR" ]; then
31
+ config_file="$CLAUDE_PROJECT_DIR/.auto-quality-review.config"
32
+
33
+ if [ -f "$config_file" ]; then
34
+ while IFS='=' read -r key value; do
35
+ # Skip empty lines and comments
36
+ [[ -z "$key" || "$key" =~ ^# ]] && continue
37
+ # Trim whitespace
38
+ key=$(echo "$key" | xargs)
39
+ value=$(echo "$value" | xargs)
40
+
41
+ case "$key" in
42
+ ask_questions)
43
+ ask_questions="$value"
44
+ ;;
45
+ esac
46
+ done < "$config_file"
47
+ fi
48
+ fi
49
+
50
+ # Try to read prompt from .safeword/prompts/quality-review.md
51
+ PROMPT_FILE=""
52
+ if [ -n "$CLAUDE_PROJECT_DIR" ] && [ -f "$CLAUDE_PROJECT_DIR/.safeword/prompts/quality-review.md" ]; then
53
+ PROMPT_FILE="$CLAUDE_PROJECT_DIR/.safeword/prompts/quality-review.md"
54
+ fi
55
+
56
+ if [ -n "$PROMPT_FILE" ]; then
57
+ # Read prompt from file, skip the header line
58
+ tail -n +3 "$PROMPT_FILE" >&2
59
+ else
60
+ # Fallback to hardcoded prompt
61
+ echo "Double check and critique your work just in case." >&2
62
+ echo "" >&2
63
+ echo "- Is it correct?" >&2
64
+ echo "- Is it elegant?" >&2
65
+ echo "- Does it adhere to the latest documentation and best practices for the relevant stack items, UX principles, domain requirements, and testing practices?" >&2
66
+
67
+ if [ "$ask_questions" = "true" ]; then
68
+ echo "- Ask me any non-obvious questions you can't research yourself in the codebase or online." >&2
69
+ fi
70
+
71
+ echo "- Think hard." >&2
72
+ echo "- Avoid bloat." >&2
73
+ fi
74
+
75
+ # Exit with code 2 to block (Stop hook behavior)
76
+ exit 2
@@ -0,0 +1,10 @@
1
+ #!/bin/bash
2
+ # Generated by setup-quality.sh v1.0.0
3
+ # To upgrade: Re-run setup script in this project
4
+ #
5
+ # SAFE WORD Claude Config - SessionStart Hook
6
+ # Injects version and status into Claude's context (silent - not displayed to user)
7
+
8
+ echo "SAFE WORD Claude Config v1.0.0 installed - auto-linting and quality review active"
9
+
10
+ exit 0
@@ -0,0 +1,96 @@
1
+ # MCP Server Configurations
2
+
3
+ Sample configurations for Model Context Protocol (MCP) servers.
4
+
5
+ ## Available Servers
6
+
7
+ | Server | Package | API Key | Purpose |
8
+ |--------|---------|---------|---------|
9
+ | **Context7** | `@upstash/context7-mcp` | Required (free) | Library docs lookups |
10
+ | **Playwright** | `@playwright/mcp` | None | Browser automation (Microsoft) |
11
+ | **Arcade** | Arcade MCP Gateway | Required | Tool gateway |
12
+
13
+ ## API Keys
14
+
15
+ | Server | Get Key |
16
+ |--------|---------|
17
+ | Context7 | [context7.com/dashboard](https://context7.com/dashboard) (free tier) |
18
+ | Arcade | [arcade.dev](https://arcade.dev) |
19
+
20
+ ## Setup
21
+
22
+ ### 1. Set Environment Variables
23
+
24
+ Add to `~/.zshrc` (or `~/.bashrc`):
25
+
26
+ ```bash
27
+ export CONTEXT7_API_KEY="your-key-here"
28
+ export ARCADE_API_KEY="your-key-here"
29
+ ```
30
+
31
+ Then reload: `source ~/.zshrc`
32
+
33
+ ### 2. Add MCP Config
34
+
35
+ **Claude Desktop** — Add to `~/.claude/claude_desktop_config.json`:
36
+
37
+ ```json
38
+ {
39
+ "mcpServers": {
40
+ "context7": {
41
+ "command": "npx",
42
+ "args": ["-y", "@upstash/context7-mcp@latest"]
43
+ },
44
+ "playwright": {
45
+ "command": "npx",
46
+ "args": ["@playwright/mcp@latest"]
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ **Cursor** — Add to `.cursor/mcp.json`:
53
+
54
+ ```json
55
+ {
56
+ "mcpServers": {
57
+ "context7": {
58
+ "command": "npx",
59
+ "args": ["-y", "@upstash/context7-mcp@latest"]
60
+ },
61
+ "playwright": {
62
+ "command": "npx",
63
+ "args": ["@playwright/mcp@latest"]
64
+ }
65
+ }
66
+ }
67
+ ```
68
+
69
+ MCP servers inherit environment variables from your shell automatically.
70
+
71
+ ## Playwright Options
72
+
73
+ | Arg | Description |
74
+ |-----|-------------|
75
+ | `--browser chromium\|firefox\|webkit` | Browser type |
76
+ | `--headless` | Run headless |
77
+ | `--user-data-dir <path>` | Persist browser profile |
78
+
79
+ Example:
80
+
81
+ ```json
82
+ {
83
+ "command": "npx",
84
+ "args": ["@playwright/mcp@latest", "--browser", "chromium", "--headless"]
85
+ }
86
+ ```
87
+
88
+ ## Context7 Usage
89
+
90
+ Once configured, use in prompts:
91
+
92
+ ```
93
+ use context7 to look up the latest React 19 useOptimistic hook documentation
94
+ ```
95
+
96
+ Context7 fetches current docs directly from source repositories.
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "arcade",
3
+ "transport": "http",
4
+ "url": "https://mcp.arcade.dev",
5
+ "headers": {
6
+ "Authorization": "Bearer YOUR_ARCADE_API_KEY"
7
+ }
8
+ }
9
+
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "context7",
3
+ "transport": "stdio",
4
+ "command": "npx",
5
+ "args": ["-y", "@upstash/context7-mcp@latest"]
6
+ }
7
+
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "playwright",
3
+ "transport": "stdio",
4
+ "command": "npx",
5
+ "args": ["@playwright/mcp@latest"]
6
+ }
7
+
@@ -0,0 +1,62 @@
1
+ {
2
+ "hooks": {
3
+ "UserPromptSubmit": [
4
+ {
5
+ "matcher": ".{20,}",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/question-protocol.sh"
10
+ }
11
+ ]
12
+ },
13
+ {
14
+ "hooks": [
15
+ {
16
+ "type": "command",
17
+ "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/inject-timestamp.sh"
18
+ }
19
+ ]
20
+ }
21
+ ],
22
+ "Stop": [
23
+ {
24
+ "hooks": [
25
+ {
26
+ "type": "command",
27
+ "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/auto-quality-review.sh"
28
+ }
29
+ ]
30
+ }
31
+ ],
32
+ "SessionStart": [
33
+ {
34
+ "hooks": [
35
+ {
36
+ "type": "command",
37
+ "command": "$CLAUDE_PROJECT_DIR/.safeword/hooks/agents-md-check.sh"
38
+ }
39
+ ]
40
+ },
41
+ {
42
+ "hooks": [
43
+ {
44
+ "type": "command",
45
+ "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/version-check.sh"
46
+ }
47
+ ]
48
+ }
49
+ ],
50
+ "PostToolUse": [
51
+ {
52
+ "matcher": "Write|Edit|MultiEdit|NotebookEdit",
53
+ "hooks": [
54
+ {
55
+ "type": "command",
56
+ "command": "$CLAUDE_PROJECT_DIR/.safeword/hooks/post-tool.sh"
57
+ }
58
+ ]
59
+ }
60
+ ]
61
+ }
62
+ }