safeword 0.2.2 → 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-M73LGONJ.js +0 -129
  184. package/dist/check-M73LGONJ.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-V5G6BGOK.js +0 -26
  190. package/dist/chunk-V5G6BGOK.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-FSFDCBL5.js +0 -166
  197. package/dist/diff-FSFDCBL5.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-MKVVQTVA.js +0 -266
  204. package/dist/setup-MKVVQTVA.js.map +0 -1
  205. package/dist/upgrade-FQOL6AF5.js +0 -134
  206. package/dist/upgrade-FQOL6AF5.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,559 @@
1
+ #!/bin/bash
2
+ ################################################################################
3
+ # Claude Code Linting Hook Setup Script
4
+ #
5
+ # Automatically detects project type and configures ESLint + Prettier.
6
+ #
7
+ # Architecture:
8
+ # .safeword/eslint/eslint-base.mjs ← Auto-generated every run. Don't edit.
9
+ # eslint.config.mjs ← Your config. Customize freely.
10
+ #
11
+ # Usage:
12
+ # bash setup-linting.sh # Setup/update linting
13
+ # bash setup-linting.sh --no-typescript # Skip TypeScript detection
14
+ # bash setup-linting.sh --no-react # Skip React detection
15
+ #
16
+ # Auto-detection:
17
+ # - TypeScript: tsconfig.json OR typescript in package.json
18
+ # - React: react in package.json
19
+ # - Astro: astro in package.json
20
+ ################################################################################
21
+
22
+ set -e
23
+
24
+ VERSION="v3.1.0"
25
+
26
+ # Parse arguments
27
+ SKIP_TYPESCRIPT=false
28
+ SKIP_REACT=false
29
+ SKIP_ASTRO=false
30
+
31
+ while [[ $# -gt 0 ]]; do
32
+ case $1 in
33
+ --no-typescript|--no-ts) SKIP_TYPESCRIPT=true; shift ;;
34
+ --no-react) SKIP_REACT=true; shift ;;
35
+ --no-astro) SKIP_ASTRO=true; shift ;;
36
+ --help|-h)
37
+ echo "Usage: bash setup-linting.sh [options]"
38
+ echo ""
39
+ echo "Options:"
40
+ echo " --no-typescript Skip TypeScript even if detected"
41
+ echo " --no-react Skip React even if detected"
42
+ echo " --no-astro Skip Astro even if detected"
43
+ echo ""
44
+ echo "Files:"
45
+ echo " $BASE_DIR/eslint-base.mjs - Auto-generated (updated every run)"
46
+ echo " eslint.config.mjs - Your config (created once, never overwritten)"
47
+ exit 0
48
+ ;;
49
+ *) echo "Unknown option: $1 (use --help for usage)"; exit 1 ;;
50
+ esac
51
+ done
52
+
53
+ echo "================================="
54
+ echo "Claude Code Linting Setup"
55
+ echo "Version: $VERSION"
56
+ echo "================================="
57
+ echo ""
58
+
59
+ PROJECT_ROOT="$(pwd)"
60
+ echo "Setting up in: $PROJECT_ROOT"
61
+ echo ""
62
+
63
+ # ============================================================================
64
+ # Step 1: Detect project type
65
+ # ============================================================================
66
+ echo "[1/5] Detecting project type..."
67
+
68
+ HAS_TYPESCRIPT=false
69
+ HAS_REACT=false
70
+ HAS_ASTRO=false
71
+
72
+ # Read dependencies from package.json
73
+ if [ -f package.json ] && command -v jq &> /dev/null; then
74
+ DEPS=$(jq -r '(.dependencies // {}), (.devDependencies // {}) | keys[]' package.json 2>/dev/null || echo "")
75
+ elif [ -f package.json ]; then
76
+ DEPS=$(grep -E '"[^"]+"\s*:' package.json | cut -d'"' -f2)
77
+ else
78
+ DEPS=""
79
+ fi
80
+
81
+ # TypeScript detection
82
+ if [ "$SKIP_TYPESCRIPT" = false ]; then
83
+ if [ -f tsconfig.json ] || echo "$DEPS" | grep -qx "typescript"; then
84
+ HAS_TYPESCRIPT=true
85
+ echo " ✓ TypeScript detected"
86
+ fi
87
+ fi
88
+
89
+ # React detection
90
+ if [ "$SKIP_REACT" = false ]; then
91
+ if echo "$DEPS" | grep -qx "react"; then
92
+ HAS_REACT=true
93
+ echo " ✓ React detected"
94
+ fi
95
+ fi
96
+
97
+ # Astro detection
98
+ if [ "$SKIP_ASTRO" = false ]; then
99
+ if echo "$DEPS" | grep -qx "astro"; then
100
+ HAS_ASTRO=true
101
+ echo " ✓ Astro detected"
102
+ fi
103
+ fi
104
+
105
+ [ "$HAS_TYPESCRIPT" = false ] && [ "$HAS_REACT" = false ] && [ "$HAS_ASTRO" = false ] && echo " → JavaScript-only project"
106
+ echo ""
107
+
108
+ # ============================================================================
109
+ # Step 2: Create package.json if needed
110
+ # ============================================================================
111
+ echo "[2/5] Checking package.json..."
112
+
113
+ if [ ! -f package.json ]; then
114
+ cat > package.json << 'EOF'
115
+ {
116
+ "name": "my-project",
117
+ "version": "1.0.0",
118
+ "type": "module",
119
+ "scripts": {},
120
+ "devDependencies": {}
121
+ }
122
+ EOF
123
+ echo " ✓ Created package.json"
124
+ else
125
+ echo " ✓ package.json exists"
126
+ fi
127
+ echo ""
128
+
129
+ # ============================================================================
130
+ # Step 3: Install packages
131
+ # ============================================================================
132
+ echo "[3/5] Installing packages..."
133
+
134
+ # Base packages (always installed)
135
+ PACKAGES="eslint @eslint/js prettier eslint-config-prettier globals"
136
+ PACKAGES+=" eslint-plugin-sonarjs @microsoft/eslint-plugin-sdl eslint-plugin-boundaries"
137
+
138
+ # Conditional packages
139
+ [ "$HAS_TYPESCRIPT" = true ] && PACKAGES+=" typescript-eslint"
140
+ [ "$HAS_REACT" = true ] && PACKAGES+=" @eslint-react/eslint-plugin eslint-plugin-react-hooks eslint-plugin-react-perf"
141
+ [ "$HAS_ASTRO" = true ] && PACKAGES+=" eslint-plugin-astro"
142
+
143
+ echo " Installing: $PACKAGES"
144
+ npm install --save-dev $PACKAGES --silent 2>&1 | grep -v "npm WARN" || true
145
+ echo " ✓ Packages installed"
146
+ echo ""
147
+
148
+ # ============================================================================
149
+ # Step 4: Generate ESLint configs
150
+ # ============================================================================
151
+ echo "[4/5] Generating ESLint configs..."
152
+
153
+ mkdir -p .safeword
154
+
155
+ # --- Always generate .safeword/eslint-base.mjs ---
156
+ BASE_DIR=".safeword/eslint"
157
+ mkdir -p "$BASE_DIR"
158
+ echo " Generating $BASE_DIR/eslint-base.mjs..."
159
+
160
+ # Build the file with prominent header
161
+ cat > "$BASE_DIR/eslint-base.mjs" << 'HEADER'
162
+ ////////////////////////////////////////////////////////////////////////////////
163
+ //
164
+ // ██████╗ ██████╗ ███╗ ██╗ ██████╗ ████████╗ ███████╗██████╗ ██╗████████╗
165
+ // ██╔══██╗██╔═══██╗ ████╗ ██║██╔═══██╗╚══██╔══╝ ██╔════╝██╔══██╗██║╚══██╔══╝
166
+ // ██║ ██║██║ ██║ ██╔██╗ ██║██║ ██║ ██║ █████╗ ██║ ██║██║ ██║
167
+ // ██║ ██║██║ ██║ ██║╚██╗██║██║ ██║ ██║ ██╔══╝ ██║ ██║██║ ██║
168
+ // ██████╔╝╚██████╔╝ ██║ ╚████║╚██████╔╝ ██║ ███████╗██████╔╝██║ ██║
169
+ // ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚══════╝╚═════╝ ╚═╝ ╚═╝
170
+ //
171
+ // AUTO-GENERATED FILE - DO NOT EDIT
172
+ //
173
+ // This file is regenerated every time you run:
174
+ // bash setup-linting.sh
175
+ //
176
+ // To customize ESLint rules, edit eslint.config.mjs instead.
177
+ // Your customizations there are preserved across regenerations.
178
+ //
179
+ ////////////////////////////////////////////////////////////////////////////////
180
+
181
+ import { globalIgnores } from 'eslint/config';
182
+ import js from '@eslint/js';
183
+ HEADER
184
+
185
+ [ "$HAS_TYPESCRIPT" = true ] && echo "import tseslint from 'typescript-eslint';" >> "$BASE_DIR/eslint-base.mjs"
186
+ [ "$HAS_REACT" = true ] && cat >> "$BASE_DIR/eslint-base.mjs" << 'REACT_IMPORTS'
187
+ import reactPlugin from '@eslint-react/eslint-plugin';
188
+ import reactHooks from 'eslint-plugin-react-hooks';
189
+ import reactPerf from 'eslint-plugin-react-perf';
190
+ REACT_IMPORTS
191
+ [ "$HAS_ASTRO" = true ] && echo "import astroPlugin from 'eslint-plugin-astro';" >> "$BASE_DIR/eslint-base.mjs"
192
+
193
+ cat >> "$BASE_DIR/eslint-base.mjs" << 'COMMON_IMPORTS'
194
+ import sonarjs from 'eslint-plugin-sonarjs';
195
+ import sdl from '@microsoft/eslint-plugin-sdl';
196
+ import boundaries from 'eslint-plugin-boundaries';
197
+ import prettier from 'eslint-config-prettier';
198
+ import globals from 'globals';
199
+
200
+ export default [
201
+ globalIgnores([
202
+ '**/node_modules/', '**/dist/', '**/build/', '**/.next/', '**/coverage/',
203
+ '**/*.min.js', '**/package-lock.json', '**/yarn.lock', '**/pnpm-lock.yaml',
204
+ ]),
205
+
206
+ // Base JavaScript
207
+ {
208
+ name: 'safeword/base-js',
209
+ files: ['**/*.{js,mjs,cjs}'],
210
+ ...js.configs.recommended,
211
+ languageOptions: {
212
+ ecmaVersion: 'latest',
213
+ sourceType: 'module',
214
+ globals: { ...globals.browser, ...globals.node, ...globals.es2025 },
215
+ },
216
+ },
217
+ COMMON_IMPORTS
218
+
219
+ # TypeScript block
220
+ [ "$HAS_TYPESCRIPT" = true ] && cat >> "$BASE_DIR/eslint-base.mjs" << 'TS_BLOCK'
221
+
222
+ // TypeScript
223
+ {
224
+ name: 'safeword/typescript',
225
+ files: ['**/*.{ts,tsx}'],
226
+ languageOptions: {
227
+ parser: tseslint.parser,
228
+ },
229
+ plugins: {
230
+ '@typescript-eslint': tseslint.plugin,
231
+ },
232
+ rules: {
233
+ ...tseslint.configs.recommended.rules,
234
+ },
235
+ },
236
+ TS_BLOCK
237
+
238
+ # React block
239
+ [ "$HAS_REACT" = true ] && cat >> "$BASE_DIR/eslint-base.mjs" << 'REACT_BLOCK'
240
+
241
+ // React
242
+ {
243
+ name: 'safeword/react',
244
+ files: ['**/*.{jsx,tsx}'],
245
+ ...reactPlugin.configs['recommended-typescript'],
246
+ plugins: {
247
+ 'react-hooks': reactHooks,
248
+ 'react-perf': reactPerf,
249
+ },
250
+ languageOptions: {
251
+ parserOptions: { ecmaFeatures: { jsx: true } },
252
+ },
253
+ rules: {
254
+ ...reactHooks.configs.recommended.rules,
255
+ 'react-perf/jsx-no-new-object-as-prop': 'warn',
256
+ 'react-perf/jsx-no-new-array-as-prop': 'warn',
257
+ 'react-perf/jsx-no-new-function-as-prop': 'warn',
258
+ },
259
+ },
260
+ REACT_BLOCK
261
+
262
+ # Astro block
263
+ [ "$HAS_ASTRO" = true ] && cat >> "$BASE_DIR/eslint-base.mjs" << 'ASTRO_BLOCK'
264
+
265
+ // Astro
266
+ ...astroPlugin.configs.recommended,
267
+ ASTRO_BLOCK
268
+
269
+ # Determine file pattern for quality/security rules
270
+ FILE_PATTERN="**/*.{js,mjs,cjs"
271
+ [ "$HAS_TYPESCRIPT" = true ] && FILE_PATTERN+=",ts,tsx"
272
+ [ "$HAS_REACT" = true ] && FILE_PATTERN+=",jsx"
273
+ FILE_PATTERN+="}"
274
+
275
+ cat >> "$BASE_DIR/eslint-base.mjs" << QUALITY_BLOCK
276
+
277
+ // Code quality (SonarJS)
278
+ {
279
+ name: 'safeword/sonarjs',
280
+ files: ['$FILE_PATTERN'],
281
+ plugins: { sonarjs },
282
+ rules: sonarjs.configs.recommended.rules,
283
+ },
284
+
285
+ // Security (Microsoft SDL)
286
+ {
287
+ name: 'safeword/security',
288
+ files: ['$FILE_PATTERN'],
289
+ plugins: { '@microsoft/sdl': sdl },
290
+ rules: {
291
+ '@microsoft/sdl/no-insecure-url': 'error',
292
+ '@microsoft/sdl/no-inner-html': 'error',
293
+ '@microsoft/sdl/no-document-write': 'error',
294
+ '@microsoft/sdl/no-html-method': 'error',
295
+ '@microsoft/sdl/no-insecure-random': 'error',
296
+ '@microsoft/sdl/no-postmessage-star-origin': 'error',
297
+ },
298
+ },
299
+
300
+ // Architecture boundaries (default layers - customize in eslint.config.mjs)
301
+ {
302
+ name: 'safeword/boundaries',
303
+ files: ['src/**/*.{js,mjs,cjs,ts,tsx,jsx}'],
304
+ plugins: { boundaries },
305
+ settings: {
306
+ 'boundaries/include': ['src/**/*'],
307
+ 'boundaries/elements': [
308
+ { type: 'app', pattern: 'src/app/**/*' },
309
+ { type: 'domain', pattern: 'src/domain/**/*' },
310
+ { type: 'infra', pattern: 'src/infra/**/*' },
311
+ { type: 'shared', pattern: 'src/shared/**/*' },
312
+ ],
313
+ },
314
+ rules: {
315
+ 'boundaries/element-types': ['error', {
316
+ default: 'disallow',
317
+ rules: [
318
+ { from: 'app', allow: ['domain', 'infra', 'shared'] },
319
+ { from: 'domain', allow: ['shared'] },
320
+ { from: 'infra', allow: ['domain', 'shared'] },
321
+ { from: 'shared', allow: [] },
322
+ ],
323
+ }],
324
+ },
325
+ },
326
+
327
+ // Prettier (must be last in base)
328
+ {
329
+ name: 'safeword/prettier',
330
+ ...prettier,
331
+ },
332
+ ];
333
+ QUALITY_BLOCK
334
+
335
+ echo " ✓ Generated $BASE_DIR/eslint-base.mjs"
336
+
337
+ # --- Create eslint.config.mjs only if it doesn't exist ---
338
+ if [ -f eslint.config.mjs ]; then
339
+ echo " ✓ eslint.config.mjs exists (your customizations preserved)"
340
+ else
341
+ cat > eslint.config.mjs << 'USER_CONFIG'
342
+ /**
343
+ * ESLint Configuration
344
+ *
345
+ * This file is YOURS to customize. It imports the auto-generated base config
346
+ * and lets you add your own rules, override defaults, and customize boundaries.
347
+ *
348
+ * The base config (.safeword/eslint-base.mjs) auto-detects:
349
+ * - TypeScript, React, Astro from package.json
350
+ * - Regenerated automatically when you run setup-linting.sh
351
+ */
352
+ import base from './.safeword/eslint/eslint-base.mjs';
353
+
354
+ export default [
355
+ // Include all base configs (TypeScript, React, boundaries, security, etc.)
356
+ ...base,
357
+
358
+ // =========================================================================
359
+ // YOUR CUSTOMIZATIONS BELOW
360
+ // =========================================================================
361
+
362
+ // Example: Override boundary rules for your project's layer structure
363
+ // {
364
+ // name: 'my-boundaries',
365
+ // files: ['src/**/*'],
366
+ // settings: {
367
+ // 'boundaries/elements': [
368
+ // { type: 'features', pattern: 'src/features/**/*' },
369
+ // { type: 'pages', pattern: 'src/pages/**/*' },
370
+ // { type: 'shared', pattern: 'src/shared/**/*' },
371
+ // ],
372
+ // },
373
+ // rules: {
374
+ // 'boundaries/element-types': ['error', {
375
+ // default: 'disallow',
376
+ // rules: [
377
+ // { from: 'pages', allow: ['features', 'shared'] },
378
+ // { from: 'features', allow: ['shared'] },
379
+ // { from: 'shared', allow: [] },
380
+ // ],
381
+ // }],
382
+ // },
383
+ // },
384
+
385
+ // Example: Add custom rules
386
+ // {
387
+ // name: 'my-rules',
388
+ // rules: {
389
+ // 'no-console': 'warn',
390
+ // '@typescript-eslint/no-explicit-any': 'off',
391
+ // },
392
+ // },
393
+ ];
394
+ USER_CONFIG
395
+ echo " ✓ Created eslint.config.mjs (customize this file)"
396
+ fi
397
+
398
+ echo ""
399
+
400
+ # ============================================================================
401
+ # Step 5: Create supporting files and hooks
402
+ # ============================================================================
403
+ echo "[5/5] Setting up hooks and configs..."
404
+
405
+ # Prettier config
406
+ if [ ! -f .prettierrc ] && [ ! -f .prettierrc.json ] && [ ! -f prettier.config.js ]; then
407
+ cat > .prettierrc << 'EOF'
408
+ {
409
+ "printWidth": 100,
410
+ "tabWidth": 2,
411
+ "useTabs": false,
412
+ "semi": true,
413
+ "singleQuote": true,
414
+ "trailingComma": "all",
415
+ "bracketSpacing": true,
416
+ "arrowParens": "avoid",
417
+ "endOfLine": "lf"
418
+ }
419
+ EOF
420
+ echo " ✓ Created .prettierrc"
421
+ fi
422
+
423
+ # Prettier ignore
424
+ if [ ! -f .prettierignore ]; then
425
+ cat > .prettierignore << 'EOF'
426
+ node_modules
427
+ dist
428
+ build
429
+ .next
430
+ coverage
431
+ *.min.js
432
+ package-lock.json
433
+ EOF
434
+ echo " ✓ Created .prettierignore"
435
+ fi
436
+
437
+ # Add npm scripts
438
+ if command -v jq &> /dev/null; then
439
+ jq '.scripts.lint = "eslint ." | .scripts.format = "prettier --write ."' package.json > package.json.tmp
440
+ mv package.json.tmp package.json
441
+ echo " ✓ Added npm scripts (lint, format)"
442
+ fi
443
+
444
+ # Claude Code hooks
445
+ mkdir -p .claude/hooks .claude/commands
446
+
447
+ cat > .claude/hooks/run-linters.sh << 'EOF'
448
+ #!/bin/bash
449
+ # Shared Linting Script - runs Prettier + ESLint on files
450
+ if [ -n "$CLAUDE_PROJECT_DIR" ]; then cd "$CLAUDE_PROJECT_DIR" || exit 1; fi
451
+ for target in "$@"; do
452
+ [ -e "$target" ] || continue
453
+ npx prettier --write "$target" 2>&1 || true
454
+ npx eslint --fix "$target" 2>&1 || true
455
+ done
456
+ EOF
457
+ chmod +x .claude/hooks/run-linters.sh
458
+
459
+ cat > .claude/hooks/auto-lint.sh << 'EOF'
460
+ #!/bin/bash
461
+ # PostToolUse hook - auto-lint changed files
462
+ input=$(cat)
463
+ file_path=$(echo "$input" | jq -r '.tool_input.file_path // .tool_input.notebook_path // empty')
464
+ [ -n "$file_path" ] && [ -f "$file_path" ] && "$CLAUDE_PROJECT_DIR/.claude/hooks/run-linters.sh" "$file_path"
465
+ exit 0
466
+ EOF
467
+ chmod +x .claude/hooks/auto-lint.sh
468
+
469
+ cat > .claude/commands/lint.md << 'EOF'
470
+ Run linting on all project files.
471
+
472
+ Execute:
473
+ ```bash
474
+ bash .claude/hooks/run-linters.sh .
475
+ ```
476
+ EOF
477
+
478
+ echo " ✓ Created Claude Code hooks"
479
+
480
+ # Update settings.json
481
+ if [ ! -f .claude/settings.json ]; then
482
+ echo '{"hooks": {}}' > .claude/settings.json
483
+ fi
484
+
485
+ # Add PostToolUse hook for auto-linting
486
+ if ! jq -e '.hooks.PostToolUse[]?.hooks[]? | select(.command == "$CLAUDE_PROJECT_DIR/.claude/hooks/auto-lint.sh")' .claude/settings.json > /dev/null 2>&1; then
487
+ jq '.hooks.PostToolUse = (.hooks.PostToolUse // []) + [{"matcher": "Write|Edit|MultiEdit|NotebookEdit", "hooks": [{"type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/auto-lint.sh", "timeout": 15}]}]' \
488
+ .claude/settings.json > .claude/settings.json.tmp
489
+ mv .claude/settings.json.tmp .claude/settings.json
490
+ echo " ✓ Added PostToolUse hook (auto-lint)"
491
+ fi
492
+
493
+ # Create and add SessionStart hook to detect framework changes
494
+ cat > .claude/hooks/check-linting-sync.sh << 'EOF'
495
+ #!/bin/bash
496
+ # SessionStart hook - reminds user to re-run setup if frameworks changed
497
+ [ ! -f ".safeword/eslint/eslint-base.mjs" ] || [ ! -f "package.json" ] && exit 0
498
+ DEPS=$(jq -r '(.dependencies//{}),(.devDependencies//{}) | keys[]' package.json 2>/dev/null || grep -oE '"[^"]+":' package.json | tr -d '":')
499
+ HAS_TS=false; HAS_REACT=false; HAS_ASTRO=false
500
+ { [ -f "tsconfig.json" ] || echo "$DEPS" | grep -qx "typescript"; } && HAS_TS=true
501
+ echo "$DEPS" | grep -qx "react" && HAS_REACT=true
502
+ echo "$DEPS" | grep -qx "astro" && HAS_ASTRO=true
503
+ CFG_TS=$(grep -q "typescript-eslint" .safeword/eslint/eslint-base.mjs && echo true || echo false)
504
+ CFG_REACT=$(grep -q "@eslint-react" .safeword/eslint/eslint-base.mjs && echo true || echo false)
505
+ CFG_ASTRO=$(grep -q "eslint-plugin-astro" .safeword/eslint/eslint-base.mjs && echo true || echo false)
506
+ MSG=""
507
+ [ "$HAS_TS" != "$CFG_TS" ] && MSG+="TypeScript "
508
+ [ "$HAS_REACT" != "$CFG_REACT" ] && MSG+="React "
509
+ [ "$HAS_ASTRO" != "$CFG_ASTRO" ] && MSG+="Astro "
510
+ [ -n "$MSG" ] && echo "⚠️ ESLint config out of sync (${MSG% }changed). Run: bash .safeword/scripts/setup-linting.sh"
511
+ exit 0
512
+ EOF
513
+ chmod +x .claude/hooks/check-linting-sync.sh
514
+
515
+ if ! jq -e '.hooks.SessionStart[]?.hooks[]? | select(.command == "$CLAUDE_PROJECT_DIR/.claude/hooks/check-linting-sync.sh")' .claude/settings.json > /dev/null 2>&1; then
516
+ jq '.hooks.SessionStart = (.hooks.SessionStart // []) + [{"hooks": [{"type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/check-linting-sync.sh"}]}]' \
517
+ .claude/settings.json > .claude/settings.json.tmp
518
+ mv .claude/settings.json.tmp .claude/settings.json
519
+ echo " ✓ Added SessionStart hook (sync check)"
520
+ fi
521
+
522
+ # /setup-linting command
523
+ cat > .claude/commands/setup-linting.md << 'EOF'
524
+ Re-run SAFEWORD linting setup (auto-detects frameworks, regenerates base config).
525
+
526
+ Execute:
527
+ ```bash
528
+ bash .safeword/scripts/setup-linting.sh
529
+ ```
530
+ EOF
531
+ echo " ✓ Created /setup-linting command"
532
+
533
+ echo ""
534
+ echo "================================="
535
+ echo "✓ Setup Complete!"
536
+ echo "================================="
537
+ echo ""
538
+ echo "Files:"
539
+ echo " .safeword/eslint/eslint-base.mjs - Auto-generated (DO NOT EDIT)"
540
+ echo " eslint.config.mjs - Your config (customize freely)"
541
+ echo ""
542
+ echo "Detected:"
543
+ [ "$HAS_TYPESCRIPT" = true ] && echo " ✓ TypeScript"
544
+ [ "$HAS_REACT" = true ] && echo " ✓ React"
545
+ [ "$HAS_ASTRO" = true ] && echo " ✓ Astro"
546
+ [ "$HAS_TYPESCRIPT" = false ] && [ "$HAS_REACT" = false ] && [ "$HAS_ASTRO" = false ] && echo " → JavaScript only"
547
+ echo ""
548
+ echo "Included:"
549
+ echo " • eslint-plugin-boundaries (architecture)"
550
+ echo " • eslint-plugin-sonarjs (code quality)"
551
+ echo " • @microsoft/eslint-plugin-sdl (security)"
552
+ echo ""
553
+ echo "Commands:"
554
+ echo " npm run lint # Check all files"
555
+ echo " npm run format # Format all files"
556
+ echo ""
557
+ echo "After adding/removing frameworks, just re-run:"
558
+ echo " bash setup-linting.sh"
559
+ echo ""
@@ -0,0 +1,136 @@
1
+ # [Project Name] Architecture
2
+
3
+ **Version:** 1.0
4
+ **Last Updated:** YYYY-MM-DD
5
+ **Status:** Design | Production | Proposed | Deprecated
6
+
7
+ ---
8
+
9
+ ## Table of Contents
10
+
11
+ - [Overview](#overview)
12
+ - [Layers & Boundaries](#layers--boundaries)
13
+ - [Data Model](#data-model)
14
+ - [Key Decisions](#key-decisions)
15
+ - [Best Practices](#best-practices)
16
+ - [Migration Strategy](#migration-strategy)
17
+
18
+ ---
19
+
20
+ ## Overview
21
+
22
+ [High-level description of the system architecture, technology choices, and design philosophy.]
23
+
24
+ ### Tech Stack
25
+
26
+ | Category | Choice | Rationale |
27
+ |----------|--------|-----------|
28
+ | Language | | |
29
+ | Framework | | |
30
+ | Database | | |
31
+ | State Management | | |
32
+
33
+ ---
34
+
35
+ ## Layers & Boundaries
36
+
37
+ ### Layer Definitions
38
+
39
+ | Layer | Directory | Responsibility |
40
+ |-------|-----------|----------------|
41
+ | app | `src/app/` | UI, routing, composition |
42
+ | domain | `src/domain/` | Business rules, pure logic |
43
+ | infra | `src/infra/` | IO, APIs, DB, external SDKs |
44
+ | shared | `src/shared/` | Utilities usable by all layers |
45
+
46
+ ### Allowed Dependencies
47
+
48
+ | From | To | Allowed | Rationale |
49
+ |------|-----|---------|-----------|
50
+ | app | domain | ✅ | UI composes business logic |
51
+ | app | infra | ✅ | UI triggers side effects |
52
+ | app | shared | ✅ | Utilities available everywhere |
53
+ | domain | app | ❌ | Domain must be framework-agnostic |
54
+ | domain | infra | ❌ | Domain contains pure logic only |
55
+ | domain | shared | ✅ | Utilities available everywhere |
56
+ | infra | domain | ✅ | Adapters may use domain types |
57
+ | infra | app | ❌ | Infra should not depend on UI |
58
+ | infra | shared | ✅ | Utilities available everywhere |
59
+ | shared | * | ❌ | Shared has no dependencies (except external libs) |
60
+
61
+ **Note:** This template allows direct app→infra. Alternative: force app→domain→infra for stricter separation (hexagonal/ports-adapters pattern).
62
+
63
+ ### Boundary Enforcement
64
+
65
+ Boundaries enforced via `eslint-plugin-boundaries`. See `.safeword/guides/architecture-guide.md` → Enforcement with eslint-plugin-boundaries for setup.
66
+
67
+ ---
68
+
69
+ ## Data Model
70
+
71
+ ### Entities
72
+
73
+ | Entity | Table/Collection | Description |
74
+ |--------|-----------------|-------------|
75
+ | | | |
76
+
77
+ ### Relationships
78
+
79
+ ```
80
+ [Entity A] 1──n [Entity B]
81
+ [Entity B] n──n [Entity C]
82
+ ```
83
+
84
+ ### Schema Notes
85
+
86
+ - [Key constraints, indexes, etc.]
87
+
88
+ ---
89
+
90
+ ## Key Decisions
91
+
92
+ ### [Decision Title]
93
+
94
+ **Status:** Active | Superseded | Deprecated
95
+ **Date:** YYYY-MM-DD
96
+
97
+ | Field | Value |
98
+ |-------|-------|
99
+ | What | [The decision in 1-2 sentences] |
100
+ | Why | [Rationale with specifics - numbers, metrics] |
101
+ | Trade-off | [What we gave up or accepted] |
102
+ | Alternatives | [Other options considered and why rejected] |
103
+ | Implementation | [File references: `src/path/file.ts:12-45`] |
104
+
105
+ ---
106
+
107
+ ## Best Practices
108
+
109
+ ### [Pattern Name]
110
+
111
+ **What:** [Brief description]
112
+ **Why:** [Rationale]
113
+ **Example:** See `src/path/example.ts`
114
+
115
+ ---
116
+
117
+ ## Migration Strategy
118
+
119
+ ### From [Previous State] to [Target State]
120
+
121
+ **Trigger:** [When to migrate]
122
+ **Steps:**
123
+ 1. [Step 1]
124
+ 2. [Step 2]
125
+
126
+ **Rollback:** [How to revert if needed]
127
+
128
+ ---
129
+
130
+ ## Appendix
131
+
132
+ ### References
133
+
134
+ - [Link to relevant docs]
135
+ - [Link to ADRs if migrating from ADR system]
136
+