Skip to content

Commit 20bf6d8

Browse files
ansonphongclaude
andcommitted
Add .claude/rules/ for contextual convention enforcement
Extract coding conventions from CLAUDE.md into 4 modular rules files (typescript, webview, yaml-operations, testing) that load contextually when editing matching file patterns. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e440874 commit 20bf6d8

5 files changed

Lines changed: 129 additions & 16 deletions

File tree

.claude/rules/testing.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Rules: Testing
2+
3+
Applies when creating or modifying files in `src/**/*.test.ts` or `src/test/`.
4+
5+
## Unit Tests (Vitest)
6+
7+
- All unit tests use Vitest — run with `npm test` (includes typecheck) or `npm run test:watch`
8+
- VS Code API is mocked via `src/__mocks__/vscode.ts` — aliased in `vitest.config.ts`
9+
- **Never create inline VS Code mocks** — always use the shared mock file
10+
- Test files live alongside source: `src/codexModel.test.ts`, `src/search/tokenizer.test.ts`
11+
- Coverage: `npm run test:coverage` — v8 provider, reports to `./coverage/`
12+
13+
## Integration Tests (@vscode/test-electron)
14+
15+
- Live in `src/test/suite/` — compiled separately via `tsconfig.test.json``out/test/`
16+
- Use Mocha (not Vitest) — the test-electron runner requires it
17+
- Fixture workspace: `src/test/fixtures/workspace/test.codex.yaml`
18+
- Require a display server — use `xvfb-run` on CI
19+
- Test real extension activation, command registration, tree provider context
20+
21+
## TDD Pattern
22+
23+
When adding new features:
24+
1. Write failing test first
25+
2. Run `npm test` to confirm it fails
26+
3. Implement minimal code to pass
27+
4. Run `npm test` to confirm it passes
28+
5. Refactor if needed, re-run tests
29+
30+
## Config Split
31+
32+
- `tsconfig.json` excludes test files (`src/**/*.test.ts`, `src/__mocks__/**`, `src/test/**`)
33+
- `tsconfig.test.json` includes only integration test files
34+
- Vitest handles its own module resolution for unit tests

.claude/rules/typescript.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Rules: TypeScript Conventions
2+
3+
Applies when creating or modifying `.ts` files in `src/`.
4+
5+
## Hard Rules
6+
7+
- **Async file ops only** — Use `fs.promises` (readFile, writeFile, stat, etc.). Never use sync variants (`readFileSync`, `writeFileSync`, `statSync`, etc.). The extension runs in VS Code's extension host — sync I/O blocks the UI.
8+
- **No `as any` type bypasses** — Use proper typing. If you need to attach metadata to an object, use a `WeakMap` (see `panelResolverKeys` pattern in `writerView/manager.ts`).
9+
- **Path traversal validation** — Always call `isPathWithinWorkspace()` + `path.resolve()` before any file operation on user-provided paths. Import from `writerView/utils/helpers.ts`.
10+
- **SVG excluded from import** — SVG is an XSS vector. Never add SVG to import/embed flows. SVGs are display-only via workspace scanner with CSP blocking scripts.
11+
12+
## Patterns
13+
14+
- Use `WeakMap` for panel metadata (resolver keys) instead of casting with `as any`
15+
- `pendingDuplicateResolvers` Map + `panelResolverKeys` WeakMap for Promise-based webview dialogs
16+
- Resolve pending promises in `onDidDispose` to prevent hangs
17+
- Module-level state lives in `extensionState.ts` — access via `getDeps()`, not global variables
18+
- Commands are registered in domain-specific modules under `commands/` — routed by `commands/register.ts`
19+
20+
## Tech Stack
21+
22+
- TypeScript ES2022, strict mode, CommonJS output
23+
- esbuild bundles `src/extension.ts``out/extension.js`
24+
- Runtime deps: `yaml`, `minimatch` — keep minimal
25+
- `vscode` is external (provided by VS Code runtime, never bundled)

.claude/rules/webview.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Rules: Webview & Writer View
2+
3+
Applies when creating or modifying files in `src/writerView/`.
4+
5+
## Security
6+
7+
- **HTML escape ALL interpolations** — Use `escapeHtml()` from `writerView/utils/helpers.ts`. It escapes `<`, `>`, `&`, `"`, and `'` (as `&#039;`). Never interpolate user content into HTML without escaping.
8+
- **CSP header required** — Every webview must include: `img-src ${webview.cspSource} data:;`. Scripts must use nonce-based CSP.
9+
- **No inline scripts** — All JavaScript goes through nonce-gated `<script>` tags. CSP blocks inline event handlers.
10+
11+
## Image Handling
12+
13+
- SHA256 content hash with file-size pre-filter for image deduplication
14+
- Images stored workspace-relative, served via `webview.asWebviewUri()`
15+
- `data:` URIs allowed in CSP for small inline images only
16+
17+
## Webview Communication
18+
19+
- Use `safePostMessage()` from helpers for extension → webview messages
20+
- Webview → extension communication via `vscode.postMessage()` with typed message objects
21+
- Always validate message types in both directions
22+
23+
## File Structure
24+
25+
```
26+
writerView/
27+
├── manager.ts # Panel pool, file locking, lifecycle
28+
├── script.ts # Webview-side JavaScript
29+
├── html/
30+
│ ├── builder.ts # Main HTML assembly
31+
│ ├── contentRenderer.ts
32+
│ ├── attributesRenderer.ts
33+
│ ├── imagesRenderer.ts
34+
│ └── imageBrowserRenderer.ts
35+
├── toolbar/ # Contextual toolbar components
36+
└── utils/
37+
└── helpers.ts # escapeHtml, isPathWithinWorkspace, safePostMessage, nonce
38+
```

.claude/rules/yaml-operations.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Rules: YAML & Codex Operations
2+
3+
Applies when creating or modifying code that reads or writes `.codex.yaml`, `.codex.json`, or `.codex.md` files.
4+
5+
## Mutation Safety
6+
7+
- **Use `withFileLock()` for all YAML writes** — Concurrent writes corrupt YAML. The file lock prevents race conditions when multiple operations (auto-save, structure editing, drag-drop) target the same file.
8+
- **Preserve YAML comments and formatting**`codexModel.ts` uses the `yaml` library's AST-preserving mode. Don't replace it with naive parse/stringify.
9+
- **Validate after mutation** — After any structural change (add/remove/move nodes), run validation to catch broken references.
10+
11+
## Format Support
12+
13+
The extension handles three formats transparently:
14+
15+
| Format | Extension | Parser Path |
16+
|--------|-----------|-------------|
17+
| Codex YAML | `.codex.yaml` | `codexModel.ts``yaml` library |
18+
| Codex JSON | `.codex.json` | `codexModel.ts``JSON.parse` |
19+
| Codex Lite | `.md` with frontmatter | `codexModel.ts` → frontmatter extraction |
20+
21+
## Auto-Fixer
22+
23+
- `autoFixer.ts` repairs missing UUIDs, metadata, legacy fields, timecodes
24+
- Auto-fixer is aggressive — it can recover severely corrupted files
25+
- Always offer auto-fix via VS Code Quick Fix code actions, not silent mutation

CLAUDE.md

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -88,22 +88,13 @@ code --install-extension *.vsix --force
8888
- **GitHub Actions**: `.github/workflows/ci.yml` — typecheck, lint, unit tests + coverage, integration tests
8989
- **Lint**: ESLint with `continue-on-error: true` (18 pre-existing errors to clean up)
9090

91-
## Coding Conventions
92-
93-
### Must Follow
94-
- **Async file ops only** — Use `fs.promises`, never sync `fs.*Sync()`
95-
- **HTML escape all interpolations** — Use `escapeHtml()` from `writerView/utils/helpers.ts` (includes single-quote `&#039;`)
96-
- **Path traversal validation** — Use `isPathWithinWorkspace()` + `path.resolve()` before any file operation on user-provided paths
97-
- **No `as any` type bypasses** — Use proper typing, WeakMap for metadata
98-
- **YAML mutation locking** — Use `withFileLock()` for concurrent-safe YAML writes
99-
- **SVG excluded from import** — XSS vector; kept in workspace scanner only (display-only, CSP blocks scripts)
100-
101-
### Patterns
102-
- WeakMap for panel metadata (resolver keys) instead of `(panel as any)`
103-
- `pendingDuplicateResolvers` Map + `panelResolverKeys` WeakMap for Promise-based webview dialogs
104-
- Resolve pending promises in `onDidDispose` to prevent hangs
105-
- CSP header: `img-src ${webview.cspSource} data:;` required for images
106-
- SHA256 content hash with size pre-filter for image deduplication
91+
## Modular Rules
92+
93+
See `.claude/rules/` for convention-specific rules that load contextually:
94+
- `typescript.md` — async FS, no `as any`, path validation, typing patterns
95+
- `webview.md` — HTML escaping, CSP headers, image handling, webview communication
96+
- `yaml-operations.md` — file locking, format support, mutation safety, auto-fixer
97+
- `testing.md` — Vitest patterns, integration tests, TDD, config split
10798

10899
### Tech Stack
109100
- **Language**: TypeScript (ES2022, strict, CommonJS)

0 commit comments

Comments
 (0)