@directive-run/knowledge 1.23.0 → 1.23.1

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-security.md CHANGED
@@ -388,8 +388,8 @@ source publishes PII into a fact and the agent's prompt template embeds
388
388
  that fact (`"Hello ${facts.email}..."`), the PII reaches the LLM call
389
389
  without hitting the input guardrail chain.
390
390
 
391
- This is the documented R5 audit finding (red team, privacy, AI-integration
392
- reviewers independently flagged it). The Tier 0 fix:
391
+ This is a documented gap in the input-only guardrail chain — the fix
392
+ is a fact-store-boundary guardrail that runs on every fact write:
393
393
 
394
394
  ```ts
395
395
  import { createSystem, createModule, t } from "@directive-run/core";
@@ -0,0 +1,178 @@
1
+ // Example: cloudflare-directive-ai
2
+ // Source: examples/cloudflare-directive-ai/src/module.ts
3
+ // Pure module file — no DOM wiring
4
+
5
+ import { createModule, createSystem } from "@directive-run/core";
6
+ import { sourceFromDOAlarm } from "@directive-run/sources/cloudflare";
7
+ import { schema, type PublishingStatus } from "./schema.js";
8
+ import type { AuditLog, Broadcaster } from "./deps.js";
9
+ import { createPublishingChain, type PublishingChain } from "./agents.js";
10
+
11
+ export interface PublishingDeps {
12
+ auditLog: AuditLog;
13
+ broadcaster: Broadcaster;
14
+ anthropicApiKey: string;
15
+ storage: DurableObjectStorage;
16
+ intervalMs?: number;
17
+ }
18
+
19
+ export interface PublishingModuleHandle {
20
+ alarmTick: () => void;
21
+ }
22
+
23
+ export function createPublishingSystem(deps: PublishingDeps) {
24
+ const chain = createPublishingChain(deps.anthropicApiKey);
25
+ const handle: PublishingModuleHandle = {
26
+ alarmTick: () => {},
27
+ };
28
+
29
+ const alarmSource = sourceFromDOAlarm({
30
+ storage: deps.storage,
31
+ intervalMs: deps.intervalMs ?? 5 * 60 * 1000,
32
+ eventName: "tick",
33
+ payload: () => ({}),
34
+ onTickRegistered: (tick) => {
35
+ handle.alarmTick = tick;
36
+ },
37
+ });
38
+
39
+ const publishingModule = createModule("publishing", {
40
+ schema,
41
+
42
+ init: (facts) => {
43
+ facts.status = "idle" satisfies PublishingStatus;
44
+ facts.currentArticle = {};
45
+ facts.ingestQueue = [];
46
+ facts.reviewQueue = [];
47
+ facts.errorLog = [];
48
+ },
49
+
50
+ derive: {
51
+ queueDepth: (facts) => facts.ingestQueue.length,
52
+ reviewDepth: (facts) => facts.reviewQueue.length,
53
+ isReadyToAggregate: (facts) =>
54
+ facts.ingestQueue.length >= 3 && facts.status === "idle",
55
+ },
56
+
57
+ events: {
58
+ ingest: (facts, payload) => {
59
+ facts.ingestQueue = [
60
+ ...facts.ingestQueue,
61
+ { url: payload.url, capturedAt: new Date().toISOString() },
62
+ ];
63
+ },
64
+ tick: (facts) => {
65
+ if (facts.status === "failed" || facts.status === "published") {
66
+ facts.status = "idle";
67
+ }
68
+ },
69
+ },
70
+
71
+ sources: {
72
+ alarm: alarmSource,
73
+ },
74
+
75
+ constraints: {
76
+ startAggregation: {
77
+ priority: 100,
78
+ when: (facts) =>
79
+ facts.ingestQueue.length >= 3 && facts.status === "idle",
80
+ require: (facts) => ({
81
+ type: "RUN_PUBLISHING_CHAIN",
82
+ sources: facts.ingestQueue.slice(0, 8),
83
+ }),
84
+ },
85
+
86
+ routeArticle: {
87
+ priority: 90,
88
+ when: (facts) => facts.status === "reviewing",
89
+ require: (facts) => ({
90
+ type: "ROUTE_ARTICLE",
91
+ article: facts.currentArticle,
92
+ }),
93
+ },
94
+ },
95
+
96
+ resolvers: {
97
+ runChain: {
98
+ requirement: "RUN_PUBLISHING_CHAIN",
99
+ key: (req) => `chain-${req.sources.map((s) => s.url).join("|")}`,
100
+ resolve: async (req, context) => {
101
+ context.facts.status = "aggregating";
102
+ context.facts.ingestQueue = context.facts.ingestQueue.slice(
103
+ req.sources.length,
104
+ );
105
+
106
+ try {
107
+ const result = await chain.run(req.sources, "demo");
108
+
109
+ context.facts.currentArticle = result;
110
+ context.facts.status = "reviewing";
111
+ await deps.auditLog.append({
112
+ event: "chain-completed",
113
+ at: new Date().toISOString(),
114
+ sources: req.sources.length,
115
+ confidence: result.confidence,
116
+ slug: result.slug,
117
+ });
118
+ } catch (err) {
119
+ const message = err instanceof Error ? err.message : String(err);
120
+ context.facts.errorLog = [
121
+ ...context.facts.errorLog,
122
+ {
123
+ at: new Date().toISOString(),
124
+ source: "publishing-chain",
125
+ message,
126
+ },
127
+ ];
128
+ context.facts.status = "failed";
129
+ await deps.auditLog.append({
130
+ event: "chain-failed",
131
+ at: new Date().toISOString(),
132
+ error: message,
133
+ });
134
+ }
135
+ },
136
+ },
137
+
138
+ routeArticle: {
139
+ requirement: "ROUTE_ARTICLE",
140
+ key: (req) => `route-${req.article.slug ?? "unknown"}`,
141
+ resolve: async (req, context) => {
142
+ const confidence = req.article.confidence ?? 0;
143
+ const slug = req.article.slug ?? "unknown";
144
+
145
+ if (confidence >= 0.85) {
146
+ await deps.broadcaster.send(req.article);
147
+ context.facts.status = "published";
148
+ await deps.auditLog.append({
149
+ event: "auto-published",
150
+ at: new Date().toISOString(),
151
+ slug,
152
+ confidence,
153
+ });
154
+ } else {
155
+ context.facts.reviewQueue = [
156
+ ...context.facts.reviewQueue,
157
+ { articleId: slug, confidence },
158
+ ];
159
+ context.facts.status = "idle";
160
+ await deps.auditLog.append({
161
+ event: "routed-to-review",
162
+ at: new Date().toISOString(),
163
+ slug,
164
+ confidence,
165
+ });
166
+ }
167
+ },
168
+ },
169
+ },
170
+ });
171
+
172
+ const system = createSystem({ module: publishingModule });
173
+
174
+ return { system, handle };
175
+ }
176
+
177
+ export type PublishingSystem = ReturnType<typeof createPublishingSystem>;
178
+ export type { PublishingChain };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@directive-run/knowledge",
3
- "version": "1.23.0",
3
+ "version": "1.23.1",
4
4
  "description": "Knowledge files, examples, and validation for Directive — the constraint-driven TypeScript runtime.",
5
5
  "license": "(MIT OR Apache-2.0)",
6
6
  "author": "Jason Comes",
@@ -52,9 +52,9 @@
52
52
  "tsup": "^8.3.5",
53
53
  "tsx": "^4.19.2",
54
54
  "typescript": "^5.7.2",
55
- "vitest": "^3.0.0",
56
- "@directive-run/core": "1.23.0",
57
- "@directive-run/ai": "1.23.0"
55
+ "vitest": "^3.2.6",
56
+ "@directive-run/core": "1.23.1",
57
+ "@directive-run/ai": "1.23.1"
58
58
  },
59
59
  "scripts": {
60
60
  "build": "tsx scripts/generate-api-skeleton.ts && tsx scripts/generate-sitemap.ts && tsx scripts/extract-examples.ts && tsup",
package/sitemap.md CHANGED
@@ -86,6 +86,7 @@ Website: https://directive.run
86
86
  - [Persistence](https://directive.run/docs/plugins/persistence)
87
87
  - [Performance](https://directive.run/docs/plugins/performance)
88
88
  - [Circuit Breaker](https://directive.run/docs/plugins/circuit-breaker)
89
+ - [Clobber Loop Detector](https://directive.run/docs/plugins/clobber-loop)
89
90
  - [Observability](https://directive.run/docs/plugins/observability)
90
91
  - [Custom Plugins](https://directive.run/docs/plugins/custom)
91
92
 
@@ -108,6 +109,14 @@ Website: https://directive.run
108
109
  - [Resolver Binding](https://directive.run/docs/resolver-binding)
109
110
  - [Audit Ledger](https://directive.run/docs/audit-ledger)
110
111
 
112
+ ### Broadcast
113
+ - [Overview](https://directive.run/docs/broadcast)
114
+ - [GitHub Action](https://directive.run/docs/broadcast/action)
115
+ - [CLI](https://directive.run/docs/broadcast/cli)
116
+ - [Cloudflare Worker](https://directive.run/docs/broadcast/worker)
117
+ - [MCP server](https://directive.run/docs/broadcast/mcp)
118
+ - [README badge](https://directive.run/docs/broadcast/badge)
119
+
111
120
  ### Examples
112
121
  - [Number Match](https://directive.run/docs/examples/counter)
113
122
  - [Auth Flow](https://directive.run/docs/examples/auth-flow)