create-merlin-brain 3.8.1 → 3.9.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/bin/install.cjs +126 -21
- package/dist/server/api/client.d.ts.map +1 -1
- package/dist/server/api/client.js +11 -7
- package/dist/server/api/client.js.map +1 -1
- package/dist/server/cost/classifier.d.ts +22 -0
- package/dist/server/cost/classifier.d.ts.map +1 -0
- package/dist/server/cost/classifier.js +137 -0
- package/dist/server/cost/classifier.js.map +1 -0
- package/dist/server/cost/tracker.d.ts +34 -0
- package/dist/server/cost/tracker.d.ts.map +1 -0
- package/dist/server/cost/tracker.js +81 -0
- package/dist/server/cost/tracker.js.map +1 -0
- package/dist/server/lang/detector.d.ts +17 -0
- package/dist/server/lang/detector.d.ts.map +1 -0
- package/dist/server/lang/detector.js +144 -0
- package/dist/server/lang/detector.js.map +1 -0
- package/dist/server/lang/rules.d.ts +21 -0
- package/dist/server/lang/rules.d.ts.map +1 -0
- package/dist/server/lang/rules.js +70 -0
- package/dist/server/lang/rules.js.map +1 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +69 -32
- package/dist/server/server.js.map +1 -1
- package/dist/server/tools/adaptive.d.ts.map +1 -1
- package/dist/server/tools/adaptive.js +2 -1
- package/dist/server/tools/adaptive.js.map +1 -1
- package/dist/server/tools/agents-index.d.ts.map +1 -1
- package/dist/server/tools/agents-index.js +6 -3
- package/dist/server/tools/agents-index.js.map +1 -1
- package/dist/server/tools/agents.d.ts.map +1 -1
- package/dist/server/tools/agents.js +10 -5
- package/dist/server/tools/agents.js.map +1 -1
- package/dist/server/tools/auto-teach.d.ts.map +1 -1
- package/dist/server/tools/auto-teach.js +2 -1
- package/dist/server/tools/auto-teach.js.map +1 -1
- package/dist/server/tools/behaviors.d.ts.map +1 -1
- package/dist/server/tools/behaviors.js +8 -4
- package/dist/server/tools/behaviors.js.map +1 -1
- package/dist/server/tools/config-sync.d.ts.map +1 -1
- package/dist/server/tools/config-sync.js +8 -4
- package/dist/server/tools/config-sync.js.map +1 -1
- package/dist/server/tools/context.d.ts.map +1 -1
- package/dist/server/tools/context.js +66 -7
- package/dist/server/tools/context.js.map +1 -1
- package/dist/server/tools/cost.d.ts +7 -0
- package/dist/server/tools/cost.d.ts.map +1 -0
- package/dist/server/tools/cost.js +53 -0
- package/dist/server/tools/cost.js.map +1 -0
- package/dist/server/tools/discoveries.d.ts.map +1 -1
- package/dist/server/tools/discoveries.js +8 -11
- package/dist/server/tools/discoveries.js.map +1 -1
- package/dist/server/tools/lite.d.ts.map +1 -1
- package/dist/server/tools/lite.js +8 -4
- package/dist/server/tools/lite.js.map +1 -1
- package/dist/server/tools/project.d.ts.map +1 -1
- package/dist/server/tools/project.js +14 -7
- package/dist/server/tools/project.js.map +1 -1
- package/dist/server/tools/route.d.ts.map +1 -1
- package/dist/server/tools/route.js +76 -13
- package/dist/server/tools/route.js.map +1 -1
- package/dist/server/tools/sights-index.d.ts.map +1 -1
- package/dist/server/tools/sights-index.js +4 -2
- package/dist/server/tools/sights-index.js.map +1 -1
- package/dist/server/tools/verification.d.ts.map +1 -1
- package/dist/server/tools/verification.js +2 -1
- package/dist/server/tools/verification.js.map +1 -1
- package/files/agents/code-organization-supervisor.md +1 -0
- package/files/agents/context-guardian.md +1 -0
- package/files/agents/docs-keeper.md +1 -0
- package/files/agents/dry-refactor.md +1 -0
- package/files/agents/elite-code-refactorer.md +1 -0
- package/files/agents/hardening-guard.md +1 -0
- package/files/agents/implementation-dev.md +1 -0
- package/files/agents/merlin-api-designer.md +1 -0
- package/files/agents/merlin-codebase-mapper.md +4 -0
- package/files/agents/merlin-debugger.md +1 -0
- package/files/agents/merlin-executor.md +1 -0
- package/files/agents/merlin-frontend.md +1 -0
- package/files/agents/merlin-integration-checker.md +1 -0
- package/files/agents/merlin-migrator.md +1 -0
- package/files/agents/merlin-milestone-auditor.md +1 -0
- package/files/agents/merlin-performance.md +1 -0
- package/files/agents/merlin-planner.md +1 -0
- package/files/agents/merlin-researcher.md +4 -0
- package/files/agents/merlin-reviewer.md +1 -0
- package/files/agents/merlin-security.md +1 -0
- package/files/agents/merlin-verifier.md +1 -0
- package/files/agents/merlin-work-verifier.md +1 -0
- package/files/agents/merlin.md +1 -0
- package/files/agents/ops-railway.md +1 -0
- package/files/agents/orchestrator-retrofit.md +1 -0
- package/files/agents/product-spec.md +1 -0
- package/files/agents/remotion.md +1 -0
- package/files/agents/system-architect.md +1 -0
- package/files/agents/tests-qa.md +1 -0
- package/files/commands/merlin/help.md +11 -0
- package/files/commands/merlin/loop-recipes.md +73 -0
- package/files/hooks/agent-sync.sh +3 -0
- package/files/hooks/check-file-size.sh +12 -0
- package/files/hooks/config-change.sh +43 -0
- package/files/hooks/instructions-loaded.sh +34 -0
- package/files/hooks/session-start.sh +5 -1
- package/files/hooks/worktree-create.sh +44 -0
- package/files/hooks/worktree-remove.sh +36 -0
- package/files/loop/lib/agents.sh +3 -0
- package/files/loop/lib/blend-handoff.sh +3 -0
- package/files/loop/lib/blend-learn.sh +3 -0
- package/files/loop/lib/blend-parallel.sh +3 -0
- package/files/loop/lib/blend-verify.sh +3 -0
- package/files/loop/lib/blend.sh +3 -0
- package/files/loop/lib/boot.sh +3 -0
- package/files/loop/lib/context.sh +3 -0
- package/files/loop/lib/discuss.sh +3 -0
- package/files/loop/lib/modes.sh +3 -0
- package/files/loop/lib/progress.sh +3 -0
- package/files/loop/lib/safety.sh +3 -0
- package/files/loop/lib/session-end.sh +3 -0
- package/files/loop/lib/sights.sh +3 -0
- package/files/loop/lib/state.sh +3 -0
- package/files/loop/lib/teams.sh +3 -0
- package/files/loop/lib/timeout.sh +3 -0
- package/files/loop/lib/tui.sh +3 -0
- package/files/loop/lib/workflow-gen.sh +3 -0
- package/files/loop/lib/workflow-run.sh +3 -0
- package/files/loop/lib/workflow.sh +3 -0
- package/files/loop/merlin-loop.sh +3 -0
- package/files/loop/merlin-session.sh +3 -0
- package/package.json +2 -1
- package/rules/go.md +38 -0
- package/rules/java.md +36 -0
- package/rules/python.md +38 -0
- package/rules/rust.md +34 -0
- package/rules/swift.md +35 -0
- package/rules/typescript.md +38 -0
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
# DEPRECATED: Use Claude Code's native /loop command instead.
|
|
3
|
+
# See /merlin:loop-recipes for pre-built patterns.
|
|
4
|
+
# This script is kept for backward compatibility only.
|
|
2
5
|
#
|
|
3
6
|
# ╔═══════════════════════════════════════════════════════════════════════════╗
|
|
4
7
|
# ║ MERLIN SESSION - Interactive Deterministic Orchestrator ║
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-merlin-brain",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"description": "Merlin - The Ultimate AI Brain for Claude Code. One install: workflows, agents, loop, and Sights MCP server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/server/index.js",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"bin/",
|
|
45
45
|
"dist/",
|
|
46
46
|
"files/",
|
|
47
|
+
"rules/",
|
|
47
48
|
"README.md"
|
|
48
49
|
],
|
|
49
50
|
"dependencies": {
|
package/rules/go.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Go Coding Rules
|
|
2
|
+
|
|
3
|
+
## Error Handling
|
|
4
|
+
- Handle every error explicitly — never discard with `_` unless truly safe (log a comment why)
|
|
5
|
+
- Return errors to the caller; only wrap with `fmt.Errorf("context: %w", err)` at boundaries
|
|
6
|
+
- Use `errors.Is` / `errors.As` for error inspection — never string comparison
|
|
7
|
+
- Sentinel errors as package-level `var ErrFoo = errors.New("...")` for exported error types
|
|
8
|
+
|
|
9
|
+
## Function Design
|
|
10
|
+
- Accept interfaces, return structs — keeps callers flexible, keeps implementations concrete
|
|
11
|
+
- Context (`context.Context`) as the first parameter on every I/O and long-running function
|
|
12
|
+
- Short variable names in small scopes (`i`, `r`, `w`); descriptive names at package scope
|
|
13
|
+
- No named return values except for `(err error)` in defer-based cleanup
|
|
14
|
+
|
|
15
|
+
## Testing
|
|
16
|
+
- Table-driven tests for all non-trivial functions:
|
|
17
|
+
```go
|
|
18
|
+
tests := []struct{ name string; input X; want Y }{...}
|
|
19
|
+
for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {...}) }
|
|
20
|
+
```
|
|
21
|
+
- Use `testify/assert` or standard `t.Errorf` — avoid panics in tests
|
|
22
|
+
- Test files in the same package (white-box) for internals, `_test` package for public API
|
|
23
|
+
|
|
24
|
+
## Concurrency
|
|
25
|
+
- No global mutable state — pass dependencies explicitly or use struct fields
|
|
26
|
+
- `sync.Mutex` for shared state; channels for signalling and work queues
|
|
27
|
+
- Always check for goroutine leaks: every goroutine must have a clear exit path
|
|
28
|
+
- Use `errgroup` for structured goroutine coordination
|
|
29
|
+
|
|
30
|
+
## Code Organisation
|
|
31
|
+
- One package per directory; package name matches directory name (no `util`, `common` packages)
|
|
32
|
+
- Interfaces defined in the consuming package, not the implementing one
|
|
33
|
+
- Constants grouped with `iota` enums; avoid magic numbers inline
|
|
34
|
+
|
|
35
|
+
## Style
|
|
36
|
+
- `gofmt` always (enforced in CI)
|
|
37
|
+
- Comments on all exported identifiers — start with the identifier name
|
|
38
|
+
- Struct field tags are valid JSON-serializable when used with encoding/json
|
package/rules/java.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Java Coding Rules
|
|
2
|
+
|
|
3
|
+
## Modern Java (16+)
|
|
4
|
+
- `record` for immutable data classes — eliminates boilerplate getters/equals/hashCode
|
|
5
|
+
- Sealed classes (`sealed interface`) for exhaustive type hierarchies
|
|
6
|
+
- Pattern matching (`instanceof Foo f`) over manual casts
|
|
7
|
+
- `switch` expressions with arrow syntax for concise pattern dispatch
|
|
8
|
+
- Text blocks for multi-line strings (SQL, JSON templates)
|
|
9
|
+
|
|
10
|
+
## Collections & Streams
|
|
11
|
+
- Stream API for transforming collections — avoid imperative loops when streams are clearer
|
|
12
|
+
- `Collectors.toUnmodifiableList/Map()` for defensive copies
|
|
13
|
+
- Prefer `List.of()`, `Map.of()` for small literals (immutable)
|
|
14
|
+
- `Optional<T>` for nullable return values — never return `null` from public methods
|
|
15
|
+
|
|
16
|
+
## Null Safety
|
|
17
|
+
- `Optional<T>` for methods that legitimately have no result
|
|
18
|
+
- `@Nullable` / `@NonNull` annotations on all public API parameters and returns
|
|
19
|
+
- Fail fast with `Objects.requireNonNull()` in constructors
|
|
20
|
+
|
|
21
|
+
## Object Design
|
|
22
|
+
- Builder pattern for types with >3 constructor parameters (use Lombok `@Builder` or manual)
|
|
23
|
+
- Dependency injection via constructor — no field injection (`@Autowired` on fields)
|
|
24
|
+
- Interfaces for all service contracts; `Impl` suffix only for the concrete class
|
|
25
|
+
- Immutable by default: `final` fields, no setters on domain objects
|
|
26
|
+
|
|
27
|
+
## Error Handling
|
|
28
|
+
- Checked exceptions for recoverable errors callers must handle
|
|
29
|
+
- Unchecked (`RuntimeException`) for programming errors and unrecoverable failures
|
|
30
|
+
- Never swallow exceptions with empty catch blocks
|
|
31
|
+
- Wrap and rethrow with context: `throw new ServiceException("failed to save user", cause)`
|
|
32
|
+
|
|
33
|
+
## Testing
|
|
34
|
+
- JUnit 5 with `@DisplayName` for descriptive test names
|
|
35
|
+
- `@ParameterizedTest` with `@MethodSource` for table-driven tests
|
|
36
|
+
- Mockito for mocking dependencies; assert interactions with `verify()`
|
package/rules/python.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Python Coding Rules
|
|
2
|
+
|
|
3
|
+
## Type Hints
|
|
4
|
+
- Type hints on all function signatures — parameters and return types
|
|
5
|
+
- Use `from __future__ import annotations` for forward references
|
|
6
|
+
- Prefer concrete types (`list[str]`) over generic aliases (`List[str]`) for Python 3.9+
|
|
7
|
+
- `Optional[X]` → `X | None` (Python 3.10+ union syntax preferred)
|
|
8
|
+
|
|
9
|
+
## Data Structures
|
|
10
|
+
- Dataclasses (`@dataclass`) for plain data containers — avoid raw dicts for structured data
|
|
11
|
+
- Pydantic for validated data (API payloads, configs) — use `model_validator` not `__init__`
|
|
12
|
+
- No mutable default arguments: `def foo(items=None): items = items or []` pattern
|
|
13
|
+
- Prefer `TypedDict` over plain `dict` when shape is known and Pydantic is overkill
|
|
14
|
+
|
|
15
|
+
## Strings & Output
|
|
16
|
+
- f-strings for all string interpolation — never `%` formatting or `.format()` for new code
|
|
17
|
+
- Multi-line strings: use triple-quoted f-strings, not concatenation
|
|
18
|
+
- `str.join()` for building strings from lists — avoid `+=` in loops
|
|
19
|
+
|
|
20
|
+
## File & Resource Handling
|
|
21
|
+
- `pathlib.Path` for all filesystem paths — never `os.path.join` in new code
|
|
22
|
+
- Context managers (`with`) for files, network connections, locks — never manual `.close()`
|
|
23
|
+
- `tempfile` module for temporary files — never hardcode `/tmp/`
|
|
24
|
+
|
|
25
|
+
## Functions & Classes
|
|
26
|
+
- Single responsibility per function; >20 lines is a signal to refactor
|
|
27
|
+
- Class methods that don't use `self` should be `@staticmethod` or module-level functions
|
|
28
|
+
- `__slots__` on data classes where performance matters
|
|
29
|
+
- Abstract base classes (`ABC`) to define interfaces; avoid duck-typing where contracts matter
|
|
30
|
+
|
|
31
|
+
## Error Handling
|
|
32
|
+
- Specific exceptions over `except Exception` — catch the narrowest type possible
|
|
33
|
+
- Custom exception classes for domain errors (inherit from `Exception` with a clear name)
|
|
34
|
+
- `logging` module, not `print()` — use structured log fields
|
|
35
|
+
|
|
36
|
+
## Async
|
|
37
|
+
- `asyncio.gather()` for concurrent coroutines — avoid sequential `await` in a loop
|
|
38
|
+
- Mark I/O-bound functions `async def`; CPU-bound code stays sync (use `ProcessPoolExecutor`)
|
package/rules/rust.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Rust Coding Rules
|
|
2
|
+
|
|
3
|
+
## Ownership & Borrowing
|
|
4
|
+
- Ownership over reference counting — prefer passing values or borrows over `Rc`/`Arc`
|
|
5
|
+
- `Arc<Mutex<T>>` for shared mutable state across threads; document why sharing is needed
|
|
6
|
+
- Avoid cloning in hot paths — profile before adding `.clone()` calls
|
|
7
|
+
- Return owned values from functions that create data; accept borrows in functions that read
|
|
8
|
+
|
|
9
|
+
## Error Handling
|
|
10
|
+
- `Result<T, E>` for all fallible operations — never panic in library code
|
|
11
|
+
- Custom error types with `thiserror` for libraries; `anyhow` for application binaries
|
|
12
|
+
- `?` operator for propagation — avoid `unwrap()` in production code; prefer `expect("reason")`
|
|
13
|
+
- Map errors at boundaries: `map_err(|e| MyError::Database(e))`
|
|
14
|
+
|
|
15
|
+
## Types & Traits
|
|
16
|
+
- Derive traits liberally: `#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]`
|
|
17
|
+
- `impl` blocks immediately after their `struct`/`enum` definition in the same file
|
|
18
|
+
- Prefer `&str` over `String` in function parameters (accepts both literals and owned strings)
|
|
19
|
+
- `Into<T>` / `From<T>` for ergonomic conversions; implement `Display` for user-facing types
|
|
20
|
+
|
|
21
|
+
## Structs & Enums
|
|
22
|
+
- Exhaustive `match` on enums — no `_ =>` catch-all unless truly irrelevant variants exist
|
|
23
|
+
- Newtype pattern (`struct UserId(u64)`) to prevent mixing domain IDs
|
|
24
|
+
- Builder pattern for structs with many optional fields (derive with `typed-builder`)
|
|
25
|
+
|
|
26
|
+
## Async
|
|
27
|
+
- `tokio` for async runtime; `async-trait` for async in trait methods
|
|
28
|
+
- `tokio::join!` / `tokio::try_join!` for concurrent futures
|
|
29
|
+
- Avoid blocking calls inside async context — use `tokio::task::spawn_blocking`
|
|
30
|
+
|
|
31
|
+
## Safety
|
|
32
|
+
- No `unsafe` without a `// SAFETY:` comment explaining the invariant
|
|
33
|
+
- Keep `unsafe` blocks as small as possible; encapsulate behind a safe API
|
|
34
|
+
- Prefer `Vec` and slices over raw pointer arithmetic
|
package/rules/swift.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Swift Coding Rules
|
|
2
|
+
|
|
3
|
+
## Concurrency (Swift 6)
|
|
4
|
+
- `async`/`await` for all asynchronous operations — no completion handler callbacks in new code
|
|
5
|
+
- Actors for shared mutable state: `actor MyService { ... }`
|
|
6
|
+
- `@MainActor` on UI-bound types and functions
|
|
7
|
+
- `Sendable` conformance required for types crossing actor boundaries — use `@unchecked Sendable` sparingly with a justification comment
|
|
8
|
+
- `async let` for independent concurrent work; `withTaskGroup` for dynamic concurrency
|
|
9
|
+
|
|
10
|
+
## Types & Values
|
|
11
|
+
- Value types (`struct`, `enum`) by default — use `class` only when reference semantics are required (identity, inheritance, Obj-C interop)
|
|
12
|
+
- Protocol-oriented design: define capabilities as protocols, extend with default implementations
|
|
13
|
+
- `enum` with associated values for discriminated unions instead of subclassing
|
|
14
|
+
- Avoid `@objc` and `NSObject` subclasses unless required for interoperability
|
|
15
|
+
|
|
16
|
+
## Optionals & Safety
|
|
17
|
+
- `guard` for early returns when preconditions fail — keeps happy path unindented
|
|
18
|
+
- Never force-unwrap (`!`) except in tests or `@IBOutlet` — use `guard let` or `if let`
|
|
19
|
+
- `??` for default values on optionals; avoid chained optionals deeper than 2 levels
|
|
20
|
+
- Mark parameters optional (`T?`) only when absence carries meaning; prefer overloads otherwise
|
|
21
|
+
|
|
22
|
+
## Memory Management
|
|
23
|
+
- `weak` references to break retain cycles (delegates, closures capturing self)
|
|
24
|
+
- `unowned` only when the object is guaranteed to outlive the reference — prefer `weak` when uncertain
|
|
25
|
+
- Use `[weak self]` captures in closures stored beyond the current scope
|
|
26
|
+
|
|
27
|
+
## Protocols & Extensions
|
|
28
|
+
- Small, focused protocols (Interface Segregation) — prefer many narrow protocols over one wide one
|
|
29
|
+
- Extensions to add protocol conformances, keeping the type definition clean
|
|
30
|
+
- `Codable` for serialisable types; `CodingKeys` enum to map non-Swift naming
|
|
31
|
+
|
|
32
|
+
## Style
|
|
33
|
+
- `let` by default; `var` only when mutation is needed
|
|
34
|
+
- 4-space indentation, Allman-style braces
|
|
35
|
+
- Prefer named parameters at call sites for clarity
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# TypeScript Coding Rules
|
|
2
|
+
|
|
3
|
+
## Type Safety
|
|
4
|
+
- Enable strict mode — no `any` without an explicit justification comment
|
|
5
|
+
- Prefer `unknown` over `any` for values of uncertain type; narrow with type guards
|
|
6
|
+
- Use `satisfies` operator for type-safe literal assignments
|
|
7
|
+
- Avoid type assertions (`as Foo`) unless interfacing with untyped third-party code
|
|
8
|
+
|
|
9
|
+
## Variables & Functions
|
|
10
|
+
- `const` by default, `let` only when reassignment is necessary — never `var`
|
|
11
|
+
- `async`/`await` over raw Promise chains; avoid `.then()` chains longer than 2 steps
|
|
12
|
+
- Explicit return types on exported functions; internal functions may infer
|
|
13
|
+
- Exhaustive switch/case: add a `default` that asserts `never` to catch future enum additions
|
|
14
|
+
|
|
15
|
+
## Interfaces & Types
|
|
16
|
+
- `interface` for object shapes (extendable, declaration-merged)
|
|
17
|
+
- `type` for unions, intersections, primitives, and mapped types
|
|
18
|
+
- No empty interfaces (`interface Foo {}`); use `Record<never, never>` or a comment
|
|
19
|
+
|
|
20
|
+
## Error Handling
|
|
21
|
+
- Typed errors: extend `Error` with named subclasses for domain errors
|
|
22
|
+
- No bare `catch (e) {}` — always log or rethrow with context
|
|
23
|
+
- Use `Result<T, E>` patterns for expected failure paths (avoid throw-for-control-flow)
|
|
24
|
+
- Wrap third-party calls in try/catch at the boundary, not deep in business logic
|
|
25
|
+
|
|
26
|
+
## Imports & Modules
|
|
27
|
+
- Use named exports; avoid default exports (harder to rename/trace)
|
|
28
|
+
- Group imports: external packages → internal modules → relative paths (blank line between)
|
|
29
|
+
- Barrel files (`index.ts`) only at module boundaries, not within a feature folder
|
|
30
|
+
|
|
31
|
+
## Async & Concurrency
|
|
32
|
+
- `Promise.all` for independent async operations (don't serialize what can parallelize)
|
|
33
|
+
- Avoid `async` functions that never `await` anything
|
|
34
|
+
- Always handle rejected promises — no floating promise anti-pattern
|
|
35
|
+
|
|
36
|
+
## Null Safety
|
|
37
|
+
- Prefer optional chaining (`?.`) and nullish coalescing (`??`) over manual null checks
|
|
38
|
+
- Avoid optional properties (`foo?: string`) on data types; use `| null` for explicitness
|