@directive-run/claude-plugin 1.18.0 → 1.19.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@directive-run/claude-plugin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.19.0",
|
|
4
4
|
"description": "Claude Code plugin for Directive — 12 skills covering modules, constraints, resolvers, derivations, AI orchestration, and adapters. Installable via Claude Code's plugin marketplace or consumable programmatically as an npm package.",
|
|
5
5
|
"license": "(MIT OR Apache-2.0)",
|
|
6
6
|
"author": "Jason Comes",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"tsx": "^4.19.2",
|
|
53
53
|
"typescript": "^5.7.2",
|
|
54
54
|
"vitest": "^3.0.0",
|
|
55
|
-
"@directive-run/knowledge": "1.
|
|
55
|
+
"@directive-run/knowledge": "1.19.0"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "tsx scripts/build-skills.ts && tsup",
|
|
@@ -101,9 +101,6 @@ const result = orchestrator.runStream(agent, input, {
|
|
|
101
101
|
system, // the Directive system whose facts feed the agent
|
|
102
102
|
keys: ["pr.headSha", "pr.state"], // REQUIRED — fact keys to watch
|
|
103
103
|
interruptWhen: (facts, changedKeys) => boolean, // optional; default: () => true
|
|
104
|
-
mode: "inject-system-message", // shipped today (default behavior).
|
|
105
|
-
// "restart" reserved for follow-up minor;
|
|
106
|
-
// behaves identically to inject-system-message today.
|
|
107
104
|
notifyOn: "interrupt-only", // default; "all-changes" emits chunk per watched change
|
|
108
105
|
onContextUpdate: (changedKeys) => void, // optional logging hook
|
|
109
106
|
},
|
|
@@ -170,26 +167,50 @@ threat model.
|
|
|
170
167
|
|
|
171
168
|
## MCP Lifecycle as a Source
|
|
172
169
|
|
|
173
|
-
`@directive-run/ai/mcp`
|
|
174
|
-
(`onConnect`, `onDisconnect`, `onToolCall`, ...) as
|
|
175
|
-
|
|
176
|
-
|
|
170
|
+
`@directive-run/ai/mcp` exposes `MCPAdapterConfig.events`
|
|
171
|
+
(`onConnect`, `onDisconnect`, `onToolCall`, `onError`, ...) as a single
|
|
172
|
+
bag of callbacks set at adapter-construction time. To bridge the
|
|
173
|
+
adapter's lifecycle into a Directive source the recipe is: declare a
|
|
174
|
+
holder that the source's `attach` populates with the live `publish`,
|
|
175
|
+
then point the adapter's `events.onConnect` / `onDisconnect` at the
|
|
176
|
+
holder. The holder pattern lets you construct the adapter and the
|
|
177
|
+
source in either order — the source's mount/unmount drives which
|
|
178
|
+
publish closure (if any) receives lifecycle events.
|
|
177
179
|
|
|
178
180
|
```ts
|
|
179
181
|
import { createSystem, createModule, t } from "@directive-run/core";
|
|
182
|
+
import type { SourcePublish } from "@directive-run/core";
|
|
180
183
|
import { createMCPAdapter } from "@directive-run/ai/mcp";
|
|
181
184
|
|
|
182
|
-
|
|
185
|
+
// Holder that the source's `attach` populates. The adapter's events
|
|
186
|
+
// forward through this — when the source is detached (`attach`'s
|
|
187
|
+
// unsubscribe runs), the holder goes null and the adapter callbacks
|
|
188
|
+
// no-op. This guarantees post-stop lifecycle events from the MCP
|
|
189
|
+
// transport can't write into a torn-down system.
|
|
190
|
+
let publishRef: SourcePublish | null = null;
|
|
191
|
+
|
|
192
|
+
const adapter = createMCPAdapter({
|
|
193
|
+
servers: [/* ... */],
|
|
194
|
+
events: {
|
|
195
|
+
onConnect: (name) => publishRef?.("MCP_SERVER_CONNECTED", { name }),
|
|
196
|
+
onDisconnect: (name) => publishRef?.("MCP_SERVER_DISCONNECTED", { name }),
|
|
197
|
+
},
|
|
198
|
+
});
|
|
183
199
|
|
|
184
200
|
const orchestrator = createModule("orchestrator", {
|
|
185
201
|
schema: {
|
|
186
202
|
facts: {
|
|
187
|
-
mcp: t.object<{
|
|
203
|
+
mcp: t.object<{
|
|
204
|
+
servers: Record<string, "connected" | "disconnected">;
|
|
205
|
+
}>(),
|
|
188
206
|
},
|
|
189
207
|
events: {
|
|
190
208
|
MCP_SERVER_CONNECTED: { name: t.string() },
|
|
191
209
|
MCP_SERVER_DISCONNECTED: { name: t.string() },
|
|
192
210
|
},
|
|
211
|
+
derivations: {
|
|
212
|
+
allServersHealthy: t.boolean(),
|
|
213
|
+
},
|
|
193
214
|
},
|
|
194
215
|
init: (f) => {
|
|
195
216
|
f.mcp = { servers: {} };
|
|
@@ -209,21 +230,19 @@ const orchestrator = createModule("orchestrator", {
|
|
|
209
230
|
},
|
|
210
231
|
},
|
|
211
232
|
derive: {
|
|
212
|
-
allServersHealthy: (
|
|
213
|
-
Object.values(
|
|
233
|
+
allServersHealthy: (facts) =>
|
|
234
|
+
Object.values(facts.mcp.servers).every((s) => s === "connected"),
|
|
214
235
|
},
|
|
215
236
|
sources: {
|
|
216
237
|
mcpLifecycle: {
|
|
217
238
|
attach: (publish) => {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
off1();
|
|
226
|
-
off2();
|
|
239
|
+
publishRef = publish;
|
|
240
|
+
// Kick the adapter's connection lifecycle once the source is
|
|
241
|
+
// attached so the first `onConnect` flows into our publish.
|
|
242
|
+
void adapter.connect();
|
|
243
|
+
return async () => {
|
|
244
|
+
publishRef = null;
|
|
245
|
+
await adapter.disconnect();
|
|
227
246
|
};
|
|
228
247
|
},
|
|
229
248
|
},
|
|
@@ -234,6 +253,14 @@ const orchestrator = createModule("orchestrator", {
|
|
|
234
253
|
Constraints can now gate agent execution on
|
|
235
254
|
`facts.allServersHealthy` — no separate health-check loop needed.
|
|
236
255
|
|
|
256
|
+
> The holder + closure pattern is the canonical bridge from any
|
|
257
|
+
> single-callback-bag third-party SDK (MCP, telemetry SDKs that take an
|
|
258
|
+
> `onEvent` config at construction) into a Directive source. The
|
|
259
|
+
> alternative — passing `publish` from inside `attach` into the
|
|
260
|
+
> adapter's events — requires the adapter to be constructed AFTER the
|
|
261
|
+
> source is created, which is awkward when the adapter is used outside
|
|
262
|
+
> Directive too.
|
|
263
|
+
|
|
237
264
|
---
|
|
238
265
|
|
|
239
266
|
## Sources × Security
|
|
@@ -421,4 +421,4 @@ sources: {
|
|
|
421
421
|
- `anti-patterns.md` (#20) — "subscribe inside an effect / useEffect" anti-pattern; prefer sources.
|
|
422
422
|
- `naming.md` — canonical-term entry for `sources` + cross-paradigm aliases (RxJS Observable, DOM EventTarget, XState callback actor, Supabase realtime).
|
|
423
423
|
- [`../ai/ai-sources.md`](../ai/ai-sources.md) — AI integration: `runStream({ liveContext })`, MCP lifecycle as a source, the `@directive-run/sources/*` adapter subpaths.
|
|
424
|
-
- [`../ai/ai-security.md`](../ai/ai-security.md#sources
|
|
424
|
+
- [`../ai/ai-security.md`](../ai/ai-security.md#sources--pii--closing-the-fact-injection-bypass) — `createFactPIIGuardrail`: closes the source → fact → agent-prompt PII bypass. Wire whenever sources publish into facts the agent reads.
|