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,80 +0,0 @@
1
- /**
2
- * Test Suite 6: Non-Interactive Setup
3
- *
4
- * Tests for CI/headless operation.
5
- */
6
-
7
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
8
- import {
9
- createTempDir,
10
- removeTempDir,
11
- createTypeScriptPackageJson,
12
- runCli,
13
- fileExists,
14
- } from '../helpers';
15
-
16
- describe('Test Suite 6: Non-Interactive Setup', () => {
17
- let tempDir: string;
18
-
19
- beforeEach(() => {
20
- tempDir = createTempDir();
21
- });
22
-
23
- afterEach(() => {
24
- removeTempDir(tempDir);
25
- });
26
-
27
- describe('Test 6.1: --yes flag skips all prompts', () => {
28
- it('should complete without hanging', async () => {
29
- createTypeScriptPackageJson(tempDir);
30
- // No git init - should skip git prompt with --yes
31
-
32
- const result = await runCli(['setup', '--yes'], {
33
- cwd: tempDir,
34
- timeout: 30000,
35
- });
36
-
37
- expect(result.exitCode).toBe(0);
38
- expect(fileExists(tempDir, '.safeword')).toBe(true);
39
-
40
- // Git should be skipped (no .git created)
41
- expect(fileExists(tempDir, '.git')).toBe(false);
42
- });
43
- });
44
-
45
- describe('Test 6.2: No TTY uses defaults', () => {
46
- it('should complete without stdin in non-TTY mode', async () => {
47
- createTypeScriptPackageJson(tempDir);
48
- // No git init
49
-
50
- // Force non-TTY by setting environment
51
- const result = await runCli(['setup'], {
52
- cwd: tempDir,
53
- timeout: 30000,
54
- env: {
55
- CI: 'true', // Many tools detect CI and use non-interactive mode
56
- TERM: 'dumb',
57
- },
58
- });
59
-
60
- // Should complete (either with defaults or --yes required message)
61
- // The exact behavior depends on implementation
62
- expect(result.exitCode).toBeDefined();
63
- });
64
- });
65
-
66
- describe('Test 6.3: Warning shown when git skipped', () => {
67
- it('should show warning about skipped git initialization', async () => {
68
- createTypeScriptPackageJson(tempDir);
69
- // No git init
70
-
71
- const result = await runCli(['setup', '--yes'], { cwd: tempDir });
72
-
73
- expect(result.exitCode).toBe(0);
74
-
75
- // Should mention skipped git
76
- const output = result.stdout + result.stderr;
77
- expect(output.toLowerCase()).toMatch(/skipped|git|warning/i);
78
- });
79
- });
80
- });
@@ -1,181 +0,0 @@
1
- /**
2
- * Test Suite: Setup - Template Bundling (Story 1)
3
- *
4
- * Tests for the "self-contained templates" feature.
5
- * The CLI should bundle full methodology files (not stubs) so
6
- * `npx safeword setup` works without external dependencies.
7
- *
8
- * First 3 tests FAIL until Story 1 is implemented.
9
- */
10
-
11
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
12
- import { readdirSync, readFileSync } from 'node:fs';
13
- import { join } from 'node:path';
14
- import {
15
- createTempDir,
16
- removeTempDir,
17
- createTypeScriptPackageJson,
18
- runCli,
19
- readTestFile,
20
- writeTestFile,
21
- fileExists,
22
- initGitRepo,
23
- } from '../helpers';
24
-
25
- describe('Setup - Template Bundling (Story 1)', () => {
26
- let tempDir: string;
27
-
28
- beforeEach(() => {
29
- tempDir = createTempDir();
30
- });
31
-
32
- afterEach(() => {
33
- removeTempDir(tempDir);
34
- });
35
-
36
- it('should install full SAFEWORD.md (not a stub)', async () => {
37
- createTypeScriptPackageJson(tempDir);
38
- initGitRepo(tempDir);
39
-
40
- await runCli(['setup', '--yes'], { cwd: tempDir });
41
-
42
- expect(fileExists(tempDir, '.safeword/SAFEWORD.md')).toBe(true);
43
-
44
- const content = readTestFile(tempDir, '.safeword/SAFEWORD.md');
45
- // Full file is ~31KB, stub is <1KB
46
- expect(content.length).toBeGreaterThan(1000);
47
- // Verify it's the full methodology file, not a stub
48
- expect(content).toContain('# Global Instructions for AI Coding Agents');
49
- });
50
-
51
- it('should install methodology guides to .safeword/guides/', async () => {
52
- createTypeScriptPackageJson(tempDir);
53
- initGitRepo(tempDir);
54
-
55
- await runCli(['setup', '--yes'], { cwd: tempDir });
56
-
57
- expect(fileExists(tempDir, '.safeword/guides')).toBe(true);
58
-
59
- const guidesDir = join(tempDir, '.safeword/guides');
60
- const mdFiles = readdirSync(guidesDir).filter((f) => f.endsWith('.md'));
61
-
62
- expect(mdFiles.length).toBeGreaterThan(0);
63
- });
64
-
65
- it('should install document templates', async () => {
66
- createTypeScriptPackageJson(tempDir);
67
- initGitRepo(tempDir);
68
-
69
- await runCli(['setup', '--yes'], { cwd: tempDir });
70
-
71
- expect(fileExists(tempDir, '.safeword/templates')).toBe(true);
72
-
73
- const templatesDir = join(tempDir, '.safeword/templates');
74
- const mdFiles = readdirSync(templatesDir).filter((f) => f.endsWith('.md'));
75
-
76
- expect(mdFiles.length).toBeGreaterThan(0);
77
- });
78
-
79
- it('should install review prompts to .safeword/prompts/', async () => {
80
- createTypeScriptPackageJson(tempDir);
81
- initGitRepo(tempDir);
82
-
83
- await runCli(['setup', '--yes'], { cwd: tempDir });
84
-
85
- expect(fileExists(tempDir, '.safeword/prompts')).toBe(true);
86
-
87
- const promptsDir = join(tempDir, '.safeword/prompts');
88
- const mdFiles = readdirSync(promptsDir).filter((f) => f.endsWith('.md'));
89
-
90
- // Should have 2 review prompts
91
- expect(mdFiles.length).toBeGreaterThan(0);
92
- });
93
-
94
- it('should block re-run and preserve user content', async () => {
95
- createTypeScriptPackageJson(tempDir);
96
- initGitRepo(tempDir);
97
-
98
- await runCli(['setup', '--yes'], { cwd: tempDir });
99
-
100
- // Create user content
101
- writeTestFile(
102
- tempDir,
103
- '.safeword/learnings/my-learning.md',
104
- '# My Learning\n\nImportant info.',
105
- );
106
-
107
- // Re-run setup should exit with error (already configured)
108
- const result = await runCli(['setup', '--yes'], { cwd: tempDir });
109
- expect(result.exitCode).toBe(1);
110
- expect(result.stderr).toContain('Already configured');
111
-
112
- // User content should be untouched
113
- expect(fileExists(tempDir, '.safeword/learnings/my-learning.md')).toBe(true);
114
- const content = readTestFile(tempDir, '.safeword/learnings/my-learning.md');
115
- expect(content).toContain('My Learning');
116
- });
117
-
118
- it('should have no broken internal links in installed templates', async () => {
119
- createTypeScriptPackageJson(tempDir);
120
- initGitRepo(tempDir);
121
-
122
- await runCli(['setup', '--yes'], { cwd: tempDir });
123
-
124
- // Collect all markdown files in .safeword/
125
- const safewordDir = join(tempDir, '.safeword');
126
- const allMdFiles: string[] = [];
127
-
128
- function collectMdFiles(dir: string) {
129
- if (!fileExists(tempDir, dir.replace(tempDir + '/', ''))) return;
130
- const entries = readdirSync(dir, { withFileTypes: true });
131
- for (const entry of entries) {
132
- const fullPath = join(dir, entry.name);
133
- if (entry.isDirectory()) {
134
- collectMdFiles(fullPath);
135
- } else if (entry.name.endsWith('.md')) {
136
- allMdFiles.push(fullPath);
137
- }
138
- }
139
- }
140
-
141
- collectMdFiles(safewordDir);
142
-
143
- // Must have at least SAFEWORD.md with links to verify
144
- expect(allMdFiles.length).toBeGreaterThan(0);
145
-
146
- // Extract all @./.safeword/ links and verify targets exist
147
- // Pattern: @./.safeword/path.md - stop at whitespace, backticks, quotes, parens, or markdown formatting
148
- const linkPattern = /@\.\/\.safeword\/[a-zA-Z0-9_\-/]+\.md/g;
149
- const brokenLinks: { file: string; link: string }[] = [];
150
- let totalLinks = 0;
151
-
152
- for (const mdFile of allMdFiles) {
153
- const content = readFileSync(mdFile, 'utf-8');
154
- const links = content.match(linkPattern) || [];
155
- totalLinks += links.length;
156
-
157
- for (const link of links) {
158
- // Convert @./.safeword/path to relative path
159
- const relativePath = link.replace('@./', '');
160
-
161
- if (!fileExists(tempDir, relativePath)) {
162
- brokenLinks.push({
163
- file: mdFile.replace(tempDir + '/', ''),
164
- link,
165
- });
166
- }
167
- }
168
- }
169
-
170
- // Report all broken links
171
- if (brokenLinks.length > 0) {
172
- const report = brokenLinks
173
- .map((b) => ` ${b.file}: ${b.link}`)
174
- .join('\n');
175
- expect.fail(`Found ${brokenLinks.length} broken links:\n${report}`);
176
- }
177
-
178
- // Should have found at least some links to validate
179
- expect(totalLinks).toBeGreaterThan(0);
180
- });
181
- });
@@ -1,215 +0,0 @@
1
- /**
2
- * Test Suite 9: Upgrade
3
- *
4
- * Tests for `safeword upgrade` 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
- } from '../helpers';
18
-
19
- describe('Test Suite 9: Upgrade', () => {
20
- let tempDir: string;
21
-
22
- beforeEach(() => {
23
- tempDir = createTempDir();
24
- });
25
-
26
- afterEach(() => {
27
- removeTempDir(tempDir);
28
- });
29
-
30
- describe('Test 9.1: Overwrites .safeword files', () => {
31
- it('should restore modified files to CLI version', async () => {
32
- await createConfiguredProject(tempDir);
33
-
34
- // Modify a safeword file
35
- const originalContent = readTestFile(tempDir, '.safeword/SAFEWORD.md');
36
- writeTestFile(tempDir, '.safeword/SAFEWORD.md', '# Modified content\n');
37
-
38
- await runCli(['upgrade'], { cwd: tempDir });
39
-
40
- const restoredContent = readTestFile(tempDir, '.safeword/SAFEWORD.md');
41
- // Should be restored (not the modified content)
42
- expect(restoredContent).not.toBe('# Modified content\n');
43
- });
44
-
45
- it('should update .safeword/version', async () => {
46
- await createConfiguredProject(tempDir);
47
-
48
- // Set an older version
49
- writeTestFile(tempDir, '.safeword/version', '0.0.1');
50
-
51
- await runCli(['upgrade'], { cwd: tempDir });
52
-
53
- const version = readTestFile(tempDir, '.safeword/version').trim();
54
- expect(version).not.toBe('0.0.1');
55
- expect(version).toMatch(/^\d+\.\d+\.\d+/);
56
- });
57
- });
58
-
59
- describe('Test 9.2: Updates skills', () => {
60
- it('should restore modified skill files', async () => {
61
- await createConfiguredProject(tempDir);
62
-
63
- // Find and modify a skill file if it exists
64
- if (fileExists(tempDir, '.claude/skills')) {
65
- // The actual skill path depends on implementation
66
- // This test structure is correct for when skills are implemented
67
- }
68
-
69
- const result = await runCli(['upgrade'], { cwd: tempDir });
70
- expect(result.exitCode).toBe(0);
71
- });
72
- });
73
-
74
- describe('Test 9.3: Preserves non-safeword hooks', () => {
75
- it('should preserve custom hooks', async () => {
76
- await createConfiguredProject(tempDir);
77
-
78
- // Add a custom hook
79
- const settings = JSON.parse(readTestFile(tempDir, '.claude/settings.json'));
80
- settings.hooks = settings.hooks || {};
81
- settings.hooks.SessionStart = settings.hooks.SessionStart || [];
82
- settings.hooks.SessionStart.push({
83
- command: 'echo "My custom hook"',
84
- description: 'Custom hook',
85
- });
86
- writeTestFile(tempDir, '.claude/settings.json', JSON.stringify(settings, null, 2));
87
-
88
- await runCli(['upgrade'], { cwd: tempDir });
89
-
90
- const updatedSettings = JSON.parse(readTestFile(tempDir, '.claude/settings.json'));
91
- const hasCustomHook = updatedSettings.hooks.SessionStart.some(
92
- (hook: { command?: string }) => hook.command === 'echo "My custom hook"',
93
- );
94
-
95
- expect(hasCustomHook).toBe(true);
96
- });
97
- });
98
-
99
- describe('Test 9.4: Same-version reinstalls', () => {
100
- it('should restore files even at same version', async () => {
101
- await createConfiguredProject(tempDir);
102
-
103
- // Get current version
104
- const version = readTestFile(tempDir, '.safeword/version').trim();
105
-
106
- // Modify a file
107
- writeTestFile(tempDir, '.safeword/SAFEWORD.md', '# Corrupted\n');
108
-
109
- await runCli(['upgrade'], { cwd: tempDir });
110
-
111
- // File should be restored
112
- const content = readTestFile(tempDir, '.safeword/SAFEWORD.md');
113
- expect(content).not.toBe('# Corrupted\n');
114
-
115
- // Version should remain same
116
- const newVersion = readTestFile(tempDir, '.safeword/version').trim();
117
- expect(newVersion).toBe(version);
118
- });
119
- });
120
-
121
- describe('Test 9.5: Refuses to downgrade', () => {
122
- it('should error when project is newer than CLI', async () => {
123
- await createConfiguredProject(tempDir);
124
-
125
- // Set a future version
126
- writeTestFile(tempDir, '.safeword/version', '99.99.99');
127
-
128
- const result = await runCli(['upgrade'], { cwd: tempDir });
129
-
130
- expect(result.exitCode).toBe(1);
131
- expect(result.stderr.toLowerCase()).toMatch(/older|downgrade|cli|update/i);
132
- });
133
- });
134
-
135
- describe('Test 9.6: Unconfigured project error', () => {
136
- it('should error on unconfigured project', async () => {
137
- createTypeScriptPackageJson(tempDir);
138
- // No setup
139
-
140
- const result = await runCli(['upgrade'], { cwd: tempDir });
141
-
142
- expect(result.exitCode).toBe(1);
143
- expect(result.stderr.toLowerCase()).toContain('not configured');
144
- expect(result.stderr.toLowerCase()).toContain('setup');
145
- });
146
- });
147
-
148
- describe('Test 9.7: Prints summary of changes', () => {
149
- it('should show what changed', async () => {
150
- await createConfiguredProject(tempDir);
151
-
152
- // Modify to create changes
153
- writeTestFile(tempDir, '.safeword/version', '0.0.1');
154
-
155
- const result = await runCli(['upgrade'], { cwd: tempDir });
156
-
157
- expect(result.exitCode).toBe(0);
158
- // Should show some summary of changes
159
- expect(result.stdout.toLowerCase()).toMatch(/upgrad|update|version|file/i);
160
- });
161
- });
162
-
163
- describe('Test 9.8: Preserves learnings directory', () => {
164
- it('should preserve user learnings on upgrade', async () => {
165
- await createConfiguredProject(tempDir);
166
-
167
- // Create user learning file
168
- writeTestFile(
169
- tempDir,
170
- '.safeword/learnings/my-custom-learning.md',
171
- '# My Learning\n\nImportant discovery about the codebase.',
172
- );
173
-
174
- // Modify version to trigger upgrade
175
- writeTestFile(tempDir, '.safeword/version', '0.0.1');
176
-
177
- await runCli(['upgrade'], { cwd: tempDir });
178
-
179
- // User learning should be preserved
180
- expect(fileExists(tempDir, '.safeword/learnings/my-custom-learning.md')).toBe(true);
181
-
182
- const content = readTestFile(tempDir, '.safeword/learnings/my-custom-learning.md');
183
- expect(content).toContain('My Learning');
184
- expect(content).toContain('Important discovery');
185
- });
186
- });
187
-
188
- describe('Test 9.9: Creates backup before upgrade', () => {
189
- it('should create .safeword.backup directory', async () => {
190
- await createConfiguredProject(tempDir);
191
-
192
- // Modify version to trigger upgrade
193
- writeTestFile(tempDir, '.safeword/version', '0.0.1');
194
-
195
- // Check for backup during upgrade (it may be deleted after success)
196
- // We verify by checking that upgrade succeeds without data loss
197
- const originalSafeword = readTestFile(tempDir, '.safeword/SAFEWORD.md');
198
-
199
- await runCli(['upgrade'], { cwd: tempDir });
200
-
201
- // After successful upgrade, backup should be deleted
202
- expect(fileExists(tempDir, '.safeword.backup')).toBe(false);
203
-
204
- // Files should still exist
205
- expect(fileExists(tempDir, '.safeword/SAFEWORD.md')).toBe(true);
206
- });
207
- });
208
-
209
- describe('Test 9.10: Restores backup on failure', () => {
210
- it.skip('should restore from backup if upgrade fails mid-way', async () => {
211
- // This test would require a way to force upgrade failure
212
- // Skipped as it requires mocking internal failures
213
- });
214
- });
215
- });