@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,463 @@
1
+ # Examples
2
+
3
+ > Auto-generated from extracted examples. Do not edit manually.
4
+
5
+ ## counter
6
+
7
+ ```typescript
8
+ // Example: counter
9
+ // Source: examples/counter/src/module.ts
10
+ // Pure module file — no DOM wiring
11
+
12
+ /**
13
+ * Counter — The simplest Directive module.
14
+ *
15
+ * Demonstrates: facts, events, derivations, one constraint, one resolver.
16
+ * Total: ~40 lines.
17
+ */
18
+
19
+ import {
20
+ type ModuleSchema,
21
+ createModule,
22
+ createSystem,
23
+ t,
24
+ } from "@directive-run/core";
25
+
26
+ const schema = {
27
+ facts: {
28
+ count: t.number(),
29
+ },
30
+ derivations: {
31
+ doubled: t.number(),
32
+ isPositive: t.boolean(),
33
+ },
34
+ events: {
35
+ increment: {},
36
+ decrement: {},
37
+ reset: {},
38
+ },
39
+ requirements: {
40
+ CLAMP_TO_ZERO: {},
41
+ },
42
+ } satisfies ModuleSchema;
43
+
44
+ export const counterModule = createModule("counter", {
45
+ schema,
46
+
47
+ init: (facts) => {
48
+ facts.count = 0;
49
+ },
50
+
51
+ derive: {
52
+ doubled: (facts) => facts.count * 2,
53
+ isPositive: (facts) => facts.count > 0,
54
+ },
55
+
56
+ events: {
57
+ increment: (facts) => {
58
+ facts.count += 1;
59
+ },
60
+ decrement: (facts) => {
61
+ facts.count -= 1;
62
+ },
63
+ reset: (facts) => {
64
+ facts.count = 0;
65
+ },
66
+ },
67
+
68
+ // When count goes negative, automatically fix it
69
+ constraints: {
70
+ noNegative: {
71
+ when: (facts) => facts.count < 0,
72
+ require: { type: "CLAMP_TO_ZERO" },
73
+ },
74
+ },
75
+
76
+ resolvers: {
77
+ clamp: {
78
+ requirement: "CLAMP_TO_ZERO",
79
+ resolve: async (_req, context) => {
80
+ context.facts.count = 0;
81
+ },
82
+ },
83
+ },
84
+ });
85
+
86
+ export const system = createSystem({ module: counterModule });
87
+ ```
88
+
89
+ ## auth-flow
90
+
91
+ ```typescript
92
+ // Example: auth-flow
93
+ // Source: examples/auth-flow/src/auth-flow.ts
94
+ // Pure module file — no DOM wiring
95
+
96
+ /**
97
+ * Auth Flow — Directive Module
98
+ *
99
+ * Demonstrates constraint `after` ordering, auto-tracked derivations
100
+ * driving constraints, resolvers with retry, effects for cleanup,
101
+ * and time-based reactivity (token expiry countdown).
102
+ */
103
+
104
+ import { type ModuleSchema, createModule, t } from "@directive-run/core";
105
+ import {
106
+ type User,
107
+ mockFetchUser,
108
+ mockLogin,
109
+ mockRefresh,
110
+ } from "./mock-auth.js";
111
+
112
+ // ============================================================================
113
+ // Types
114
+ // ============================================================================
115
+
116
+ export type AuthStatus =
117
+ | "idle"
118
+ | "authenticating"
119
+ | "authenticated"
120
+ | "refreshing"
121
+ | "expired";
122
+
123
+ export interface EventLogEntry {
124
+ timestamp: number;
125
+ event: string;
126
+ detail: string;
127
+ }
128
+
129
+ // ============================================================================
130
+ // Schema
131
+ // ============================================================================
132
+
133
+ export const authFlowSchema = {
134
+ facts: {
135
+ email: t.string(),
136
+ password: t.string(),
137
+ token: t.string(),
138
+ refreshToken: t.string(),
139
+ expiresAt: t.number(),
140
+ user: t.object<User | null>(),
141
+ status: t.string<AuthStatus>(),
142
+ loginRequested: t.boolean(),
143
+ now: t.number(),
144
+ tokenTTL: t.number(),
145
+ refreshBuffer: t.number(),
146
+ loginFailRate: t.number(),
147
+ refreshFailRate: t.number(),
148
+ eventLog: t.array<EventLogEntry>(),
149
+ },
150
+ derivations: {
151
+ isAuthenticated: t.boolean(),
152
+ isExpiringSoon: t.boolean(),
153
+ canRefresh: t.boolean(),
154
+ tokenTimeRemaining: t.number(),
155
+ canLogin: t.boolean(),
156
+ },
157
+ events: {
158
+ setEmail: { value: t.string() },
159
+ setPassword: { value: t.string() },
160
+ requestLogin: {},
161
+ logout: {},
162
+ forceExpire: {},
163
+ setTokenTTL: { value: t.number() },
164
+ setRefreshBuffer: { value: t.number() },
165
+ setLoginFailRate: { value: t.number() },
166
+ setRefreshFailRate: { value: t.number() },
167
+ tick: {},
168
+ },
169
+ requirements: {
170
+ LOGIN: { email: t.string(), password: t.string() },
171
+ REFRESH_TOKEN: { refreshToken: t.string() },
172
+ FETCH_USER: { token: t.string() },
173
+ },
174
+ } satisfies ModuleSchema;
175
+
176
+ // ============================================================================
177
+ // Helpers
178
+ // ============================================================================
179
+
180
+ function addLogEntry(facts: any, event: string, detail: string): void {
181
+ const log = [...facts.eventLog];
182
+ log.push({ timestamp: Date.now(), event, detail });
183
+ facts.eventLog = log;
184
+ }
185
+
186
+ // ============================================================================
187
+ // Module
188
+ // ============================================================================
189
+
190
+ export const authFlowModule = createModule("auth-flow", {
191
+ schema: authFlowSchema,
192
+
193
+ init: (facts) => {
194
+ facts.email = "alice@test.com";
195
+ facts.password = "password";
196
+ facts.token = "";
197
+ facts.refreshToken = "";
198
+ facts.expiresAt = 0;
199
+ facts.user = null;
200
+ facts.status = "idle";
201
+ facts.loginRequested = false;
202
+ facts.now = Date.now();
203
+ facts.tokenTTL = 30;
204
+ facts.refreshBuffer = 5;
205
+ facts.loginFailRate = 0;
206
+ facts.refreshFailRate = 0;
207
+ facts.eventLog = [];
208
+ },
209
+
210
+ // ============================================================================
211
+ // Derivations
212
+ // ============================================================================
213
+
214
+ derive: {
215
+ isAuthenticated: (facts) => facts.status === "authenticated",
216
+
217
+ isExpiringSoon: (facts) => {
218
+ if (facts.token === "") {
219
+ return false;
220
+ }
221
+
222
+ return facts.now > facts.expiresAt - facts.refreshBuffer * 1000;
223
+ },
224
+
225
+ canRefresh: (facts) => {
226
+ return facts.refreshToken !== "" && facts.status !== "refreshing";
227
+ },
228
+
229
+ tokenTimeRemaining: (facts) => {
230
+ if (facts.token === "") {
231
+ return 0;
232
+ }
233
+
234
+ return Math.max(0, Math.round((facts.expiresAt - facts.now) / 1000));
235
+ },
236
+
237
+ canLogin: (facts) => {
238
+ return (
239
+ facts.email.trim() !== "" &&
240
+ facts.password.trim() !== "" &&
241
+ (facts.status === "idle" || facts.status === "expired")
242
+ );
243
+ },
244
+ },
245
+
246
+ // ============================================================================
247
+ // Events
248
+ // ============================================================================
249
+
250
+ events: {
251
+ setEmail: (facts, { value }) => {
252
+ facts.email = value;
253
+ },
254
+
255
+ setPassword: (facts, { value }) => {
256
+ facts.password = value;
257
+ },
258
+
259
+ requestLogin: (facts) => {
260
+ facts.loginRequested = true;
261
+ facts.status = "authenticating";
262
+ facts.token = "";
263
+ facts.refreshToken = "";
264
+ facts.expiresAt = 0;
265
+ facts.user = null;
266
+ facts.eventLog = [];
267
+ },
268
+
269
+ logout: (facts) => {
270
+ facts.token = "";
271
+ facts.refreshToken = "";
272
+ facts.expiresAt = 0;
273
+ facts.user = null;
274
+ facts.status = "idle";
275
+ facts.loginRequested = false;
276
+ },
277
+
278
+ forceExpire: (facts) => {
279
+ facts.expiresAt = 0;
280
+ },
281
+
282
+ setTokenTTL: (facts, { value }) => {
283
+ facts.tokenTTL = value;
284
+ },
285
+
286
+ setRefreshBuffer: (facts, { value }) => {
287
+ facts.refreshBuffer = value;
288
+ },
289
+
290
+ setLoginFailRate: (facts, { value }) => {
291
+ facts.loginFailRate = value;
292
+ },
293
+
294
+ setRefreshFailRate: (facts, { value }) => {
295
+ facts.refreshFailRate = value;
296
+ },
297
+
298
+ tick: (facts) => {
299
+ facts.now = Date.now();
300
+ },
301
+ },
302
+
303
+ // ============================================================================
304
+ // Constraints
305
+ // ============================================================================
306
+
307
+ constraints: {
308
+ needsLogin: {
309
+ priority: 100,
310
+ when: (facts) => {
311
+ return facts.loginRequested && facts.status === "authenticating";
312
+ },
313
+ require: (facts) => ({
314
+ type: "LOGIN",
315
+ email: facts.email,
316
+ password: facts.password,
317
+ }),
318
+ },
319
+
320
+ refreshNeeded: {
321
+ priority: 90,
322
+ when: (facts) => {
323
+ const isExpiringSoon =
324
+ facts.token !== "" &&
325
+ facts.now > facts.expiresAt - facts.refreshBuffer * 1000;
326
+ const canRefresh =
327
+ facts.refreshToken !== "" && facts.status !== "refreshing";
328
+
329
+ return isExpiringSoon && canRefresh && facts.status === "authenticated";
330
+ },
331
+ require: (facts) => ({
332
+ type: "REFRESH_TOKEN",
333
+ refreshToken: facts.refreshToken,
334
+ }),
335
+ },
336
+
337
+ needsUser: {
338
+ priority: 80,
339
+ after: ["refreshNeeded"],
340
+ when: (facts) => {
341
+ return (
342
+ facts.token !== "" &&
343
+ facts.user === null &&
344
+ facts.status !== "authenticating"
345
+ );
346
+ },
347
+ require: (facts) => ({
348
+ type: "FETCH_USER",
349
+ token: facts.token,
350
+ }),
351
+ },
352
+ },
353
+
354
+ // ============================================================================
355
+ // Resolvers
356
+ // ============================================================================
357
+
358
+ resolvers: {
359
+ login: {
360
+ requirement: "LOGIN",
361
+ timeout: 10000,
362
+ resolve: async (req, context) => {
363
+ addLogEntry(context.facts, "login", "Authenticating...");
364
+
365
+ try {
366
+ const tokens = await mockLogin(
367
+ req.email,
368
+ req.password,
369
+ context.facts.loginFailRate,
370
+ context.facts.tokenTTL,
371
+ );
372
+ context.facts.token = tokens.token;
373
+ context.facts.refreshToken = tokens.refreshToken;
374
+ context.facts.expiresAt = Date.now() + tokens.expiresIn * 1000;
375
+ context.facts.status = "authenticated";
376
+ context.facts.user = null; // trigger needsUser constraint
377
+ addLogEntry(
378
+ context.facts,
379
+ "login-success",
380
+ `Token: ${tokens.token.slice(0, 12)}...`,
381
+ );
382
+ } catch (err) {
383
+ const msg = err instanceof Error ? err.message : "Unknown error";
384
+ context.facts.status = "idle";
385
+ context.facts.loginRequested = false;
386
+ addLogEntry(context.facts, "login-error", msg);
387
+ throw err;
388
+ }
389
+ },
390
+ },
391
+
392
+ refreshToken: {
393
+ requirement: "REFRESH_TOKEN",
394
+ retry: { attempts: 2, backoff: "exponential" },
395
+ timeout: 10000,
396
+ resolve: async (req, context) => {
397
+ context.facts.status = "refreshing";
398
+ addLogEntry(context.facts, "refresh", "Refreshing token...");
399
+
400
+ try {
401
+ const tokens = await mockRefresh(
402
+ req.refreshToken,
403
+ context.facts.refreshFailRate,
404
+ context.facts.tokenTTL,
405
+ );
406
+ context.facts.token = tokens.token;
407
+ context.facts.refreshToken = tokens.refreshToken;
408
+ context.facts.expiresAt = Date.now() + tokens.expiresIn * 1000;
409
+ context.facts.status = "authenticated";
410
+ addLogEntry(
411
+ context.facts,
412
+ "refresh-success",
413
+ `New token: ${tokens.token.slice(0, 12)}...`,
414
+ );
415
+ } catch (err) {
416
+ const msg = err instanceof Error ? err.message : "Unknown error";
417
+ context.facts.token = "";
418
+ context.facts.refreshToken = "";
419
+ context.facts.expiresAt = 0;
420
+ context.facts.status = "expired";
421
+ addLogEntry(context.facts, "refresh-error", msg);
422
+ throw err;
423
+ }
424
+ },
425
+ },
426
+
427
+ fetchUser: {
428
+ requirement: "FETCH_USER",
429
+ resolve: async (req, context) => {
430
+ addLogEntry(context.facts, "fetch-user", "Fetching user profile...");
431
+
432
+ try {
433
+ const user = await mockFetchUser(req.token);
434
+ context.facts.user = user;
435
+ addLogEntry(
436
+ context.facts,
437
+ "fetch-user-success",
438
+ `${user.name} (${user.role})`,
439
+ );
440
+ } catch (err) {
441
+ const msg = err instanceof Error ? err.message : "Unknown error";
442
+ addLogEntry(context.facts, "fetch-user-error", msg);
443
+ }
444
+ },
445
+ },
446
+ },
447
+
448
+ // ============================================================================
449
+ // Effects
450
+ // ============================================================================
451
+
452
+ effects: {
453
+ logStatusChange: {
454
+ deps: ["status"],
455
+ run: (facts, prev) => {
456
+ if (prev && prev.status !== facts.status) {
457
+ addLogEntry(facts, "status", `${prev.status} → ${facts.status}`);
458
+ }
459
+ },
460
+ },
461
+ },
462
+ });
463
+ ```