@directive-run/claude-plugin 1.16.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.
Files changed (83) hide show
  1. package/.claude-plugin/plugin.json +6 -0
  2. package/LICENSE +26 -0
  3. package/README.md +113 -0
  4. package/dist/index.cjs +2 -0
  5. package/dist/index.cjs.map +1 -0
  6. package/dist/index.d.cts +66 -0
  7. package/dist/index.d.ts +66 -0
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -0
  10. package/package.json +64 -0
  11. package/skills/README.md +9 -0
  12. package/skills/building-ai-agents/SKILL.md +414 -0
  13. package/skills/building-ai-agents/ai-adapters.md +257 -0
  14. package/skills/building-ai-agents/ai-agents-streaming.md +307 -0
  15. package/skills/building-ai-agents/ai-communication.md +304 -0
  16. package/skills/building-ai-agents/api-skeleton.md +5 -0
  17. package/skills/building-ai-agents/examples.md +849 -0
  18. package/skills/building-ai-orchestrators/SKILL.md +401 -0
  19. package/skills/building-ai-orchestrators/ai-multi-agent.md +375 -0
  20. package/skills/building-ai-orchestrators/ai-orchestrator.md +466 -0
  21. package/skills/building-ai-orchestrators/ai-tasks.md +268 -0
  22. package/skills/building-ai-orchestrators/api-skeleton.md +5 -0
  23. package/skills/building-ai-orchestrators/examples.md +1609 -0
  24. package/skills/building-directive-systems/SKILL.md +499 -0
  25. package/skills/building-directive-systems/api-skeleton.md +5 -0
  26. package/skills/building-directive-systems/examples.md +4149 -0
  27. package/skills/building-directive-systems/multi-module.md +327 -0
  28. package/skills/building-directive-systems/plugins.md +361 -0
  29. package/skills/building-directive-systems/react-adapter.md +376 -0
  30. package/skills/building-directive-systems/system-api.md +463 -0
  31. package/skills/getting-started-with-directive/SKILL.md +198 -0
  32. package/skills/getting-started-with-directive/api-skeleton.md +5 -0
  33. package/skills/getting-started-with-directive/core-patterns.md +240 -0
  34. package/skills/getting-started-with-directive/examples.md +87 -0
  35. package/skills/getting-started-with-directive/sitemap.md +202 -0
  36. package/skills/hardening-ai-systems/SKILL.md +377 -0
  37. package/skills/hardening-ai-systems/ai-budget-resilience.md +408 -0
  38. package/skills/hardening-ai-systems/ai-guardrails-memory.md +370 -0
  39. package/skills/hardening-ai-systems/ai-security.md +400 -0
  40. package/skills/hardening-ai-systems/api-skeleton.md +5 -0
  41. package/skills/hardening-ai-systems/examples.md +628 -0
  42. package/skills/migrating-to-directive/SKILL.md +249 -0
  43. package/skills/migrating-to-directive/anti-patterns.md +382 -0
  44. package/skills/migrating-to-directive/api-skeleton.md +5 -0
  45. package/skills/migrating-to-directive/core-patterns.md +240 -0
  46. package/skills/migrating-to-directive/examples.md +511 -0
  47. package/skills/migrating-to-directive/schema-types.md +273 -0
  48. package/skills/reviewing-directive-code/SKILL.md +232 -0
  49. package/skills/reviewing-directive-code/anti-patterns.md +382 -0
  50. package/skills/reviewing-directive-code/api-skeleton.md +5 -0
  51. package/skills/reviewing-directive-code/core-patterns.md +240 -0
  52. package/skills/reviewing-directive-code/examples.md +463 -0
  53. package/skills/reviewing-directive-code/naming.md +321 -0
  54. package/skills/scaffolding-directive-modules/SKILL.md +218 -0
  55. package/skills/scaffolding-directive-modules/api-skeleton.md +5 -0
  56. package/skills/scaffolding-directive-modules/core-patterns.md +240 -0
  57. package/skills/scaffolding-directive-modules/examples.md +1386 -0
  58. package/skills/scaffolding-directive-modules/naming.md +321 -0
  59. package/skills/scaffolding-directive-modules/schema-types.md +273 -0
  60. package/skills/testing-ai-systems/SKILL.md +398 -0
  61. package/skills/testing-ai-systems/ai-debug-observability.md +329 -0
  62. package/skills/testing-ai-systems/ai-mcp-rag.md +293 -0
  63. package/skills/testing-ai-systems/ai-testing-evals.md +485 -0
  64. package/skills/testing-ai-systems/api-skeleton.md +5 -0
  65. package/skills/testing-ai-systems/examples.md +1261 -0
  66. package/skills/testing-directive-code/SKILL.md +479 -0
  67. package/skills/testing-directive-code/api-skeleton.md +5 -0
  68. package/skills/testing-directive-code/examples.md +156 -0
  69. package/skills/testing-directive-code/history.md +351 -0
  70. package/skills/testing-directive-code/testing.md +412 -0
  71. package/skills/writing-directive-constraints/SKILL.md +486 -0
  72. package/skills/writing-directive-constraints/api-skeleton.md +5 -0
  73. package/skills/writing-directive-constraints/constraints.md +274 -0
  74. package/skills/writing-directive-constraints/error-boundaries.md +330 -0
  75. package/skills/writing-directive-constraints/examples.md +1361 -0
  76. package/skills/writing-directive-constraints/resolvers.md +367 -0
  77. package/skills/writing-directive-modules/SKILL.md +342 -0
  78. package/skills/writing-directive-modules/anti-patterns.md +382 -0
  79. package/skills/writing-directive-modules/api-skeleton.md +5 -0
  80. package/skills/writing-directive-modules/core-patterns.md +240 -0
  81. package/skills/writing-directive-modules/examples.md +1639 -0
  82. package/skills/writing-directive-modules/naming.md +321 -0
  83. package/skills/writing-directive-modules/schema-types.md +273 -0
@@ -0,0 +1,351 @@
1
+ # History & Snapshots
2
+
3
+ > Covers `@directive-run/core` — time-travel: snapshot, undo/redo, replay, export/import, changeset grouping.
4
+
5
+ Directive records fact changes as snapshots, enabling undo/redo, replay, export/import, and changeset grouping.
6
+
7
+ ## Decision Tree: "Should I enable history?"
8
+
9
+ ```
10
+ What's the use case?
11
+ ├── Debugging during development → Yes, enable with maxSnapshots cap
12
+ ├── Production app → No, disable for performance
13
+ ├── Bug reproduction → Enable, use export() to share
14
+ ├── Testing → Usually no – use assertFact/assertDerivation instead
15
+ └── Demo / presentation → Yes, great for showing state changes
16
+ ```
17
+
18
+ ## Enabling History
19
+
20
+ ```typescript
21
+ import { createSystem } from "@directive-run/core";
22
+
23
+ const system = createSystem({
24
+ module: myModule,
25
+ history: {
26
+ maxSnapshots: 100, // Cap memory usage (default: 100)
27
+ },
28
+ });
29
+ ```
30
+
31
+ History is disabled by default. When disabled, `system.history` is `null`. When enabled, snapshots are recorded automatically after every fact mutation.
32
+
33
+ ## Filtering Snapshot Events
34
+
35
+ By default every event that changes facts creates a snapshot. Use `history.snapshotEvents` on your module to limit which events create snapshots — keeps undo/redo clean by excluding UI-only events like selection or timer ticks.
36
+
37
+ ```typescript
38
+ const game = createModule("game", {
39
+ schema: gameSchema,
40
+
41
+ // Only these events appear in undo/redo history.
42
+ // Omit to snapshot ALL events (the default).
43
+ history: {
44
+ snapshotEvents: [
45
+ "inputNumber",
46
+ "requestHint",
47
+ "newGame",
48
+ ],
49
+ },
50
+
51
+ events: {
52
+ tick: (facts) => { /* no snapshot */ },
53
+ selectCell: (facts, { index }) => { /* no snapshot */ },
54
+ inputNumber: (facts, { value }) => { /* creates snapshot */ },
55
+ requestHint: (facts) => { /* creates snapshot */ },
56
+ newGame: (facts, { difficulty }) => { /* creates snapshot */ },
57
+ },
58
+ });
59
+ ```
60
+
61
+ ### Filtering by Module
62
+
63
+ In a multi-module system, control which modules create snapshots at the system level:
64
+
65
+ ```typescript
66
+ const system = createSystem({
67
+ modules: { ui: uiModule, game: gameModule },
68
+ history: {
69
+ maxSnapshots: 100,
70
+ snapshotModules: ["game"], // Only game events create snapshots
71
+ },
72
+ });
73
+ ```
74
+
75
+ **Rules:**
76
+ - `snapshotEvents` omitted → all events snapshot (per module)
77
+ - `snapshotModules` omitted → all modules snapshot (per system)
78
+ - Both provided → they intersect (module must be in `snapshotModules` AND event in `snapshotEvents`)
79
+ - Direct fact mutations (`system.facts.x = 5`) always snapshot regardless of filtering
80
+ - `snapshotEvents` entries are type-checked against schema events
81
+
82
+ ## Core API: `system.history` (`HistoryAPI`)
83
+
84
+ ```typescript
85
+ const history = system.history; // HistoryAPI | null
86
+
87
+ if (history) {
88
+ // Read-only state
89
+ history.snapshots; // Snapshot[] — all recorded snapshots
90
+ history.currentIndex; // number — position in the snapshot array
91
+ history.isPaused; // boolean — whether recording is paused
92
+
93
+ // Navigation
94
+ history.goBack(); // Step backward one snapshot (changeset-aware)
95
+ history.goBack(3); // Step backward 3 snapshots
96
+ history.goForward(); // Step forward one snapshot (changeset-aware)
97
+ history.goForward(3); // Step forward 3 snapshots
98
+ history.goTo(snapshotId); // Jump to a specific snapshot by its ID
99
+ history.replay(); // Jump to the first snapshot
100
+
101
+ // Export / Import (JSON strings)
102
+ history.export(); // Serialize entire history to JSON string
103
+ history.import(json); // Restore history from JSON string
104
+
105
+ // Changesets — group multiple snapshots into one undo/redo unit
106
+ history.beginChangeset("Move piece");
107
+ // ... mutations happen ...
108
+ history.endChangeset();
109
+
110
+ // Recording control
111
+ history.pause(); // Temporarily stop recording snapshots
112
+ history.resume(); // Resume recording
113
+ }
114
+ ```
115
+
116
+ ### Snapshot Structure
117
+
118
+ ```typescript
119
+ interface Snapshot {
120
+ id: number; // Auto-incrementing identifier
121
+ timestamp: number; // When captured (Date.now())
122
+ facts: Record<string, unknown>; // Complete copy of all fact values
123
+ trigger: string; // What caused this snapshot (e.g., "fact:count")
124
+ }
125
+ ```
126
+
127
+ ## Framework Hook: `useHistory` (`HistoryState`)
128
+
129
+ Each framework adapter provides a reactive `useHistory` hook that re-renders on snapshot changes. Returns `null` when history is disabled, otherwise a `HistoryState` object that wraps the core API with convenience properties.
130
+
131
+ ```typescript
132
+ interface SnapshotMeta {
133
+ id: number; // Snapshot identifier
134
+ timestamp: number; // When captured
135
+ trigger: string; // What caused this snapshot
136
+ }
137
+
138
+ interface HistoryState {
139
+ // Convenience booleans (not on core API)
140
+ canGoBack: boolean; // True when currentIndex > 0
141
+ canGoForward: boolean; // True when currentIndex < totalSnapshots - 1
142
+ currentIndex: number;
143
+ totalSnapshots: number;
144
+
145
+ // Snapshot access (metadata only — keeps re-renders cheap)
146
+ snapshots: SnapshotMeta[];
147
+ getSnapshotFacts: (id: number) => Record<string, unknown> | null;
148
+
149
+ // Navigation
150
+ goTo: (snapshotId: number) => void;
151
+ goBack: (steps: number) => void;
152
+ goForward: (steps: number) => void;
153
+ replay: () => void;
154
+
155
+ // Session persistence
156
+ exportSession: () => string; // Wraps history.export()
157
+ importSession: (json: string) => void; // Wraps history.import()
158
+
159
+ // Changesets
160
+ beginChangeset: (label: string) => void;
161
+ endChangeset: () => void;
162
+
163
+ // Recording control
164
+ isPaused: boolean;
165
+ pause: () => void;
166
+ resume: () => void;
167
+ }
168
+ ```
169
+
170
+ ### React Example
171
+
172
+ ```tsx
173
+ import { useHistory } from "@directive-run/react";
174
+
175
+ function HistoryToolbar() {
176
+ const history = useHistory(system);
177
+ if (!history) return null;
178
+
179
+ return (
180
+ <div>
181
+ <button onClick={() => history.goBack()} disabled={!history.canGoBack}>Undo</button>
182
+ <button onClick={() => history.goForward()} disabled={!history.canGoForward}>Redo</button>
183
+ <span>{history.currentIndex + 1} / {history.totalSnapshots}</span>
184
+ </div>
185
+ );
186
+ }
187
+ ```
188
+
189
+ ## Undo/Redo Pattern
190
+
191
+ ```typescript
192
+ const system = createSystem({
193
+ module: editorModule,
194
+ history: { maxSnapshots: 200 },
195
+ });
196
+
197
+ system.start();
198
+
199
+ // User makes changes
200
+ system.facts.text = "Hello";
201
+ system.facts.text = "Hello, world";
202
+ system.facts.text = "Hello, world!";
203
+
204
+ const history = system.history!;
205
+
206
+ // Undo (one step back)
207
+ history.goBack();
208
+ console.log(system.facts.text); // "Hello, world"
209
+
210
+ history.goBack();
211
+ console.log(system.facts.text); // "Hello"
212
+
213
+ // Redo (one step forward)
214
+ history.goForward();
215
+ console.log(system.facts.text); // "Hello, world"
216
+ ```
217
+
218
+ ## How Snapshots Work
219
+
220
+ Snapshots are taken **once per reconciliation cycle**, not per individual fact change. All synchronous fact mutations within the same event handler batch into a single snapshot. One `goBack()` reverts all changes from that event.
221
+
222
+ ## Changesets: Grouping Multiple Events
223
+
224
+ Changesets group snapshots from **multiple separate events** into one undo/redo unit. Useful when a single user action triggers a sequence of events.
225
+
226
+ ```typescript
227
+ const history = system.history!;
228
+
229
+ // Two separate events = two snapshots
230
+ system.events.pickUp({ index: 0 }); // → snapshot 1
231
+ system.events.place({ from: 0, to: 1 }); // → snapshot 2
232
+ // goBack() only reverts the place — need two goBack() calls
233
+
234
+ // With changeset — grouped into one undo unit
235
+ history.beginChangeset("Move piece");
236
+ system.events.pickUp({ index: 0 }); // → snapshot 1 ─┐
237
+ system.events.place({ from: 0, to: 1 }); // → snapshot 2 ─┘ grouped
238
+ history.endChangeset();
239
+ // One goBack() reverts both events
240
+ ```
241
+
242
+ Also works for direct fact mutations across separate synchronous blocks:
243
+
244
+ ```typescript
245
+ history.beginChangeset("Update user");
246
+ system.facts.firstName = "Alice";
247
+ system.facts.lastName = "Smith";
248
+ // These batch into one snapshot synchronously, but changeset
249
+ // still works if an async gap separates them
250
+ history.endChangeset();
251
+ ```
252
+
253
+ Always close your changesets. If you forget `endChangeset()`, all subsequent mutations get grouped into the same changeset.
254
+
255
+ ## Exporting and Importing History
256
+
257
+ Serialize the full snapshot history for bug reports or debugging.
258
+
259
+ ```typescript
260
+ const history = system.history!;
261
+
262
+ // Export — returns a JSON string
263
+ const exported = history.export();
264
+ localStorage.setItem("debug-session", exported);
265
+
266
+ // Import — restore from a JSON string
267
+ const saved = localStorage.getItem("debug-session");
268
+ if (saved) {
269
+ history.import(saved);
270
+
271
+ // Step through the user's exact state sequence
272
+ history.goTo(0); // First snapshot
273
+ history.goTo(5); // When the bug occurred
274
+ }
275
+ ```
276
+
277
+ ## Performance: maxSnapshots
278
+
279
+ Every fact mutation creates a snapshot. Cap the number to control memory:
280
+
281
+ ```typescript
282
+ // Low memory — keeps last 20 snapshots, discards oldest
283
+ history: { maxSnapshots: 20 },
284
+
285
+ // Development — generous cap for deep debugging
286
+ history: { maxSnapshots: 500 },
287
+
288
+ // Default if not specified
289
+ history: true, // maxSnapshots defaults to 100
290
+ ```
291
+
292
+ When the cap is reached, the oldest snapshot is discarded (ring buffer / FIFO).
293
+
294
+ ## Common Mistakes
295
+
296
+ ### Enabling history in production
297
+
298
+ ```typescript
299
+ // WRONG — snapshots consume memory on every mutation
300
+ const system = createSystem({
301
+ module: myModule,
302
+ history: true,
303
+ });
304
+
305
+ // CORRECT — gate on environment
306
+ const system = createSystem({
307
+ module: myModule,
308
+ history: process.env.NODE_ENV === "development"
309
+ ? { maxSnapshots: 100 }
310
+ : false,
311
+ });
312
+ ```
313
+
314
+ ### Forgetting to end a changeset
315
+
316
+ ```typescript
317
+ // WRONG — changeset never closed, all subsequent mutations are grouped
318
+ history.beginChangeset("update");
319
+ system.facts.name = "Alice";
320
+ // ... forgot endChangeset()
321
+ system.facts.unrelated = true; // Still part of the changeset!
322
+
323
+ // CORRECT — always close changesets
324
+ history.beginChangeset("update");
325
+ system.facts.name = "Alice";
326
+ history.endChangeset();
327
+ ```
328
+
329
+ ### Accessing history when disabled
330
+
331
+ ```typescript
332
+ // WRONG — history not enabled, system.history is null
333
+ const system = createSystem({ module: myModule });
334
+ system.history.goBack(); // TypeError!
335
+
336
+ // CORRECT — check before using
337
+ if (system.history) {
338
+ system.history.goBack();
339
+ }
340
+
341
+ // Or enable it
342
+ const system = createSystem({
343
+ module: myModule,
344
+ history: true,
345
+ });
346
+ ```
347
+
348
+ ## See also
349
+
350
+ - [`system-api.md`](./system-api.md) — `history` config in `createSystem` + the full `system.history.*` API
351
+ - [`testing.md`](./testing.md) — replay-driven testing patterns that pair with recorded snapshots