@directive-run/knowledge 0.2.0 → 0.4.2

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 (54) hide show
  1. package/README.md +3 -3
  2. package/ai/ai-adapters.md +7 -7
  3. package/ai/ai-agents-streaming.md +8 -8
  4. package/ai/ai-budget-resilience.md +5 -5
  5. package/ai/ai-communication.md +1 -1
  6. package/ai/ai-guardrails-memory.md +7 -7
  7. package/ai/ai-mcp-rag.md +5 -5
  8. package/ai/ai-multi-agent.md +14 -14
  9. package/ai/ai-orchestrator.md +8 -8
  10. package/ai/ai-security.md +2 -2
  11. package/ai/ai-tasks.md +9 -9
  12. package/ai/ai-testing-evals.md +2 -2
  13. package/core/anti-patterns.md +39 -39
  14. package/core/constraints.md +15 -15
  15. package/core/core-patterns.md +9 -9
  16. package/core/error-boundaries.md +7 -7
  17. package/core/multi-module.md +16 -16
  18. package/core/naming.md +21 -21
  19. package/core/plugins.md +14 -14
  20. package/core/react-adapter.md +13 -13
  21. package/core/resolvers.md +14 -14
  22. package/core/schema-types.md +22 -22
  23. package/core/system-api.md +16 -16
  24. package/core/testing.md +5 -5
  25. package/core/time-travel.md +20 -20
  26. package/dist/index.cjs +6 -105
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.js +7 -97
  29. package/dist/index.js.map +1 -1
  30. package/examples/ab-testing.ts +18 -90
  31. package/examples/ai-checkpoint.ts +68 -87
  32. package/examples/ai-guardrails.ts +20 -70
  33. package/examples/auth-flow.ts +2 -2
  34. package/examples/batch-resolver.ts +19 -59
  35. package/examples/contact-form.ts +220 -69
  36. package/examples/counter.ts +77 -95
  37. package/examples/dashboard-loader.ts +37 -55
  38. package/examples/debounce-constraints.ts +0 -2
  39. package/examples/dynamic-modules.ts +17 -20
  40. package/examples/error-boundaries.ts +30 -81
  41. package/examples/newsletter.ts +22 -49
  42. package/examples/notifications.ts +24 -23
  43. package/examples/optimistic-updates.ts +36 -41
  44. package/examples/pagination.ts +2 -2
  45. package/examples/permissions.ts +22 -32
  46. package/examples/provider-routing.ts +26 -83
  47. package/examples/shopping-cart.ts +8 -8
  48. package/examples/sudoku.ts +55 -62
  49. package/examples/theme-locale.ts +4 -7
  50. package/examples/time-machine.ts +12 -90
  51. package/examples/topic-guard.ts +30 -38
  52. package/examples/url-sync.ts +8 -8
  53. package/examples/websocket.ts +5 -5
  54. package/package.json +3 -3
@@ -1,12 +1,12 @@
1
1
  // Example: ab-testing
2
- // Source: examples/ab-testing/src/main.ts
3
- // Extracted for AI rules — DOM wiring stripped
2
+ // Source: examples/ab-testing/src/module.ts
3
+ // Pure module fileno DOM wiring
4
4
 
5
5
  /**
6
- * A/B Testing Engine — DOM Rendering & System Wiring
6
+ * A/B Testing Engine — Directive Module
7
7
  *
8
- * Creates the Directive system, subscribes to state changes,
9
- * renders experiment cards and event timeline.
8
+ * Types, schema, helpers, module definition, timeline, and system creation
9
+ * for a constraint-driven A/B testing engine with deterministic hashing.
10
10
  */
11
11
 
12
12
  import {
@@ -21,20 +21,20 @@ import { devtoolsPlugin } from "@directive-run/core/plugins";
21
21
  // Types
22
22
  // ============================================================================
23
23
 
24
- interface Variant {
24
+ export interface Variant {
25
25
  id: string;
26
26
  weight: number;
27
27
  label: string;
28
28
  }
29
29
 
30
- interface Experiment {
30
+ export interface Experiment {
31
31
  id: string;
32
32
  name: string;
33
33
  variants: Variant[];
34
34
  active: boolean;
35
35
  }
36
36
 
37
- interface TimelineEntry {
37
+ export interface TimelineEntry {
38
38
  time: number;
39
39
  event: string;
40
40
  detail: string;
@@ -78,9 +78,9 @@ function pickVariant(
78
78
  // Timeline
79
79
  // ============================================================================
80
80
 
81
- const timeline: TimelineEntry[] = [];
81
+ export const timeline: TimelineEntry[] = [];
82
82
 
83
- function log(type: "event" | "constraint" | "resolver", msg: string) {
83
+ export function addLog(type: "event" | "constraint" | "resolver", msg: string) {
84
84
  console.log(`[AB] [${type}] ${msg}`);
85
85
 
86
86
  // Classify for timeline
@@ -125,16 +125,16 @@ function log(type: "event" | "constraint" | "resolver", msg: string) {
125
125
  // Schema
126
126
  // ============================================================================
127
127
 
128
- const schema = {
128
+ export const schema = {
129
129
  facts: {
130
- experiments: t.object<Experiment[]>(),
130
+ experiments: t.array<Experiment>(),
131
131
  assignments: t.object<Record<string, string>>(),
132
132
  exposures: t.object<Record<string, number>>(),
133
133
  userId: t.string(),
134
134
  paused: t.boolean(),
135
135
  },
136
136
  derivations: {
137
- activeExperiments: t.object<Experiment[]>(),
137
+ activeExperiments: t.array<Experiment>(),
138
138
  assignedCount: t.number(),
139
139
  exposedCount: t.number(),
140
140
  },
@@ -142,7 +142,7 @@ const schema = {
142
142
  registerExperiment: {
143
143
  id: t.string(),
144
144
  name: t.string(),
145
- variants: t.object<Variant[]>(),
145
+ variants: t.array<Variant>(),
146
146
  },
147
147
  assignVariant: { experimentId: t.string(), variantId: t.string() },
148
148
  recordExposure: { experimentId: t.string() },
@@ -173,9 +173,7 @@ const abTesting = createModule("ab-testing", {
173
173
 
174
174
  derive: {
175
175
  activeExperiments: (facts) =>
176
- (facts.experiments as Experiment[]).filter(
177
- (e) => e.active && !facts.paused,
178
- ),
176
+ facts.experiments.filter((e: Experiment) => e.active && !facts.paused),
179
177
  assignedCount: (facts) => Object.keys(facts.assignments).length,
180
178
  exposedCount: (facts) => Object.keys(facts.exposures).length,
181
179
  },
@@ -283,7 +281,7 @@ const abTesting = createModule("ab-testing", {
283
281
  ...context.facts.assignments,
284
282
  [req.experimentId]: variantId,
285
283
  };
286
- log("resolver", `Assigned ${req.experimentId} → ${variantId}`);
284
+ addLog("resolver", `Assigned ${req.experimentId} → ${variantId}`);
287
285
  },
288
286
  },
289
287
 
@@ -295,7 +293,7 @@ const abTesting = createModule("ab-testing", {
295
293
  ...context.facts.exposures,
296
294
  [req.experimentId]: now,
297
295
  };
298
- log(
296
+ addLog(
299
297
  "resolver",
300
298
  `Exposure tracked: ${req.experimentId} (variant: ${req.variantId}) at ${new Date(now).toLocaleTimeString()}`,
301
299
  );
@@ -308,78 +306,8 @@ const abTesting = createModule("ab-testing", {
308
306
  // System
309
307
  // ============================================================================
310
308
 
311
- const system = createSystem({
309
+ export const system = createSystem({
312
310
  module: abTesting,
313
311
  debug: { runHistory: true },
314
312
  plugins: [devtoolsPlugin({ name: "ab-testing" })],
315
313
  });
316
- system.start();
317
-
318
- // ============================================================================
319
- // DOM References
320
- // ============================================================================
321
-
322
- // Stats
323
-
324
- // Timeline
325
-
326
- // ============================================================================
327
- // Render
328
- // ============================================================================
329
-
330
- function escapeHtml(text: string): string {
331
-
332
- return div.innerHTML;
333
- }
334
-
335
-
336
- // ============================================================================
337
- // Subscribe
338
- // ============================================================================
339
-
340
- system.subscribe(
341
- [
342
- "experiments",
343
- "assignments",
344
- "exposures",
345
- "userId",
346
- "paused",
347
- "activeExperiments",
348
- "assignedCount",
349
- "exposedCount",
350
- ],
351
- render,
352
- );
353
-
354
- // Button handlers
355
-
356
-
357
- // ============================================================================
358
- // Register sample experiments
359
- // ============================================================================
360
-
361
- system.events.registerExperiment({
362
- id: "theme-icons",
363
- name: "Theme Icons",
364
- variants: [
365
- { id: "custom-svg", weight: 50, label: "Custom SVG" },
366
- { id: "phosphor", weight: 50, label: "Phosphor" },
367
- ],
368
- });
369
- log("event", "Registered experiment: theme-icons");
370
-
371
- system.events.registerExperiment({
372
- id: "cta-color",
373
- name: "CTA Button Color",
374
- variants: [
375
- { id: "brand", weight: 50, label: "Brand" },
376
- { id: "green", weight: 30, label: "Green" },
377
- { id: "orange", weight: 20, label: "Orange" },
378
- ],
379
- });
380
- log("event", "Registered experiment: cta-color");
381
-
382
- // Initial render
383
- render();
384
-
385
- // Signal to tests that initialization is complete
@@ -1,9 +1,9 @@
1
1
  // Example: ai-checkpoint
2
- // Source: examples/ai-checkpoint/src/main.ts
3
- // Extracted for AI rules — DOM wiring stripped
2
+ // Source: examples/ai-checkpoint/src/module.ts
3
+ // Pure module fileno DOM wiring
4
4
 
5
5
  /**
6
- * AI Pipeline Checkpoint — 4-Stage Document Processing with Save/Restore
6
+ * AI Pipeline Checkpoint — Module Definition
7
7
  *
8
8
  * 4-stage pipeline (extract → summarize → classify → archive) with checkpoint
9
9
  * at every stage. Save/restore/delete checkpoints. Retry with backoff on failures.
@@ -27,7 +27,7 @@ import { devtoolsPlugin } from "@directive-run/core/plugins";
27
27
  // Types
28
28
  // ============================================================================
29
29
 
30
- type PipelineStage =
30
+ export type PipelineStage =
31
31
  | "idle"
32
32
  | "extract"
33
33
  | "summarize"
@@ -36,21 +36,21 @@ type PipelineStage =
36
36
  | "done"
37
37
  | "error";
38
38
 
39
- interface StageResult {
39
+ export interface StageResult {
40
40
  stage: string;
41
41
  output: string;
42
42
  tokens: number;
43
43
  durationMs: number;
44
44
  }
45
45
 
46
- interface CheckpointEntry {
46
+ export interface CheckpointEntry {
47
47
  id: string;
48
48
  label: string;
49
49
  createdAt: string;
50
50
  stage: PipelineStage;
51
51
  }
52
52
 
53
- interface TimelineEntry {
53
+ export interface TimelineEntry {
54
54
  time: number;
55
55
  event: string;
56
56
  detail: string;
@@ -61,7 +61,12 @@ interface TimelineEntry {
61
61
  // Constants
62
62
  // ============================================================================
63
63
 
64
- const STAGES: PipelineStage[] = ["extract", "summarize", "classify", "archive"];
64
+ export const STAGES: PipelineStage[] = [
65
+ "extract",
66
+ "summarize",
67
+ "classify",
68
+ "archive",
69
+ ];
65
70
 
66
71
  const STAGE_CONFIG = {
67
72
  extract: {
@@ -92,9 +97,9 @@ const STAGE_CONFIG = {
92
97
  // Timeline
93
98
  // ============================================================================
94
99
 
95
- const timeline: TimelineEntry[] = [];
100
+ export const timeline: TimelineEntry[] = [];
96
101
 
97
- function addTimeline(
102
+ export function addTimeline(
98
103
  event: string,
99
104
  detail: string,
100
105
  type: TimelineEntry["type"],
@@ -109,23 +114,25 @@ function addTimeline(
109
114
  // Checkpoint Store
110
115
  // ============================================================================
111
116
 
112
- const checkpointStore = new InMemoryCheckpointStore({ maxCheckpoints: 20 });
117
+ export const checkpointStore = new InMemoryCheckpointStore({
118
+ maxCheckpoints: 20,
119
+ });
113
120
 
114
121
  // ============================================================================
115
122
  // Schema
116
123
  // ============================================================================
117
124
 
118
- const schema = {
125
+ export const schema = {
119
126
  facts: {
120
127
  currentStage: t.string<PipelineStage>(),
121
- stageResults: t.object<StageResult[]>(),
128
+ stageResults: t.array<StageResult>(),
122
129
  totalTokens: t.number(),
123
130
  retryCount: t.number(),
124
131
  maxRetries: t.number(),
125
132
  failStage: t.string(),
126
133
  isRunning: t.boolean(),
127
134
  lastError: t.string(),
128
- checkpoints: t.object<CheckpointEntry[]>(),
135
+ checkpoints: t.array<CheckpointEntry>(),
129
136
  selectedCheckpoint: t.string(),
130
137
  },
131
138
  derivations: {
@@ -173,11 +180,11 @@ const pipelineModule = createModule("pipeline", {
173
180
  return 100;
174
181
  }
175
182
  if (facts.currentStage === "error") {
176
- const idx = (facts.stageResults as StageResult[]).length;
183
+ const idx = facts.stageResults.length;
177
184
 
178
185
  return Math.round((idx / STAGES.length) * 100);
179
186
  }
180
- const idx = STAGES.indexOf(facts.currentStage as PipelineStage);
187
+ const idx = STAGES.indexOf(facts.currentStage);
181
188
 
182
189
  return Math.round((idx / STAGES.length) * 100);
183
190
  },
@@ -189,7 +196,7 @@ const pipelineModule = createModule("pipeline", {
189
196
  return STAGES.length;
190
197
  }
191
198
 
192
- return STAGES.indexOf(facts.currentStage as PipelineStage);
199
+ return STAGES.indexOf(facts.currentStage);
193
200
  },
194
201
  canAdvance: (facts) => {
195
202
  return (
@@ -229,12 +236,11 @@ const pipelineModule = createModule("pipeline", {
229
236
  // System
230
237
  // ============================================================================
231
238
 
232
- const system = createSystem({
239
+ export const system = createSystem({
233
240
  module: pipelineModule,
234
241
  debug: { runHistory: true },
235
242
  plugins: [devtoolsPlugin({ name: "ai-checkpoint" })],
236
243
  });
237
- system.start();
238
244
 
239
245
  // ============================================================================
240
246
  // Pipeline Logic
@@ -263,8 +269,11 @@ async function runStage(stage: PipelineStage): Promise<StageResult> {
263
269
  };
264
270
  }
265
271
 
266
- async function runStageWithRetry(stage: PipelineStage): Promise<StageResult> {
267
- const maxRetries = system.facts.maxRetries as number;
272
+ export async function runStageWithRetry(
273
+ stage: PipelineStage,
274
+ renderCallback: () => void,
275
+ ): Promise<StageResult> {
276
+ const maxRetries = system.facts.maxRetries;
268
277
  let lastError: Error | null = null;
269
278
 
270
279
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
@@ -272,30 +281,34 @@ async function runStageWithRetry(stage: PipelineStage): Promise<StageResult> {
272
281
  if (attempt > 0) {
273
282
  const delay = Math.min(500 * 2 ** (attempt - 1), 4000);
274
283
  const jitter = Math.random() * delay * 0.1;
275
- system.facts.retryCount = (system.facts.retryCount as number) + 1;
284
+ system.facts.retryCount = system.facts.retryCount + 1;
285
+ addTimeline(
276
286
  "retry",
277
287
  `${stage}: attempt ${attempt + 1}/${maxRetries + 1} (delay ${Math.round(delay)}ms)`,
278
288
  "retry",
279
289
  );
280
- render();
290
+ renderCallback();
281
291
  await new Promise((resolve) => setTimeout(resolve, delay + jitter));
282
292
  }
283
293
 
284
294
  return await runStage(stage);
285
295
  } catch (err) {
286
296
  lastError = err instanceof Error ? err : new Error(String(err));
297
+ addTimeline("error", `${stage}: ${lastError.message}`, "error");
287
298
  }
288
299
  }
289
300
 
290
301
  throw lastError!;
291
302
  }
292
303
 
293
- async function advancePipeline() {
304
+ export async function advancePipeline(
305
+ renderCallback: () => void,
306
+ ): Promise<void> {
294
307
  if (system.facts.isRunning) {
295
308
  return;
296
309
  }
297
310
 
298
- const current = system.facts.currentStage as PipelineStage;
311
+ const current = system.facts.currentStage;
299
312
  let nextStage: PipelineStage;
300
313
 
301
314
  if (current === "idle") {
@@ -314,14 +327,15 @@ async function advancePipeline() {
314
327
 
315
328
  system.facts.isRunning = true;
316
329
  system.facts.currentStage = nextStage;
317
- render();
330
+ addTimeline("stage", `${nextStage}: starting`, "stage");
331
+ renderCallback();
318
332
 
319
333
  try {
320
- const result = await runStageWithRetry(nextStage);
321
- const results = [...(system.facts.stageResults as StageResult[]), result];
334
+ const result = await runStageWithRetry(nextStage, renderCallback);
335
+ const results = [...system.facts.stageResults, result];
322
336
  system.facts.stageResults = results;
323
- system.facts.totalTokens =
324
- (system.facts.totalTokens as number) + result.tokens;
337
+ system.facts.totalTokens = system.facts.totalTokens + result.tokens;
338
+ addTimeline(
325
339
  "success",
326
340
  `${nextStage}: complete (${result.tokens} tokens)`,
327
341
  "success",
@@ -330,18 +344,20 @@ async function advancePipeline() {
330
344
  const idx = STAGES.indexOf(nextStage);
331
345
  if (idx >= STAGES.length - 1) {
332
346
  system.facts.currentStage = "done";
347
+ addTimeline("info", "pipeline complete", "info");
333
348
  } else {
334
349
  system.facts.currentStage = nextStage;
335
350
  }
336
351
  } catch (err) {
337
352
  system.facts.currentStage = "error";
338
353
  system.facts.lastError = err instanceof Error ? err.message : String(err);
354
+ addTimeline("error", `pipeline halted: ${system.facts.lastError}`, "error");
339
355
  } finally {
340
356
  system.facts.isRunning = false;
341
357
  }
342
358
  }
343
359
 
344
- async function autoRun() {
360
+ export async function autoRun(renderCallback: () => void): Promise<void> {
345
361
  if (system.facts.isRunning) {
346
362
  return;
347
363
  }
@@ -351,18 +367,20 @@ async function autoRun() {
351
367
  system.facts.totalTokens = 0;
352
368
  system.facts.retryCount = 0;
353
369
  system.facts.lastError = "";
370
+ addTimeline("info", "auto-run started", "info");
354
371
 
355
372
  for (const stage of STAGES) {
356
373
  system.facts.isRunning = true;
357
374
  system.facts.currentStage = stage;
358
- render();
375
+ addTimeline("stage", `${stage}: starting`, "stage");
376
+ renderCallback();
359
377
 
360
378
  try {
361
- const result = await runStageWithRetry(stage);
362
- const results = [...(system.facts.stageResults as StageResult[]), result];
379
+ const result = await runStageWithRetry(stage, renderCallback);
380
+ const results = [...system.facts.stageResults, result];
363
381
  system.facts.stageResults = results;
364
- system.facts.totalTokens =
365
- (system.facts.totalTokens as number) + result.tokens;
382
+ system.facts.totalTokens = system.facts.totalTokens + result.tokens;
383
+ addTimeline(
366
384
  "success",
367
385
  `${stage}: complete (${result.tokens} tokens)`,
368
386
  "success",
@@ -371,6 +389,7 @@ async function autoRun() {
371
389
  system.facts.currentStage = "error";
372
390
  system.facts.lastError = err instanceof Error ? err.message : String(err);
373
391
  system.facts.isRunning = false;
392
+ addTimeline(
374
393
  "error",
375
394
  `pipeline halted at ${stage}: ${system.facts.lastError}`,
376
395
  "error",
@@ -383,14 +402,15 @@ async function autoRun() {
383
402
  }
384
403
 
385
404
  system.facts.currentStage = "done";
405
+ addTimeline("info", "pipeline complete (auto-run)", "info");
386
406
  }
387
407
 
388
408
  // ============================================================================
389
409
  // Checkpoint Logic
390
410
  // ============================================================================
391
411
 
392
- async function saveCheckpoint() {
393
- const stage = system.facts.currentStage as PipelineStage;
412
+ export async function saveCheckpoint(): Promise<void> {
413
+ const stage = system.facts.currentStage;
394
414
  const id = createCheckpointId();
395
415
  const label = `Stage: ${stage} (${new Date().toLocaleTimeString()})`;
396
416
 
@@ -420,21 +440,21 @@ async function saveCheckpoint() {
420
440
  createdAt: checkpoint.createdAt,
421
441
  stage,
422
442
  };
423
- system.facts.checkpoints = [
424
- ...(system.facts.checkpoints as CheckpointEntry[]),
425
- entry,
426
- ];
443
+ system.facts.checkpoints = [...system.facts.checkpoints, entry];
427
444
 
445
+ addTimeline("checkpoint", `saved: ${label}`, "checkpoint");
428
446
  }
429
447
 
430
- async function restoreCheckpoint(checkpointId: string) {
448
+ export async function restoreCheckpoint(checkpointId: string): Promise<void> {
431
449
  const checkpoint = await checkpointStore.load(checkpointId);
432
450
  if (!checkpoint) {
451
+ addTimeline("error", "checkpoint not found", "error");
433
452
 
434
453
  return;
435
454
  }
436
455
 
437
456
  if (!validateCheckpoint(checkpoint)) {
457
+ addTimeline("error", "invalid checkpoint data", "error");
438
458
 
439
459
  return;
440
460
  }
@@ -448,62 +468,23 @@ async function restoreCheckpoint(checkpointId: string) {
448
468
  system.facts.isRunning = false;
449
469
 
450
470
  if (checkpoint.timelineExport) {
471
+ const savedTimeline = JSON.parse(checkpoint.timelineExport);
451
472
  timeline.length = 0;
452
473
  for (const entry of savedTimeline) {
453
474
  timeline.push(entry);
454
475
  }
455
476
  }
456
477
 
478
+ addTimeline("checkpoint", `restored: ${checkpoint.label}`, "checkpoint");
457
479
  }
458
480
 
459
- async function deleteCheckpoint(checkpointId: string) {
481
+ export async function deleteCheckpoint(checkpointId: string): Promise<void> {
460
482
  const deleted = await checkpointStore.delete(checkpointId);
461
483
  if (deleted) {
462
- const checkpoints = (system.facts.checkpoints as CheckpointEntry[]).filter(
484
+ const checkpoints = system.facts.checkpoints.filter(
463
485
  (c) => c.id !== checkpointId,
464
486
  );
465
487
  system.facts.checkpoints = checkpoints;
488
+ addTimeline("checkpoint", "deleted checkpoint", "checkpoint");
466
489
  }
467
490
  }
468
-
469
- // ============================================================================
470
- // DOM References
471
- // ============================================================================
472
-
473
-
474
- // ============================================================================
475
- // Render
476
- // ============================================================================
477
-
478
- function escapeHtml(text: string): string {
479
-
480
- return div.innerHTML;
481
- }
482
-
483
-
484
- // ============================================================================
485
- // Subscribe
486
- // ============================================================================
487
-
488
- const allKeys = [
489
- ...Object.keys(schema.facts),
490
- ...Object.keys(schema.derivations),
491
- ];
492
- system.subscribe(allKeys, render);
493
-
494
- // ============================================================================
495
- // Controls
496
- // ============================================================================
497
-
498
-
499
- "cp-fail-stage",
500
-
501
- // Delegated click for checkpoint restore/delete
502
-
503
- "cp-max-retries",
504
-
505
- // ============================================================================
506
- // Initial Render
507
- // ============================================================================
508
-
509
- render();