safeword 0.2.4 → 0.2.5

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-RR4M334C.js +266 -0
  22. package/dist/setup-RR4M334C.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,325 +0,0 @@
1
- /**
2
- * Setup command - Initialize safeword in a project
3
- */
4
-
5
- import { join } from 'node:path';
6
- import { VERSION } from '../version.js';
7
- import {
8
- exists,
9
- ensureDir,
10
- writeFile,
11
- readJson,
12
- writeJson,
13
- updateJson,
14
- copyDir,
15
- copyFile,
16
- getTemplatesDir,
17
- makeScriptsExecutable,
18
- } from '../utils/fs.js';
19
- import { info, success, warn, error, header, listItem } from '../utils/output.js';
20
- import { isGitRepo, installGitHook } from '../utils/git.js';
21
- import { detectProjectType } from '../utils/project-detector.js';
22
- import { filterOutSafewordHooks } from '../utils/hooks.js';
23
- import { ensureAgentsMdLink } from '../utils/agents-md.js';
24
- import { PRETTIERRC, getEslintConfig, SETTINGS_HOOKS } from '../templates/index.js';
25
-
26
- export interface SetupOptions {
27
- yes?: boolean;
28
- }
29
-
30
- interface PackageJson {
31
- name?: string;
32
- version?: string;
33
- scripts?: Record<string, string>;
34
- dependencies?: Record<string, string>;
35
- devDependencies?: Record<string, string>;
36
- }
37
-
38
- export async function setup(options: SetupOptions): Promise<void> {
39
- const cwd = process.cwd();
40
- const safewordDir = join(cwd, '.safeword');
41
-
42
- // Check if already configured
43
- if (exists(safewordDir)) {
44
- error('Already configured. Run `safeword upgrade` to update.');
45
- process.exit(1);
46
- }
47
-
48
- // Check for package.json
49
- const packageJsonPath = join(cwd, 'package.json');
50
- if (!exists(packageJsonPath)) {
51
- error('No package.json found. Run this command in a Node.js project.');
52
- process.exit(1);
53
- }
54
-
55
- const isNonInteractive = options.yes || !process.stdin.isTTY;
56
-
57
- header('Safeword Setup');
58
- info(`Version: ${VERSION}`);
59
-
60
- // Track created files for summary
61
- const created: string[] = [];
62
- const modified: string[] = [];
63
-
64
- try {
65
- const templatesDir = getTemplatesDir();
66
-
67
- // 1. Create .safeword directory structure and copy templates
68
- info('\nCreating .safeword directory...');
69
-
70
- ensureDir(safewordDir);
71
- ensureDir(join(safewordDir, 'learnings'));
72
- ensureDir(join(safewordDir, 'planning', 'user-stories'));
73
- ensureDir(join(safewordDir, 'planning', 'design'));
74
- ensureDir(join(safewordDir, 'tickets', 'completed'));
75
-
76
- // Copy full SAFEWORD.md from templates
77
- copyFile(join(templatesDir, 'SAFEWORD.md'), join(safewordDir, 'SAFEWORD.md'));
78
- writeFile(join(safewordDir, 'version'), VERSION);
79
-
80
- // Copy methodology guides
81
- copyDir(join(templatesDir, 'guides'), join(safewordDir, 'guides'));
82
-
83
- // Copy document templates (to 'templates' to match links in SAFEWORD.md)
84
- copyDir(join(templatesDir, 'doc-templates'), join(safewordDir, 'templates'));
85
-
86
- // Copy review prompts
87
- copyDir(join(templatesDir, 'prompts'), join(safewordDir, 'prompts'));
88
-
89
- // Copy lib scripts and make executable
90
- copyDir(join(templatesDir, 'lib'), join(safewordDir, 'lib'));
91
- makeScriptsExecutable(join(safewordDir, 'lib'));
92
-
93
- // Copy hook scripts and make executable
94
- copyDir(join(templatesDir, 'hooks'), join(safewordDir, 'hooks'));
95
- makeScriptsExecutable(join(safewordDir, 'hooks'));
96
-
97
- created.push('.safeword/');
98
- success('Created .safeword directory');
99
-
100
- // 2. Handle AGENTS.md
101
- info('\nConfiguring AGENTS.md...');
102
- const agentsMdResult = ensureAgentsMdLink(cwd);
103
- if (agentsMdResult === 'created') {
104
- created.push('AGENTS.md');
105
- success('Created AGENTS.md');
106
- } else if (agentsMdResult === 'modified') {
107
- modified.push('AGENTS.md');
108
- success('Prepended link to AGENTS.md');
109
- } else {
110
- info('AGENTS.md already has safeword link');
111
- }
112
-
113
- // 3. Register Claude Code hooks
114
- info('\nRegistering Claude Code hooks...');
115
-
116
- const claudeDir = join(cwd, '.claude');
117
- const settingsPath = join(claudeDir, 'settings.json');
118
-
119
- ensureDir(claudeDir);
120
-
121
- try {
122
- updateJson<{ hooks?: Record<string, unknown[]> }>(settingsPath, existing => {
123
- const hooks = existing?.hooks ?? {};
124
-
125
- // Merge hooks, preserving existing non-safeword hooks
126
- for (const [event, newHooks] of Object.entries(SETTINGS_HOOKS)) {
127
- const existingHooks = (hooks[event] as unknown[]) ?? [];
128
- const nonSafewordHooks = filterOutSafewordHooks(existingHooks);
129
- hooks[event] = [...nonSafewordHooks, ...newHooks];
130
- }
131
-
132
- return { ...existing, hooks };
133
- });
134
-
135
- if (exists(settingsPath)) {
136
- modified.push('.claude/settings.json');
137
- } else {
138
- created.push('.claude/settings.json');
139
- }
140
- success('Registered hooks in .claude/settings.json');
141
- } catch (err) {
142
- error(`Failed to register hooks: ${err instanceof Error ? err.message : 'Unknown error'}`);
143
- process.exit(1);
144
- }
145
-
146
- // 4. Copy skills
147
- info('\nInstalling skills...');
148
-
149
- const skillsDir = join(claudeDir, 'skills');
150
- copyDir(join(templatesDir, 'skills'), skillsDir);
151
-
152
- created.push('.claude/skills/safeword-quality-reviewer/');
153
- success('Installed skills');
154
-
155
- // 5. Copy slash commands
156
- info('\nInstalling slash commands...');
157
-
158
- const commandsDir = join(claudeDir, 'commands');
159
- copyDir(join(templatesDir, 'commands'), commandsDir);
160
-
161
- created.push('.claude/commands/');
162
- success('Installed slash commands');
163
-
164
- // 6. Setup MCP servers
165
- info('\nConfiguring MCP servers...');
166
-
167
- const mcpConfigPath = join(cwd, '.mcp.json');
168
-
169
- updateJson<{ mcpServers?: Record<string, unknown> }>(mcpConfigPath, existing => {
170
- const mcpServers = existing?.mcpServers ?? {};
171
-
172
- // Add safeword MCP servers (context7 and playwright)
173
- mcpServers.context7 = {
174
- command: 'npx',
175
- args: ['-y', '@upstash/context7-mcp@latest'],
176
- };
177
- mcpServers.playwright = {
178
- command: 'npx',
179
- args: ['@playwright/mcp@latest'],
180
- };
181
-
182
- return { ...existing, mcpServers };
183
- });
184
-
185
- if (exists(mcpConfigPath)) {
186
- modified.push('.mcp.json');
187
- } else {
188
- created.push('.mcp.json');
189
- }
190
- success('Configured MCP servers');
191
-
192
- // 7. Setup linting
193
- info('\nConfiguring linting...');
194
-
195
- const packageJson = readJson<PackageJson>(packageJsonPath);
196
- if (!packageJson) {
197
- error('Failed to read package.json');
198
- process.exit(1);
199
- }
200
-
201
- const projectType = detectProjectType(packageJson);
202
-
203
- // Create ESLint config
204
- const eslintConfigPath = join(cwd, 'eslint.config.mjs');
205
- if (!exists(eslintConfigPath)) {
206
- writeFile(eslintConfigPath, getEslintConfig(projectType));
207
- created.push('eslint.config.mjs');
208
- success('Created eslint.config.mjs');
209
- } else {
210
- info('eslint.config.mjs already exists');
211
- }
212
-
213
- // Create Prettier config
214
- const prettierrcPath = join(cwd, '.prettierrc');
215
- if (!exists(prettierrcPath)) {
216
- writeFile(prettierrcPath, PRETTIERRC);
217
- created.push('.prettierrc');
218
- success('Created .prettierrc');
219
- } else {
220
- info('.prettierrc already exists');
221
- }
222
-
223
- // Create markdownlint config
224
- const markdownlintPath = join(cwd, '.markdownlint.jsonc');
225
- if (!exists(markdownlintPath)) {
226
- copyFile(join(templatesDir, 'markdownlint.jsonc'), markdownlintPath);
227
- created.push('.markdownlint.jsonc');
228
- success('Created .markdownlint.jsonc');
229
- } else {
230
- info('.markdownlint.jsonc already exists');
231
- }
232
-
233
- // Add scripts to package.json
234
- try {
235
- const scripts = packageJson.scripts ?? {};
236
- let scriptsModified = false;
237
-
238
- if (!scripts.lint) {
239
- scripts.lint = 'eslint .';
240
- scriptsModified = true;
241
- }
242
-
243
- if (!scripts['lint:md']) {
244
- scripts['lint:md'] = 'markdownlint-cli2 "**/*.md" "#node_modules"';
245
- scriptsModified = true;
246
- }
247
-
248
- if (!scripts.format) {
249
- scripts.format = 'prettier --write .';
250
- scriptsModified = true;
251
- }
252
-
253
- if (!scripts['format:check']) {
254
- scripts['format:check'] = 'prettier --check .';
255
- scriptsModified = true;
256
- }
257
-
258
- if (scriptsModified) {
259
- packageJson.scripts = scripts;
260
- writeJson(packageJsonPath, packageJson);
261
- modified.push('package.json');
262
- success('Added lint and format scripts');
263
- }
264
- } catch (err) {
265
- error(
266
- `Failed to update package.json: ${err instanceof Error ? err.message : 'Unknown error'}`,
267
- );
268
- process.exit(1);
269
- }
270
-
271
- // 8. Handle git repository
272
- info('\nConfiguring git...');
273
-
274
- if (isGitRepo(cwd)) {
275
- installGitHook(cwd);
276
- modified.push('.git/hooks/pre-commit');
277
- success('Installed git pre-commit hook');
278
- } else if (isNonInteractive) {
279
- warn('Skipped git initialization (non-interactive mode)');
280
- warn('Git hooks not installed (no repository)');
281
- } else {
282
- // Interactive mode - would prompt here
283
- // For now, skip in all cases
284
- warn('Skipped git initialization (no .git directory)');
285
- warn('Git hooks not installed (no repository)');
286
- }
287
-
288
- // 9. Note about dependencies
289
- info('\nNote: Install linting dependencies manually:');
290
- listItem('npm install -D eslint prettier @eslint/js');
291
- if (projectType.typescript) {
292
- listItem('npm install -D typescript-eslint');
293
- }
294
- if (projectType.react) {
295
- listItem('npm install -D eslint-plugin-react eslint-plugin-react-hooks');
296
- }
297
-
298
- // Print summary
299
- header('Setup Complete');
300
-
301
- if (created.length > 0) {
302
- info('\nCreated:');
303
- for (const file of created) {
304
- listItem(file);
305
- }
306
- }
307
-
308
- if (modified.length > 0) {
309
- info('\nModified:');
310
- for (const file of modified) {
311
- listItem(file);
312
- }
313
- }
314
-
315
- info('\nNext steps:');
316
- listItem('Install linting dependencies (see above)');
317
- listItem('Run `safeword check` to verify setup');
318
- listItem('Commit the new files to git');
319
-
320
- success(`\nSafeword ${VERSION} installed successfully!`);
321
- } catch (err) {
322
- error(`Setup failed: ${err instanceof Error ? err.message : 'Unknown error'}`);
323
- process.exit(1);
324
- }
325
- }
@@ -1,163 +0,0 @@
1
- /**
2
- * Upgrade command - Update safeword configuration to latest version
3
- */
4
-
5
- import { join } from 'node:path';
6
- import { VERSION } from '../version.js';
7
- import {
8
- exists,
9
- ensureDir,
10
- writeFile,
11
- readFileSafe,
12
- updateJson,
13
- copyDir,
14
- copyFile,
15
- getTemplatesDir,
16
- makeScriptsExecutable,
17
- } from '../utils/fs.js';
18
- import { info, success, error, header, listItem } from '../utils/output.js';
19
- import { isGitRepo, installGitHook } from '../utils/git.js';
20
- import { compareVersions } from '../utils/version.js';
21
- import { filterOutSafewordHooks } from '../utils/hooks.js';
22
- import { ensureAgentsMdLink } from '../utils/agents-md.js';
23
- import { SETTINGS_HOOKS } from '../templates/index.js';
24
-
25
- export async function upgrade(): Promise<void> {
26
- const cwd = process.cwd();
27
- const safewordDir = join(cwd, '.safeword');
28
-
29
- // Check if configured
30
- if (!exists(safewordDir)) {
31
- error('Not configured. Run `safeword setup` first.');
32
- process.exit(1);
33
- }
34
-
35
- // Read project version
36
- const versionPath = join(safewordDir, 'version');
37
- const projectVersion = readFileSafe(versionPath)?.trim() ?? '0.0.0';
38
-
39
- // Check for downgrade
40
- if (compareVersions(VERSION, projectVersion) < 0) {
41
- error(`CLI v${VERSION} is older than project v${projectVersion}.`);
42
- error('Update the CLI first: npm install -g safeword');
43
- process.exit(1);
44
- }
45
-
46
- header('Safeword Upgrade');
47
- info(`Upgrading from v${projectVersion} to v${VERSION}`);
48
-
49
- const updated: string[] = [];
50
- const unchanged: string[] = [];
51
-
52
- try {
53
- const templatesDir = getTemplatesDir();
54
-
55
- // 1. Update .safeword directory
56
- info('\nUpdating .safeword directory...');
57
-
58
- // Update core files from templates
59
- copyFile(join(templatesDir, 'SAFEWORD.md'), join(safewordDir, 'SAFEWORD.md'));
60
- writeFile(join(safewordDir, 'version'), VERSION);
61
- updated.push('.safeword/SAFEWORD.md');
62
- updated.push('.safeword/version');
63
-
64
- // Update guides, templates, prompts from templates
65
- copyDir(join(templatesDir, 'guides'), join(safewordDir, 'guides'));
66
- copyDir(join(templatesDir, 'doc-templates'), join(safewordDir, 'templates'));
67
- copyDir(join(templatesDir, 'prompts'), join(safewordDir, 'prompts'));
68
-
69
- // Update lib scripts and make executable
70
- copyDir(join(templatesDir, 'lib'), join(safewordDir, 'lib'));
71
- makeScriptsExecutable(join(safewordDir, 'lib'));
72
-
73
- // Update hook scripts and make executable
74
- copyDir(join(templatesDir, 'hooks'), join(safewordDir, 'hooks'));
75
- makeScriptsExecutable(join(safewordDir, 'hooks'));
76
-
77
- updated.push('.safeword/guides/');
78
- updated.push('.safeword/templates/');
79
- updated.push('.safeword/prompts/');
80
- updated.push('.safeword/hooks/');
81
- success('Updated .safeword directory');
82
-
83
- // 2. Verify AGENTS.md link
84
- info('\nVerifying AGENTS.md...');
85
- const agentsMdResult = ensureAgentsMdLink(cwd);
86
- if (agentsMdResult === 'created') {
87
- updated.push('AGENTS.md');
88
- success('Created AGENTS.md');
89
- } else if (agentsMdResult === 'modified') {
90
- updated.push('AGENTS.md');
91
- success('Restored link to AGENTS.md');
92
- } else {
93
- unchanged.push('AGENTS.md');
94
- info('AGENTS.md link is present');
95
- }
96
-
97
- // 3. Update Claude Code hooks
98
- info('\nUpdating Claude Code hooks...');
99
-
100
- const claudeDir = join(cwd, '.claude');
101
- const settingsPath = join(claudeDir, 'settings.json');
102
-
103
- ensureDir(claudeDir);
104
-
105
- updateJson<{ hooks?: Record<string, unknown[]> }>(settingsPath, existing => {
106
- const hooks = existing?.hooks ?? {};
107
-
108
- // Merge hooks, preserving existing non-safeword hooks
109
- for (const [event, newHooks] of Object.entries(SETTINGS_HOOKS)) {
110
- const existingHooks = (hooks[event] as unknown[]) ?? [];
111
- const nonSafewordHooks = filterOutSafewordHooks(existingHooks);
112
- hooks[event] = [...nonSafewordHooks, ...newHooks];
113
- }
114
-
115
- return { ...existing, hooks };
116
- });
117
-
118
- updated.push('.claude/settings.json');
119
- success('Updated hooks in .claude/settings.json');
120
-
121
- // 4. Update skills and commands
122
- info('\nUpdating skills and commands...');
123
-
124
- copyDir(join(templatesDir, 'skills'), join(claudeDir, 'skills'));
125
- copyDir(join(templatesDir, 'commands'), join(claudeDir, 'commands'));
126
-
127
- updated.push('.claude/skills/');
128
- updated.push('.claude/commands/');
129
- success('Updated skills and commands');
130
-
131
- // 5. Update git hooks if repo exists
132
- if (isGitRepo(cwd)) {
133
- info('\nUpdating git hooks...');
134
- installGitHook(cwd);
135
- updated.push('.git/hooks/pre-commit');
136
- success('Updated git pre-commit hook');
137
- }
138
-
139
- // Print summary
140
- header('Upgrade Complete');
141
-
142
- info(`\nVersion: v${projectVersion} → v${VERSION}`);
143
-
144
- if (updated.length > 0) {
145
- info('\nUpdated:');
146
- for (const file of updated) {
147
- listItem(file);
148
- }
149
- }
150
-
151
- if (unchanged.length > 0) {
152
- info('\nUnchanged:');
153
- for (const file of unchanged) {
154
- listItem(file);
155
- }
156
- }
157
-
158
- success(`\nSafeword upgraded to v${VERSION}`);
159
- } catch (err) {
160
- error(`Upgrade failed: ${err instanceof Error ? err.message : 'Unknown error'}`);
161
- process.exit(1);
162
- }
163
- }
@@ -1,3 +0,0 @@
1
- // Public API exports
2
- export { VERSION } from './version.js';
3
- export type { ProjectType } from './utils/project-detector.js';
@@ -1,58 +0,0 @@
1
- /**
2
- * Configuration templates - ESLint config generation and hook settings
3
- */
4
-
5
- export function getEslintConfig(options: {
6
- typescript?: boolean;
7
- react?: boolean;
8
- nextjs?: boolean;
9
- }): string {
10
- const imports: string[] = ['import js from "@eslint/js";'];
11
- const configs: string[] = ['js.configs.recommended'];
12
-
13
- if (options.typescript) {
14
- imports.push('import tseslint from "typescript-eslint";');
15
- configs.push('...tseslint.configs.recommended');
16
- }
17
-
18
- if (options.react || options.nextjs) {
19
- imports.push('import react from "eslint-plugin-react";');
20
- imports.push('import reactHooks from "eslint-plugin-react-hooks";');
21
- configs.push('react.configs.flat.recommended');
22
- configs.push('react.configs.flat["jsx-runtime"]');
23
- configs.push(
24
- '{ plugins: { "react-hooks": reactHooks }, rules: reactHooks.configs.recommended.rules }',
25
- );
26
- }
27
-
28
- return `${imports.join('\n')}
29
-
30
- export default [
31
- ${configs.join(',\n ')},
32
- {
33
- ignores: ["node_modules/", "dist/", ".next/", "build/"],
34
- },
35
- ];
36
- `;
37
- }
38
-
39
- export const SETTINGS_HOOKS = {
40
- SessionStart: [
41
- {
42
- command: 'bash .safeword/hooks/agents-md-check.sh',
43
- description: 'Safeword: Verify AGENTS.md link',
44
- },
45
- ],
46
- UserPromptSubmit: [
47
- {
48
- command: 'bash .safeword/hooks/inject-timestamp.sh',
49
- description: 'Safeword: Inject current timestamp',
50
- },
51
- ],
52
- PostToolUse: [
53
- {
54
- command: 'bash .safeword/hooks/post-tool.sh 2>/dev/null || true',
55
- description: 'Safeword: Post-tool validation',
56
- },
57
- ],
58
- };
@@ -1,18 +0,0 @@
1
- /**
2
- * Content templates - static string content
3
- *
4
- * Note: Most templates (SAFEWORD.md, hooks, skills, guides, etc.) are now
5
- * file-based in the templates/ directory. This file contains only small
6
- * string constants that are used inline.
7
- */
8
-
9
- export const AGENTS_MD_LINK = '**⚠️ ALWAYS READ FIRST: @./.safeword/SAFEWORD.md**';
10
-
11
- export const PRETTIERRC = `{
12
- "semi": true,
13
- "singleQuote": true,
14
- "tabWidth": 2,
15
- "trailingComma": "es5",
16
- "printWidth": 100
17
- }
18
- `;
@@ -1,12 +0,0 @@
1
- /**
2
- * Bundled templates for safeword setup
3
- *
4
- * Re-exports all templates from organized modules.
5
- */
6
-
7
- // Content templates (static string constants)
8
- // Note: Most templates are now file-based in templates/ directory
9
- export { AGENTS_MD_LINK, PRETTIERRC } from './content.js';
10
-
11
- // Configuration templates (ESLint, hooks settings)
12
- export { getEslintConfig, SETTINGS_HOOKS } from './config.js';
@@ -1,66 +0,0 @@
1
- /**
2
- * AGENTS.md file utilities
3
- */
4
-
5
- import { join } from 'node:path';
6
- import { exists, readFile, writeFile } from './fs.js';
7
- import { AGENTS_MD_LINK } from '../templates/index.js';
8
-
9
- const SAFEWORD_LINK_MARKER = '@./.safeword/SAFEWORD.md';
10
-
11
- /**
12
- * Check if AGENTS.md has the safeword link
13
- */
14
- export function hasAgentsMdLink(cwd: string): boolean {
15
- const agentsMdPath = join(cwd, 'AGENTS.md');
16
- if (!exists(agentsMdPath)) return false;
17
- const content = readFile(agentsMdPath);
18
- return content.includes(SAFEWORD_LINK_MARKER);
19
- }
20
-
21
- /**
22
- * Ensure AGENTS.md exists and has the safeword link.
23
- * Returns 'created' | 'modified' | 'unchanged'
24
- */
25
- export function ensureAgentsMdLink(cwd: string): 'created' | 'modified' | 'unchanged' {
26
- const agentsMdPath = join(cwd, 'AGENTS.md');
27
-
28
- if (!exists(agentsMdPath)) {
29
- writeFile(agentsMdPath, `${AGENTS_MD_LINK}\n`);
30
- return 'created';
31
- }
32
-
33
- const content = readFile(agentsMdPath);
34
- if (!content.includes(SAFEWORD_LINK_MARKER)) {
35
- writeFile(agentsMdPath, `${AGENTS_MD_LINK}\n\n${content}`);
36
- return 'modified';
37
- }
38
-
39
- return 'unchanged';
40
- }
41
-
42
- /**
43
- * Remove safeword link from AGENTS.md.
44
- * Returns true if link was removed.
45
- */
46
- export function removeAgentsMdLink(cwd: string): boolean {
47
- const agentsMdPath = join(cwd, 'AGENTS.md');
48
- if (!exists(agentsMdPath)) return false;
49
-
50
- const content = readFile(agentsMdPath);
51
- const lines = content.split('\n');
52
- const filteredLines = lines.filter((line) => !line.includes(SAFEWORD_LINK_MARKER));
53
-
54
- // Remove extra blank lines at the start
55
- while (filteredLines.length > 0 && filteredLines[0].trim() === '') {
56
- filteredLines.shift();
57
- }
58
-
59
- const newContent = filteredLines.join('\n');
60
- if (newContent !== content) {
61
- writeFile(agentsMdPath, newContent);
62
- return true;
63
- }
64
-
65
- return false;
66
- }