@directive-run/knowledge 1.15.0 → 1.17.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/ai/ai-adapters.md +5 -0
- package/ai/ai-agents-streaming.md +5 -0
- package/ai/ai-budget-resilience.md +6 -0
- package/ai/ai-communication.md +5 -0
- package/ai/ai-debug-observability.md +6 -0
- package/ai/ai-guardrails-memory.md +6 -0
- package/ai/ai-mcp-rag.md +7 -0
- package/ai/ai-multi-agent.md +7 -0
- package/ai/ai-orchestrator.md +9 -0
- package/ai/ai-security.md +5 -0
- package/ai/ai-tasks.md +5 -0
- package/ai/ai-testing-evals.md +6 -0
- package/compositions.json +216 -0
- package/core/anti-patterns.md +9 -0
- package/core/constraints.md +7 -0
- package/core/core-patterns.md +10 -0
- package/core/error-boundaries.md +6 -0
- package/core/history.md +5 -0
- package/core/multi-module.md +7 -0
- package/core/naming.md +120 -91
- package/core/plugins.md +5 -0
- package/core/react-adapter.md +6 -0
- package/core/resolvers.md +8 -0
- package/core/schema-types.md +6 -0
- package/core/system-api.md +8 -0
- package/core/testing.md +6 -0
- package/dist/index.cjs +8 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +101 -1
- package/dist/index.d.ts +101 -1
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/migration.json +277 -0
- package/package.json +6 -4
- package/sitemap.md +6 -0
package/core/naming.md
CHANGED
|
@@ -2,81 +2,116 @@
|
|
|
2
2
|
|
|
3
3
|
> Covers all `@directive-run/*` packages — terminology, parameter names, return-style rules.
|
|
4
4
|
|
|
5
|
-
Directive
|
|
5
|
+
Directive uses precise vocabulary by design: each concept has one canonical name across every package, every language adapter, and every doc. The names are non-negotiable for code Directive ships, AND every term has a cross-paradigm alias so a developer coming from Redux / Zustand / XState / Jotai / React Query can find the right Directive concept on the first search.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
This file is both the rules and the bridge. Search for the term you already know; you'll land on the Directive equivalent.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
Resolver parameter names?
|
|
11
|
-
→ (req, context) req = requirement, NEVER "request"
|
|
12
|
-
→ NEVER (req, ctx) context is NEVER abbreviated
|
|
9
|
+
## Coming from another library? Start here
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
| If you call it… | (in this library) | Directive calls it… | Why the name |
|
|
12
|
+
|---|---|---|---|
|
|
13
|
+
| **state**, **store**, **atom**, **signal**, **observable** | Redux, Zustand, Jotai, Preact Signals, MobX | **facts** | "Facts about the world" — the system observes them. Same value-bag role as state, with a proxy that auto-tracks reads. |
|
|
14
|
+
| **selector**, **computed**, **getter**, **memo**, **derived store** | Redux, Vue/MobX, Zustand getters, Memoize, Svelte | **derivations** / `derive` | Auto-tracked computed values. No dep arrays. Directive's name aligns with "derived from facts." |
|
|
15
|
+
| **action**, **dispatch**, **reducer**, **command**, **intent** | Redux, Redux Toolkit, CQRS | **events** + **resolvers** | Events are the user-facing trigger; resolvers fulfill them. Reducers are split into the two halves Directive cares about. |
|
|
16
|
+
| **thunk**, **saga**, **effect**, **middleware**, **listener** | Redux Toolkit, redux-saga, redux-observable, NgRx | **resolvers** | Async logic that mutates state in response to a requirement. Same role as a thunk; declared once, run by the runtime. |
|
|
17
|
+
| **rule**, **condition**, **guard**, **trigger**, **policy** | XState guards, Cerbos, OPA, business-rule engines | **constraints** | Declarative "when X is true, Y must happen." Constraints emit requirements; resolvers fulfill them. |
|
|
18
|
+
| **request**, **query**, **side-effect spec** | React Query / TanStack Query queries, Apollo queries | **requirements** | The object a constraint emits. The runtime dedupes them, dispatches to resolvers, tracks status. |
|
|
19
|
+
| **subscription**, **listener**, **reaction**, **watcher** | Zustand subscribe, MobX reactions, Redux subscriptions | **effects** | Side-effects that run when watched facts change. Cleaner than `subscribe()` callbacks because effects auto-track. |
|
|
20
|
+
| **slice**, **feature**, **domain**, **bounded context** | Redux Toolkit slices, NgRx feature modules | **modules** | Encapsulates facts + derivations + constraints + resolvers + events for one bounded slice of the system. |
|
|
21
|
+
| **store**, **container**, **context**, **app state** | Redux Store, Pinia, React Context, NgRx Store | **system** | The runtime that wires modules together, evaluates constraints, dispatches resolvers, and exposes observation. |
|
|
22
|
+
| **state machine**, **statechart**, **xstate machine** | XState | (closest: **module** + **constraints**) | Directive isn't a state machine — but if your XState `states` model business rules (not UI flow), constraints + facts express the same logic declaratively with no transition functions. |
|
|
23
|
+
| **cache**, **query cache**, **stale-while-revalidate** | TanStack Query, SWR, Apollo cache | (closest: `@directive-run/query` + **constraints**) | Use `@directive-run/query` for the cache; constraints decide when refetches fire. Directive doesn't replace TanStack Query — it composes with it. |
|
|
24
|
+
| **agent**, **chain**, **graph**, **workflow** | LangChain, LangGraph, OpenAI Assistants | **agent** + **orchestrator** | `@directive-run/ai` keeps the names — agents are agents, orchestrators are orchestrators — but they run under the same constraint engine as the rest of Directive. |
|
|
25
|
+
| **guardrail**, **filter**, **safety check**, **moderation** | OpenAI moderation API, NVIDIA NeMo Guardrails | **guardrails** | Same name, same role; declarative input/output/tool-call checks. |
|
|
17
26
|
|
|
18
|
-
|
|
19
|
-
→ "facts" NEVER "state", "store", "atoms"
|
|
20
|
-
→ system.facts.count NEVER system.state.count
|
|
27
|
+
If your term isn't in the table, search the canonical name in this doc's [Terminology quick reference](#terminology-quick-reference) — both directions are listed.
|
|
21
28
|
|
|
22
|
-
|
|
23
|
-
→ "constraints" NEVER "rules", "conditions", "triggers"
|
|
24
|
-
→ when() + require() NEVER if/then, trigger/action
|
|
29
|
+
## Canonical terms (non-negotiable for code Directive ships)
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
Above is the bridge from your existing vocabulary. Below are the canonical names — the only ones that should appear in `@directive-run/*` source, tests, docs, and generated AI rules.
|
|
32
|
+
|
|
33
|
+
### `facts` — the value bag
|
|
34
|
+
|
|
35
|
+
Not state, not store, not atoms. **Facts.** Accessed at `system.facts.x`. Mutated through events and resolvers. Read through derivations, hooks, and `system.facts.$store`.
|
|
36
|
+
|
|
37
|
+
### `derivations` — auto-tracked computed values
|
|
38
|
+
|
|
39
|
+
Declared via `derive: { name: (facts) => … }`. Read at `system.derive.name`. The hook is `useDerived` (not `useComputed`, not `useSelector` — Directive's `useSelector` is a different, broader primitive that takes a selector function).
|
|
40
|
+
|
|
41
|
+
### `constraints` — when-then declarations
|
|
42
|
+
|
|
43
|
+
Declared via `constraints: { name: { when: …, require: … } }`. The `when` returns a boolean; the `require` returns a requirement.
|
|
44
|
+
|
|
45
|
+
### `resolvers` — requirement fulfillment
|
|
46
|
+
|
|
47
|
+
Declared via `resolvers: { name: { requirement: …, resolve: async (req, context) => … } }`. Mutate `context.facts`; never return data from `resolve`.
|
|
48
|
+
|
|
49
|
+
### `requirements` — what constraints emit
|
|
50
|
+
|
|
51
|
+
Tagged union `{ type: "FETCH_USER", … }`. Constraints emit them; the runtime dedupes by `type` + `key()`; resolvers fulfill them.
|
|
52
|
+
|
|
53
|
+
### `effects` — side effects from watched changes
|
|
54
|
+
|
|
55
|
+
Declared via `effects: { name: { run: (facts, prev) => … } }`. Run on relevant fact changes. The auto-tracking dependency model means no `deps` array unless you specifically need a partial dep set.
|
|
56
|
+
|
|
57
|
+
### `events` — typed mutation entry points
|
|
58
|
+
|
|
59
|
+
Declared via `events: { name: (facts, payload) => … }`. Called as `system.events.name(payload)`. The typed events accessor is the canonical way to dispatch — `system.dispatch({type, ...payload})` works but the typed accessor carries autocomplete.
|
|
30
60
|
|
|
31
|
-
|
|
61
|
+
### `module` — bounded slice
|
|
62
|
+
|
|
63
|
+
Created via `createModule(name, { schema, init, derive, effects, events, constraints, resolvers })`. Composes into systems.
|
|
64
|
+
|
|
65
|
+
### `system` — the runtime
|
|
66
|
+
|
|
67
|
+
Created via `createSystem({ module })` or `createSystem({ modules: { x, y } })`. Hosts the reconciliation loop.
|
|
68
|
+
|
|
69
|
+
## Parameter naming
|
|
32
70
|
|
|
33
71
|
### `req` = requirement (NOT request)
|
|
34
72
|
|
|
35
|
-
The `req` parameter in resolvers and constraint `key()` functions is short for **requirement**
|
|
73
|
+
The `req` parameter in resolvers and constraint `key()` functions is short for **requirement** — the object emitted by a constraint's `require` property.
|
|
36
74
|
|
|
37
75
|
```typescript
|
|
38
|
-
// CORRECT
|
|
76
|
+
// CORRECT — req is a requirement
|
|
39
77
|
resolvers: {
|
|
40
78
|
fetchUser: {
|
|
41
79
|
requirement: "FETCH_USER",
|
|
42
80
|
key: (req) => `fetch-${req.userId}`,
|
|
43
81
|
resolve: async (req, context) => {
|
|
44
82
|
// req.type === "FETCH_USER"
|
|
45
|
-
// req.userId from the requirement payload
|
|
46
83
|
const user = await fetchUser(req.userId);
|
|
47
84
|
context.facts.user = user;
|
|
48
85
|
},
|
|
49
86
|
},
|
|
50
87
|
},
|
|
51
88
|
|
|
52
|
-
// WRONG
|
|
89
|
+
// WRONG — never "request" or "r"
|
|
53
90
|
resolve: async (request, context) => { /* ... */ },
|
|
54
91
|
resolve: async (r, context) => { /* ... */ },
|
|
55
92
|
```
|
|
56
93
|
|
|
57
|
-
### `context` is
|
|
94
|
+
### `context` is never abbreviated
|
|
58
95
|
|
|
59
96
|
```typescript
|
|
60
97
|
// CORRECT
|
|
61
98
|
resolve: async (req, context) => {
|
|
62
99
|
context.facts.status = "loaded";
|
|
63
|
-
context.signal;
|
|
64
|
-
context.snapshot();
|
|
100
|
+
context.signal; // AbortSignal
|
|
101
|
+
context.snapshot(); // facts snapshot
|
|
65
102
|
},
|
|
66
103
|
|
|
67
|
-
// WRONG
|
|
104
|
+
// WRONG — never abbreviate to ctx
|
|
68
105
|
resolve: async (req, ctx) => { /* ... */ },
|
|
69
106
|
```
|
|
70
107
|
|
|
71
|
-
## Return
|
|
108
|
+
## Return style
|
|
72
109
|
|
|
73
|
-
###
|
|
110
|
+
### Braces for `if` blocks with `return` (NOT for arrow expressions)
|
|
74
111
|
|
|
75
112
|
The brace rule applies to control-flow blocks — not to arrow-expression bodies.
|
|
76
113
|
|
|
77
|
-
**Arrow expressions** (single-line derivations, predicates, computed
|
|
78
|
-
requirements): the concise form is preferred. No braces, no explicit
|
|
79
|
-
`return`.
|
|
114
|
+
**Arrow expressions** (single-line derivations, predicates, computed requirements): the concise form is preferred. No braces, no explicit `return`.
|
|
80
115
|
|
|
81
116
|
```typescript
|
|
82
117
|
// CORRECT — single-line arrow expressions stay concise
|
|
@@ -93,25 +128,24 @@ constraints: {
|
|
|
93
128
|
},
|
|
94
129
|
```
|
|
95
130
|
|
|
96
|
-
**Control-flow statements** (`if`, `for`, `while`): braces required, even
|
|
97
|
-
for single-line bodies. Single-line `if (x) return y` shapes are never used.
|
|
131
|
+
**Control-flow statements** (`if`, `for`, `while`): braces required, even for single-line bodies. Single-line `if (x) return y` shapes are never used.
|
|
98
132
|
|
|
99
133
|
```typescript
|
|
100
|
-
// WRONG
|
|
134
|
+
// WRONG — single-line if return
|
|
101
135
|
if (facts.user) return "ready";
|
|
102
136
|
|
|
103
|
-
// CORRECT
|
|
137
|
+
// CORRECT — always wrap the body in braces
|
|
104
138
|
if (facts.user) {
|
|
105
139
|
return "ready";
|
|
106
140
|
}
|
|
107
141
|
```
|
|
108
142
|
|
|
109
|
-
### Blank
|
|
143
|
+
### Blank line before `return`
|
|
110
144
|
|
|
111
145
|
Add a blank line before `return` when there is code above it. Skip the blank line when `return` is the first statement in a block.
|
|
112
146
|
|
|
113
147
|
```typescript
|
|
114
|
-
// CORRECT
|
|
148
|
+
// CORRECT — blank line before return when code precedes it
|
|
115
149
|
function getStatus(facts) {
|
|
116
150
|
const phase = facts.phase;
|
|
117
151
|
const hasUser = facts.user !== null;
|
|
@@ -119,12 +153,12 @@ function getStatus(facts) {
|
|
|
119
153
|
return phase === "ready" && hasUser;
|
|
120
154
|
}
|
|
121
155
|
|
|
122
|
-
// CORRECT
|
|
156
|
+
// CORRECT — no blank line when return is first statement
|
|
123
157
|
function isReady(facts) {
|
|
124
158
|
return facts.phase === "ready";
|
|
125
159
|
}
|
|
126
160
|
|
|
127
|
-
// CORRECT
|
|
161
|
+
// CORRECT — blank line after brace-style return block
|
|
128
162
|
function process(facts) {
|
|
129
163
|
if (!facts.ready) {
|
|
130
164
|
return null;
|
|
@@ -134,26 +168,20 @@ function process(facts) {
|
|
|
134
168
|
|
|
135
169
|
return result;
|
|
136
170
|
}
|
|
137
|
-
|
|
138
|
-
// WRONG – no blank line before return after code
|
|
139
|
-
function getStatus(facts) {
|
|
140
|
-
const phase = facts.phase;
|
|
141
|
-
return phase === "ready"; // Missing blank line
|
|
142
|
-
}
|
|
143
171
|
```
|
|
144
172
|
|
|
145
|
-
## Multi-
|
|
173
|
+
## Multi-line code formatting
|
|
146
174
|
|
|
147
175
|
Never put properties or statements on a single line inside braces. Always expand to one item per line with proper indentation. This applies everywhere: schema definitions, init functions, events, effects, requirement types, and any other object or block.
|
|
148
176
|
|
|
149
177
|
```typescript
|
|
150
|
-
// WRONG
|
|
178
|
+
// WRONG — properties crammed on one line
|
|
151
179
|
schema: {
|
|
152
180
|
facts: { phase: t.string(), count: t.number() },
|
|
153
181
|
requirements: { FETCH_USER: { id: t.string() }, RESET: {} },
|
|
154
182
|
},
|
|
155
183
|
|
|
156
|
-
// CORRECT
|
|
184
|
+
// CORRECT — one property per line, always expanded
|
|
157
185
|
schema: {
|
|
158
186
|
facts: {
|
|
159
187
|
phase: t.string(),
|
|
@@ -167,41 +195,31 @@ schema: {
|
|
|
167
195
|
},
|
|
168
196
|
},
|
|
169
197
|
|
|
170
|
-
// WRONG
|
|
198
|
+
// WRONG — statements crammed on one line
|
|
171
199
|
init: (facts) => { facts.phase = "idle"; facts.count = 0; },
|
|
172
200
|
|
|
173
|
-
// CORRECT
|
|
201
|
+
// CORRECT — one statement per line
|
|
174
202
|
init: (facts) => {
|
|
175
203
|
facts.phase = "idle";
|
|
176
204
|
facts.count = 0;
|
|
177
205
|
},
|
|
178
|
-
|
|
179
|
-
// WRONG
|
|
180
|
-
events: { reset: (facts) => { facts.count = 0; facts.phase = "idle"; } },
|
|
181
|
-
|
|
182
|
-
// CORRECT
|
|
183
|
-
events: {
|
|
184
|
-
reset: (facts) => {
|
|
185
|
-
facts.count = 0;
|
|
186
|
-
facts.phase = "idle";
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
206
|
```
|
|
190
207
|
|
|
191
208
|
Single-expression arrows (no braces) are fine on one line. Empty objects `{}` are fine inline.
|
|
209
|
+
|
|
192
210
|
```typescript
|
|
193
|
-
// OK
|
|
211
|
+
// OK — single expression, no braces
|
|
194
212
|
derive: {
|
|
195
213
|
isReady: (facts) => facts.phase === "ready",
|
|
196
214
|
},
|
|
197
215
|
|
|
198
|
-
// OK
|
|
216
|
+
// OK — empty object
|
|
199
217
|
RESET: {},
|
|
200
218
|
```
|
|
201
219
|
|
|
202
|
-
## Multi-
|
|
220
|
+
## Multi-module naming
|
|
203
221
|
|
|
204
|
-
### `facts.self.*` for
|
|
222
|
+
### `facts.self.*` for own module
|
|
205
223
|
|
|
206
224
|
In multi-module systems, constraints, effects, and derivations with `crossModuleDeps` receive namespaced facts. Own module facts are always at `facts.self.*`.
|
|
207
225
|
|
|
@@ -214,7 +232,7 @@ constraints: {
|
|
|
214
232
|
},
|
|
215
233
|
},
|
|
216
234
|
|
|
217
|
-
// WRONG
|
|
235
|
+
// WRONG — bare facts.* in multi-module context
|
|
218
236
|
constraints: {
|
|
219
237
|
loadWhenAuth: {
|
|
220
238
|
when: (facts) => facts.isAuthenticated && !facts.loaded,
|
|
@@ -223,48 +241,48 @@ constraints: {
|
|
|
223
241
|
},
|
|
224
242
|
```
|
|
225
243
|
|
|
226
|
-
### System-
|
|
244
|
+
### System-level access uses dot notation
|
|
227
245
|
|
|
228
246
|
```typescript
|
|
229
|
-
// CORRECT
|
|
247
|
+
// CORRECT — dot notation through namespace proxy
|
|
230
248
|
system.facts.auth.token;
|
|
231
249
|
system.facts.cart.items;
|
|
232
250
|
system.derive.auth.isLoggedIn;
|
|
233
251
|
system.events.auth.login({ token: "..." });
|
|
234
252
|
|
|
235
|
-
// WRONG
|
|
253
|
+
// WRONG — bracket notation with internal separator
|
|
236
254
|
system.facts["auth::token"];
|
|
237
255
|
system.facts["auth_token"];
|
|
238
256
|
```
|
|
239
257
|
|
|
240
|
-
## Type
|
|
258
|
+
## Type casting rules
|
|
241
259
|
|
|
242
|
-
### Never
|
|
260
|
+
### Never cast when reading
|
|
243
261
|
|
|
244
262
|
The schema provides all types. Do not add `as` casts when reading facts or derivations from the system.
|
|
245
263
|
|
|
246
264
|
```typescript
|
|
247
|
-
// CORRECT
|
|
265
|
+
// CORRECT — schema provides the type
|
|
248
266
|
const profile = system.facts.profile;
|
|
249
267
|
const isReady = system.derive.isReady;
|
|
250
268
|
|
|
251
|
-
// WRONG
|
|
269
|
+
// WRONG — unnecessary cast
|
|
252
270
|
const profile = system.facts.profile as UserProfile;
|
|
253
271
|
const isReady = system.derive.isReady as boolean;
|
|
254
272
|
```
|
|
255
273
|
|
|
256
|
-
### Cast
|
|
274
|
+
### Cast only in schema definition
|
|
257
275
|
|
|
258
|
-
Type assertions are only valid in schema definition using the `{} as {}` pattern:
|
|
276
|
+
Type assertions are only valid in schema definition using the `{} as {}` pattern, or via the `t.*` builders (preferred):
|
|
259
277
|
|
|
260
278
|
```typescript
|
|
261
|
-
// CORRECT
|
|
279
|
+
// CORRECT — cast in schema definition
|
|
262
280
|
schema: {
|
|
263
281
|
facts: {} as { profile: UserProfile; settings: AppSettings },
|
|
264
282
|
derivations: {} as { displayName: string },
|
|
265
283
|
},
|
|
266
284
|
|
|
267
|
-
//
|
|
285
|
+
// PREFERRED — t.* builders
|
|
268
286
|
schema: {
|
|
269
287
|
facts: {
|
|
270
288
|
profile: t.object<UserProfile>(),
|
|
@@ -276,17 +294,28 @@ schema: {
|
|
|
276
294
|
},
|
|
277
295
|
```
|
|
278
296
|
|
|
279
|
-
## Terminology
|
|
297
|
+
## Terminology quick reference
|
|
298
|
+
|
|
299
|
+
Two-way lookup. Search the term you know.
|
|
280
300
|
|
|
281
|
-
| Directive
|
|
301
|
+
| Directive term | Cross-paradigm aliases (use these to search) |
|
|
282
302
|
|---|---|
|
|
283
|
-
| facts | state, store, atoms, signals |
|
|
284
|
-
| derivations / derive | computed, selectors, getters, memos |
|
|
285
|
-
| constraints | rules, conditions, triggers, guards |
|
|
286
|
-
| resolvers | handlers, actions, reducers, sagas |
|
|
287
|
-
| requirements | requests, commands, intents |
|
|
288
|
-
| effects | watchers, subscriptions, reactions |
|
|
289
|
-
|
|
|
290
|
-
|
|
|
291
|
-
|
|
|
292
|
-
|
|
|
303
|
+
| **facts** | state, store, atoms, signals, observables, model |
|
|
304
|
+
| **derivations** / `derive` | computed, selectors, getters, memos, derived stores, $: blocks (Svelte) |
|
|
305
|
+
| **constraints** | rules, conditions, triggers, guards, policies, invariants |
|
|
306
|
+
| **resolvers** | handlers, actions, reducers, sagas, thunks, effects (Redux), middleware, listeners |
|
|
307
|
+
| **requirements** | requests, commands, intents, queries (TanStack), tasks |
|
|
308
|
+
| **effects** | watchers, subscriptions, reactions, autoruns, listeners |
|
|
309
|
+
| **events** | actions, intents, commands, methods (Pinia), signals (NgRx) |
|
|
310
|
+
| **module** | slice, feature, domain, bounded context, NgRx feature module |
|
|
311
|
+
| **system** | store, container, context, app state, app shell |
|
|
312
|
+
| **`req`** (parameter) | request, r, requirement (spelled out) |
|
|
313
|
+
| **`context`** (parameter) | ctx, c, resolverContext |
|
|
314
|
+
|
|
315
|
+
The forbidden direction is also non-negotiable: in code Directive ships, the columns reverse. Do NOT use `state`, `store`, `selectors`, `computed`, `actions`, `reducers`, `subscriptions`, `slices`, `request`, or `ctx` in `@directive-run/*` source. The alias map is for retrieval — the canonical names are for code.
|
|
316
|
+
|
|
317
|
+
## See also
|
|
318
|
+
|
|
319
|
+
- [`core-patterns.md`](./core-patterns.md) — the actual code shapes every naming rule here applies to
|
|
320
|
+
- [`multi-module.md`](./multi-module.md) — `facts.self.*` convention and dot-notation rules
|
|
321
|
+
- [`anti-patterns.md`](./anti-patterns.md) — naming-shaped mistakes (`request` for `req`, `ctx` for `context`, hallucinated TS schema types)
|
package/core/plugins.md
CHANGED
|
@@ -354,3 +354,8 @@ persistencePlugin({
|
|
|
354
354
|
exclude: ["authToken", "isLoading", "error"],
|
|
355
355
|
})
|
|
356
356
|
```
|
|
357
|
+
|
|
358
|
+
## See also
|
|
359
|
+
|
|
360
|
+
- [`system-api.md`](./system-api.md) — `plugins:` option on `createSystem` and the lifecycle hooks plugins observe
|
|
361
|
+
- [`error-boundaries.md`](./error-boundaries.md) — `createCircuitBreaker` and the resilience plugins that pair with error boundaries
|
package/core/react-adapter.md
CHANGED
|
@@ -368,3 +368,9 @@ const handleClick = useCallback(() => events.increment(), [events]);
|
|
|
368
368
|
const events = useEvents(system);
|
|
369
369
|
<button onClick={() => events.increment()}>+</button>
|
|
370
370
|
```
|
|
371
|
+
|
|
372
|
+
## See also
|
|
373
|
+
|
|
374
|
+
- [`system-api.md`](./system-api.md) — the system instance the hooks here read from + the SSR/hydration story
|
|
375
|
+
- [`core-patterns.md`](./core-patterns.md) — the module shape every React example here assumes you've built
|
|
376
|
+
- [`anti-patterns.md`](./anti-patterns.md) — the hallucinated React hooks (`useEvent`, `useSystem`, `DirectiveProvider`) that AI assistants reach for
|
package/core/resolvers.md
CHANGED
|
@@ -357,3 +357,11 @@ system.start();
|
|
|
357
357
|
await system.settle();
|
|
358
358
|
console.log(system.facts.data); // Resolved value
|
|
359
359
|
```
|
|
360
|
+
|
|
361
|
+
## See also
|
|
362
|
+
|
|
363
|
+
- [`constraints.md`](./constraints.md) — the demand side of the loop; what emits the requirements this resolver fulfills
|
|
364
|
+
- [`core-patterns.md`](./core-patterns.md) — how resolvers fit into the module shape
|
|
365
|
+
- [`error-boundaries.md`](./error-boundaries.md) — recovery strategies when a resolver throws (retry, fallback, circuit breaker)
|
|
366
|
+
- [`testing.md`](./testing.md) — mock resolvers via `mocks.resolvers` and the programmatic `mockResolver(type)` helper
|
|
367
|
+
- [`anti-patterns.md`](./anti-patterns.md) — the resolver-shaped mistakes (returning data from `resolve`, abbreviating `context` to `ctx`)
|
package/core/schema-types.md
CHANGED
|
@@ -265,3 +265,9 @@ const myModule = createModule("simple", {
|
|
|
265
265
|
```
|
|
266
266
|
|
|
267
267
|
This gives full TypeScript inference but skips runtime validation. Use `t.*()` when you want dev-mode validation, transforms, or self-documenting schemas.
|
|
268
|
+
|
|
269
|
+
## See also
|
|
270
|
+
|
|
271
|
+
- [`core-patterns.md`](./core-patterns.md) — where the schemas these builders define get attached (modules)
|
|
272
|
+
- [`system-api.md`](./system-api.md) — schema flows through `createSystem` and shows up on `system.facts.*`
|
|
273
|
+
- [`anti-patterns.md`](./anti-patterns.md) — hallucinated schema types (`t.map`, `t.set`, `t.date`, `t.promise`, `t.tuple`, `t.record`, `t.any`) that don't exist
|
package/core/system-api.md
CHANGED
|
@@ -453,3 +453,11 @@ system.start();
|
|
|
453
453
|
system.stop();
|
|
454
454
|
system.destroy();
|
|
455
455
|
```
|
|
456
|
+
|
|
457
|
+
## See also
|
|
458
|
+
|
|
459
|
+
- [`core-patterns.md`](./core-patterns.md) — the modules that go into `createSystem({ module: ... })`
|
|
460
|
+
- [`multi-module.md`](./multi-module.md) — `createSystem({ modules: { ... } })` for namespaced systems
|
|
461
|
+
- [`history.md`](./history.md) — the `history:` config and the `system.history.*` time-travel surface
|
|
462
|
+
- [`plugins.md`](./plugins.md) — the `plugins:` config and the lifecycle hooks plugins observe
|
|
463
|
+
- [`react-adapter.md`](./react-adapter.md) — consuming a system from React components
|
package/core/testing.md
CHANGED
|
@@ -404,3 +404,9 @@ resolve: (req, context) => { context.facts.x = 1; }
|
|
|
404
404
|
| `system.assertFactSet(key, value?)` | instance method | Assert a fact value |
|
|
405
405
|
| `system.assertFactChanges(key, n)` | instance method | Assert the change count for a fact |
|
|
406
406
|
| `system.waitForIdle(maxWait?)` | instance method | Wait for in-flight resolvers (default 5000ms) |
|
|
407
|
+
|
|
408
|
+
## See also
|
|
409
|
+
|
|
410
|
+
- [`resolvers.md`](./resolvers.md) — the resolver shape `mocks.resolvers` replaces and the retry/cancel semantics tests need to know about
|
|
411
|
+
- [`core-patterns.md`](./core-patterns.md) — the module shape `createTestSystem({ module })` is testing
|
|
412
|
+
- [`history.md`](./history.md) — recorded snapshots for replay-based testing patterns
|
package/dist/index.cjs
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
'use strict';var fs=require('fs'),path=require('path'),url=require('url');var _documentCurrentScript=typeof document!=='undefined'?document.currentScript:null;var
|
|
1
|
+
'use strict';var fs=require('fs'),path=require('path'),url=require('url');var _documentCurrentScript=typeof document!=='undefined'?document.currentScript:null;var L=path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))),P=path.resolve(L,".."),a=null;function k(){let t=[path.join(P,"core","anti-patterns.md"),path.join(P,"..","core","anti-patterns.md")];for(let e of t)if(fs.existsSync(e))return e;return t[0]??""}function z(t){return t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").replace(/-{2,}/g,"-")}function K(t){let e=t.toLowerCase();return /schema|builder/.test(e)?"schema":/constraint|cross-?module|require/.test(e)?"constraint":/resolver|settle|start/.test(e)?"resolver":/deriv|passthrough/.test(e)?"derivation":/effect/.test(e)?"effect":/usedirective|react|hook/.test(e)?"react":/import|bracket|deep import|name|context|abbreviat/.test(e)?"naming":("module")}function G(t){let e=t.toLowerCase();return /nonexistent|missing|no error|deep import|async logic/.test(e)?"error":"warning"}function U(t){let e=t.split(`
|
|
2
|
+
`),r=[],n=null,o=/^##\s+(\d+)\.\s+(.+?)\s*$/;for(let s of e){let i=o.exec(s);if(i?.[1]&&i?.[2]){n&&r.push(n),n={number:Number(i[1]),title:i[2],body:""};continue}if(n){if(/^##\s+\D/.test(s)){r.push(n),n=null;break}n.body+=`${s}
|
|
3
|
+
`;}}return n&&r.push(n),r}function $(t){let e=t.match(/```typescript\n([\s\S]*?)```/),r=[];for(let p of t.split(`
|
|
4
|
+
`)){if(p.startsWith("```"))break;r.push(p);}let n=r.join(`
|
|
5
|
+
`).trim();if(!e?.[1])return {explanation:n};let o=e[1],s=o.match(/\/\/\s*WRONG[^\n]*\n([\s\S]*?)(?:\/\/\s*CORRECT|$)/),i=o.match(/\/\/\s*CORRECT[^\n]*\n([\s\S]*)/);return {explanation:n,badExample:s?.[1]?.trim()??void 0,goodExample:i?.[1]?.trim()??void 0}}function h(){if(a)return a;let t=k(),e;try{e=fs.readFileSync(t,"utf-8");}catch{return a=Object.freeze([]),a}let n=U(e).map(o=>{let{explanation:s,badExample:i,goodExample:p}=$(o.body);return {id:z(o.title),number:o.number,title:o.title,severity:G(o.title),category:K(o.title),explanation:s,badExample:i,goodExample:p}});return a=Object.freeze(n),a}function D(){return h()}function B(t){return h().find(e=>e.id===t)}function W(){a=null;}var V=path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))),C=path.resolve(V,".."),R=["redux","zustand","xstate","mobx","jotai","recoil"],u=null;function Y(){let t=[path.join(C,"migration.json"),path.join(C,"..","migration.json")];for(let e of t)if(fs.existsSync(e))return e;return t[0]??""}function S(){if(u)return u;try{let t=fs.readFileSync(Y(),"utf-8"),e=JSON.parse(t);u=Object.freeze(e.sources??[]);}catch{u=Object.freeze([]);}return u}function Z(){return R}function tt(){return S()}function et(t){return S().find(e=>e.id===t)}function nt(){u=null;}var ct=path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))),E=path.resolve(ct,".."),g=null;function lt(){let t=[path.join(E,"compositions.json"),path.join(E,"..","compositions.json")];for(let e of t)if(fs.existsSync(e))return e;return t[0]??""}function m(){if(g)return g;try{let t=fs.readFileSync(lt(),"utf-8"),e=JSON.parse(t);g=Object.freeze(e.edges??[]);}catch{g=Object.freeze([]);}return g}function ut(){return m()}function gt(t){return m().filter(e=>e.from===t)}function pt(t){return m().filter(e=>e.to===t)}function ft(){g=null;}var Pt=path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))),v=path.resolve(Pt,"..");function f(t){let e=path.join(v,t);if(fs.existsSync(e))return e;let r=path.join(v,"..",t);return fs.existsSync(r)?r:e}var ht=f("core"),At=f("ai"),Ct=f("examples"),Rt=f("api-skeleton.md"),c=null,l=null;function y(t,e){try{let r=fs.readdirSync(t).filter(n=>n.endsWith(".md")||n.endsWith(".ts"));for(let n of r){let o=n.replace(/\.(md|ts)$/,"");e.set(o,fs.readFileSync(path.join(t,n),"utf-8"));}}catch(r){if(r.code!=="ENOENT")throw r}}function w(){let t=new Map;y(ht,t),y(At,t);try{t.set("api-skeleton",fs.readFileSync(Rt,"utf-8"));}catch{}return t}function _(){let t=new Map;return y(Ct,t),t}function St(t){return c||(c=w()),c.get(t)??""}function Gt(){return c||(c=w()),c}function Mt(t){return l||(l=_()),l.get(t)??""}function Ut(){return l||(l=_()),l}function $t(t){return t.map(e=>St(e)).filter(Boolean).join(`
|
|
2
6
|
|
|
3
7
|
---
|
|
4
8
|
|
|
5
|
-
`)}function
|
|
9
|
+
`)}function Dt(t){return t.map(e=>{let r=Mt(e);return r?`### Example: ${e}
|
|
6
10
|
|
|
7
11
|
\`\`\`typescript
|
|
8
|
-
${
|
|
12
|
+
${r}
|
|
9
13
|
\`\`\``:""}).filter(Boolean).join(`
|
|
10
14
|
|
|
11
|
-
`)}function
|
|
15
|
+
`)}function Bt(){c=null,l=null;}exports.MIGRATION_SOURCES=R;exports.clearAntiPatternCache=W;exports.clearCache=Bt;exports.clearCompositionsCache=ft;exports.clearMigrationCache=nt;exports.getAllExamples=Ut;exports.getAllKnowledge=Gt;exports.getAntiPatternById=B;exports.getAntiPatterns=D;exports.getCompositions=ut;exports.getCompositionsFor=gt;exports.getExample=Mt;exports.getExampleFiles=Dt;exports.getKnowledge=St;exports.getKnowledgeFiles=$t;exports.getMigrationPattern=et;exports.getMigrationPatterns=tt;exports.getMigrationSources=Z;exports.getReverseCompositionsFor=pt;//# sourceMappingURL=index.cjs.map
|
|
12
16
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["__dirname","dirname","fileURLToPath","PKG_ROOT","resolve","resolveAsset","name","fromDist","join","existsSync","fromSrc","CORE_DIR","AI_DIR","EXAMPLES_DIR","API_SKELETON_PATH","knowledgeCache","exampleCache","loadDir","dir","map","files","readdirSync","f","file","readFileSync","err","loadAllKnowledge","loadAllExamples","getKnowledge","getAllKnowledge","getExample","getAllExamples","getKnowledgeFiles","names","getExampleFiles","content","clearCache"],"mappings":"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","file":"index.cjs","sourcesContent":["import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// Resolve package root: works both in src/ (dev) and dist/ (bundled)\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\n/**\n * Resolve a path relative to the package root.\n * Tries dist-relative first (bundled), then src-relative (dev).\n */\nfunction resolveAsset(name: string): string {\n const fromDist = join(PKG_ROOT, name);\n if (existsSync(fromDist)) {\n return fromDist;\n }\n\n const fromSrc = join(PKG_ROOT, \"..\", name);\n if (existsSync(fromSrc)) {\n return fromSrc;\n }\n\n return fromDist; // default, will just return empty maps\n}\n\nconst CORE_DIR = resolveAsset(\"core\");\nconst AI_DIR = resolveAsset(\"ai\");\nconst EXAMPLES_DIR = resolveAsset(\"examples\");\nconst API_SKELETON_PATH = resolveAsset(\"api-skeleton.md\");\n\nlet knowledgeCache: Map<string, string> | null = null;\nlet exampleCache: Map<string, string> | null = null;\n\nfunction loadDir(dir: string, map: Map<string, string>): void {\n try {\n const files = readdirSync(dir).filter(\n (f) => f.endsWith(\".md\") || f.endsWith(\".ts\"),\n );\n for (const file of files) {\n const name = file.replace(/\\.(md|ts)$/, \"\");\n map.set(name, readFileSync(join(dir, file), \"utf-8\"));\n }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n // directory does not exist — expected during tests or incomplete installs\n }\n}\n\nfunction loadAllKnowledge(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(CORE_DIR, map);\n loadDir(AI_DIR, map);\n\n // Include api-skeleton\n try {\n map.set(\"api-skeleton\", readFileSync(API_SKELETON_PATH, \"utf-8\"));\n } catch {\n // may not exist yet\n }\n\n return map;\n}\n\nfunction loadAllExamples(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(EXAMPLES_DIR, map);\n\n return map;\n}\n\nexport function getKnowledge(name: string): string {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache.get(name) ?? \"\";\n}\n\nexport function getAllKnowledge(): ReadonlyMap<string, string> {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache;\n}\n\nexport function getExample(name: string): string {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache.get(name) ?? \"\";\n}\n\nexport function getAllExamples(): ReadonlyMap<string, string> {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache;\n}\n\nexport function getKnowledgeFiles(names: string[]): string {\n return names\n .map((name) => getKnowledge(name))\n .filter(Boolean)\n .join(\"\\n\\n---\\n\\n\");\n}\n\nexport function getExampleFiles(names: string[]): string {\n return names\n .map((name) => {\n const content = getExample(name);\n if (!content) {\n return \"\";\n }\n\n return `### Example: ${name}\\n\\n\\`\\`\\`typescript\\n${content}\\n\\`\\`\\``;\n })\n .filter(Boolean)\n .join(\"\\n\\n\");\n}\n\n/** Clear cached knowledge and examples. Useful for dev/watch mode. */\nexport function clearCache(): void {\n knowledgeCache = null;\n exampleCache = null;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/parsers/anti-patterns.ts","../src/parsers/migration.ts","../src/parsers/compositions.ts","../src/index.ts"],"names":["__dirname","dirname","fileURLToPath","PKG_ROOT","resolve","cache","resolveSourcePath","candidates","join","c","existsSync","slugify","title","categorize","lower","severityFor","splitSections","md","lines","sections","current","heading","line","match","extractExamples","body","codeBlock","explanationLines","explanation","code","wrongMatch","correctMatch","loadAntiPatterns","sourcePath","readFileSync","out","section","badExample","goodExample","getAntiPatterns","getAntiPatternById","id","ap","clearAntiPatternCache","MIGRATION_SOURCES","load","raw","parsed","getMigrationSources","getMigrationPatterns","getMigrationPattern","source","p","clearMigrationCache","getCompositions","getCompositionsFor","packageName","getReverseCompositionsFor","clearCompositionsCache","resolveAsset","name","fromDist","fromSrc","CORE_DIR","AI_DIR","EXAMPLES_DIR","API_SKELETON_PATH","knowledgeCache","exampleCache","loadDir","dir","map","files","readdirSync","f","file","err","loadAllKnowledge","loadAllExamples","getKnowledge","getAllKnowledge","getExample","getAllExamples","getKnowledgeFiles","names","getExampleFiles","content","clearCache"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Parser for `packages/knowledge/core/anti-patterns.md` → structured\n * `AntiPattern[]` data. Lazy + cached so the cost is paid once per\n * process at first call.\n *\n * The source markdown is organized as numbered sections (`## N. Title`)\n * each containing a TypeScript code block with `// WRONG` and\n * `// CORRECT` examples. Some sections include prose between the\n * heading and the code block — captured as `explanation`.\n *\n * IDs are kebab-cased slugs derived from the heading text; stable\n * across releases as long as the heading isn't renamed.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\nexport type AntiPatternSeverity = \"error\" | \"warning\" | \"info\";\nexport type AntiPatternCategory =\n | \"module\"\n | \"schema\"\n | \"constraint\"\n | \"resolver\"\n | \"derivation\"\n | \"effect\"\n | \"naming\"\n | \"react\"\n | \"composition\";\n\nexport interface AntiPattern {\n /** Stable slug, derived from the heading text. */\n id: string;\n /** Section number in the source markdown (1..N). */\n number: number;\n /** Human-readable title (the heading text minus the number prefix). */\n title: string;\n /** Default severity. Heuristic; tunable per-rule later. */\n severity: AntiPatternSeverity;\n /** Heuristic category from title keywords. */\n category: AntiPatternCategory;\n /** Body prose between heading and the first code block (often empty). */\n explanation: string;\n /** The `// WRONG` example, if present. */\n badExample?: string;\n /** The `// CORRECT` example, if present. */\n goodExample?: string;\n}\n\nlet cache: ReadonlyArray<AntiPattern> | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"core\", \"anti-patterns.md\"),\n join(PKG_ROOT, \"..\", \"core\", \"anti-patterns.md\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction slugify(title: string): string {\n return title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .replace(/-{2,}/g, \"-\");\n}\n\nfunction categorize(title: string): AntiPatternCategory {\n const lower = title.toLowerCase();\n if (/schema|builder/.test(lower)) {\n return \"schema\";\n }\n if (/constraint|cross-?module|require/.test(lower)) {\n return \"constraint\";\n }\n if (/resolver|settle|start/.test(lower)) {\n return \"resolver\";\n }\n if (/deriv|passthrough/.test(lower)) {\n return \"derivation\";\n }\n if (/effect/.test(lower)) {\n return \"effect\";\n }\n if (/usedirective|react|hook/.test(lower)) {\n return \"react\";\n }\n if (/import|bracket|deep import|name|context|abbreviat/.test(lower)) {\n return \"naming\";\n }\n if (/init|module|config/.test(lower)) {\n return \"module\";\n }\n return \"module\";\n}\n\nfunction severityFor(title: string): AntiPatternSeverity {\n const lower = title.toLowerCase();\n if (/nonexistent|missing|no error|deep import|async logic/.test(lower)) {\n return \"error\";\n }\n return \"warning\";\n}\n\ninterface Section {\n number: number;\n title: string;\n body: string;\n}\n\nfunction splitSections(md: string): Section[] {\n const lines = md.split(\"\\n\");\n const sections: Section[] = [];\n let current: Section | null = null;\n const heading = /^##\\s+(\\d+)\\.\\s+(.+?)\\s*$/;\n for (const line of lines) {\n const match = heading.exec(line);\n if (match?.[1] && match?.[2]) {\n if (current) {\n sections.push(current);\n }\n current = {\n number: Number(match[1]),\n title: match[2],\n body: \"\",\n };\n continue;\n }\n if (current) {\n // Stop at the first non-numbered ## section (e.g. \"Quick Reference Checklist\")\n if (/^##\\s+\\D/.test(line)) {\n sections.push(current);\n current = null;\n break;\n }\n current.body += `${line}\\n`;\n }\n }\n if (current) {\n sections.push(current);\n }\n return sections;\n}\n\nfunction extractExamples(body: string): {\n explanation: string;\n badExample?: string;\n goodExample?: string;\n} {\n const codeBlock = body.match(/```typescript\\n([\\s\\S]*?)```/);\n const explanationLines: string[] = [];\n for (const line of body.split(\"\\n\")) {\n if (line.startsWith(\"```\")) {\n break;\n }\n explanationLines.push(line);\n }\n const explanation = explanationLines.join(\"\\n\").trim();\n\n if (!codeBlock?.[1]) {\n return { explanation };\n }\n\n const code = codeBlock[1];\n // Split on the WRONG/CORRECT comment markers.\n const wrongMatch = code.match(\n /\\/\\/\\s*WRONG[^\\n]*\\n([\\s\\S]*?)(?:\\/\\/\\s*CORRECT|$)/,\n );\n const correctMatch = code.match(/\\/\\/\\s*CORRECT[^\\n]*\\n([\\s\\S]*)/);\n\n return {\n explanation,\n badExample: wrongMatch?.[1]?.trim() ?? undefined,\n goodExample: correctMatch?.[1]?.trim() ?? undefined,\n };\n}\n\nfunction loadAntiPatterns(): ReadonlyArray<AntiPattern> {\n if (cache) {\n return cache;\n }\n\n const sourcePath = resolveSourcePath();\n let md: string;\n try {\n md = readFileSync(sourcePath, \"utf-8\");\n } catch {\n cache = Object.freeze([]);\n return cache;\n }\n\n const sections = splitSections(md);\n const out: AntiPattern[] = sections.map((section) => {\n const { explanation, badExample, goodExample } = extractExamples(\n section.body,\n );\n return {\n id: slugify(section.title),\n number: section.number,\n title: section.title,\n severity: severityFor(section.title),\n category: categorize(section.title),\n explanation,\n badExample,\n goodExample,\n };\n });\n\n cache = Object.freeze(out);\n return cache;\n}\n\n/** Return every parsed anti-pattern, stable order, frozen. */\nexport function getAntiPatterns(): ReadonlyArray<AntiPattern> {\n return loadAntiPatterns();\n}\n\n/** Look up one anti-pattern by its slug id. */\nexport function getAntiPatternById(id: string): AntiPattern | undefined {\n return loadAntiPatterns().find((ap) => ap.id === id);\n}\n\n/** Clear the in-memory cache. Test / watch-mode helper. */\nexport function clearAntiPatternCache(): void {\n cache = null;\n}\n","/**\n * Loader for `packages/knowledge/migration.json` → structured\n * migration patterns. Lazy + cached.\n *\n * The JSON ships in the published tarball; consumers don't need to\n * parse markdown at runtime.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\n/** Supported source-library identifiers. */\nexport const MIGRATION_SOURCES = [\n \"redux\",\n \"zustand\",\n \"xstate\",\n \"mobx\",\n \"jotai\",\n \"recoil\",\n] as const;\nexport type MigrationSourceId = (typeof MIGRATION_SOURCES)[number];\n\nexport interface MigrationConceptRow {\n from: string;\n to: string;\n note: string;\n}\n\nexport interface MigrationPattern {\n id: MigrationSourceId;\n name: string;\n conceptMap: MigrationConceptRow[];\n steps: string[];\n before: string;\n after: string;\n}\n\ninterface MigrationFile {\n version: number;\n sources: MigrationPattern[];\n}\n\nlet cache: ReadonlyArray<MigrationPattern> | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"migration.json\"),\n join(PKG_ROOT, \"..\", \"migration.json\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction load(): ReadonlyArray<MigrationPattern> {\n if (cache) {\n return cache;\n }\n try {\n const raw = readFileSync(resolveSourcePath(), \"utf-8\");\n const parsed = JSON.parse(raw) as MigrationFile;\n cache = Object.freeze(parsed.sources ?? []);\n } catch {\n cache = Object.freeze([]);\n }\n return cache;\n}\n\n/** All supported source library IDs. */\nexport function getMigrationSources(): ReadonlyArray<MigrationSourceId> {\n return MIGRATION_SOURCES;\n}\n\n/** All migration patterns, in registry order. */\nexport function getMigrationPatterns(): ReadonlyArray<MigrationPattern> {\n return load();\n}\n\n/** One migration pattern by its source-library id. */\nexport function getMigrationPattern(\n source: string,\n): MigrationPattern | undefined {\n return load().find((p) => p.id === source);\n}\n\n/** Test / watch-mode helper. */\nexport function clearMigrationCache(): void {\n cache = null;\n}\n","/**\n * Loader for `packages/knowledge/compositions.json` → typed\n * composition graph. Lazy + cached.\n *\n * The JSON ships in the published tarball. Adjacency list rather\n * than per-package projections so consumers can answer both\n * \"what does X compose with?\" and \"what composes with X?\" without\n * duplicate data.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n// After bundling, all parsers live in dist/index.js — one level up\n// from dist reaches the package root. In src/ during dev, the file is\n// two levels up; the fallback in `resolveSourcePath` handles that.\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\nexport interface CompositionEdge {\n from: string;\n to: string;\n reason: string;\n}\n\ninterface CompositionsFile {\n version: number;\n edges: CompositionEdge[];\n}\n\nlet cache: ReadonlyArray<CompositionEdge> | null = null;\n\nfunction resolveSourcePath(): string {\n const candidates = [\n join(PKG_ROOT, \"compositions.json\"),\n join(PKG_ROOT, \"..\", \"compositions.json\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) {\n return c;\n }\n }\n return candidates[0] ?? \"\";\n}\n\nfunction load(): ReadonlyArray<CompositionEdge> {\n if (cache) {\n return cache;\n }\n try {\n const raw = readFileSync(resolveSourcePath(), \"utf-8\");\n const parsed = JSON.parse(raw) as CompositionsFile;\n cache = Object.freeze(parsed.edges ?? []);\n } catch {\n cache = Object.freeze([]);\n }\n return cache;\n}\n\n/** All composition edges as a flat list. */\nexport function getCompositions(): ReadonlyArray<CompositionEdge> {\n return load();\n}\n\n/**\n * All edges originating at the given package. Returns an empty array\n * when the package is unknown or has no outgoing compositions.\n */\nexport function getCompositionsFor(\n packageName: string,\n): ReadonlyArray<CompositionEdge> {\n return load().filter((e) => e.from === packageName);\n}\n\n/**\n * All edges arriving at the given package — \"who composes WITH me?\"\n */\nexport function getReverseCompositionsFor(\n packageName: string,\n): ReadonlyArray<CompositionEdge> {\n return load().filter((e) => e.to === packageName);\n}\n\n/** Test / watch-mode helper. */\nexport function clearCompositionsCache(): void {\n cache = null;\n}\n","import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// Resolve package root: works both in src/ (dev) and dist/ (bundled)\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\n/**\n * Resolve a path relative to the package root.\n * Tries dist-relative first (bundled), then src-relative (dev).\n */\nfunction resolveAsset(name: string): string {\n const fromDist = join(PKG_ROOT, name);\n if (existsSync(fromDist)) {\n return fromDist;\n }\n\n const fromSrc = join(PKG_ROOT, \"..\", name);\n if (existsSync(fromSrc)) {\n return fromSrc;\n }\n\n return fromDist; // default, will just return empty maps\n}\n\nconst CORE_DIR = resolveAsset(\"core\");\nconst AI_DIR = resolveAsset(\"ai\");\nconst EXAMPLES_DIR = resolveAsset(\"examples\");\nconst API_SKELETON_PATH = resolveAsset(\"api-skeleton.md\");\n\nlet knowledgeCache: Map<string, string> | null = null;\nlet exampleCache: Map<string, string> | null = null;\n\nfunction loadDir(dir: string, map: Map<string, string>): void {\n try {\n const files = readdirSync(dir).filter(\n (f) => f.endsWith(\".md\") || f.endsWith(\".ts\"),\n );\n for (const file of files) {\n const name = file.replace(/\\.(md|ts)$/, \"\");\n map.set(name, readFileSync(join(dir, file), \"utf-8\"));\n }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n // directory does not exist — expected during tests or incomplete installs\n }\n}\n\nfunction loadAllKnowledge(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(CORE_DIR, map);\n loadDir(AI_DIR, map);\n\n // Include api-skeleton\n try {\n map.set(\"api-skeleton\", readFileSync(API_SKELETON_PATH, \"utf-8\"));\n } catch {\n // may not exist yet\n }\n\n return map;\n}\n\nfunction loadAllExamples(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(EXAMPLES_DIR, map);\n\n return map;\n}\n\nexport function getKnowledge(name: string): string {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache.get(name) ?? \"\";\n}\n\nexport function getAllKnowledge(): ReadonlyMap<string, string> {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache;\n}\n\nexport function getExample(name: string): string {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache.get(name) ?? \"\";\n}\n\nexport function getAllExamples(): ReadonlyMap<string, string> {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache;\n}\n\nexport function getKnowledgeFiles(names: string[]): string {\n return names\n .map((name) => getKnowledge(name))\n .filter(Boolean)\n .join(\"\\n\\n---\\n\\n\");\n}\n\nexport function getExampleFiles(names: string[]): string {\n return names\n .map((name) => {\n const content = getExample(name);\n if (!content) {\n return \"\";\n }\n\n return `### Example: ${name}\\n\\n\\`\\`\\`typescript\\n${content}\\n\\`\\`\\``;\n })\n .filter(Boolean)\n .join(\"\\n\\n\");\n}\n\n/** Clear cached knowledge and examples. Useful for dev/watch mode. */\nexport function clearCache(): void {\n knowledgeCache = null;\n exampleCache = null;\n}\n\n// ---------------------------------------------------------------------------\n// Structured data APIs (v1.16.0 — back the MCP `list_review_rules`,\n// `get_review_rule`, `list_migration_sources`, `get_migration_pattern`,\n// `get_composable_packages` tools).\n// ---------------------------------------------------------------------------\n\nexport {\n type AntiPattern,\n type AntiPatternCategory,\n type AntiPatternSeverity,\n clearAntiPatternCache,\n getAntiPatternById,\n getAntiPatterns,\n} from \"./parsers/anti-patterns.js\";\n\nexport {\n type MigrationConceptRow,\n type MigrationPattern,\n type MigrationSourceId,\n MIGRATION_SOURCES,\n clearMigrationCache,\n getMigrationPattern,\n getMigrationPatterns,\n getMigrationSources,\n} from \"./parsers/migration.js\";\n\nexport {\n type CompositionEdge,\n clearCompositionsCache,\n getCompositions,\n getCompositionsFor,\n getReverseCompositionsFor,\n} from \"./parsers/compositions.js\";\n"]}
|