safeword 0.2.4 → 0.2.6

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/dist/check-3NGQ4NR5.js +129 -0
  2. package/dist/check-3NGQ4NR5.js.map +1 -0
  3. package/dist/chunk-2XWIUEQK.js +190 -0
  4. package/dist/chunk-2XWIUEQK.js.map +1 -0
  5. package/dist/chunk-GZRQL3SX.js +146 -0
  6. package/dist/chunk-GZRQL3SX.js.map +1 -0
  7. package/dist/chunk-ORQHKDT2.js +10 -0
  8. package/dist/chunk-ORQHKDT2.js.map +1 -0
  9. package/dist/chunk-W66Z3C5H.js +21 -0
  10. package/dist/chunk-W66Z3C5H.js.map +1 -0
  11. package/dist/cli.d.ts +1 -0
  12. package/dist/cli.js +34 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/diff-Y6QTAW4O.js +166 -0
  15. package/dist/diff-Y6QTAW4O.js.map +1 -0
  16. package/dist/index.d.ts +11 -0
  17. package/dist/index.js +7 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/reset-3ACTIYYE.js +143 -0
  20. package/dist/reset-3ACTIYYE.js.map +1 -0
  21. package/dist/setup-AIL5RL45.js +276 -0
  22. package/dist/setup-AIL5RL45.js.map +1 -0
  23. package/dist/upgrade-6AR3DHUV.js +134 -0
  24. package/dist/upgrade-6AR3DHUV.js.map +1 -0
  25. package/package.json +44 -19
  26. package/{.safeword → templates}/hooks/agents-md-check.sh +0 -0
  27. package/{.safeword → templates}/hooks/post-tool.sh +0 -0
  28. package/{.safeword → templates}/hooks/pre-commit.sh +0 -0
  29. package/.claude/commands/arch-review.md +0 -32
  30. package/.claude/commands/lint.md +0 -6
  31. package/.claude/commands/quality-review.md +0 -13
  32. package/.claude/commands/setup-linting.md +0 -6
  33. package/.claude/hooks/auto-lint.sh +0 -6
  34. package/.claude/hooks/auto-quality-review.sh +0 -170
  35. package/.claude/hooks/check-linting-sync.sh +0 -17
  36. package/.claude/hooks/inject-timestamp.sh +0 -6
  37. package/.claude/hooks/question-protocol.sh +0 -12
  38. package/.claude/hooks/run-linters.sh +0 -8
  39. package/.claude/hooks/run-quality-review.sh +0 -76
  40. package/.claude/hooks/version-check.sh +0 -10
  41. package/.claude/mcp/README.md +0 -96
  42. package/.claude/mcp/arcade.sample.json +0 -9
  43. package/.claude/mcp/context7.sample.json +0 -7
  44. package/.claude/mcp/playwright.sample.json +0 -7
  45. package/.claude/settings.json +0 -62
  46. package/.claude/skills/quality-reviewer/SKILL.md +0 -190
  47. package/.claude/skills/safeword-quality-reviewer/SKILL.md +0 -13
  48. package/.env.arcade.example +0 -4
  49. package/.env.example +0 -11
  50. package/.gitmodules +0 -4
  51. package/.safeword/SAFEWORD.md +0 -33
  52. package/.safeword/eslint/eslint-base.mjs +0 -101
  53. package/.safeword/guides/architecture-guide.md +0 -404
  54. package/.safeword/guides/code-philosophy.md +0 -174
  55. package/.safeword/guides/context-files-guide.md +0 -405
  56. package/.safeword/guides/data-architecture-guide.md +0 -183
  57. package/.safeword/guides/design-doc-guide.md +0 -165
  58. package/.safeword/guides/learning-extraction.md +0 -515
  59. package/.safeword/guides/llm-instruction-design.md +0 -239
  60. package/.safeword/guides/llm-prompting.md +0 -95
  61. package/.safeword/guides/tdd-best-practices.md +0 -570
  62. package/.safeword/guides/test-definitions-guide.md +0 -243
  63. package/.safeword/guides/testing-methodology.md +0 -573
  64. package/.safeword/guides/user-story-guide.md +0 -237
  65. package/.safeword/guides/zombie-process-cleanup.md +0 -214
  66. package/.safeword/planning/002-user-story-quality-evaluation.md +0 -1840
  67. package/.safeword/planning/003-langsmith-eval-setup-prompt.md +0 -363
  68. package/.safeword/planning/004-llm-eval-test-cases.md +0 -3226
  69. package/.safeword/planning/005-architecture-enforcement-system.md +0 -169
  70. package/.safeword/planning/006-reactive-fix-prevention-research.md +0 -135
  71. package/.safeword/planning/011-cli-ux-vision.md +0 -330
  72. package/.safeword/planning/012-project-structure-cleanup.md +0 -154
  73. package/.safeword/planning/README.md +0 -39
  74. package/.safeword/planning/automation-plan-v2.md +0 -1225
  75. package/.safeword/planning/automation-plan-v3.md +0 -1291
  76. package/.safeword/planning/automation-plan.md +0 -3058
  77. package/.safeword/planning/design/005-cli-implementation.md +0 -343
  78. package/.safeword/planning/design/013-cli-self-contained-templates.md +0 -596
  79. package/.safeword/planning/design/013a-eslint-plugin-suite.md +0 -256
  80. package/.safeword/planning/design/013b-implementation-snippets.md +0 -385
  81. package/.safeword/planning/design/013c-config-isolation-strategy.md +0 -242
  82. package/.safeword/planning/design/code-philosophy-improvements.md +0 -60
  83. package/.safeword/planning/mcp-analysis.md +0 -545
  84. package/.safeword/planning/phase2-subagents-vs-skills-analysis.md +0 -451
  85. package/.safeword/planning/settings-improvements.md +0 -970
  86. package/.safeword/planning/test-definitions/005-cli-implementation.md +0 -1301
  87. package/.safeword/planning/test-definitions/cli-self-contained-templates.md +0 -205
  88. package/.safeword/planning/user-stories/001-guides-review-user-stories.md +0 -1381
  89. package/.safeword/planning/user-stories/003-reactive-fix-prevention.md +0 -132
  90. package/.safeword/planning/user-stories/004-technical-constraints.md +0 -86
  91. package/.safeword/planning/user-stories/005-cli-implementation.md +0 -311
  92. package/.safeword/planning/user-stories/cli-self-contained-templates.md +0 -172
  93. package/.safeword/planning/versioned-distribution.md +0 -740
  94. package/.safeword/prompts/arch-review.md +0 -43
  95. package/.safeword/prompts/quality-review.md +0 -11
  96. package/.safeword/scripts/arch-review.sh +0 -235
  97. package/.safeword/scripts/check-linting-sync.sh +0 -58
  98. package/.safeword/scripts/setup-linting.sh +0 -559
  99. package/.safeword/templates/architecture-template.md +0 -136
  100. package/.safeword/templates/ci/architecture-check.yml +0 -79
  101. package/.safeword/templates/design-doc-template.md +0 -127
  102. package/.safeword/templates/test-definitions-feature.md +0 -100
  103. package/.safeword/templates/ticket-template.md +0 -74
  104. package/.safeword/templates/user-stories-template.md +0 -82
  105. package/.safeword/tickets/001-guides-review-user-stories.md +0 -83
  106. package/.safeword/tickets/002-architecture-enforcement.md +0 -211
  107. package/.safeword/tickets/003-reactive-fix-prevention.md +0 -57
  108. package/.safeword/tickets/004-technical-constraints-in-user-stories.md +0 -39
  109. package/.safeword/tickets/005-cli-implementation.md +0 -248
  110. package/.safeword/tickets/006-flesh-out-skills.md +0 -43
  111. package/.safeword/tickets/007-flesh-out-questioning.md +0 -44
  112. package/.safeword/tickets/008-upgrade-questioning.md +0 -58
  113. package/.safeword/tickets/009-naming-conventions.md +0 -41
  114. package/.safeword/tickets/010-safeword-md-cleanup.md +0 -34
  115. package/.safeword/tickets/011-cursor-setup.md +0 -86
  116. package/.safeword/tickets/README.md +0 -73
  117. package/.safeword/version +0 -1
  118. package/AGENTS.md +0 -59
  119. package/CLAUDE.md +0 -12
  120. package/README.md +0 -347
  121. package/docs/001-cli-implementation-plan.md +0 -856
  122. package/docs/elite-dx-implementation-plan.md +0 -1034
  123. package/framework/README.md +0 -131
  124. package/framework/mcp/README.md +0 -96
  125. package/framework/mcp/arcade.sample.json +0 -8
  126. package/framework/mcp/context7.sample.json +0 -6
  127. package/framework/mcp/playwright.sample.json +0 -6
  128. package/framework/scripts/arch-review.sh +0 -235
  129. package/framework/scripts/check-linting-sync.sh +0 -58
  130. package/framework/scripts/load-env.sh +0 -49
  131. package/framework/scripts/setup-claude.sh +0 -223
  132. package/framework/scripts/setup-linting.sh +0 -559
  133. package/framework/scripts/setup-quality.sh +0 -477
  134. package/framework/scripts/setup-safeword.sh +0 -550
  135. package/framework/templates/ci/architecture-check.yml +0 -78
  136. package/learnings/ai-sdk-v5-breaking-changes.md +0 -178
  137. package/learnings/e2e-test-zombie-processes.md +0 -231
  138. package/learnings/milkdown-crepe-editor-property.md +0 -96
  139. package/learnings/prosemirror-fragment-traversal.md +0 -119
  140. package/packages/cli/AGENTS.md +0 -1
  141. package/packages/cli/ARCHITECTURE.md +0 -279
  142. package/packages/cli/package.json +0 -51
  143. package/packages/cli/src/cli.ts +0 -63
  144. package/packages/cli/src/commands/check.ts +0 -166
  145. package/packages/cli/src/commands/diff.ts +0 -209
  146. package/packages/cli/src/commands/reset.ts +0 -190
  147. package/packages/cli/src/commands/setup.ts +0 -325
  148. package/packages/cli/src/commands/upgrade.ts +0 -163
  149. package/packages/cli/src/index.ts +0 -3
  150. package/packages/cli/src/templates/config.ts +0 -58
  151. package/packages/cli/src/templates/content.ts +0 -18
  152. package/packages/cli/src/templates/index.ts +0 -12
  153. package/packages/cli/src/utils/agents-md.ts +0 -66
  154. package/packages/cli/src/utils/fs.ts +0 -179
  155. package/packages/cli/src/utils/git.ts +0 -124
  156. package/packages/cli/src/utils/hooks.ts +0 -29
  157. package/packages/cli/src/utils/output.ts +0 -60
  158. package/packages/cli/src/utils/project-detector.test.ts +0 -185
  159. package/packages/cli/src/utils/project-detector.ts +0 -44
  160. package/packages/cli/src/utils/version.ts +0 -28
  161. package/packages/cli/src/version.ts +0 -6
  162. package/packages/cli/templates/SAFEWORD.md +0 -776
  163. package/packages/cli/templates/doc-templates/architecture-template.md +0 -136
  164. package/packages/cli/templates/doc-templates/design-doc-template.md +0 -134
  165. package/packages/cli/templates/doc-templates/test-definitions-feature.md +0 -131
  166. package/packages/cli/templates/doc-templates/ticket-template.md +0 -82
  167. package/packages/cli/templates/doc-templates/user-stories-template.md +0 -92
  168. package/packages/cli/templates/guides/architecture-guide.md +0 -423
  169. package/packages/cli/templates/guides/code-philosophy.md +0 -195
  170. package/packages/cli/templates/guides/context-files-guide.md +0 -457
  171. package/packages/cli/templates/guides/data-architecture-guide.md +0 -200
  172. package/packages/cli/templates/guides/design-doc-guide.md +0 -171
  173. package/packages/cli/templates/guides/learning-extraction.md +0 -552
  174. package/packages/cli/templates/guides/llm-instruction-design.md +0 -248
  175. package/packages/cli/templates/guides/llm-prompting.md +0 -102
  176. package/packages/cli/templates/guides/tdd-best-practices.md +0 -615
  177. package/packages/cli/templates/guides/test-definitions-guide.md +0 -334
  178. package/packages/cli/templates/guides/testing-methodology.md +0 -618
  179. package/packages/cli/templates/guides/user-story-guide.md +0 -256
  180. package/packages/cli/templates/guides/zombie-process-cleanup.md +0 -219
  181. package/packages/cli/templates/hooks/agents-md-check.sh +0 -27
  182. package/packages/cli/templates/hooks/post-tool.sh +0 -4
  183. package/packages/cli/templates/hooks/pre-commit.sh +0 -10
  184. package/packages/cli/templates/prompts/arch-review.md +0 -43
  185. package/packages/cli/templates/prompts/quality-review.md +0 -10
  186. package/packages/cli/templates/skills/safeword-quality-reviewer/SKILL.md +0 -207
  187. package/packages/cli/tests/commands/check.test.ts +0 -129
  188. package/packages/cli/tests/commands/cli.test.ts +0 -89
  189. package/packages/cli/tests/commands/diff.test.ts +0 -115
  190. package/packages/cli/tests/commands/reset.test.ts +0 -310
  191. package/packages/cli/tests/commands/self-healing.test.ts +0 -170
  192. package/packages/cli/tests/commands/setup-blocking.test.ts +0 -71
  193. package/packages/cli/tests/commands/setup-core.test.ts +0 -135
  194. package/packages/cli/tests/commands/setup-git.test.ts +0 -139
  195. package/packages/cli/tests/commands/setup-hooks.test.ts +0 -334
  196. package/packages/cli/tests/commands/setup-linting.test.ts +0 -189
  197. package/packages/cli/tests/commands/setup-noninteractive.test.ts +0 -80
  198. package/packages/cli/tests/commands/setup-templates.test.ts +0 -181
  199. package/packages/cli/tests/commands/upgrade.test.ts +0 -215
  200. package/packages/cli/tests/helpers.ts +0 -243
  201. package/packages/cli/tests/npm-package.test.ts +0 -83
  202. package/packages/cli/tests/technical-constraints.test.ts +0 -96
  203. package/packages/cli/tsconfig.json +0 -25
  204. package/packages/cli/tsup.config.ts +0 -11
  205. package/packages/cli/vitest.config.ts +0 -23
  206. package/promptfoo.yaml +0 -3270
  207. /package/{framework → templates}/SAFEWORD.md +0 -0
  208. /package/{packages/cli/templates → templates}/commands/arch-review.md +0 -0
  209. /package/{packages/cli/templates → templates}/commands/lint.md +0 -0
  210. /package/{packages/cli/templates → templates}/commands/quality-review.md +0 -0
  211. /package/{framework/templates → templates/doc-templates}/architecture-template.md +0 -0
  212. /package/{framework/templates → templates/doc-templates}/design-doc-template.md +0 -0
  213. /package/{framework/templates → templates/doc-templates}/test-definitions-feature.md +0 -0
  214. /package/{framework/templates → templates/doc-templates}/ticket-template.md +0 -0
  215. /package/{framework/templates → templates/doc-templates}/user-stories-template.md +0 -0
  216. /package/{framework → templates}/guides/architecture-guide.md +0 -0
  217. /package/{framework → templates}/guides/code-philosophy.md +0 -0
  218. /package/{framework → templates}/guides/context-files-guide.md +0 -0
  219. /package/{framework → templates}/guides/data-architecture-guide.md +0 -0
  220. /package/{framework → templates}/guides/design-doc-guide.md +0 -0
  221. /package/{framework → templates}/guides/learning-extraction.md +0 -0
  222. /package/{framework → templates}/guides/llm-instruction-design.md +0 -0
  223. /package/{framework → templates}/guides/llm-prompting.md +0 -0
  224. /package/{framework → templates}/guides/tdd-best-practices.md +0 -0
  225. /package/{framework → templates}/guides/test-definitions-guide.md +0 -0
  226. /package/{framework → templates}/guides/testing-methodology.md +0 -0
  227. /package/{framework → templates}/guides/user-story-guide.md +0 -0
  228. /package/{framework → templates}/guides/zombie-process-cleanup.md +0 -0
  229. /package/{packages/cli/templates → templates}/hooks/inject-timestamp.sh +0 -0
  230. /package/{packages/cli/templates → templates}/lib/common.sh +0 -0
  231. /package/{packages/cli/templates → templates}/lib/jq-fallback.sh +0 -0
  232. /package/{packages/cli/templates → templates}/markdownlint.jsonc +0 -0
  233. /package/{framework → templates}/prompts/arch-review.md +0 -0
  234. /package/{framework → templates}/prompts/quality-review.md +0 -0
  235. /package/{framework/skills/quality-reviewer → templates/skills/safeword-quality-reviewer}/SKILL.md +0 -0
@@ -1,310 +0,0 @@
1
- /**
2
- * Test Suite 11: Reset
3
- *
4
- * Tests for `safeword reset` command.
5
- */
6
-
7
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
8
- import {
9
- createTempDir,
10
- removeTempDir,
11
- createTypeScriptPackageJson,
12
- createConfiguredProject,
13
- runCli,
14
- readTestFile,
15
- writeTestFile,
16
- fileExists,
17
- initGitRepo,
18
- } from '../helpers';
19
-
20
- describe('Test Suite 11: Reset', () => {
21
- let tempDir: string;
22
-
23
- beforeEach(() => {
24
- tempDir = createTempDir();
25
- });
26
-
27
- afterEach(() => {
28
- removeTempDir(tempDir);
29
- });
30
-
31
- describe('Test 11.1: Prompts for confirmation', () => {
32
- // In TTY mode, should prompt. We test the prompt message content.
33
- it('should mention removing safeword', async () => {
34
- await createConfiguredProject(tempDir);
35
-
36
- // With --yes, it shouldn't prompt but we can check the output
37
- const result = await runCli(['reset', '--yes'], { cwd: tempDir });
38
-
39
- // Should mention what it's removing
40
- const output = result.stdout + result.stderr;
41
- expect(output.toLowerCase()).toMatch(/remov|reset|safeword/i);
42
- });
43
- });
44
-
45
- describe('Test 11.2: --yes auto-confirms', () => {
46
- it('should skip confirmation and remove .safeword', async () => {
47
- await createConfiguredProject(tempDir);
48
-
49
- expect(fileExists(tempDir, '.safeword')).toBe(true);
50
-
51
- const result = await runCli(['reset', '--yes'], { cwd: tempDir });
52
-
53
- expect(result.exitCode).toBe(0);
54
- expect(fileExists(tempDir, '.safeword')).toBe(false);
55
- });
56
- });
57
-
58
- describe('Test 11.3: No TTY auto-confirms', () => {
59
- it('should auto-confirm in non-TTY mode', async () => {
60
- await createConfiguredProject(tempDir);
61
-
62
- const result = await runCli(['reset'], {
63
- cwd: tempDir,
64
- env: { CI: 'true' },
65
- });
66
-
67
- // Should complete without hanging
68
- expect(result.exitCode).toBeDefined();
69
- });
70
- });
71
-
72
- describe('Test 11.4: Removes .safeword directory', () => {
73
- it('should remove .safeword/ completely', async () => {
74
- await createConfiguredProject(tempDir);
75
-
76
- expect(fileExists(tempDir, '.safeword')).toBe(true);
77
- expect(fileExists(tempDir, '.safeword/SAFEWORD.md')).toBe(true);
78
-
79
- await runCli(['reset', '--yes'], { cwd: tempDir });
80
-
81
- expect(fileExists(tempDir, '.safeword')).toBe(false);
82
- });
83
- });
84
-
85
- describe('Test 11.5: Removes hooks from settings.json', () => {
86
- it('should remove safeword hooks but preserve custom hooks', async () => {
87
- await createConfiguredProject(tempDir);
88
-
89
- // Add a custom hook
90
- const settings = JSON.parse(readTestFile(tempDir, '.claude/settings.json'));
91
- settings.hooks.SessionStart = settings.hooks.SessionStart || [];
92
- settings.hooks.SessionStart.push({
93
- command: 'echo "Custom preserved hook"',
94
- description: 'Custom',
95
- });
96
- writeTestFile(tempDir, '.claude/settings.json', JSON.stringify(settings, null, 2));
97
-
98
- await runCli(['reset', '--yes'], { cwd: tempDir });
99
-
100
- expect(fileExists(tempDir, '.claude/settings.json')).toBe(true);
101
-
102
- const updatedSettings = JSON.parse(readTestFile(tempDir, '.claude/settings.json'));
103
-
104
- // Custom hook preserved
105
- const hasCustom = updatedSettings.hooks?.SessionStart?.some(
106
- (h: { command?: string }) => h.command === 'echo "Custom preserved hook"',
107
- );
108
- expect(hasCustom).toBe(true);
109
-
110
- // Safeword hooks removed (no references to .safeword)
111
- const settingsStr = JSON.stringify(updatedSettings);
112
- expect(settingsStr).not.toContain('.safeword/hooks');
113
- });
114
- });
115
-
116
- describe('Test 11.6: Removes safeword skills', () => {
117
- it('should remove safeword-* skill directories', async () => {
118
- await createConfiguredProject(tempDir);
119
-
120
- // Verify skills exist after setup
121
- const skillsExist = fileExists(tempDir, '.claude/skills');
122
-
123
- await runCli(['reset', '--yes'], { cwd: tempDir });
124
-
125
- // After reset, safeword skills should be gone
126
- // but .claude/skills directory may remain if empty or have other skills
127
- if (skillsExist) {
128
- // Check no safeword-* directories remain
129
- // This would require listing directory contents
130
- // For now, verify the command completed
131
- }
132
- });
133
- });
134
-
135
- describe('Test 11.7: Removes git hook markers', () => {
136
- it('should remove safeword markers from pre-commit', async () => {
137
- createTypeScriptPackageJson(tempDir);
138
- initGitRepo(tempDir);
139
-
140
- // Create custom pre-commit content
141
- writeTestFile(
142
- tempDir,
143
- '.git/hooks/pre-commit',
144
- `#!/bin/bash
145
- # Custom content before
146
- echo "Before safeword"
147
-
148
- # SAFEWORD_ARCH_CHECK_START
149
- echo "Safeword check"
150
- # SAFEWORD_ARCH_CHECK_END
151
-
152
- # Custom content after
153
- echo "After safeword"
154
- `,
155
- );
156
-
157
- await runCli(['setup', '--yes'], { cwd: tempDir });
158
- await runCli(['reset', '--yes'], { cwd: tempDir });
159
-
160
- const content = readTestFile(tempDir, '.git/hooks/pre-commit');
161
-
162
- // Markers and content between them removed
163
- expect(content).not.toContain('SAFEWORD_ARCH_CHECK_START');
164
- expect(content).not.toContain('SAFEWORD_ARCH_CHECK_END');
165
- expect(content).not.toContain('Safeword check');
166
-
167
- // Custom content preserved
168
- expect(content).toContain('Before safeword');
169
- expect(content).toContain('After safeword');
170
- });
171
- });
172
-
173
- describe('Test 11.8: Removes link from AGENTS.md', () => {
174
- it('should remove safeword link but preserve other content', async () => {
175
- await createConfiguredProject(tempDir);
176
-
177
- // Add custom content to AGENTS.md
178
- const content = readTestFile(tempDir, 'AGENTS.md');
179
- writeTestFile(tempDir, 'AGENTS.md', content + '\n## My Custom Section\n\nCustom content.\n');
180
-
181
- await runCli(['reset', '--yes'], { cwd: tempDir });
182
-
183
- expect(fileExists(tempDir, 'AGENTS.md')).toBe(true);
184
-
185
- const updatedContent = readTestFile(tempDir, 'AGENTS.md');
186
-
187
- // Link removed
188
- expect(updatedContent).not.toContain('@./.safeword/SAFEWORD.md');
189
-
190
- // Custom content preserved
191
- expect(updatedContent).toContain('My Custom Section');
192
- expect(updatedContent).toContain('Custom content');
193
- });
194
- });
195
-
196
- describe('Test 11.9: Preserves linting config', () => {
197
- it('should keep eslint and prettier config', async () => {
198
- await createConfiguredProject(tempDir);
199
-
200
- expect(fileExists(tempDir, 'eslint.config.mjs')).toBe(true);
201
- expect(fileExists(tempDir, '.prettierrc')).toBe(true);
202
-
203
- const pkgBefore = JSON.parse(readTestFile(tempDir, 'package.json'));
204
-
205
- await runCli(['reset', '--yes'], { cwd: tempDir });
206
-
207
- // Linting files preserved
208
- expect(fileExists(tempDir, 'eslint.config.mjs')).toBe(true);
209
- expect(fileExists(tempDir, '.prettierrc')).toBe(true);
210
-
211
- // Scripts preserved
212
- const pkgAfter = JSON.parse(readTestFile(tempDir, 'package.json'));
213
- expect(pkgAfter.scripts?.lint).toBe(pkgBefore.scripts?.lint);
214
- expect(pkgAfter.scripts?.format).toBe(pkgBefore.scripts?.format);
215
- });
216
- });
217
-
218
- describe('Test 11.10: Unconfigured project message', () => {
219
- it('should show nothing to remove message', async () => {
220
- createTypeScriptPackageJson(tempDir);
221
- // No setup
222
-
223
- const result = await runCli(['reset', '--yes'], { cwd: tempDir });
224
-
225
- expect(result.exitCode).toBe(0);
226
- expect(result.stdout.toLowerCase()).toMatch(/nothing|already|not configured/i);
227
- });
228
- });
229
-
230
- describe('Test 11.11: Removes safeword slash commands', () => {
231
- it('should remove safeword commands but preserve custom ones', async () => {
232
- await createConfiguredProject(tempDir);
233
-
234
- // Verify commands directory exists after setup
235
- expect(fileExists(tempDir, '.claude/commands')).toBe(true);
236
-
237
- // Add a custom command that should be preserved
238
- writeTestFile(
239
- tempDir,
240
- '.claude/commands/my-custom-command.md',
241
- '# My Custom Command\n\nDo something custom.',
242
- );
243
-
244
- await runCli(['reset', '--yes'], { cwd: tempDir });
245
-
246
- // Custom command should be preserved
247
- expect(fileExists(tempDir, '.claude/commands/my-custom-command.md')).toBe(true);
248
- const customContent = readTestFile(tempDir, '.claude/commands/my-custom-command.md');
249
- expect(customContent).toContain('My Custom Command');
250
-
251
- // Safeword commands should be removed (quality-review, arch-review, lint)
252
- expect(fileExists(tempDir, '.claude/commands/quality-review.md')).toBe(false);
253
- });
254
- });
255
-
256
- describe('Test 11.12: Removes MCP servers from .mcp.json', () => {
257
- it('should remove context7 and playwright servers', async () => {
258
- await createConfiguredProject(tempDir);
259
-
260
- // Verify MCP config exists
261
- expect(fileExists(tempDir, '.mcp.json')).toBe(true);
262
-
263
- // Add a custom MCP server
264
- const mcpConfig = JSON.parse(readTestFile(tempDir, '.mcp.json'));
265
- mcpConfig.mcpServers['my-custom-server'] = {
266
- command: 'my-server',
267
- args: ['--port', '3000'],
268
- };
269
- writeTestFile(tempDir, '.mcp.json', JSON.stringify(mcpConfig, null, 2));
270
-
271
- await runCli(['reset', '--yes'], { cwd: tempDir });
272
-
273
- // .mcp.json should still exist with custom server
274
- expect(fileExists(tempDir, '.mcp.json')).toBe(true);
275
-
276
- const updatedConfig = JSON.parse(readTestFile(tempDir, '.mcp.json'));
277
-
278
- // Custom server preserved
279
- expect(updatedConfig.mcpServers['my-custom-server']).toBeDefined();
280
- expect(updatedConfig.mcpServers['my-custom-server'].command).toBe('my-server');
281
-
282
- // Safeword servers removed
283
- expect(updatedConfig.mcpServers.context7).toBeUndefined();
284
- expect(updatedConfig.mcpServers.playwright).toBeUndefined();
285
- });
286
-
287
- it('should delete or empty .mcp.json if only safeword servers remain', async () => {
288
- await createConfiguredProject(tempDir);
289
-
290
- // Overwrite with only safeword servers
291
- const mcpConfig = {
292
- mcpServers: {
293
- context7: { command: 'npx', args: ['@context7/mcp'] },
294
- playwright: { command: 'npx', args: ['@playwright/mcp'] },
295
- },
296
- };
297
- writeTestFile(tempDir, '.mcp.json', JSON.stringify(mcpConfig, null, 2));
298
-
299
- await runCli(['reset', '--yes'], { cwd: tempDir });
300
-
301
- // Either .mcp.json is deleted OR mcpServers is empty
302
- if (fileExists(tempDir, '.mcp.json')) {
303
- const updatedConfig = JSON.parse(readTestFile(tempDir, '.mcp.json'));
304
- const serverCount = Object.keys(updatedConfig.mcpServers || {}).length;
305
- expect(serverCount).toBe(0);
306
- }
307
- // If file doesn't exist, test passes implicitly
308
- });
309
- });
310
- });
@@ -1,170 +0,0 @@
1
- /**
2
- * Test Suite 12: AGENTS.md Self-Healing
3
- *
4
- * Tests for SessionStart hook that maintains AGENTS.md link.
5
- */
6
-
7
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
8
- import { execSync } from 'node:child_process';
9
- import { join } from 'node:path';
10
- import {
11
- createTempDir,
12
- removeTempDir,
13
- createConfiguredProject,
14
- runCli,
15
- readTestFile,
16
- writeTestFile,
17
- fileExists,
18
- measureTimeSync,
19
- } from '../helpers';
20
- import { unlinkSync } from 'node:fs';
21
-
22
- describe('Test Suite 12: AGENTS.md Self-Healing', () => {
23
- let tempDir: string;
24
-
25
- beforeEach(() => {
26
- tempDir = createTempDir();
27
- });
28
-
29
- afterEach(() => {
30
- removeTempDir(tempDir);
31
- });
32
-
33
- /**
34
- * Helper to run the self-healing hook script
35
- */
36
- function runSelfHealingHook(dir: string): { stdout: string; exitCode: number } {
37
- // The hook script location depends on implementation
38
- // Typically: .safeword/hooks/agents-md-check.sh
39
- const hookPath = join(dir, '.safeword/hooks/agents-md-check.sh');
40
-
41
- if (!fileExists(dir, '.safeword/hooks/agents-md-check.sh')) {
42
- // Hook may have different name - check for any agents-related hook
43
- // For now, return a placeholder
44
- return { stdout: '', exitCode: 0 };
45
- }
46
-
47
- try {
48
- const stdout = execSync(`bash "${hookPath}"`, {
49
- cwd: dir,
50
- encoding: 'utf-8',
51
- stdio: ['pipe', 'pipe', 'pipe'],
52
- });
53
- return { stdout, exitCode: 0 };
54
- } catch (error: unknown) {
55
- const execError = error as { stdout?: string; status?: number };
56
- return {
57
- stdout: execError.stdout ?? '',
58
- exitCode: execError.status ?? 1,
59
- };
60
- }
61
- }
62
-
63
- describe('Test 12.1: Hook detects missing link', () => {
64
- it('should detect when safeword link is missing', async () => {
65
- await createConfiguredProject(tempDir);
66
-
67
- // Remove the safeword link from AGENTS.md
68
- const content = readTestFile(tempDir, 'AGENTS.md');
69
- const withoutLink = content
70
- .split('\n')
71
- .filter(line => !line.includes('@./.safeword/SAFEWORD.md'))
72
- .join('\n');
73
- writeTestFile(tempDir, 'AGENTS.md', withoutLink);
74
-
75
- const result = runSelfHealingHook(tempDir);
76
-
77
- // Hook should indicate repair is needed or perform repair
78
- // The exact output depends on implementation
79
- expect(result.exitCode).toBeDefined();
80
- });
81
- });
82
-
83
- describe('Test 12.2: Hook re-adds missing link', () => {
84
- it('should restore removed link', async () => {
85
- await createConfiguredProject(tempDir);
86
-
87
- // Remove the safeword link
88
- const content = readTestFile(tempDir, 'AGENTS.md');
89
- const withoutLink = '# My Project\n\nSome content without the link.\n';
90
- writeTestFile(tempDir, 'AGENTS.md', withoutLink);
91
-
92
- // Run hook
93
- runSelfHealingHook(tempDir);
94
-
95
- // Link should be restored
96
- const updatedContent = readTestFile(tempDir, 'AGENTS.md');
97
- expect(updatedContent).toContain('@./.safeword/SAFEWORD.md');
98
-
99
- // Original content preserved
100
- expect(updatedContent).toContain('My Project');
101
- expect(updatedContent).toContain('Some content');
102
- });
103
- });
104
-
105
- describe('Test 12.3: Hook shows warning on restoration', () => {
106
- it('should output message when restoring', async () => {
107
- await createConfiguredProject(tempDir);
108
-
109
- // Remove link
110
- writeTestFile(tempDir, 'AGENTS.md', '# No link\n');
111
-
112
- const result = runSelfHealingHook(tempDir);
113
-
114
- // Should mention restoration
115
- const output = result.stdout.toLowerCase();
116
- expect(output).toMatch(/restor|repair|add|fix|agents/i);
117
- });
118
- });
119
-
120
- describe('Test 12.4: Hook recreates deleted AGENTS.md', () => {
121
- it('should recreate AGENTS.md if deleted', async () => {
122
- await createConfiguredProject(tempDir);
123
-
124
- // Delete AGENTS.md entirely
125
- unlinkSync(join(tempDir, 'AGENTS.md'));
126
- expect(fileExists(tempDir, 'AGENTS.md')).toBe(false);
127
-
128
- // Run hook
129
- runSelfHealingHook(tempDir);
130
-
131
- // AGENTS.md should be recreated
132
- expect(fileExists(tempDir, 'AGENTS.md')).toBe(true);
133
-
134
- const content = readTestFile(tempDir, 'AGENTS.md');
135
- expect(content).toContain('@./.safeword/SAFEWORD.md');
136
- });
137
- });
138
-
139
- describe('Test 12.5: Hook prevents duplicates', () => {
140
- it('should not add duplicate links', async () => {
141
- await createConfiguredProject(tempDir);
142
-
143
- // Verify link exists
144
- const contentBefore = readTestFile(tempDir, 'AGENTS.md');
145
- expect(contentBefore).toContain('@./.safeword/SAFEWORD.md');
146
-
147
- // Run hook multiple times
148
- runSelfHealingHook(tempDir);
149
- runSelfHealingHook(tempDir);
150
- runSelfHealingHook(tempDir);
151
-
152
- // Count links
153
- const contentAfter = readTestFile(tempDir, 'AGENTS.md');
154
- const linkCount = (contentAfter.match(/@\.\/\.safeword\/SAFEWORD\.md/g) || []).length;
155
-
156
- expect(linkCount).toBe(1);
157
- });
158
- });
159
-
160
- describe('Test 12.6: Hook exits cleanly', () => {
161
- it('should exit with code 0 and complete quickly', async () => {
162
- await createConfiguredProject(tempDir);
163
-
164
- const { result, timeMs } = measureTimeSync(() => runSelfHealingHook(tempDir));
165
-
166
- expect(result.exitCode).toBe(0);
167
- expect(timeMs).toBeLessThan(1000); // Should complete in under 1 second
168
- });
169
- });
170
- });
@@ -1,71 +0,0 @@
1
- /**
2
- * Test Suite 5: Setup Blocks on Existing
3
- *
4
- * Tests for setup error when already configured.
5
- */
6
-
7
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
8
- import { mkdirSync } from 'node:fs';
9
- import { join } from 'node:path';
10
- import {
11
- createTempDir,
12
- removeTempDir,
13
- createTypeScriptPackageJson,
14
- runCli,
15
- readTestFile,
16
- writeTestFile,
17
- fileExists,
18
- } from '../helpers';
19
-
20
- describe('Test Suite 5: Setup Blocks on Existing', () => {
21
- let tempDir: string;
22
-
23
- beforeEach(() => {
24
- tempDir = createTempDir();
25
- });
26
-
27
- afterEach(() => {
28
- removeTempDir(tempDir);
29
- });
30
-
31
- describe('Test 5.1: Error when .safeword exists', () => {
32
- it('should error with exit 1 when .safeword/ already exists', async () => {
33
- createTypeScriptPackageJson(tempDir);
34
-
35
- // Create existing .safeword directory
36
- mkdirSync(join(tempDir, '.safeword'));
37
-
38
- const result = await runCli(['setup'], { cwd: tempDir });
39
-
40
- expect(result.exitCode).toBe(1);
41
- expect(result.stderr.toLowerCase()).toContain('already configured');
42
- expect(result.stderr.toLowerCase()).toContain('upgrade');
43
- });
44
- });
45
-
46
- describe('Test 5.2: No files modified on error', () => {
47
- it('should not modify files when erroring', async () => {
48
- createTypeScriptPackageJson(tempDir);
49
-
50
- // Create existing .safeword directory
51
- mkdirSync(join(tempDir, '.safeword'));
52
-
53
- // Create AGENTS.md with known content
54
- const originalContent = '# Original AGENTS.md\n\nThis should not change.\n';
55
- writeTestFile(tempDir, 'AGENTS.md', originalContent);
56
-
57
- const result = await runCli(['setup'], { cwd: tempDir });
58
-
59
- expect(result.exitCode).toBe(1);
60
-
61
- // AGENTS.md should be unchanged
62
- const content = readTestFile(tempDir, 'AGENTS.md');
63
- expect(content).toBe(originalContent);
64
-
65
- // No new files should be created
66
- expect(fileExists(tempDir, '.claude')).toBe(false);
67
- expect(fileExists(tempDir, 'eslint.config.mjs')).toBe(false);
68
- expect(fileExists(tempDir, '.prettierrc')).toBe(false);
69
- });
70
- });
71
- });
@@ -1,135 +0,0 @@
1
- /**
2
- * Test Suite 2: Setup - Core Files
3
- *
4
- * Tests for .safeword/ directory creation and AGENTS.md handling.
5
- */
6
-
7
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
8
- import {
9
- createTempDir,
10
- removeTempDir,
11
- createTypeScriptPackageJson,
12
- runCli,
13
- readTestFile,
14
- writeTestFile,
15
- fileExists,
16
- initGitRepo,
17
- createConfiguredProject,
18
- } from '../helpers';
19
-
20
- describe('Test Suite 2: Setup - Core Files', () => {
21
- let tempDir: string;
22
-
23
- beforeEach(() => {
24
- tempDir = createTempDir();
25
- });
26
-
27
- afterEach(() => {
28
- removeTempDir(tempDir);
29
- });
30
-
31
- describe('Test 2.1: Creates .safeword directory structure', () => {
32
- it('should create complete .safeword/ directory', async () => {
33
- createTypeScriptPackageJson(tempDir);
34
- initGitRepo(tempDir);
35
-
36
- const result = await runCli(['setup', '--yes'], { cwd: tempDir });
37
-
38
- expect(result.exitCode).toBe(0);
39
-
40
- // Core structure
41
- expect(fileExists(tempDir, '.safeword')).toBe(true);
42
- expect(fileExists(tempDir, '.safeword/SAFEWORD.md')).toBe(true);
43
- expect(fileExists(tempDir, '.safeword/version')).toBe(true);
44
-
45
- // Subdirectories
46
- expect(fileExists(tempDir, '.safeword/guides')).toBe(true);
47
- expect(fileExists(tempDir, '.safeword/templates')).toBe(true);
48
- expect(fileExists(tempDir, '.safeword/hooks')).toBe(true);
49
- });
50
-
51
- it('should write CLI version to .safeword/version', async () => {
52
- createTypeScriptPackageJson(tempDir);
53
- initGitRepo(tempDir);
54
-
55
- await runCli(['setup', '--yes'], { cwd: tempDir });
56
-
57
- const version = readTestFile(tempDir, '.safeword/version').trim();
58
- // Should be semver format
59
- expect(version).toMatch(/^\d+\.\d+\.\d+(-[\w.]+)?$/);
60
- });
61
- });
62
-
63
- describe('Test 2.2: Creates AGENTS.md if missing', () => {
64
- it('should create AGENTS.md with safeword link', async () => {
65
- createTypeScriptPackageJson(tempDir);
66
- initGitRepo(tempDir);
67
-
68
- await runCli(['setup', '--yes'], { cwd: tempDir });
69
-
70
- expect(fileExists(tempDir, 'AGENTS.md')).toBe(true);
71
-
72
- const content = readTestFile(tempDir, 'AGENTS.md');
73
- expect(content).toContain('**⚠️ ALWAYS READ FIRST: @./.safeword/SAFEWORD.md**');
74
- });
75
- });
76
-
77
- describe('Test 2.3: Prepends link to existing AGENTS.md', () => {
78
- it('should prepend link without losing content', async () => {
79
- createTypeScriptPackageJson(tempDir);
80
- initGitRepo(tempDir);
81
-
82
- // Create existing AGENTS.md
83
- const existingContent = '# My Project\n\nExisting content here.\n';
84
- writeTestFile(tempDir, 'AGENTS.md', existingContent);
85
-
86
- await runCli(['setup', '--yes'], { cwd: tempDir });
87
-
88
- const content = readTestFile(tempDir, 'AGENTS.md');
89
-
90
- // Link should be first
91
- const lines = content.split('\n');
92
- expect(lines[0]).toContain('**⚠️ ALWAYS READ FIRST: @./.safeword/SAFEWORD.md**');
93
-
94
- // Original content preserved
95
- expect(content).toContain('# My Project');
96
- expect(content).toContain('Existing content here.');
97
- });
98
- });
99
-
100
- describe('Test 2.4: No duplicate links in AGENTS.md on upgrade', () => {
101
- it('should not add duplicate link on upgrade', async () => {
102
- // First setup
103
- await createConfiguredProject(tempDir);
104
-
105
- // Verify link exists
106
- const contentBefore = readTestFile(tempDir, 'AGENTS.md');
107
- const linkCount = (contentBefore.match(/@\.\/\.safeword\/SAFEWORD\.md/g) || []).length;
108
- expect(linkCount).toBe(1);
109
-
110
- // Run upgrade
111
- await runCli(['upgrade'], { cwd: tempDir });
112
-
113
- // Count links after
114
- const contentAfter = readTestFile(tempDir, 'AGENTS.md');
115
- const linkCountAfter = (contentAfter.match(/@\.\/\.safeword\/SAFEWORD\.md/g) || []).length;
116
-
117
- expect(linkCountAfter).toBe(1);
118
- });
119
- });
120
-
121
- describe('Test 2.5: Prints summary of created files', () => {
122
- it('should output summary of created files', async () => {
123
- createTypeScriptPackageJson(tempDir);
124
- initGitRepo(tempDir);
125
-
126
- const result = await runCli(['setup', '--yes'], { cwd: tempDir });
127
-
128
- expect(result.exitCode).toBe(0);
129
-
130
- // Should mention what was created
131
- expect(result.stdout).toMatch(/created|Created/i);
132
- expect(result.stdout).toMatch(/\.safeword|safeword/i);
133
- });
134
- });
135
- });