@pavp/wavefront 0.1.0
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/LICENSE +21 -0
- package/README.md +226 -0
- package/agents/i18n-tokens.md +58 -0
- package/agents/mapper.md +64 -0
- package/agents/module-builder.md +90 -0
- package/agents/reviewer.md +65 -0
- package/agents/tester.md +84 -0
- package/bin/wavefront.js +91 -0
- package/commands/wavefront-change.md +26 -0
- package/commands/wavefront-execute.md +28 -0
- package/commands/wavefront-feature.md +25 -0
- package/commands/wavefront-fix.md +28 -0
- package/commands/wavefront-init.md +27 -0
- package/commands/wavefront-plan.md +30 -0
- package/commands/wavefront-ship.md +26 -0
- package/commands/wavefront-state.md +23 -0
- package/commands/wavefront-verify.md +24 -0
- package/hooks/lint-after-edit.sh +43 -0
- package/hooks/typecheck-on-stop.sh +27 -0
- package/install.sh +83 -0
- package/package.json +67 -0
- package/planning-templates/PHASE_PLAN.md +37 -0
- package/planning-templates/PROJECT.md +18 -0
- package/planning-templates/REQUIREMENTS.md +27 -0
- package/planning-templates/ROADMAP.md +12 -0
- package/planning-templates/STATE.md +21 -0
- package/settings.template.json +29 -0
- package/skills/clean-architecture/SKILL.md +46 -0
- package/skills/component-composition/SKILL.md +67 -0
- package/skills/component-composition/examples/compound-component.md +62 -0
- package/skills/data-fetching-react-query/SKILL.md +68 -0
- package/skills/design-intake/SKILL.md +69 -0
- package/skills/design-system-inventory/SKILL.md +38 -0
- package/skills/forms-rhf-zod/SKILL.md +75 -0
- package/skills/gateway-pattern/SKILL.md +79 -0
- package/skills/hook-patterns/SKILL.md +74 -0
- package/skills/i18n-next-intl/SKILL.md +59 -0
- package/skills/module-structure/SKILL.md +98 -0
- package/skills/mui-design-tokens/SKILL.md +60 -0
- package/skills/naming-conventions/SKILL.md +65 -0
- package/skills/repository-pattern/SKILL.md +128 -0
- package/skills/requirement-intake/SKILL.md +65 -0
- package/skills/responsive-layouts/SKILL.md +64 -0
- package/skills/selector-pattern/SKILL.md +59 -0
- package/skills/store-zustand/SKILL.md +63 -0
- package/skills/sync-audit/SKILL.md +52 -0
- package/skills/testing-jest-rtl/SKILL.md +83 -0
- package/uninstall.sh +36 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sync-audit
|
|
3
|
+
description: Detect drift between wavefront's self-contained skills and the scaffold they were distilled from, by comparing each skill's source_version pin against the current scaffold. Read when running an audit or before trusting skills on a newer scaffold.
|
|
4
|
+
source: wavefront framework meta — audits the other skills
|
|
5
|
+
source_version: 8edaa0b
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Sync audit (drift detection)
|
|
9
|
+
|
|
10
|
+
wavefront skills are **self-contained** (copied knowledge, not links to scaffold `docs/`). The tradeoff: they can drift as the scaffold evolves. This skill is the promised mitigation — it detects drift so skills get re-pinned deliberately.
|
|
11
|
+
|
|
12
|
+
## What each skill carries
|
|
13
|
+
|
|
14
|
+
Every `*/SKILL.md` frontmatter has:
|
|
15
|
+
- `source:` — the scaffold file(s)/doc(s) it was distilled from.
|
|
16
|
+
- `source_version:` — the scaffold git commit it was pinned at (currently `8edaa0b`).
|
|
17
|
+
|
|
18
|
+
Drift = the scaffold's `source` files changed since `source_version`.
|
|
19
|
+
|
|
20
|
+
## Audit procedure
|
|
21
|
+
|
|
22
|
+
Inputs: path to a scaffold checkout (or the generated app, which mirrors it). Without it, degrade to a frontmatter-only report (list pins, can't diff).
|
|
23
|
+
|
|
24
|
+
1. **Collect pins:** read `source_version` + `source` from all `.claude/skills/*/SKILL.md`. Confirm they agree on one version (they should).
|
|
25
|
+
2. **Get scaffold HEAD:** in the scaffold repo, `git rev-parse --short HEAD`. If it equals the pin → CLEAN, stop.
|
|
26
|
+
3. **Diff source files:** `git diff --name-only <pin> <HEAD> -- <union of all skills' source paths>`.
|
|
27
|
+
- Map each changed file back to the skill(s) whose `source:` references it.
|
|
28
|
+
4. **Classify:**
|
|
29
|
+
- **STALE (action needed):** a skill's `source` file changed → its content may be wrong.
|
|
30
|
+
- **PIN-ONLY (cheap):** no source file changed but `source_version` < HEAD → just bump the pin (content still valid). This was the case for `8148abf → 8edaa0b`.
|
|
31
|
+
5. **Report:** per-skill verdict + the diff summary for STALE ones + a suggested re-pin/re-distill list. Read-only — never auto-rewrite skills.
|
|
32
|
+
|
|
33
|
+
## Output shape
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
wavefront sync-audit — pin 8edaa0b vs scaffold <HEAD>
|
|
37
|
+
CLEAN: <n> skills (no source change)
|
|
38
|
+
PIN-ONLY: <skills> → bump source_version to <HEAD>
|
|
39
|
+
STALE: <skill> ← <changed file> (re-distill: <what to recheck>)
|
|
40
|
+
Verdict: <CLEAN | PIN-ONLY bump | RE-DISTILL needed>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Re-pin vs re-distill
|
|
44
|
+
- **PIN-ONLY:** bulk-bump `source_version` across skills (mechanical).
|
|
45
|
+
- **STALE:** read the changed source file, update that skill's content, then bump its pin. One skill at a time.
|
|
46
|
+
|
|
47
|
+
## Notes
|
|
48
|
+
- Scaffold source moves independently of wavefront; expect periodic PIN-ONLY drift.
|
|
49
|
+
- Generated apps == scaffold at their generation commit, so a generated app is a valid diff target when the scaffold repo isn't handy.
|
|
50
|
+
|
|
51
|
+
## Related
|
|
52
|
+
Audits all pattern/core skills: [[clean-architecture]] [[module-structure]] [[naming-conventions]] [[repository-pattern]] [[gateway-pattern]] [[data-fetching-react-query]] [[store-zustand]] [[selector-pattern]] [[hook-patterns]] [[forms-rhf-zod]] [[mui-design-tokens]] [[testing-jest-rtl]] [[i18n-next-intl]]
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing-jest-rtl
|
|
3
|
+
description: Jest + React Testing Library conventions in scaffold-nextjs-app — renderWithProviders, faker mock factories, colocated tests. Read before writing tests.
|
|
4
|
+
source: scaffold-nextjs-app/docs/testing.md + test/utils, test/entities, src/modules/todo/**/*.test.*
|
|
5
|
+
source_version: 8edaa0b
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Testing: Jest + RTL
|
|
9
|
+
|
|
10
|
+
Tests colocate next to source as `*.test.ts` / `*.test.tsx`. Everything is imported from `@test/utils` (lint forbids importing RTL / `react-dom` directly in feature tests).
|
|
11
|
+
|
|
12
|
+
## Coverage is per-layer (mirror todo)
|
|
13
|
+
The scaffold tests EVERY layer — `src/modules/todo` ships a colocated test for api, gateway, repository (queries + mutations), store, each selector, business + controller hooks, each helper, each component, and the view. Match that: one colocated test per piece with logic, not just the happy-path hook.
|
|
14
|
+
- **Unit:** pure pieces alone — helpers, store, a presentational component with mock props.
|
|
15
|
+
- **Integration:** pieces wired through providers — `renderHookWithProviders` for a business hook (hook→repository→gateway→api), a view with real hooks.
|
|
16
|
+
Cover both. A module with one test is undertested.
|
|
17
|
+
|
|
18
|
+
## Import surface
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { renderWithProviders, renderHookWithProviders, screen, fireEvent, waitFor } from '@test/utils';
|
|
22
|
+
import { createMockTodo, createMockTodos } from '@test/entities/todo.mock'; // faker factories
|
|
23
|
+
```
|
|
24
|
+
- `renderWithProviders(ui, opts)` — wraps in `AllProviders` (QueryClient + Theme + intl). Returns `{ queryClient, ...result }`.
|
|
25
|
+
- `renderHookWithProviders(hook, opts)` — same providers for hooks.
|
|
26
|
+
- Options: `{ queryClient?, queryClientOptions?, initialStoreStates? }` — seed Zustand via `initialStoreStates`.
|
|
27
|
+
|
|
28
|
+
## Component test
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { fireEvent, renderWithProviders, screen, waitFor } from '@test/utils';
|
|
32
|
+
import { TodoForm } from './todo-form.component';
|
|
33
|
+
|
|
34
|
+
describe('TodoForm', () => {
|
|
35
|
+
const mockOnSubmit = jest.fn();
|
|
36
|
+
beforeEach(() => mockOnSubmit.mockClear());
|
|
37
|
+
|
|
38
|
+
it('calls onSubmit with form data', async () => {
|
|
39
|
+
renderWithProviders(<TodoForm isCreating={false} onSubmit={mockOnSubmit} />);
|
|
40
|
+
fireEvent.change(screen.getByRole('textbox', { name: /title/i }), { target: { value: 'Test' } });
|
|
41
|
+
await waitFor(() => expect(screen.getByRole('button', { name: /add/i })).not.toBeDisabled());
|
|
42
|
+
fireEvent.click(screen.getByRole('button', { name: /add/i }));
|
|
43
|
+
expect(mockOnSubmit).toHaveBeenCalledWith({ title: 'Test', description: '', priority: 'medium' });
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Hook test
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { renderHookWithProviders, waitFor } from '@test/utils';
|
|
52
|
+
const { result } = renderHookWithProviders(() => useTodoStatsSelector(), {
|
|
53
|
+
initialStoreStates: { 'todo-store': { filters: {} } },
|
|
54
|
+
});
|
|
55
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Mock factories (per entity)
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
// test/entities/[entity].mock.ts
|
|
62
|
+
import { faker } from '@faker-js/faker';
|
|
63
|
+
export const createMockTodo = (overrides: Partial<Todo> = {}): Todo => ({
|
|
64
|
+
id: faker.number.int(), title: faker.lorem.sentence(), completed: false, ...overrides,
|
|
65
|
+
});
|
|
66
|
+
export const createMockTodos = (count: number, base = {}): Todo[] =>
|
|
67
|
+
Array.from({ length: count }, (_, i) => createMockTodo({ id: i + 1, ...base }));
|
|
68
|
+
// + specialized (createCompletedTodo) + deterministic (createDeterministicTodo with faker.seed)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Conventions
|
|
72
|
+
- Query priority: `getByRole` > `getByLabelText` > `getByText`; avoid testid unless necessary (`data-testid` exists for some views).
|
|
73
|
+
- Async UI: wrap assertions in `waitFor`. Use `jest.fn()` for callbacks, clear in `beforeEach`.
|
|
74
|
+
- Test behavior, not implementation. Seed data with factories, not inline literals.
|
|
75
|
+
- `__mocks__` (next-intl, next/navigation, zustand, mixpanel, screeb, fonts/styles) are pre-wired in `test/__mocks__` + `test/jest.setup.tsx` — rely on them.
|
|
76
|
+
- Run: `yarn test` / `yarn test:watch` / `yarn test:changed`. Filter by path with `yarn test --testPathPatterns=<name>` (Jest 30 — note the plural; old `--testPathPattern` errors).
|
|
77
|
+
- Coverage threshold is **85% global**: running a single new file fails the coverage gate (exit 1) even when tests pass. That exit is the threshold, not a test failure — judge by `Tests: N passed`. Add enough tests for the module, or run the full suite, before treating exit 1 as red.
|
|
78
|
+
|
|
79
|
+
## TDD note (confirm mode with user)
|
|
80
|
+
RED→GREEN supported but the scaffold's existing tests are post-hoc. Default to writing tests against the built component unless the user asks for strict RED-first.
|
|
81
|
+
|
|
82
|
+
## Related skills
|
|
83
|
+
[[mui-design-tokens]] · [[hook-patterns]] · [[i18n-next-intl]] · [[naming-conventions]]
|
package/uninstall.sh
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# wavefront uninstaller — removes the surface (symlinks or copies) from a target app.
|
|
3
|
+
# Usage: ./uninstall.sh <target-app> [--purge-home]
|
|
4
|
+
# --purge-home also remove ~/.wavefront (the global install)
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
HOME_DIR="${WAVEFRONT_HOME:-$HOME/.wavefront}"
|
|
8
|
+
SURFACE=(agents skills commands planning-templates)
|
|
9
|
+
|
|
10
|
+
die() { echo "error: $*" >&2; exit 1; }
|
|
11
|
+
|
|
12
|
+
[ $# -ge 1 ] || die "usage: ./uninstall.sh <target-app> [--purge-home]"
|
|
13
|
+
TARGET="$1"; PURGE="${2:-}"
|
|
14
|
+
CLAUDE_DIR="$TARGET/.claude"
|
|
15
|
+
|
|
16
|
+
[ -d "$CLAUDE_DIR" ] || die ".claude not found in $TARGET"
|
|
17
|
+
|
|
18
|
+
for d in "${SURFACE[@]}"; do
|
|
19
|
+
link="$CLAUDE_DIR/$d"
|
|
20
|
+
if [ -L "$link" ]; then
|
|
21
|
+
rm -f "$link"; echo "removed symlink $link"
|
|
22
|
+
elif [ -d "$link" ]; then
|
|
23
|
+
rm -rf "$link"; echo "removed copy $link"
|
|
24
|
+
fi
|
|
25
|
+
done
|
|
26
|
+
|
|
27
|
+
# hooks (copied) + the settings template we wrote
|
|
28
|
+
[ -d "$CLAUDE_DIR/hooks" ] && { rm -rf "$CLAUDE_DIR/hooks"; echo "removed $CLAUDE_DIR/hooks"; }
|
|
29
|
+
[ -f "$CLAUDE_DIR/settings.wavefront.json" ] && { rm -f "$CLAUDE_DIR/settings.wavefront.json"; echo "removed settings.wavefront.json"; }
|
|
30
|
+
echo "note: if you merged the hooks block into settings.json, remove it manually."
|
|
31
|
+
|
|
32
|
+
if [ "$PURGE" = "--purge-home" ]; then
|
|
33
|
+
rm -rf "$HOME_DIR"; echo "purged $HOME_DIR"
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
echo "✓ uninstall done."
|