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,343 @@
|
|
|
1
|
+
# Design: Safeword CLI
|
|
2
|
+
|
|
3
|
+
**Guide**: `@./.safeword/guides/design-doc-guide.md` - Principles, structure guidelines, and avoiding bloat
|
|
4
|
+
**Template**: `@./.safeword/templates/design-doc-template.md`
|
|
5
|
+
|
|
6
|
+
**Related**: User Stories: `.safeword/planning/user-stories/005-cli-implementation.md` | Test Definitions: `.safeword/planning/test-definitions/005-cli-implementation.md`
|
|
7
|
+
|
|
8
|
+
**TDD Note**: This design implements tests from Test Definitions. Reference specific test scenarios (e.g., "Test 3.1: Registers hooks in settings.json").
|
|
9
|
+
|
|
10
|
+
## Architecture
|
|
11
|
+
|
|
12
|
+
The CLI is a TypeScript Node.js application structured around command handlers. Each command (setup, check, upgrade, diff, reset) is an independent module that shares utilities for file operations, prompting, and output formatting.
|
|
13
|
+
|
|
14
|
+
The core principle is **idempotent operations with explicit state**: the CLI reads project state from `.safeword/version` and `.claude/settings.json`, performs operations, and writes state back. No global state or caching between runs.
|
|
15
|
+
|
|
16
|
+
**Diagram**:
|
|
17
|
+
```
|
|
18
|
+
┌─────────────────────────────────────────────────────────┐
|
|
19
|
+
│ CLI Entry │
|
|
20
|
+
│ (parse args, route to command) │
|
|
21
|
+
└─────────────────────────────────────────────────────────┘
|
|
22
|
+
│
|
|
23
|
+
┌─────────────────┼─────────────────┐
|
|
24
|
+
▼ ▼ ▼
|
|
25
|
+
┌─────────┐ ┌──────────┐ ┌─────────┐
|
|
26
|
+
│ setup │ │ check │ │ reset │
|
|
27
|
+
│ upgrade │ │ diff │ │ │
|
|
28
|
+
└────┬────┘ └────┬─────┘ └────┬────┘
|
|
29
|
+
│ │ │
|
|
30
|
+
└────────────────┼─────────────────┘
|
|
31
|
+
▼
|
|
32
|
+
┌─────────────────────┐
|
|
33
|
+
│ Utilities │
|
|
34
|
+
│ ─────────────────── │
|
|
35
|
+
│ • FileManager │
|
|
36
|
+
│ • HookManager │
|
|
37
|
+
│ • Prompter │
|
|
38
|
+
│ • ProjectDetector │
|
|
39
|
+
│ • OutputFormatter │
|
|
40
|
+
└─────────────────────┘
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Components
|
|
44
|
+
|
|
45
|
+
### Component 1: CLI Entry (`src/cli.ts`)
|
|
46
|
+
|
|
47
|
+
**What**: Parses arguments, routes to command handlers, handles global flags
|
|
48
|
+
**Where**: `packages/cli/src/cli.ts`
|
|
49
|
+
**Interface**:
|
|
50
|
+
```typescript
|
|
51
|
+
// Entry point
|
|
52
|
+
async function main(args: string[]): Promise<void>;
|
|
53
|
+
|
|
54
|
+
// Parsed options available to all commands
|
|
55
|
+
interface GlobalOptions {
|
|
56
|
+
version: boolean;
|
|
57
|
+
help: boolean;
|
|
58
|
+
yes: boolean; // --yes flag
|
|
59
|
+
verbose: boolean; // --verbose flag
|
|
60
|
+
offline: boolean; // --offline flag
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Dependencies**: Commander.js (arg parsing), all command modules
|
|
65
|
+
**Tests**: Test 1.1-1.3 (version, help, bare command)
|
|
66
|
+
|
|
67
|
+
### Component 2: Setup Command (`src/commands/setup.ts`)
|
|
68
|
+
|
|
69
|
+
**What**: Orchestrates full project setup - files, hooks, skills, linting, AGENTS.md
|
|
70
|
+
**Where**: `packages/cli/src/commands/setup.ts`
|
|
71
|
+
**Interface**:
|
|
72
|
+
```typescript
|
|
73
|
+
interface SetupOptions {
|
|
74
|
+
yes: boolean; // Skip prompts
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function setup(options: SetupOptions): Promise<void>;
|
|
78
|
+
|
|
79
|
+
// Throws SetupError on failure (exit 1)
|
|
80
|
+
// Returns normally on success (exit 0)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Dependencies**: FileManager, HookManager, Prompter, ProjectDetector, LintingSetup
|
|
84
|
+
**Tests**: Test 2.1-2.5, 3.1-3.5, 4.4-4.8, 5.1-5.2, 6.1-6.3, 7.1-7.5
|
|
85
|
+
|
|
86
|
+
### Component 2b: Other Commands (check, upgrade, diff, reset)
|
|
87
|
+
|
|
88
|
+
| Command | File | What | Dependencies | Tests |
|
|
89
|
+
|---------|------|------|--------------|-------|
|
|
90
|
+
| check | `commands/check.ts` | Show versions, verify structure, check for updates | FileManager, npm registry fetch | 8.1-8.7 |
|
|
91
|
+
| upgrade | `commands/upgrade.ts` | Overwrite .safeword/, update hooks/skills | FileManager, HookManager | 9.1-9.7 |
|
|
92
|
+
| diff | `commands/diff.ts` | Compare project vs bundled templates | FileManager | 10.1-10.5 |
|
|
93
|
+
| reset | `commands/reset.ts` | Remove .safeword/, hooks, skills, AGENTS.md link | FileManager, HookManager, Prompter | 11.1-11.10 |
|
|
94
|
+
|
|
95
|
+
All commands share the same pattern: parse options → check project state → perform operation → output result.
|
|
96
|
+
|
|
97
|
+
### Component 3: FileManager (`src/utils/file-manager.ts`)
|
|
98
|
+
|
|
99
|
+
**What**: Handles all file system operations - copy, write, read, delete with atomic operations
|
|
100
|
+
**Where**: `packages/cli/src/utils/file-manager.ts`
|
|
101
|
+
**Interface**:
|
|
102
|
+
```typescript
|
|
103
|
+
interface FileManager {
|
|
104
|
+
// Template operations
|
|
105
|
+
copyTemplates(dest: string): Promise<string[]>;
|
|
106
|
+
|
|
107
|
+
// Version file
|
|
108
|
+
readVersion(projectRoot: string): Promise<string | null>;
|
|
109
|
+
writeVersion(projectRoot: string, version: string): Promise<void>;
|
|
110
|
+
|
|
111
|
+
// AGENTS.md operations
|
|
112
|
+
prependAgentsLink(projectRoot: string): Promise<void>;
|
|
113
|
+
removeAgentsLink(projectRoot: string): Promise<void>;
|
|
114
|
+
hasAgentsLink(projectRoot: string): Promise<boolean>;
|
|
115
|
+
|
|
116
|
+
// Diff operations
|
|
117
|
+
diffTemplates(projectRoot: string): Promise<DiffResult>;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
interface DiffResult {
|
|
121
|
+
added: string[];
|
|
122
|
+
modified: string[];
|
|
123
|
+
unchanged: string[];
|
|
124
|
+
removed: string[];
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Dependencies**: Node fs/promises, path
|
|
129
|
+
**Tests**: Test 2.1-2.4, 9.1, 10.1-10.4, 11.4, 11.8
|
|
130
|
+
|
|
131
|
+
### Component 4: HookManager (`src/utils/hook-manager.ts`)
|
|
132
|
+
|
|
133
|
+
**What**: Manages Claude Code hooks in settings.json and git hooks in .git/hooks/
|
|
134
|
+
**Where**: `packages/cli/src/utils/hook-manager.ts`
|
|
135
|
+
**Interface**:
|
|
136
|
+
```typescript
|
|
137
|
+
interface HookManager {
|
|
138
|
+
// Claude hooks
|
|
139
|
+
registerClaudeHooks(projectRoot: string): Promise<void>;
|
|
140
|
+
removeClaudeHooks(projectRoot: string): Promise<void>;
|
|
141
|
+
getClaudeHooks(projectRoot: string): Promise<ClaudeSettings>;
|
|
142
|
+
|
|
143
|
+
// Git hooks
|
|
144
|
+
installGitHooks(projectRoot: string): Promise<void>;
|
|
145
|
+
removeGitHooks(projectRoot: string): Promise<void>;
|
|
146
|
+
|
|
147
|
+
// Skills
|
|
148
|
+
copySkills(projectRoot: string): Promise<void>;
|
|
149
|
+
removeSkills(projectRoot: string): Promise<void>;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Marker constants for git hooks
|
|
153
|
+
const GIT_HOOK_START = '# SAFEWORD_ARCH_CHECK_START';
|
|
154
|
+
const GIT_HOOK_END = '# SAFEWORD_ARCH_CHECK_END';
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Dependencies**: FileManager (for file ops)
|
|
158
|
+
**Tests**: Test 3.1-3.5, 7.4-7.5, 11.5-11.7
|
|
159
|
+
|
|
160
|
+
### Component 5: Prompter (`src/utils/prompter.ts`)
|
|
161
|
+
|
|
162
|
+
**What**: Handles interactive prompts with TTY detection and --yes override
|
|
163
|
+
**Where**: `packages/cli/src/utils/prompter.ts`
|
|
164
|
+
**Interface**:
|
|
165
|
+
```typescript
|
|
166
|
+
interface Prompter {
|
|
167
|
+
// Check if running interactively
|
|
168
|
+
isInteractive(): boolean;
|
|
169
|
+
|
|
170
|
+
// Prompt with automatic default in non-interactive mode
|
|
171
|
+
confirm(message: string, defaultValue: boolean): Promise<boolean>;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Factory to inject --yes flag
|
|
175
|
+
function createPrompter(options: { yes: boolean }): Prompter;
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Dependencies**: Node readline, process.stdin.isTTY
|
|
179
|
+
**Tests**: Test 6.1-6.3, 7.1-7.3, 11.1-11.3
|
|
180
|
+
|
|
181
|
+
### Component 6: ProjectDetector (`src/utils/project-detector.ts`)
|
|
182
|
+
|
|
183
|
+
**What**: Detects project type from package.json for linting configuration
|
|
184
|
+
**Where**: `packages/cli/src/utils/project-detector.ts`
|
|
185
|
+
**Interface**:
|
|
186
|
+
```typescript
|
|
187
|
+
interface ProjectType {
|
|
188
|
+
typescript: boolean;
|
|
189
|
+
react: boolean;
|
|
190
|
+
nextjs: boolean;
|
|
191
|
+
astro: boolean;
|
|
192
|
+
node: boolean;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function detectProjectType(packageJson: PackageJson): ProjectType;
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Dependencies**: None (pure function)
|
|
199
|
+
**Tests**: Test 4.1-4.3
|
|
200
|
+
|
|
201
|
+
### Component 7: LintingSetup (`src/utils/linting-setup.ts`)
|
|
202
|
+
|
|
203
|
+
**What**: Installs and configures ESLint + Prettier based on detected project type
|
|
204
|
+
**Where**: `packages/cli/src/utils/linting-setup.ts`
|
|
205
|
+
**Interface**:
|
|
206
|
+
```typescript
|
|
207
|
+
interface LintingSetup {
|
|
208
|
+
// Full setup - install deps, create configs, add scripts
|
|
209
|
+
configure(projectRoot: string, projectType: ProjectType): Promise<void>;
|
|
210
|
+
|
|
211
|
+
// Individual operations
|
|
212
|
+
installDependencies(projectRoot: string, projectType: ProjectType): Promise<void>;
|
|
213
|
+
createEslintConfig(projectRoot: string, projectType: ProjectType): Promise<void>;
|
|
214
|
+
createPrettierConfig(projectRoot: string): Promise<void>;
|
|
215
|
+
addPackageScripts(projectRoot: string): Promise<void>;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Throws LintingError on failure (exit 1 - core failure)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Dependencies**: ProjectDetector, child_process (for npm/pnpm install), FileManager
|
|
222
|
+
**Tests**: Test 4.4-4.8
|
|
223
|
+
|
|
224
|
+
## Data Model
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
// Project state (read from .safeword/version)
|
|
228
|
+
interface ProjectState {
|
|
229
|
+
configured: boolean;
|
|
230
|
+
version: string | null; // null if unconfigured
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Claude settings structure
|
|
234
|
+
interface ClaudeSettings {
|
|
235
|
+
hooks?: {
|
|
236
|
+
SessionStart?: HookConfig[];
|
|
237
|
+
PostToolUse?: HookConfig[];
|
|
238
|
+
Stop?: HookConfig[];
|
|
239
|
+
// ... other hook types
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
interface HookConfig {
|
|
244
|
+
matcher?: string;
|
|
245
|
+
hooks: Array<{
|
|
246
|
+
type: 'command';
|
|
247
|
+
command: string;
|
|
248
|
+
timeout?: number;
|
|
249
|
+
}>;
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Component Interaction
|
|
254
|
+
|
|
255
|
+
**Setup Flow:**
|
|
256
|
+
```
|
|
257
|
+
CLI Entry → Setup Command
|
|
258
|
+
→ FileManager.copyTemplates()
|
|
259
|
+
→ HookManager.registerClaudeHooks()
|
|
260
|
+
→ HookManager.copySkills()
|
|
261
|
+
→ LintingSetup.configure()
|
|
262
|
+
→ Prompter.confirm() [if no git]
|
|
263
|
+
→ HookManager.installGitHooks() [if git]
|
|
264
|
+
→ FileManager.prependAgentsLink()
|
|
265
|
+
→ FileManager.writeVersion()
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**Reset Flow:**
|
|
269
|
+
```
|
|
270
|
+
CLI Entry → Reset Command
|
|
271
|
+
→ Prompter.confirm()
|
|
272
|
+
→ FileManager.remove('.safeword/')
|
|
273
|
+
→ HookManager.removeClaudeHooks()
|
|
274
|
+
→ HookManager.removeSkills()
|
|
275
|
+
→ HookManager.removeGitHooks()
|
|
276
|
+
→ FileManager.removeAgentsLink()
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## User Flow
|
|
280
|
+
|
|
281
|
+
1. User runs `npx safeword setup` in project directory
|
|
282
|
+
2. CLI checks for existing `.safeword/` → errors if found
|
|
283
|
+
3. CLI detects project type from package.json
|
|
284
|
+
4. CLI copies templates to `.safeword/`
|
|
285
|
+
5. CLI registers hooks in `.claude/settings.json`
|
|
286
|
+
6. CLI installs ESLint + Prettier, creates configs
|
|
287
|
+
7. CLI checks for `.git/` → prompts if missing (skips with --yes)
|
|
288
|
+
8. CLI prepends link to `AGENTS.md`
|
|
289
|
+
9. CLI prints success summary with file counts
|
|
290
|
+
|
|
291
|
+
## Key Decisions
|
|
292
|
+
|
|
293
|
+
### Decision 1: Commander.js for argument parsing
|
|
294
|
+
|
|
295
|
+
**What**: Use Commander.js instead of manual argv parsing or alternatives (yargs, meow)
|
|
296
|
+
**Why**: Most popular (40k+ GitHub stars), excellent TypeScript support, subcommand pattern matches our design, minimal bundle size impact
|
|
297
|
+
**Trade-off**: External dependency vs zero-dep (but arg parsing is complex enough to warrant it)
|
|
298
|
+
|
|
299
|
+
### Decision 2: Marker-based git hooks
|
|
300
|
+
|
|
301
|
+
**What**: Use comment markers (`SAFEWORD_ARCH_CHECK_START/END`) for git hook content
|
|
302
|
+
**Why**: Allows coexistence with other tools (husky, lint-staged) that also modify pre-commit hooks
|
|
303
|
+
**Trade-off**: Slightly more complex removal logic, but essential for ecosystem compatibility
|
|
304
|
+
|
|
305
|
+
### Decision 3: Bundled templates
|
|
306
|
+
|
|
307
|
+
**What**: Ship templates as part of npm package, copy on setup (not fetch from GitHub)
|
|
308
|
+
**Why**: Works offline, faster setup, version-locked to CLI, no network dependency
|
|
309
|
+
**Trade-off**: Larger package size (~500KB), but acceptable for CLI tool
|
|
310
|
+
|
|
311
|
+
### Decision 4: No config file
|
|
312
|
+
|
|
313
|
+
**What**: No `.safewordrc` or similar - all behavior via flags
|
|
314
|
+
**Why**: Simpler mental model, npx-first means config rarely persists anyway, flags are explicit
|
|
315
|
+
**Trade-off**: Can't persist preferences, but `--yes` covers the main use case (CI)
|
|
316
|
+
|
|
317
|
+
## Implementation Notes
|
|
318
|
+
|
|
319
|
+
**Constraints**:
|
|
320
|
+
- Node 18+ required (use engines field in package.json)
|
|
321
|
+
- Must work with npm, pnpm, yarn, bun for linting deps install
|
|
322
|
+
- Max 500ms startup time (lazy-load heavy modules)
|
|
323
|
+
|
|
324
|
+
**Error Handling**:
|
|
325
|
+
- Core failures (can't write files, linting fails) → exit 1 with clear message
|
|
326
|
+
- Warnings (no git, offline) → exit 0 with warning in output
|
|
327
|
+
- Use custom error classes: `SetupError`, `ConfigError`, `NetworkError`
|
|
328
|
+
|
|
329
|
+
**Gotchas**:
|
|
330
|
+
- Always check for existing `.safeword/` before any writes in setup
|
|
331
|
+
- AGENTS.md link must be exact string match for removal
|
|
332
|
+
- Git hooks must preserve existing content outside markers
|
|
333
|
+
- settings.json might not exist yet - create if missing
|
|
334
|
+
|
|
335
|
+
**Open Questions**:
|
|
336
|
+
- [ ] Which npm registry endpoint for version check? (registry.npmjs.org/safeword/latest)
|
|
337
|
+
- [ ] Should we support Bun's package manager for linting install?
|
|
338
|
+
|
|
339
|
+
## References
|
|
340
|
+
|
|
341
|
+
- [CLI UX Vision](../../.agents/planning/011-cli-ux-vision.md)
|
|
342
|
+
- [Ticket #005](../../.agents/tickets/005-cli-implementation.md)
|
|
343
|
+
- [Commander.js docs](https://github.com/tj/commander.js)
|