erne-universal 0.10.21 → 0.10.23

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 CHANGED
@@ -1,35 +1,185 @@
1
- <!-- ERNE-GENERATED -->
2
- <!-- erne-profile: standard -->
3
- # erne-universal ERNE Configuration
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
- - **Framework**: React Native
7
- - **Language**: JavaScript
8
- - **Navigation**: None
9
- - **State**: None
10
- - **Styling**: StyleSheet.create
11
- - **Lists**: FlatList (built-in)
12
- - **Images**: Image (built-in)
13
- - **Testing**: None configured
14
- - **Build**: Manual
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
- - Use secure storage for tokens avoid AsyncStorage for sensitive data
20
- - Conventional Commits: feat:, fix:, refactor:, test:, docs:, chore:
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
- ## Dashboard
27
- ERNE includes a visual dashboard for monitoring agents, project health, worker status, and documentation.
28
- Launch: `npx erne-universal dashboard`
29
- The dashboard shows 6 tabs: HQ (pixel-art agent office), Worker (autonomous tickets), Health (doctor score), Docs (generated documentation), Project (stack & MCP), Insights (analytics).
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
- ## Rules
32
- @import .claude/rules/common/
176
+ ## Available Skills
33
177
 
34
- ## Skills
35
- @import .claude/skills/
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 node_modules/erne-universal/scripts/hooks/run-with-flags.js dashboard-event.js',
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 node_modules/erne-universal/scripts/hooks/run-with-flags.js dashboard-event.js',
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 node_modules/erne-universal/scripts/hooks/run-with-flags.js dashboard-event.js',
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 scripts
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 node_modules path so they resolve from user's project root
342
- const pkgRelPrefix = 'node_modules/erne-universal/scripts/hooks/run-with-flags.js';
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', pkgRelPrefix);
354
+ hook.command = hook.command.replace('scripts/hooks/run-with-flags.js', localPrefix);
348
355
  }
349
356
  }
350
357
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "erne-universal",
3
- "version": "0.10.21",
3
+ "version": "0.10.23",
4
4
  "description": "Complete AI coding agent harness for React Native and Expo development",
5
5
  "keywords": [
6
6
  "react-native",
@@ -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 { process.exit(0); }
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
- const configPath =
47
- process.env.ERNE_HOOKS_CONFIG ||
48
- path.resolve(__dirname, '../../hooks/hooks.json');
49
- try {
50
- return JSON.parse(fs.readFileSync(configPath, 'utf8'));
51
- } catch {
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();
@@ -95,7 +95,7 @@ try {
95
95
  }
96
96
  } catch { /* skip */ }
97
97
 
98
- // ─── Dashboard auto-start ────────────────────────────────────────────────────
98
+ // ─── Dashboard detection (no auto-start — use `npx erne-universal dashboard`) ─
99
99
 
100
100
  let dashboardUrl = '';
101
101
 
@@ -103,28 +103,8 @@ if (hasSettings) {
103
103
  try {
104
104
  const { getRegisteredPort } = require('./lib/port-registry');
105
105
  const existingPort = getRegisteredPort(projectDir);
106
-
107
106
  if (existingPort) {
108
107
  dashboardUrl = `http://localhost:${existingPort}`;
109
- } else if (!process.env.ERNE_SKIP_DASHBOARD) {
110
- // Try to start dashboard in background
111
- try {
112
- const dashboardDir = path.resolve(__dirname, '..', '..', 'dashboard');
113
- const serverScript = path.join(dashboardDir, 'server.js');
114
- const depsExist = fs.existsSync(path.join(dashboardDir, 'node_modules', 'better-sqlite3'));
115
-
116
- if (fs.existsSync(serverScript) && depsExist) {
117
- const { fork } = require('child_process');
118
- const child = fork(serverScript, [], {
119
- cwd: projectDir,
120
- detached: true,
121
- stdio: 'ignore',
122
- env: { ...process.env, ERNE_PROJECT_DIR: projectDir },
123
- });
124
- child.unref();
125
- dashboardUrl = 'http://localhost:3333 (starting...)';
126
- }
127
- } catch { /* dashboard not available — skip */ }
128
108
  }
129
109
  } catch { /* port-registry not available — skip */ }
130
110
  }