erne-universal 0.10.21 → 0.10.22
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.md +174 -24
- package/lib/dashboard.js +3 -3
- package/lib/generate.js +11 -4
- package/package.json +1 -1
- package/scripts/hooks/audit-refresh.js +4 -1
- package/scripts/hooks/run-with-flags.js +23 -7
package/CLAUDE.md
CHANGED
|
@@ -1,35 +1,185 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# ERNE — Everything React Native & Expo
|
|
2
|
+
|
|
3
|
+
You are working in an ERNE-powered React Native/Expo project.
|
|
4
4
|
|
|
5
5
|
## Project Stack
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **Testing**:
|
|
14
|
-
- **
|
|
6
|
+
|
|
7
|
+
> **Note:** When `erne init` runs in a project, this section is replaced with a stack summary generated from deep detection of the project's actual dependencies (state management, navigation, styling, lists, images, forms, storage, testing, build system).
|
|
8
|
+
|
|
9
|
+
- **Framework**: React Native with Expo (managed or bare)
|
|
10
|
+
- **Language**: TypeScript (strict mode)
|
|
11
|
+
- **Navigation**: Detected at init (Expo Router, React Navigation, etc.)
|
|
12
|
+
- **State**: Detected at init (Zustand, Redux Toolkit, MobX, etc.)
|
|
13
|
+
- **Testing**: Jest + React Native Testing Library + Detox
|
|
14
|
+
- **Styling**: Detected at init (StyleSheet.create, NativeWind, etc.)
|
|
15
15
|
|
|
16
16
|
## Key Rules
|
|
17
|
+
|
|
18
|
+
### Code Style
|
|
17
19
|
- Functional components only with `const` + arrow functions
|
|
20
|
+
- PascalCase for components, camelCase for hooks/utils, SCREAMING_SNAKE for constants
|
|
18
21
|
- Named exports only (no default exports)
|
|
19
|
-
-
|
|
20
|
-
-
|
|
22
|
+
- Group imports: react → react-native → expo → external → internal → types
|
|
23
|
+
- Max component length: 250 lines — extract if larger
|
|
24
|
+
|
|
25
|
+
### Performance
|
|
26
|
+
- Memoize with `React.memo`, `useMemo`, `useCallback` where measurable
|
|
27
|
+
- Use `FlashList` over `FlatList` for large lists (100+ items)
|
|
28
|
+
- Avoid anonymous functions in JSX render paths
|
|
29
|
+
- Optimize images: WebP format, resizeMode, caching
|
|
30
|
+
- Keep JS bundle under 1.5MB
|
|
31
|
+
|
|
32
|
+
### Testing
|
|
33
|
+
- Every new component/hook needs a test file
|
|
34
|
+
- Test user behavior, not implementation details
|
|
35
|
+
- Mock native modules at `__mocks__/` level
|
|
36
|
+
- E2E critical paths with Detox
|
|
37
|
+
|
|
38
|
+
### Security
|
|
39
|
+
- Never hardcode secrets — use environment variables
|
|
40
|
+
- Validate all deep link parameters
|
|
41
|
+
- Pin SSL certificates for sensitive API calls
|
|
42
|
+
- Use secure storage for tokens (expo-secure-store, react-native-keychain, etc.)
|
|
43
|
+
|
|
44
|
+
### Git
|
|
45
|
+
- Conventional Commits: `feat:`, `fix:`, `refactor:`, `test:`, `docs:`, `chore:`
|
|
46
|
+
- Branch naming: `feat/`, `fix/`, `refactor/` prefix
|
|
47
|
+
- Atomic commits — one logical change per commit
|
|
48
|
+
|
|
49
|
+
## Workflow Orchestration
|
|
50
|
+
|
|
51
|
+
### 1. Plan Mode Default
|
|
52
|
+
- Enter plan mode for ANY non-trivial task (3+ steps or architectural decisions)
|
|
53
|
+
- If something goes sideways, STOP and re-plan immediately — don't keep pushing
|
|
54
|
+
- Use plan mode for verification steps, not just building
|
|
55
|
+
- Write detailed specs upfront to reduce ambiguity
|
|
56
|
+
|
|
57
|
+
### 2. Subagent Strategy
|
|
58
|
+
- Use subagents liberally to keep main context window clean
|
|
59
|
+
- Offload research, exploration, and parallel analysis to subagents
|
|
60
|
+
- For complex problems, throw more compute at it via subagents
|
|
61
|
+
- One task per subagent for focused execution
|
|
62
|
+
|
|
63
|
+
### 3. Self-Improvement Loop
|
|
64
|
+
- After ANY correction from the user: save a `feedback` memory via the memory system
|
|
65
|
+
- Write rules for yourself that prevent the same mistake
|
|
66
|
+
- Memory is auto-loaded each session — no manual review needed
|
|
67
|
+
|
|
68
|
+
### 4. Verification Before Done
|
|
69
|
+
- Never mark a task complete without proving it works
|
|
70
|
+
- Diff behavior between main and your changes when relevant
|
|
71
|
+
- Ask yourself: "Would a staff engineer approve this?"
|
|
72
|
+
- Run tests, check logs, demonstrate correctness
|
|
73
|
+
|
|
74
|
+
### 5. Demand Elegance (Balanced)
|
|
75
|
+
- For non-trivial changes: pause and ask "is there a more elegant way?"
|
|
76
|
+
- If a fix feels hacky: "Knowing everything I know now, implement the elegant solution"
|
|
77
|
+
- Skip this for simple, obvious fixes — don't over-engineer
|
|
78
|
+
- Challenge your own work before presenting it
|
|
79
|
+
|
|
80
|
+
### 6. Autonomous Bug Fixing
|
|
81
|
+
- When given a bug report: just fix it. Don't ask for hand-holding
|
|
82
|
+
- Point at logs, errors, failing tests — then resolve them
|
|
83
|
+
- Zero context switching required from the user
|
|
84
|
+
- Go fix failing CI tests without being told how
|
|
85
|
+
|
|
86
|
+
## Smart Agent Routing
|
|
87
|
+
|
|
88
|
+
When a user's message matches these signals, automatically use the corresponding agent via a subagent. The user should NOT need to type explicit `/commands` — detect intent from context. Explicit `/command` invocations always override auto-routing.
|
|
89
|
+
|
|
90
|
+
**How routing works:** Read the user's message. If it matches trigger signals below, dispatch the matching agent as a subagent. If multiple agents could match, prefer the more specific one. If unclear, ask the user.
|
|
91
|
+
|
|
92
|
+
**Image detection:** When the user shares an image/screenshot alongside a description of a visual problem, ALWAYS route to visual-debugger.
|
|
93
|
+
|
|
94
|
+
| Agent | Trigger Signals |
|
|
95
|
+
|-------|----------------|
|
|
96
|
+
| `visual-debugger` | Image in chat with UI issue, screenshot, "doesn't look right", "UI is broken", "layout not working", "fix this" + image, spacing, alignment, overflow, "wrong colors", "doesn't match Figma", pixel, responsive, "design issue", "visual bug", "cut off", overlapping, "not centered", "wrong font", "dark mode broken", "safe area", notch, "status bar", "keyboard covers" |
|
|
97
|
+
| `performance-profiler` | "slow", lag, FPS, "memory leak", jank, freeze, hanging, "bundle size", TTI, "startup time", "re-render", heavy, "animation stutter", "frame drop", "battery drain", "CPU usage", "JS thread blocked", "bridge overhead", "large list", "image loading slow", "splash screen long", ANR |
|
|
98
|
+
| `code-reviewer` | review, PR, refactor, "code quality", "clean up", "best practice", "technical debt", "code smell", maintainability, "check my code", "is this okay", "anti-pattern", readability, DRY, SOLID, "type safety" |
|
|
99
|
+
| `architect` | "how to build", architecture, structure, plan, "system design", "new feature", "want to add", "how to approach", decompose, "design pattern", "folder structure", "state management", "data flow", "API design", "navigation structure", monorepo, "separation of concerns" |
|
|
100
|
+
| `feature-builder` | implement, build, create, "add feature", "create component", "write this", "make this", scaffold, "add screen", "wire up", integrate, "connect to API", "hook up", "add functionality", CRUD |
|
|
101
|
+
| `tdd-guide` | test, coverage, jest, detox, TDD, "write test", "unit test", e2e, "failing test", "test broken", "snapshot test", mock, fixture, "testing library", "integration test", "test flaky" |
|
|
102
|
+
| `expo-config-resolver` | build error, red screen, crash, "won't start", error, "build failed", metro, babel, "config issue", "EAS build", "can't build", "module not found", "pod install", gradle, "Xcode error", "Android build", "iOS build", "linking error", prebuild, "app.json", "app.config", "plugin not working", "white screen", "blank screen" |
|
|
103
|
+
| `native-bridge-builder` | "native module", bridge, "turbo module", Swift, Kotlin, Java, "Objective-C", "native code", "platform specific", "expo module", JSI, Fabric, "New Architecture", codegen, "C++", "native view", Nitro, "expo-modules-core" |
|
|
104
|
+
| `upgrade-assistant` | upgrade, update, version, migration, "breaking change", deprecated, "Expo SDK", "React Native version", bump, migrate, changelog, compatibility, "peer dependency", outdated, "npx expo install --fix" |
|
|
105
|
+
| `ui-designer` | component, button, modal, form, screen, page, tab, "navigation UI", "build UI", "design system", styled, theme, icon, animation, transition, gesture, "bottom sheet", drawer, header, card, skeleton, loading, toast |
|
|
106
|
+
| `pipeline-orchestrator` | deploy, publish, EAS, "app store", "play store", "CI/CD", release, "OTA update", submit, distribution, TestFlight, "internal testing", "code signing", provisioning, certificate, keystore, fastlane, "GitHub Actions" |
|
|
107
|
+
| `senior-developer` | "what do you think", opinion, advice, approach, tradeoff, "not sure how", mentor, "help me decide", "best way to", "should I", "pros and cons", "compare options", "which is better", "common pitfall", "production ready", scalable |
|
|
108
|
+
| `documentation-generator` | "generate docs", "document this", "write documentation", "project overview", "architecture docs", "what does this project do", "onboard me", "explain codebase", "project structure", "how does this work" |
|
|
109
|
+
|
|
110
|
+
## Task Management
|
|
111
|
+
|
|
112
|
+
1. **Plan First**: Use plan mode or TodoWrite for non-trivial tasks
|
|
113
|
+
2. **Verify Plan**: Check in before starting implementation
|
|
114
|
+
3. **Track Progress**: Use built-in task system (TodoWrite/TaskCreate) to mark progress
|
|
115
|
+
4. **Explain Changes**: High-level summary at each step
|
|
116
|
+
5. **Capture Lessons**: Save corrections as `feedback` memories
|
|
117
|
+
|
|
118
|
+
## Core Principles
|
|
119
|
+
|
|
120
|
+
- **Simplicity First**: Make every change as simple as possible. Impact minimal code.
|
|
121
|
+
- **No Laziness**: Find root causes. No temporary fixes. Senior developer standards.
|
|
122
|
+
- **Minimal Impact**: Changes should only touch what's necessary. Avoid introducing bugs.
|
|
21
123
|
|
|
22
124
|
## Available Commands
|
|
23
|
-
/erne-plan, /erne-code-review, /erne-tdd, /erne-build-fix, /erne-perf, /erne-upgrade, /erne-native-module, /erne-debug, /erne-debug-visual, /erne-deploy,
|
|
24
|
-
/erne-component, /erne-navigate, /erne-animate, /erne-orchestrate, /erne-quality-gate, /erne-code, /erne-feature, /erne-worker, /erne-audit, /erne-learn, /erne-retrospective, /erne-setup-device
|
|
25
125
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
126
|
+
Use `/erne-plan`, `/erne-code-review`, `/erne-tdd`, `/erne-build-fix`, `/erne-perf`, `/erne-upgrade`, `/erne-native-module`, `/erne-navigate`, `/erne-animate`, `/erne-deploy`, `/erne-component`, `/erne-debug`, `/erne-debug-visual`, `/erne-audit`, `/erne-quality-gate`, `/erne-code`, `/erne-feature`, `/erne-learn`, `/erne-retrospective`, `/erne-setup-device` for guided workflows.
|
|
127
|
+
|
|
128
|
+
## Worker Mode (Autonomous Ticket Execution)
|
|
129
|
+
|
|
130
|
+
ERNE can run as an autonomous worker that polls a ticket provider, picks up ready tasks, and executes the full pipeline without human intervention.
|
|
131
|
+
|
|
132
|
+
### Quick Start
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
erne worker --config worker.json
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### How It Works
|
|
139
|
+
|
|
140
|
+
1. Polls a configured provider (ClickUp, GitHub Issues, Linear, Jira, or local JSON) for tickets marked as ready
|
|
141
|
+
2. Validates each ticket has sufficient detail (title, description, acceptance criteria)
|
|
142
|
+
3. Scores confidence (0-100) — skips tickets below the configured threshold
|
|
143
|
+
4. Generates an implementation plan from ticket context + project audit data
|
|
144
|
+
5. Executes in an isolated git worktree to avoid disrupting the main branch
|
|
145
|
+
6. Runs the test suite and verifies no regressions
|
|
146
|
+
7. Performs automated self-review against ERNE coding standards
|
|
147
|
+
8. Compares audit health score before and after changes
|
|
148
|
+
9. Creates a pull request with summary, test results, and ticket link
|
|
149
|
+
|
|
150
|
+
### Quality Gates
|
|
151
|
+
|
|
152
|
+
Each ticket must pass these gates before a PR is created:
|
|
153
|
+
- Confidence score above threshold (default: 70)
|
|
154
|
+
- All existing tests pass
|
|
155
|
+
- No audit score regression
|
|
156
|
+
- Self-review finds no critical issues
|
|
157
|
+
|
|
158
|
+
### Configuration
|
|
159
|
+
|
|
160
|
+
See `worker.example.json` for a full template. Key options:
|
|
161
|
+
- `provider.type` — clickup, github, linear, jira, local
|
|
162
|
+
- `provider.poll_interval_seconds` — How often to check for new tickets (default: 60)
|
|
163
|
+
- `erne.min_confidence` — Minimum confidence score to attempt a ticket (default: 70)
|
|
164
|
+
- `erne.hook_profile` — ERNE hook profile to use (minimal, standard, strict)
|
|
165
|
+
- `repo.path` — Absolute path to the local repository
|
|
166
|
+
- `repo.base_branch` — Branch to create worktrees from (default: main)
|
|
167
|
+
|
|
168
|
+
### CLI Options
|
|
169
|
+
|
|
170
|
+
| Flag | Description |
|
|
171
|
+
|------|-------------|
|
|
172
|
+
| `--config <path>` | Path to worker config JSON (required) |
|
|
173
|
+
| `--dry-run` | Fetch and display tickets without executing |
|
|
174
|
+
| `--once` | Process one ticket then exit |
|
|
30
175
|
|
|
31
|
-
##
|
|
32
|
-
@import .claude/rules/common/
|
|
176
|
+
## Available Skills
|
|
33
177
|
|
|
34
|
-
|
|
35
|
-
|
|
178
|
+
Skills in `skills/` activate automatically:
|
|
179
|
+
- `coding-standards` — Audit and enforce standards
|
|
180
|
+
- `tdd-workflow` — Red-green-refactor cycle
|
|
181
|
+
- `performance-optimization` — Diagnose and fix perf issues
|
|
182
|
+
- `security-review` — Mobile security audit
|
|
183
|
+
- `native-module-scaffold` — Create Turbo/Expo modules
|
|
184
|
+
- `upgrade-workflow` — Version migration guide
|
|
185
|
+
- `continuous-learning-v2` — Pattern extraction and learning
|
package/lib/dashboard.js
CHANGED
|
@@ -97,14 +97,14 @@ async function ensureHooksConfigured() {
|
|
|
97
97
|
event: 'PreToolUse',
|
|
98
98
|
pattern: 'Agent',
|
|
99
99
|
script: 'dashboard-event.js',
|
|
100
|
-
command: 'node
|
|
100
|
+
command: 'node .claude/hooks/scripts/run-with-flags.js dashboard-event.js',
|
|
101
101
|
profiles: ['minimal', 'standard', 'strict'],
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
104
|
event: 'PostToolUse',
|
|
105
105
|
pattern: 'Agent',
|
|
106
106
|
script: 'dashboard-event.js',
|
|
107
|
-
command: 'node
|
|
107
|
+
command: 'node .claude/hooks/scripts/run-with-flags.js dashboard-event.js',
|
|
108
108
|
profiles: ['minimal', 'standard', 'strict'],
|
|
109
109
|
}
|
|
110
110
|
);
|
|
@@ -113,7 +113,7 @@ async function ensureHooksConfigured() {
|
|
|
113
113
|
const dashboardHook = {
|
|
114
114
|
pattern: 'Agent',
|
|
115
115
|
script: 'dashboard-event.js',
|
|
116
|
-
command: 'node
|
|
116
|
+
command: 'node .claude/hooks/scripts/run-with-flags.js dashboard-event.js',
|
|
117
117
|
profiles: ['minimal', 'standard', 'strict'],
|
|
118
118
|
};
|
|
119
119
|
if (!data.PreToolUse) data.PreToolUse = [];
|
package/lib/generate.js
CHANGED
|
@@ -267,12 +267,18 @@ function generateConfig(erneRoot, targetDir, detection, profile, mcpSelections)
|
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
-
// Copy hook
|
|
270
|
+
// Copy hook configs (hooks.json, profiles/)
|
|
271
271
|
const hooksSrc = path.join(erneRoot, 'hooks');
|
|
272
272
|
if (fs.existsSync(hooksSrc)) {
|
|
273
273
|
copyDir(hooksSrc, path.join(targetDir, 'hooks'));
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
+
// Copy hook scripts locally so they work without node_modules/erne-universal
|
|
277
|
+
const hookScriptsSrc = path.join(erneRoot, 'scripts', 'hooks');
|
|
278
|
+
if (fs.existsSync(hookScriptsSrc)) {
|
|
279
|
+
copyDir(hookScriptsSrc, path.join(targetDir, 'hooks', 'scripts'));
|
|
280
|
+
}
|
|
281
|
+
|
|
276
282
|
// 2. Copy base rules (common + framework layers)
|
|
277
283
|
for (const layer of ruleLayers) {
|
|
278
284
|
const layerSrc = path.join(erneRoot, 'rules', layer);
|
|
@@ -338,13 +344,14 @@ function generateConfig(erneRoot, targetDir, detection, profile, mcpSelections)
|
|
|
338
344
|
const profileHooks = JSON.parse(fs.readFileSync(profileHooksPath, 'utf8'));
|
|
339
345
|
const merged = mergeHookProfile(masterHooks, profileHooks, profile);
|
|
340
346
|
|
|
341
|
-
// Rewrite hook commands to use
|
|
342
|
-
|
|
347
|
+
// Rewrite hook commands to use local .claude/hooks/scripts/ path
|
|
348
|
+
// (works whether installed via npx, global, or node_modules)
|
|
349
|
+
const localPrefix = '.claude/hooks/scripts/run-with-flags.js';
|
|
343
350
|
for (const [event, hooks] of Object.entries(merged)) {
|
|
344
351
|
if (event === '_meta' || !Array.isArray(hooks)) continue;
|
|
345
352
|
for (const hook of hooks) {
|
|
346
353
|
if (hook.command && hook.command.includes('scripts/hooks/run-with-flags.js')) {
|
|
347
|
-
hook.command = hook.command.replace('scripts/hooks/run-with-flags.js',
|
|
354
|
+
hook.command = hook.command.replace('scripts/hooks/run-with-flags.js', localPrefix);
|
|
348
355
|
}
|
|
349
356
|
}
|
|
350
357
|
}
|
package/package.json
CHANGED
|
@@ -25,7 +25,10 @@ try {
|
|
|
25
25
|
// Refresh scan (JSON only, skip dep health for speed)
|
|
26
26
|
let runScan;
|
|
27
27
|
try { runScan = require('erne-universal/lib/audit-scanner').runScan; } catch {
|
|
28
|
-
try { runScan = require('../../lib/audit-scanner').runScan; } catch {
|
|
28
|
+
try { runScan = require('../../lib/audit-scanner').runScan; } catch {
|
|
29
|
+
// When running from .claude/hooks/scripts/, try resolving from project root node_modules
|
|
30
|
+
try { runScan = require(path.join(cwd, 'node_modules', 'erne-universal', 'lib', 'audit-scanner')).runScan; } catch { process.exit(0); }
|
|
31
|
+
}
|
|
29
32
|
}
|
|
30
33
|
const auditData = runScan(cwd, { skipDepHealth: true, maxFiles: 500 });
|
|
31
34
|
|
|
@@ -43,14 +43,30 @@ function resolveProfile() {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
function loadHooksConfig() {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return { hooks: [] };
|
|
46
|
+
if (process.env.ERNE_HOOKS_CONFIG) {
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(fs.readFileSync(process.env.ERNE_HOOKS_CONFIG, 'utf8'));
|
|
49
|
+
} catch {
|
|
50
|
+
return { hooks: [] };
|
|
51
|
+
}
|
|
53
52
|
}
|
|
53
|
+
|
|
54
|
+
// Try multiple locations:
|
|
55
|
+
// 1. .claude/hooks/hooks.json (copied master config — has profiles array for filtering)
|
|
56
|
+
// 2. ../../hooks/hooks.json (dev: running from scripts/hooks/ in ERNE repo)
|
|
57
|
+
const projectDir = process.env.ERNE_PROJECT_DIR || process.cwd();
|
|
58
|
+
const candidates = [
|
|
59
|
+
path.join(projectDir, '.claude', 'hooks', 'hooks.json'),
|
|
60
|
+
path.resolve(__dirname, '../../hooks/hooks.json'),
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
for (const candidate of candidates) {
|
|
64
|
+
try {
|
|
65
|
+
return JSON.parse(fs.readFileSync(candidate, 'utf8'));
|
|
66
|
+
} catch { /* try next */ }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { hooks: [] };
|
|
54
70
|
}
|
|
55
71
|
|
|
56
72
|
const profile = resolveProfile();
|