safeword 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/arch-review.md +32 -0
- package/.claude/commands/lint.md +6 -0
- package/.claude/commands/quality-review.md +13 -0
- package/.claude/commands/setup-linting.md +6 -0
- package/.claude/hooks/auto-lint.sh +6 -0
- package/.claude/hooks/auto-quality-review.sh +170 -0
- package/.claude/hooks/check-linting-sync.sh +17 -0
- package/.claude/hooks/inject-timestamp.sh +6 -0
- package/.claude/hooks/question-protocol.sh +12 -0
- package/.claude/hooks/run-linters.sh +8 -0
- package/.claude/hooks/run-quality-review.sh +76 -0
- package/.claude/hooks/version-check.sh +10 -0
- package/.claude/mcp/README.md +96 -0
- package/.claude/mcp/arcade.sample.json +9 -0
- package/.claude/mcp/context7.sample.json +7 -0
- package/.claude/mcp/playwright.sample.json +7 -0
- package/.claude/settings.json +62 -0
- package/.claude/skills/quality-reviewer/SKILL.md +190 -0
- package/.claude/skills/safeword-quality-reviewer/SKILL.md +13 -0
- package/.env.arcade.example +4 -0
- package/.env.example +11 -0
- package/.gitmodules +4 -0
- package/.safeword/SAFEWORD.md +33 -0
- package/.safeword/eslint/eslint-base.mjs +101 -0
- package/.safeword/guides/architecture-guide.md +404 -0
- package/.safeword/guides/code-philosophy.md +174 -0
- package/.safeword/guides/context-files-guide.md +405 -0
- package/.safeword/guides/data-architecture-guide.md +183 -0
- package/.safeword/guides/design-doc-guide.md +165 -0
- package/.safeword/guides/learning-extraction.md +515 -0
- package/.safeword/guides/llm-instruction-design.md +239 -0
- package/.safeword/guides/llm-prompting.md +95 -0
- package/.safeword/guides/tdd-best-practices.md +570 -0
- package/.safeword/guides/test-definitions-guide.md +243 -0
- package/.safeword/guides/testing-methodology.md +573 -0
- package/.safeword/guides/user-story-guide.md +237 -0
- package/.safeword/guides/zombie-process-cleanup.md +214 -0
- package/{templates → .safeword}/hooks/agents-md-check.sh +0 -0
- package/{templates → .safeword}/hooks/post-tool.sh +0 -0
- package/{templates → .safeword}/hooks/pre-commit.sh +0 -0
- package/.safeword/planning/002-user-story-quality-evaluation.md +1840 -0
- package/.safeword/planning/003-langsmith-eval-setup-prompt.md +363 -0
- package/.safeword/planning/004-llm-eval-test-cases.md +3226 -0
- package/.safeword/planning/005-architecture-enforcement-system.md +169 -0
- package/.safeword/planning/006-reactive-fix-prevention-research.md +135 -0
- package/.safeword/planning/011-cli-ux-vision.md +330 -0
- package/.safeword/planning/012-project-structure-cleanup.md +154 -0
- package/.safeword/planning/README.md +39 -0
- package/.safeword/planning/automation-plan-v2.md +1225 -0
- package/.safeword/planning/automation-plan-v3.md +1291 -0
- package/.safeword/planning/automation-plan.md +3058 -0
- package/.safeword/planning/design/005-cli-implementation.md +343 -0
- package/.safeword/planning/design/013-cli-self-contained-templates.md +596 -0
- package/.safeword/planning/design/013a-eslint-plugin-suite.md +256 -0
- package/.safeword/planning/design/013b-implementation-snippets.md +385 -0
- package/.safeword/planning/design/013c-config-isolation-strategy.md +242 -0
- package/.safeword/planning/design/code-philosophy-improvements.md +60 -0
- package/.safeword/planning/mcp-analysis.md +545 -0
- package/.safeword/planning/phase2-subagents-vs-skills-analysis.md +451 -0
- package/.safeword/planning/settings-improvements.md +970 -0
- package/.safeword/planning/test-definitions/005-cli-implementation.md +1301 -0
- package/.safeword/planning/test-definitions/cli-self-contained-templates.md +205 -0
- package/.safeword/planning/user-stories/001-guides-review-user-stories.md +1381 -0
- package/.safeword/planning/user-stories/003-reactive-fix-prevention.md +132 -0
- package/.safeword/planning/user-stories/004-technical-constraints.md +86 -0
- package/.safeword/planning/user-stories/005-cli-implementation.md +311 -0
- package/.safeword/planning/user-stories/cli-self-contained-templates.md +172 -0
- package/.safeword/planning/versioned-distribution.md +740 -0
- package/.safeword/prompts/arch-review.md +43 -0
- package/.safeword/prompts/quality-review.md +11 -0
- package/.safeword/scripts/arch-review.sh +235 -0
- package/.safeword/scripts/check-linting-sync.sh +58 -0
- package/.safeword/scripts/setup-linting.sh +559 -0
- package/.safeword/templates/architecture-template.md +136 -0
- package/.safeword/templates/ci/architecture-check.yml +79 -0
- package/.safeword/templates/design-doc-template.md +127 -0
- package/.safeword/templates/test-definitions-feature.md +100 -0
- package/.safeword/templates/ticket-template.md +74 -0
- package/.safeword/templates/user-stories-template.md +82 -0
- package/.safeword/tickets/001-guides-review-user-stories.md +83 -0
- package/.safeword/tickets/002-architecture-enforcement.md +211 -0
- package/.safeword/tickets/003-reactive-fix-prevention.md +57 -0
- package/.safeword/tickets/004-technical-constraints-in-user-stories.md +39 -0
- package/.safeword/tickets/005-cli-implementation.md +248 -0
- package/.safeword/tickets/006-flesh-out-skills.md +43 -0
- package/.safeword/tickets/007-flesh-out-questioning.md +44 -0
- package/.safeword/tickets/008-upgrade-questioning.md +58 -0
- package/.safeword/tickets/009-naming-conventions.md +41 -0
- package/.safeword/tickets/010-safeword-md-cleanup.md +34 -0
- package/.safeword/tickets/011-cursor-setup.md +86 -0
- package/.safeword/tickets/README.md +73 -0
- package/.safeword/version +1 -0
- package/AGENTS.md +59 -0
- package/CLAUDE.md +12 -0
- package/README.md +347 -0
- package/docs/001-cli-implementation-plan.md +856 -0
- package/docs/elite-dx-implementation-plan.md +1034 -0
- package/framework/README.md +131 -0
- package/framework/mcp/README.md +96 -0
- package/framework/mcp/arcade.sample.json +8 -0
- package/framework/mcp/context7.sample.json +6 -0
- package/framework/mcp/playwright.sample.json +6 -0
- package/framework/scripts/arch-review.sh +235 -0
- package/framework/scripts/check-linting-sync.sh +58 -0
- package/framework/scripts/load-env.sh +49 -0
- package/framework/scripts/setup-claude.sh +223 -0
- package/framework/scripts/setup-linting.sh +559 -0
- package/framework/scripts/setup-quality.sh +477 -0
- package/framework/scripts/setup-safeword.sh +550 -0
- package/framework/templates/ci/architecture-check.yml +78 -0
- package/learnings/ai-sdk-v5-breaking-changes.md +178 -0
- package/learnings/e2e-test-zombie-processes.md +231 -0
- package/learnings/milkdown-crepe-editor-property.md +96 -0
- package/learnings/prosemirror-fragment-traversal.md +119 -0
- package/package.json +19 -43
- package/packages/cli/AGENTS.md +1 -0
- package/packages/cli/ARCHITECTURE.md +279 -0
- package/packages/cli/package.json +51 -0
- package/packages/cli/src/cli.ts +63 -0
- package/packages/cli/src/commands/check.ts +166 -0
- package/packages/cli/src/commands/diff.ts +209 -0
- package/packages/cli/src/commands/reset.ts +190 -0
- package/packages/cli/src/commands/setup.ts +325 -0
- package/packages/cli/src/commands/upgrade.ts +163 -0
- package/packages/cli/src/index.ts +3 -0
- package/packages/cli/src/templates/config.ts +58 -0
- package/packages/cli/src/templates/content.ts +18 -0
- package/packages/cli/src/templates/index.ts +12 -0
- package/packages/cli/src/utils/agents-md.ts +66 -0
- package/packages/cli/src/utils/fs.ts +179 -0
- package/packages/cli/src/utils/git.ts +124 -0
- package/packages/cli/src/utils/hooks.ts +29 -0
- package/packages/cli/src/utils/output.ts +60 -0
- package/packages/cli/src/utils/project-detector.test.ts +185 -0
- package/packages/cli/src/utils/project-detector.ts +44 -0
- package/packages/cli/src/utils/version.ts +28 -0
- package/packages/cli/src/version.ts +6 -0
- package/packages/cli/templates/SAFEWORD.md +776 -0
- package/packages/cli/templates/doc-templates/architecture-template.md +136 -0
- package/packages/cli/templates/doc-templates/design-doc-template.md +134 -0
- package/packages/cli/templates/doc-templates/test-definitions-feature.md +131 -0
- package/packages/cli/templates/doc-templates/ticket-template.md +82 -0
- package/packages/cli/templates/doc-templates/user-stories-template.md +92 -0
- package/packages/cli/templates/guides/architecture-guide.md +423 -0
- package/packages/cli/templates/guides/code-philosophy.md +195 -0
- package/packages/cli/templates/guides/context-files-guide.md +457 -0
- package/packages/cli/templates/guides/data-architecture-guide.md +200 -0
- package/packages/cli/templates/guides/design-doc-guide.md +171 -0
- package/packages/cli/templates/guides/learning-extraction.md +552 -0
- package/packages/cli/templates/guides/llm-instruction-design.md +248 -0
- package/packages/cli/templates/guides/llm-prompting.md +102 -0
- package/packages/cli/templates/guides/tdd-best-practices.md +615 -0
- package/packages/cli/templates/guides/test-definitions-guide.md +334 -0
- package/packages/cli/templates/guides/testing-methodology.md +618 -0
- package/packages/cli/templates/guides/user-story-guide.md +256 -0
- package/packages/cli/templates/guides/zombie-process-cleanup.md +219 -0
- package/packages/cli/templates/hooks/agents-md-check.sh +27 -0
- package/packages/cli/templates/hooks/post-tool.sh +4 -0
- package/packages/cli/templates/hooks/pre-commit.sh +10 -0
- package/packages/cli/templates/prompts/arch-review.md +43 -0
- package/packages/cli/templates/prompts/quality-review.md +10 -0
- package/packages/cli/templates/skills/safeword-quality-reviewer/SKILL.md +207 -0
- package/packages/cli/tests/commands/check.test.ts +129 -0
- package/packages/cli/tests/commands/cli.test.ts +89 -0
- package/packages/cli/tests/commands/diff.test.ts +115 -0
- package/packages/cli/tests/commands/reset.test.ts +310 -0
- package/packages/cli/tests/commands/self-healing.test.ts +170 -0
- package/packages/cli/tests/commands/setup-blocking.test.ts +71 -0
- package/packages/cli/tests/commands/setup-core.test.ts +135 -0
- package/packages/cli/tests/commands/setup-git.test.ts +139 -0
- package/packages/cli/tests/commands/setup-hooks.test.ts +334 -0
- package/packages/cli/tests/commands/setup-linting.test.ts +189 -0
- package/packages/cli/tests/commands/setup-noninteractive.test.ts +80 -0
- package/packages/cli/tests/commands/setup-templates.test.ts +181 -0
- package/packages/cli/tests/commands/upgrade.test.ts +215 -0
- package/packages/cli/tests/helpers.ts +243 -0
- package/packages/cli/tests/npm-package.test.ts +83 -0
- package/packages/cli/tests/technical-constraints.test.ts +96 -0
- package/packages/cli/tsconfig.json +25 -0
- package/packages/cli/tsup.config.ts +11 -0
- package/packages/cli/vitest.config.ts +23 -0
- package/promptfoo.yaml +3270 -0
- package/dist/check-3NGQ4NR5.js +0 -129
- package/dist/check-3NGQ4NR5.js.map +0 -1
- package/dist/chunk-2XWIUEQK.js +0 -190
- package/dist/chunk-2XWIUEQK.js.map +0 -1
- package/dist/chunk-GZRQL3SX.js +0 -146
- package/dist/chunk-GZRQL3SX.js.map +0 -1
- package/dist/chunk-ORQHKDT2.js +0 -10
- package/dist/chunk-ORQHKDT2.js.map +0 -1
- package/dist/chunk-W66Z3C5H.js +0 -21
- package/dist/chunk-W66Z3C5H.js.map +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -34
- package/dist/cli.js.map +0 -1
- package/dist/diff-Y6QTAW4O.js +0 -166
- package/dist/diff-Y6QTAW4O.js.map +0 -1
- package/dist/index.d.ts +0 -11
- package/dist/index.js +0 -7
- package/dist/index.js.map +0 -1
- package/dist/reset-3ACTIYYE.js +0 -143
- package/dist/reset-3ACTIYYE.js.map +0 -1
- package/dist/setup-RR4M334C.js +0 -266
- package/dist/setup-RR4M334C.js.map +0 -1
- package/dist/upgrade-6AR3DHUV.js +0 -134
- package/dist/upgrade-6AR3DHUV.js.map +0 -1
- /package/{templates → framework}/SAFEWORD.md +0 -0
- /package/{templates → framework}/guides/architecture-guide.md +0 -0
- /package/{templates → framework}/guides/code-philosophy.md +0 -0
- /package/{templates → framework}/guides/context-files-guide.md +0 -0
- /package/{templates → framework}/guides/data-architecture-guide.md +0 -0
- /package/{templates → framework}/guides/design-doc-guide.md +0 -0
- /package/{templates → framework}/guides/learning-extraction.md +0 -0
- /package/{templates → framework}/guides/llm-instruction-design.md +0 -0
- /package/{templates → framework}/guides/llm-prompting.md +0 -0
- /package/{templates → framework}/guides/tdd-best-practices.md +0 -0
- /package/{templates → framework}/guides/test-definitions-guide.md +0 -0
- /package/{templates → framework}/guides/testing-methodology.md +0 -0
- /package/{templates → framework}/guides/user-story-guide.md +0 -0
- /package/{templates → framework}/guides/zombie-process-cleanup.md +0 -0
- /package/{templates → framework}/prompts/arch-review.md +0 -0
- /package/{templates → framework}/prompts/quality-review.md +0 -0
- /package/{templates/skills/safeword-quality-reviewer → framework/skills/quality-reviewer}/SKILL.md +0 -0
- /package/{templates/doc-templates → framework/templates}/architecture-template.md +0 -0
- /package/{templates/doc-templates → framework/templates}/design-doc-template.md +0 -0
- /package/{templates/doc-templates → framework/templates}/test-definitions-feature.md +0 -0
- /package/{templates/doc-templates → framework/templates}/ticket-template.md +0 -0
- /package/{templates/doc-templates → framework/templates}/user-stories-template.md +0 -0
- /package/{templates → packages/cli/templates}/commands/arch-review.md +0 -0
- /package/{templates → packages/cli/templates}/commands/lint.md +0 -0
- /package/{templates → packages/cli/templates}/commands/quality-review.md +0 -0
- /package/{templates → packages/cli/templates}/hooks/inject-timestamp.sh +0 -0
- /package/{templates → packages/cli/templates}/lib/common.sh +0 -0
- /package/{templates → packages/cli/templates}/lib/jq-fallback.sh +0 -0
- /package/{templates → packages/cli/templates}/markdownlint.jsonc +0 -0
|
@@ -0,0 +1,856 @@
|
|
|
1
|
+
# Safeword CLI Implementation Plan
|
|
2
|
+
|
|
3
|
+
**Goal:** Ship TypeScript CLI that replaces bash scripts with elite developer experience.
|
|
4
|
+
|
|
5
|
+
**Strategy:** Project-local (committable, version-pinnable) with optional plugin wrapper in Phase 2.
|
|
6
|
+
|
|
7
|
+
**Non-goal:** Don't try to be Superpowers. Stay focused on quality enforcement, not skill libraries.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Phase 1: Core CLI (Ship This First)
|
|
12
|
+
|
|
13
|
+
**Target:** v1.0.0 - Functional replacement for bash scripts with better UX
|
|
14
|
+
|
|
15
|
+
### 1.1 Project Setup
|
|
16
|
+
|
|
17
|
+
**Create CLI package structure:**
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
mkdir -p packages/cli/src/{commands,lib,templates}
|
|
21
|
+
cd packages/cli
|
|
22
|
+
npm init -y
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Install dependencies:**
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Core CLI
|
|
29
|
+
npm install commander @clack/prompts
|
|
30
|
+
|
|
31
|
+
# File operations
|
|
32
|
+
npm install fs-extra globby
|
|
33
|
+
|
|
34
|
+
# Utilities
|
|
35
|
+
npm install picocolors execa
|
|
36
|
+
|
|
37
|
+
# Dev dependencies
|
|
38
|
+
npm install -D typescript @types/node @types/fs-extra tsx vitest
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Why these choices:**
|
|
42
|
+
|
|
43
|
+
- `commander` - Industry standard CLI framework
|
|
44
|
+
- `@clack/prompts` - Modern, beautiful prompts (used by Astro/Vite)
|
|
45
|
+
- `fs-extra` - Promise-based fs with extras (copy, ensureDir)
|
|
46
|
+
- `execa` - Better child_process (run npm, git commands)
|
|
47
|
+
- `tsx` - Fast TypeScript execution for dev/testing
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
### 1.2 Core Commands
|
|
52
|
+
|
|
53
|
+
**Priority order (ship incrementally):**
|
|
54
|
+
|
|
55
|
+
**1.2.1 `safeword init` (CRITICAL PATH)**
|
|
56
|
+
|
|
57
|
+
**Purpose:** Replace `setup-safeword.sh` with interactive setup
|
|
58
|
+
|
|
59
|
+
**Features:**
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
safeword init # Interactive with prompts
|
|
63
|
+
safeword init --yes # Accept all defaults
|
|
64
|
+
safeword init --ci # Non-interactive (CI mode)
|
|
65
|
+
safeword init --linting-only # Skip quality review
|
|
66
|
+
safeword init --quality-only # Skip linting
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Flow:**
|
|
70
|
+
|
|
71
|
+
1. Detect project type (Next.js, React, Electron, TypeScript, etc.)
|
|
72
|
+
2. Prompt for install mode (or use defaults in --yes/--ci)
|
|
73
|
+
3. Copy templates from npm package to `.safeword/` and `.claude/`
|
|
74
|
+
4. Install linting dependencies (biome or eslint+prettier)
|
|
75
|
+
5. Update `package.json` (add scripts, optionally add CLI to devDeps)
|
|
76
|
+
6. Register hooks in `.claude/settings.json`
|
|
77
|
+
7. Create/update `SAFEWORD.md` with .safeword/SAFEWORD.md reference
|
|
78
|
+
8. Run automatic verification (see 1.2.2)
|
|
79
|
+
9. Print success summary with next steps
|
|
80
|
+
|
|
81
|
+
**Auto-detection logic:**
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
export async function detectProjectType(): Promise<ProjectType> {
|
|
85
|
+
const hasFile = (path: string) => fs.existsSync(path);
|
|
86
|
+
const pkgJson = await readPackageJson();
|
|
87
|
+
|
|
88
|
+
// Check dependencies
|
|
89
|
+
const deps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };
|
|
90
|
+
|
|
91
|
+
if (deps['@biomejs/biome']) return 'biome';
|
|
92
|
+
if (deps['next']) return 'nextjs';
|
|
93
|
+
if (deps['electron']) return 'electron';
|
|
94
|
+
if (deps['astro']) return 'astro';
|
|
95
|
+
if (deps['react']) return 'react';
|
|
96
|
+
if (deps['typescript'] || hasFile('tsconfig.json')) return 'typescript';
|
|
97
|
+
|
|
98
|
+
return 'minimal';
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Output (interactive mode):**
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
$ safeword init
|
|
106
|
+
|
|
107
|
+
○ Detecting project type...
|
|
108
|
+
✓ Next.js with TypeScript
|
|
109
|
+
|
|
110
|
+
○ Install options:
|
|
111
|
+
○ Recommended (auto-linting + quality review)
|
|
112
|
+
○ Auto-linting only
|
|
113
|
+
○ Quality review only
|
|
114
|
+
|
|
115
|
+
◆ Choice
|
|
116
|
+
│ ● Recommended (auto-linting + quality review)
|
|
117
|
+
└
|
|
118
|
+
|
|
119
|
+
○ Installing...
|
|
120
|
+
|
|
121
|
+
▲ Linting (biome, 15.2 MB)
|
|
122
|
+
▲ Quality review
|
|
123
|
+
▲ Guides (12 files)
|
|
124
|
+
|
|
125
|
+
✓ Configured in 4.2s
|
|
126
|
+
|
|
127
|
+
○ Verification
|
|
128
|
+
|
|
129
|
+
Files:
|
|
130
|
+
✓ .safeword/SAFEWORD.md
|
|
131
|
+
✓ .safeword/guides/ (12 guides)
|
|
132
|
+
✓ .claude/hooks/ (3 hooks)
|
|
133
|
+
✓ .claude/settings.json
|
|
134
|
+
✓ SAFEWORD.md
|
|
135
|
+
|
|
136
|
+
Hooks:
|
|
137
|
+
✓ PostToolUse → auto-lint.sh
|
|
138
|
+
✓ Stop → auto-quality-review.sh
|
|
139
|
+
|
|
140
|
+
Linting:
|
|
141
|
+
✓ biome.jsonc configured
|
|
142
|
+
✓ npm run lint works
|
|
143
|
+
|
|
144
|
+
✓ All checks passed!
|
|
145
|
+
|
|
146
|
+
○ Next steps
|
|
147
|
+
|
|
148
|
+
git add .safeword .claude SAFEWORD.md package.json
|
|
149
|
+
git commit -m "Add safeword config"
|
|
150
|
+
|
|
151
|
+
Try it: Ask Claude to create a file
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
**1.2.2 `safeword verify` (CRITICAL PATH)**
|
|
157
|
+
|
|
158
|
+
**Purpose:** Health check + auto-repair
|
|
159
|
+
|
|
160
|
+
**Features:**
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
safeword verify # Show status, exit 0/1
|
|
164
|
+
safeword verify --auto-init # Init if not configured (teammate onboarding)
|
|
165
|
+
safeword verify --repair # Fix broken hooks
|
|
166
|
+
safeword verify --ci # CI mode (minimal output)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Checks:**
|
|
170
|
+
|
|
171
|
+
1. `.safeword/SAFEWORD.md` exists
|
|
172
|
+
2. `.safeword/guides/` exists (count files)
|
|
173
|
+
3. `.claude/hooks/` exists (verify scripts executable)
|
|
174
|
+
4. `.claude/settings.json` exists and valid JSON
|
|
175
|
+
5. Hooks registered (PostToolUse, Stop)
|
|
176
|
+
6. `SAFEWORD.md` or `CLAUDE.md` references `.safeword/SAFEWORD.md`
|
|
177
|
+
7. Linting configured (biome.jsonc or eslint.config.mjs exists)
|
|
178
|
+
8. npm scripts exist (`lint`, `format`)
|
|
179
|
+
|
|
180
|
+
**Repair logic:**
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
async function repair() {
|
|
184
|
+
// Re-register hooks if missing
|
|
185
|
+
if (!hooksRegistered()) {
|
|
186
|
+
await registerHooks();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Fix executable permissions
|
|
190
|
+
await fs.chmod('.claude/hooks/auto-lint.sh', 0o755);
|
|
191
|
+
await fs.chmod('.claude/hooks/auto-quality-review.sh', 0o755);
|
|
192
|
+
|
|
193
|
+
// Re-add SAFEWORD.md reference if missing
|
|
194
|
+
if (!agentsHasReference()) {
|
|
195
|
+
await addSafewordReference();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Use case (teammate onboarding):**
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
// package.json
|
|
204
|
+
{
|
|
205
|
+
"scripts": {
|
|
206
|
+
"prepare": "safeword verify --silent || echo 'ℹ Run: npx safeword init'"
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Teammate runs `npm install` → `prepare` hook runs → Prints message if not configured.
|
|
212
|
+
|
|
213
|
+
**Note:** Don't use `postinstall` (security red flag). Use `prepare` (runs in dev only).
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
**1.2.3 `safeword --version` (CRITICAL PATH)**
|
|
218
|
+
|
|
219
|
+
**Purpose:** Show CLI version
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
safeword --version
|
|
223
|
+
# 1.0.0
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Implementation:**
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
// Read from package.json
|
|
230
|
+
import { readFileSync } from 'fs';
|
|
231
|
+
import { join } from 'path';
|
|
232
|
+
|
|
233
|
+
const pkgPath = join(__dirname, '../package.json');
|
|
234
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
235
|
+
|
|
236
|
+
program.version(pkg.version);
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
**1.2.4 `safeword status` (NICE TO HAVE)**
|
|
242
|
+
|
|
243
|
+
**Purpose:** Show detailed project state
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
safeword status
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Output:**
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
Safeword Status
|
|
253
|
+
|
|
254
|
+
Project: /Users/alex/projects/my-app
|
|
255
|
+
Version: 1.0.0 (latest: 1.2.0 - run `safeword upgrade` to update)
|
|
256
|
+
|
|
257
|
+
Components:
|
|
258
|
+
✓ Auto-linting (biome)
|
|
259
|
+
✓ Quality review hooks
|
|
260
|
+
✓ 12 guides in .safeword/
|
|
261
|
+
|
|
262
|
+
Hooks:
|
|
263
|
+
✓ PostToolUse → auto-lint.sh (active)
|
|
264
|
+
✓ Stop → auto-quality-review.sh (active)
|
|
265
|
+
|
|
266
|
+
Config:
|
|
267
|
+
• enabled: true
|
|
268
|
+
• ask_questions: true
|
|
269
|
+
• linting_mode: biome
|
|
270
|
+
|
|
271
|
+
To update: safeword upgrade
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Data sources:**
|
|
275
|
+
|
|
276
|
+
- `.safeword/version` file (created by init)
|
|
277
|
+
- `.claude/settings.json` (hook registration)
|
|
278
|
+
- `.auto-quality-review.config` (user preferences)
|
|
279
|
+
- Check npm registry for latest version
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
### 1.3 Template Embedding
|
|
284
|
+
|
|
285
|
+
**Strategy:** Embed all templates in npm package (no external downloads, no cache complexity)
|
|
286
|
+
|
|
287
|
+
**Structure:**
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
packages/cli/src/templates/
|
|
291
|
+
├── SAFEWORD.md # Core patterns (copied from framework/SAFEWORD.md)
|
|
292
|
+
├── guides/ # All guides
|
|
293
|
+
│ ├── testing-methodology.md
|
|
294
|
+
│ ├── code-philosophy.md
|
|
295
|
+
│ ├── user-story-guide.md
|
|
296
|
+
│ └── ... (all existing guides)
|
|
297
|
+
├── hooks/ # Hook scripts
|
|
298
|
+
│ ├── auto-lint.sh
|
|
299
|
+
│ ├── auto-quality-review.sh
|
|
300
|
+
│ ├── run-linters.sh
|
|
301
|
+
│ └── run-quality-review.sh
|
|
302
|
+
└── config/ # Config file templates
|
|
303
|
+
├── eslint.config.mjs
|
|
304
|
+
├── biome.jsonc
|
|
305
|
+
└── prettierrc
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**Copy operation:**
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
import { copy } from 'fs-extra';
|
|
312
|
+
import { join } from 'path';
|
|
313
|
+
|
|
314
|
+
export async function copyTemplates(projectDir: string) {
|
|
315
|
+
const templatesDir = join(__dirname, '../templates');
|
|
316
|
+
const targetDir = join(projectDir, '.safeword');
|
|
317
|
+
|
|
318
|
+
// Copy everything
|
|
319
|
+
await copy(templatesDir, targetDir);
|
|
320
|
+
|
|
321
|
+
// Write version file
|
|
322
|
+
const version = require('../package.json').version;
|
|
323
|
+
await fs.writeFile(join(targetDir, 'version'), version);
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Why embed vs download:**
|
|
328
|
+
|
|
329
|
+
- Templates are ~2MB total (tiny for npm)
|
|
330
|
+
- Offline support (no network needed after npx download)
|
|
331
|
+
- Simpler code (no cache management)
|
|
332
|
+
- npm already caches packages in `~/.npm/_npx/`
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
### 1.4 Non-Interactive Mode (CI/CD)
|
|
337
|
+
|
|
338
|
+
**Auto-detect non-interactive environments:**
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
const isCI =
|
|
342
|
+
!process.stdin.isTTY || process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true';
|
|
343
|
+
|
|
344
|
+
if (isCI && !options.yes && !options.ci) {
|
|
345
|
+
console.error('Error: Interactive prompts require TTY');
|
|
346
|
+
console.error('Use --yes or --ci flag for non-interactive mode');
|
|
347
|
+
process.exit(1);
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**CI mode behavior:**
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
safeword init --ci
|
|
355
|
+
|
|
356
|
+
# No colors (plain text)
|
|
357
|
+
# No progress bars
|
|
358
|
+
# No prompts (use defaults)
|
|
359
|
+
# Minimal output (errors + summary only)
|
|
360
|
+
# Exit code 0 = success, 1 = failure
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**GitHub Actions example:**
|
|
364
|
+
|
|
365
|
+
```yaml
|
|
366
|
+
name: Verify Safeword
|
|
367
|
+
on: [push]
|
|
368
|
+
|
|
369
|
+
jobs:
|
|
370
|
+
verify:
|
|
371
|
+
runs-on: ubuntu-latest
|
|
372
|
+
steps:
|
|
373
|
+
- uses: actions/checkout@v3
|
|
374
|
+
- uses: actions/setup-node@v3
|
|
375
|
+
- run: npm install
|
|
376
|
+
- run: npx @safeword/cli verify --ci
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
### 1.5 Package Manager Detection
|
|
382
|
+
|
|
383
|
+
**Problem:** Mutating `package.json` breaks yarn/pnpm lockfiles
|
|
384
|
+
|
|
385
|
+
**Solution:** Detect package manager and use appropriate command
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
export async function detectPackageManager(): Promise<'npm' | 'yarn' | 'pnpm'> {
|
|
389
|
+
if (await fs.pathExists('pnpm-lock.yaml')) return 'pnpm';
|
|
390
|
+
if (await fs.pathExists('yarn.lock')) return 'yarn';
|
|
391
|
+
return 'npm';
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export async function runPackageManagerCommand(
|
|
395
|
+
command: string,
|
|
396
|
+
pkgManager: 'npm' | 'yarn' | 'pnpm',
|
|
397
|
+
) {
|
|
398
|
+
const cmds = {
|
|
399
|
+
npm: `npm ${command}`,
|
|
400
|
+
yarn: `yarn ${command}`,
|
|
401
|
+
pnpm: `pnpm ${command}`,
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
await execa(cmds[pkgManager], { shell: true });
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
**Ask before mutating package.json:**
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
if (!options.yes && !options.ci) {
|
|
412
|
+
const { addToDeps } = await prompts({
|
|
413
|
+
type: 'confirm',
|
|
414
|
+
name: 'addToDeps',
|
|
415
|
+
message: `Add @safeword/cli to devDependencies? (${pkgManager})`,
|
|
416
|
+
initial: true,
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
if (addToDeps) {
|
|
420
|
+
await addToPackageJson(pkgManager);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
### 1.6 XDG Compliance (Global Learnings)
|
|
428
|
+
|
|
429
|
+
**Follow XDG Base Directory spec:**
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
import { homedir } from 'os';
|
|
433
|
+
import { join } from 'path';
|
|
434
|
+
|
|
435
|
+
export function getGlobalLearningsDir(): string {
|
|
436
|
+
const xdgDataHome = process.env.XDG_DATA_HOME || join(homedir(), '.local/share');
|
|
437
|
+
return join(xdgDataHome, 'safeword/learnings');
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
export function getConfigDir(): string {
|
|
441
|
+
const xdgConfigHome = process.env.XDG_CONFIG_HOME || join(homedir(), '.config');
|
|
442
|
+
return join(xdgConfigHome, 'safeword');
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
**Structure:**
|
|
447
|
+
|
|
448
|
+
```
|
|
449
|
+
~/.local/share/safeword/
|
|
450
|
+
└── .safeword/learnings/ # Project learnings
|
|
451
|
+
|
|
452
|
+
~/.config/safeword/
|
|
453
|
+
└── config.json # CLI preferences (future)
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
**Phase 1:** Only implement if adding `safeword learning add` command. Otherwise defer to Phase 2.
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
### 1.7 Testing Strategy
|
|
461
|
+
|
|
462
|
+
**Unit tests (vitest):**
|
|
463
|
+
|
|
464
|
+
```typescript
|
|
465
|
+
// tests/detect.test.ts
|
|
466
|
+
import { describe, it, expect } from 'vitest';
|
|
467
|
+
import { detectProjectType } from '../src/lib/detect';
|
|
468
|
+
|
|
469
|
+
describe('detectProjectType', () => {
|
|
470
|
+
it('detects Next.js projects', async () => {
|
|
471
|
+
// Mock fs to return package.json with next dep
|
|
472
|
+
const type = await detectProjectType();
|
|
473
|
+
expect(type).toBe('nextjs');
|
|
474
|
+
});
|
|
475
|
+
});
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
**Integration tests (mock fs):**
|
|
479
|
+
|
|
480
|
+
```typescript
|
|
481
|
+
import { vol } from 'memfs';
|
|
482
|
+
import { init } from '../src/commands/init';
|
|
483
|
+
|
|
484
|
+
describe('safeword init', () => {
|
|
485
|
+
beforeEach(() => {
|
|
486
|
+
vol.reset();
|
|
487
|
+
vol.fromJSON({
|
|
488
|
+
'/project/package.json': JSON.stringify({ name: 'test' }),
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
it('creates .safeword directory', async () => {
|
|
493
|
+
await init({ yes: true });
|
|
494
|
+
expect(vol.existsSync('/project/.safeword')).toBe(true);
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
**Manual smoke test:**
|
|
500
|
+
|
|
501
|
+
```bash
|
|
502
|
+
# In packages/cli
|
|
503
|
+
npm link
|
|
504
|
+
|
|
505
|
+
# In test project
|
|
506
|
+
cd ~/test-project
|
|
507
|
+
safeword init --yes
|
|
508
|
+
safeword verify
|
|
509
|
+
safeword status
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
## Phase 1 Checklist
|
|
515
|
+
|
|
516
|
+
**Must have (blocking v1.0.0 release):**
|
|
517
|
+
|
|
518
|
+
- [ ] `safeword init` with interactive prompts
|
|
519
|
+
- [ ] `safeword init --yes` (non-interactive)
|
|
520
|
+
- [ ] `safeword init --ci` (CI mode)
|
|
521
|
+
- [ ] `safeword verify` (health check)
|
|
522
|
+
- [ ] `safeword --version`
|
|
523
|
+
- [ ] Auto-detect project type (Next.js, React, etc.)
|
|
524
|
+
- [ ] Copy templates to `.safeword/` and `.claude/`
|
|
525
|
+
- [ ] Install linting dependencies
|
|
526
|
+
- [ ] Register hooks in `.claude/settings.json`
|
|
527
|
+
- [ ] Create/update SAFEWORD.md reference
|
|
528
|
+
- [ ] Automatic verification after init
|
|
529
|
+
- [ ] Package manager detection (npm/yarn/pnpm)
|
|
530
|
+
- [ ] Non-TTY detection (auto-enable --ci mode)
|
|
531
|
+
|
|
532
|
+
**Nice to have (can ship after v1.0.0):**
|
|
533
|
+
|
|
534
|
+
- [ ] `safeword status` (detailed health report)
|
|
535
|
+
- [ ] `safeword verify --repair` (auto-fix broken hooks)
|
|
536
|
+
- [ ] Unit tests (70%+ coverage)
|
|
537
|
+
- [ ] Integration tests (smoke tests)
|
|
538
|
+
|
|
539
|
+
**Defer to Phase 2:**
|
|
540
|
+
|
|
541
|
+
- [ ] `safeword upgrade` (update templates)
|
|
542
|
+
- [ ] `safeword learning add/list` (manage learnings)
|
|
543
|
+
- [ ] Global learnings directory
|
|
544
|
+
- [ ] Version migration tooling
|
|
545
|
+
- [ ] Claude Code plugin wrapper
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
## Publishing (npm)
|
|
550
|
+
|
|
551
|
+
**Package name:** `@safeword/cli`
|
|
552
|
+
|
|
553
|
+
**package.json:**
|
|
554
|
+
|
|
555
|
+
```json
|
|
556
|
+
{
|
|
557
|
+
"name": "@safeword/cli",
|
|
558
|
+
"version": "1.0.0",
|
|
559
|
+
"description": "TDD workflows and quality patterns for Claude Code",
|
|
560
|
+
"bin": {
|
|
561
|
+
"safeword": "./dist/cli.js"
|
|
562
|
+
},
|
|
563
|
+
"files": ["dist/", "templates/"],
|
|
564
|
+
"keywords": ["claude-code", "tdd", "quality", "linting", "hooks"],
|
|
565
|
+
"repository": "github:TheMostlyGreat/safeword",
|
|
566
|
+
"license": "MIT"
|
|
567
|
+
}
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
**Build:**
|
|
571
|
+
|
|
572
|
+
```json
|
|
573
|
+
{
|
|
574
|
+
"scripts": {
|
|
575
|
+
"build": "tsc",
|
|
576
|
+
"dev": "tsx src/cli.ts",
|
|
577
|
+
"test": "vitest"
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
**Publish:**
|
|
583
|
+
|
|
584
|
+
```bash
|
|
585
|
+
npm run build
|
|
586
|
+
npm publish --access public
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
**Usage after publish:**
|
|
590
|
+
|
|
591
|
+
```bash
|
|
592
|
+
npx @safeword/cli init # Download + run (cached)
|
|
593
|
+
npm install -g @safeword/cli # Global install
|
|
594
|
+
safeword init # Run globally
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
## Migration from Bash Scripts
|
|
600
|
+
|
|
601
|
+
**Current state:**
|
|
602
|
+
|
|
603
|
+
- `setup-safeword.sh` (270 lines)
|
|
604
|
+
- `setup-linting.sh` (738 lines)
|
|
605
|
+
- `setup-quality.sh` (531 lines)
|
|
606
|
+
|
|
607
|
+
**Total:** ~1500 lines of bash
|
|
608
|
+
|
|
609
|
+
**Target:** ~800 lines of TypeScript (more maintainable, testable, cross-platform)
|
|
610
|
+
|
|
611
|
+
**Migration path:**
|
|
612
|
+
|
|
613
|
+
1. Ship CLI alongside bash scripts (backwards compatible)
|
|
614
|
+
2. Update README to recommend CLI
|
|
615
|
+
3. Mark bash scripts as deprecated (add warning banner)
|
|
616
|
+
4. Remove bash scripts in v2.0.0
|
|
617
|
+
|
|
618
|
+
**Deprecation notice in bash scripts:**
|
|
619
|
+
|
|
620
|
+
```bash
|
|
621
|
+
echo "⚠️ WARNING: Bash setup scripts are deprecated"
|
|
622
|
+
echo " Use the new CLI instead: npx @safeword/cli init"
|
|
623
|
+
echo " Bash scripts will be removed in v2.0.0"
|
|
624
|
+
echo ""
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
---
|
|
628
|
+
|
|
629
|
+
## Documentation Updates
|
|
630
|
+
|
|
631
|
+
**Update README.md:**
|
|
632
|
+
|
|
633
|
+
````markdown
|
|
634
|
+
## Quick Start
|
|
635
|
+
|
|
636
|
+
**1. Install:**
|
|
637
|
+
|
|
638
|
+
```bash
|
|
639
|
+
npx @safeword/cli init
|
|
640
|
+
```
|
|
641
|
+
````
|
|
642
|
+
|
|
643
|
+
**2. Verify:**
|
|
644
|
+
|
|
645
|
+
```bash
|
|
646
|
+
npx @safeword/cli verify
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
**3. Commit:**
|
|
650
|
+
|
|
651
|
+
```bash
|
|
652
|
+
git add .safeword .claude SAFEWORD.md package.json
|
|
653
|
+
git commit -m "Add safeword config"
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
````
|
|
657
|
+
|
|
658
|
+
**Add CLI reference docs:**
|
|
659
|
+
```markdown
|
|
660
|
+
## CLI Reference
|
|
661
|
+
|
|
662
|
+
### safeword init
|
|
663
|
+
Initialize safeword in current project
|
|
664
|
+
|
|
665
|
+
Options:
|
|
666
|
+
--yes Accept all defaults
|
|
667
|
+
--ci Non-interactive mode (CI/CD)
|
|
668
|
+
--linting-only Skip quality review setup
|
|
669
|
+
--quality-only Skip linting setup
|
|
670
|
+
|
|
671
|
+
### safeword verify
|
|
672
|
+
Verify safeword configuration
|
|
673
|
+
|
|
674
|
+
Options:
|
|
675
|
+
--auto-init Auto-initialize if not configured
|
|
676
|
+
--repair Fix broken hooks
|
|
677
|
+
--ci CI mode (exit 0/1)
|
|
678
|
+
|
|
679
|
+
### safeword status
|
|
680
|
+
Show detailed project status
|
|
681
|
+
|
|
682
|
+
### safeword --version
|
|
683
|
+
Show CLI version
|
|
684
|
+
````
|
|
685
|
+
|
|
686
|
+
---
|
|
687
|
+
|
|
688
|
+
## Timeline Estimate
|
|
689
|
+
|
|
690
|
+
**Week 1: Setup + Core Commands**
|
|
691
|
+
|
|
692
|
+
- Day 1-2: Project setup, dependencies, TypeScript config
|
|
693
|
+
- Day 3-4: `safeword init` command (basic functionality)
|
|
694
|
+
- Day 5: `safeword verify` command
|
|
695
|
+
|
|
696
|
+
**Week 2: Templates + Auto-Detection**
|
|
697
|
+
|
|
698
|
+
- Day 1-2: Embed templates in package
|
|
699
|
+
- Day 3-4: Project type detection logic
|
|
700
|
+
- Day 5: Template copying + hook registration
|
|
701
|
+
|
|
702
|
+
**Week 3: Polish + Testing**
|
|
703
|
+
|
|
704
|
+
- Day 1-2: Interactive prompts (clack/prompts)
|
|
705
|
+
- Day 3: CI mode, package manager detection
|
|
706
|
+
- Day 4-5: Testing (unit + integration)
|
|
707
|
+
|
|
708
|
+
**Week 4: Publish + Migrate**
|
|
709
|
+
|
|
710
|
+
- Day 1: Build system, publish to npm
|
|
711
|
+
- Day 2-3: Update README, add CLI docs
|
|
712
|
+
- Day 4-5: Test in real projects, fix bugs
|
|
713
|
+
|
|
714
|
+
**Total: 4 weeks to v1.0.0**
|
|
715
|
+
|
|
716
|
+
---
|
|
717
|
+
|
|
718
|
+
## Success Criteria
|
|
719
|
+
|
|
720
|
+
**v1.0.0 is ready when:**
|
|
721
|
+
|
|
722
|
+
1. ✅ CLI fully replaces bash scripts (feature parity)
|
|
723
|
+
2. ✅ One-command setup works: `npx @safeword/cli init`
|
|
724
|
+
3. ✅ Verification catches broken configs: `safeword verify`
|
|
725
|
+
4. ✅ CI mode works in GitHub Actions
|
|
726
|
+
5. ✅ Published to npm as `@safeword/cli`
|
|
727
|
+
6. ✅ README updated with new install instructions
|
|
728
|
+
7. ✅ Tested in 3+ real projects (Next.js, React, TypeScript)
|
|
729
|
+
8. ✅ No critical bugs (linting works, hooks trigger)
|
|
730
|
+
|
|
731
|
+
**Ship when these are green. Don't wait for perfect.**
|
|
732
|
+
|
|
733
|
+
---
|
|
734
|
+
|
|
735
|
+
## Phase 2: Advanced Features (Future)
|
|
736
|
+
|
|
737
|
+
**Defer these until v1.0.0 shipped and validated:**
|
|
738
|
+
|
|
739
|
+
- `safeword upgrade` - Update project templates
|
|
740
|
+
- `safeword learning add/list` - Manage learnings
|
|
741
|
+
- Version migration tooling (`safeword migrate`)
|
|
742
|
+
- Claude Code plugin wrapper (`/safeword:init`)
|
|
743
|
+
- Health monitoring (daily status reports)
|
|
744
|
+
- Team analytics (hook usage stats)
|
|
745
|
+
|
|
746
|
+
**Get feedback first. Don't over-engineer.**
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
## Anti-Patterns to Avoid
|
|
751
|
+
|
|
752
|
+
**❌ Don't:**
|
|
753
|
+
|
|
754
|
+
- Build version migration before v2.0.0 exists
|
|
755
|
+
- Add cache management (npm already caches)
|
|
756
|
+
- Convert guides to "skills" (terminology confusion)
|
|
757
|
+
- Make it a Claude Code plugin (lose project-local benefits)
|
|
758
|
+
- Use `postinstall` scripts (security red flag)
|
|
759
|
+
- Support every edge case (ship fast, iterate)
|
|
760
|
+
|
|
761
|
+
**✅ Do:**
|
|
762
|
+
|
|
763
|
+
- Start with MVP (init + verify)
|
|
764
|
+
- Ship incrementally (don't wait for perfect)
|
|
765
|
+
- Test in real projects early
|
|
766
|
+
- Get feedback before Phase 2
|
|
767
|
+
- Keep it simple (no premature abstraction)
|
|
768
|
+
- Follow XDG standards (if adding global state)
|
|
769
|
+
|
|
770
|
+
---
|
|
771
|
+
|
|
772
|
+
## Decision Log
|
|
773
|
+
|
|
774
|
+
**Decisions made:**
|
|
775
|
+
|
|
776
|
+
1. ✅ TypeScript CLI (not bash) - Maintainability > speed
|
|
777
|
+
2. ✅ npx distribution (not curl) - Target audience has Node.js
|
|
778
|
+
3. ✅ Project-local (not plugin) - Team consistency + versioning
|
|
779
|
+
4. ✅ `@clack/prompts` (not inquirer) - Modern, actively maintained
|
|
780
|
+
5. ✅ Embed templates (not download) - Offline support
|
|
781
|
+
6. ✅ `prepare` script (not postinstall) - Security
|
|
782
|
+
7. ✅ XDG compliance (for global learnings) - Standards matter
|
|
783
|
+
|
|
784
|
+
**Decisions deferred:**
|
|
785
|
+
|
|
786
|
+
1. ⏸ Claude Code plugin wrapper - Wait for v1.0.0 feedback
|
|
787
|
+
2. ⏸ Version migration tooling - Wait for v2.0.0
|
|
788
|
+
3. ⏸ Learning management - Wait for user demand
|
|
789
|
+
4. ⏸ Status command - Nice to have, not blocking
|
|
790
|
+
|
|
791
|
+
**Questions to answer during implementation:**
|
|
792
|
+
|
|
793
|
+
1. Should `safeword verify --auto-init` run automatically on `npm install`?
|
|
794
|
+
2. Should we ask before mutating `package.json` in `--yes` mode?
|
|
795
|
+
3. Should `safeword status` check npm registry for updates (network call)?
|
|
796
|
+
4. How much output is too much in CI mode?
|
|
797
|
+
|
|
798
|
+
---
|
|
799
|
+
|
|
800
|
+
## Next Steps
|
|
801
|
+
|
|
802
|
+
**Start here:**
|
|
803
|
+
|
|
804
|
+
1. **Create CLI package:**
|
|
805
|
+
|
|
806
|
+
```bash
|
|
807
|
+
mkdir -p packages/cli/src/{commands,lib,templates}
|
|
808
|
+
cd packages/cli
|
|
809
|
+
npm init -y
|
|
810
|
+
npm install commander @clack/prompts fs-extra picocolors execa
|
|
811
|
+
npm install -D typescript @types/node tsx vitest
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
2. **Copy templates:**
|
|
815
|
+
|
|
816
|
+
```bash
|
|
817
|
+
cp ../SAFEWORD.md src/templates/SAFEWORD.md
|
|
818
|
+
cp -r ../guides src/templates/guides
|
|
819
|
+
cp -r ../.claude/hooks src/templates/hooks
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
3. **Build `safeword init` skeleton:**
|
|
823
|
+
|
|
824
|
+
```typescript
|
|
825
|
+
// src/cli.ts
|
|
826
|
+
#!/usr/bin/env node
|
|
827
|
+
import { Command } from 'commander';
|
|
828
|
+
import { init } from './commands/init';
|
|
829
|
+
|
|
830
|
+
const program = new Command();
|
|
831
|
+
|
|
832
|
+
program
|
|
833
|
+
.name('safeword')
|
|
834
|
+
.version('1.0.0');
|
|
835
|
+
|
|
836
|
+
program
|
|
837
|
+
.command('init')
|
|
838
|
+
.option('--yes', 'Accept all defaults')
|
|
839
|
+
.option('--ci', 'Non-interactive mode')
|
|
840
|
+
.action(init);
|
|
841
|
+
|
|
842
|
+
program.parse();
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
4. **Test locally:**
|
|
846
|
+
|
|
847
|
+
```bash
|
|
848
|
+
chmod +x src/cli.ts
|
|
849
|
+
npm link
|
|
850
|
+
cd ~/test-project
|
|
851
|
+
safeword init --yes
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
5. **Iterate until it works, then ship.**
|
|
855
|
+
|
|
856
|
+
**Don't overthink. Start coding.**
|