@clowder-ai/plugin-contract 0.1.0-beta.9 → 0.3.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 (182) hide show
  1. package/dist/codegen/generate-contract.d.ts +6 -0
  2. package/dist/codegen/generate-contract.d.ts.map +1 -1
  3. package/dist/codegen/generate-contract.js +338 -44
  4. package/dist/codegen/generate-contract.js.map +1 -1
  5. package/dist/conformance/fixtures.d.ts +3 -1
  6. package/dist/conformance/fixtures.d.ts.map +1 -1
  7. package/dist/conformance/fixtures.js +2 -1
  8. package/dist/conformance/fixtures.js.map +1 -1
  9. package/dist/conformance/index.d.ts +3 -3
  10. package/dist/conformance/index.d.ts.map +1 -1
  11. package/dist/conformance/index.js +3 -3
  12. package/dist/conformance/index.js.map +1 -1
  13. package/dist/conformance/messaging-behavior-fixture.d.ts +12 -0
  14. package/dist/conformance/messaging-behavior-fixture.d.ts.map +1 -0
  15. package/dist/conformance/messaging-behavior-fixture.js +24 -0
  16. package/dist/conformance/messaging-behavior-fixture.js.map +1 -0
  17. package/dist/conformance/messaging-loopback-adapter.d.ts +0 -3
  18. package/dist/conformance/messaging-loopback-adapter.d.ts.map +1 -1
  19. package/dist/conformance/messaging-loopback-adapter.js +1 -77
  20. package/dist/conformance/messaging-loopback-adapter.js.map +1 -1
  21. package/dist/conformance/messaging-loopback-state.d.ts +0 -6
  22. package/dist/conformance/messaging-loopback-state.d.ts.map +1 -1
  23. package/dist/conformance/messaging-loopback-state.js +0 -20
  24. package/dist/conformance/messaging-loopback-state.js.map +1 -1
  25. package/dist/conformance/runner.d.ts.map +1 -1
  26. package/dist/conformance/runner.js +3 -1
  27. package/dist/conformance/runner.js.map +1 -1
  28. package/dist/docx-materialization.d.ts +8 -0
  29. package/dist/docx-materialization.d.ts.map +1 -0
  30. package/dist/docx-materialization.js +19 -0
  31. package/dist/docx-materialization.js.map +1 -0
  32. package/dist/generated/contract.generated.d.ts +1637 -87
  33. package/dist/generated/contract.generated.d.ts.map +1 -1
  34. package/dist/generated/contract.generated.js +70 -9
  35. package/dist/generated/contract.generated.js.map +1 -1
  36. package/dist/index.d.ts +2 -3
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +2 -3
  39. package/dist/index.js.map +1 -1
  40. package/dist/types/index.d.ts +0 -1
  41. package/dist/types/index.d.ts.map +1 -1
  42. package/dist/types/index.js +0 -1
  43. package/dist/types/index.js.map +1 -1
  44. package/dist/validation/catalog.d.ts +21 -0
  45. package/dist/validation/catalog.d.ts.map +1 -0
  46. package/dist/validation/catalog.js +140 -0
  47. package/dist/validation/catalog.js.map +1 -0
  48. package/dist/validation/cloud-conversation-host.d.ts +18 -0
  49. package/dist/validation/cloud-conversation-host.d.ts.map +1 -0
  50. package/dist/validation/cloud-conversation-host.js +83 -0
  51. package/dist/validation/cloud-conversation-host.js.map +1 -0
  52. package/dist/validation/companion-bridge.d.ts +6 -0
  53. package/dist/validation/companion-bridge.d.ts.map +1 -0
  54. package/dist/validation/companion-bridge.js +198 -0
  55. package/dist/validation/companion-bridge.js.map +1 -0
  56. package/dist/validation/docx-materialization.d.ts +6 -0
  57. package/dist/validation/docx-materialization.d.ts.map +1 -0
  58. package/dist/validation/docx-materialization.js +36 -0
  59. package/dist/validation/docx-materialization.js.map +1 -0
  60. package/dist/validation/index.d.ts +9 -1
  61. package/dist/validation/index.d.ts.map +1 -1
  62. package/dist/validation/index.js +9 -1
  63. package/dist/validation/index.js.map +1 -1
  64. package/dist/validation/manifest.d.ts.map +1 -1
  65. package/dist/validation/manifest.js +317 -0
  66. package/dist/validation/manifest.js.map +1 -1
  67. package/dist/validation/members.d.ts +4 -0
  68. package/dist/validation/members.d.ts.map +1 -0
  69. package/dist/validation/members.js +11 -0
  70. package/dist/validation/members.js.map +1 -0
  71. package/dist/validation/messaging-semantic.d.ts.map +1 -1
  72. package/dist/validation/messaging-semantic.js +98 -0
  73. package/dist/validation/messaging-semantic.js.map +1 -1
  74. package/dist/validation/messaging-wire.d.ts +42 -0
  75. package/dist/validation/messaging-wire.d.ts.map +1 -0
  76. package/dist/validation/messaging-wire.js +184 -0
  77. package/dist/validation/messaging-wire.js.map +1 -0
  78. package/dist/validation/operation-rows.d.ts +25 -0
  79. package/dist/validation/operation-rows.d.ts.map +1 -0
  80. package/dist/validation/operation-rows.js +135 -0
  81. package/dist/validation/operation-rows.js.map +1 -0
  82. package/dist/validation/signals.d.ts +1 -10
  83. package/dist/validation/signals.d.ts.map +1 -1
  84. package/dist/validation/signals.js +0 -174
  85. package/dist/validation/signals.js.map +1 -1
  86. package/dist/variant.d.ts +114 -0
  87. package/dist/variant.d.ts.map +1 -0
  88. package/dist/variant.js +305 -0
  89. package/dist/variant.js.map +1 -0
  90. package/dist/wire/constants.d.ts +2 -1
  91. package/dist/wire/constants.d.ts.map +1 -1
  92. package/dist/wire/constants.js +2 -1
  93. package/dist/wire/constants.js.map +1 -1
  94. package/dist/wire/dispatch.d.ts +49 -0
  95. package/dist/wire/dispatch.d.ts.map +1 -0
  96. package/dist/wire/dispatch.js +870 -0
  97. package/dist/wire/dispatch.js.map +1 -0
  98. package/dist/wire/disposition-fixtures.d.ts +10 -2
  99. package/dist/wire/disposition-fixtures.d.ts.map +1 -1
  100. package/dist/wire/disposition-fixtures.js +539 -108
  101. package/dist/wire/disposition-fixtures.js.map +1 -1
  102. package/dist/wire/disposition.d.ts +3 -4
  103. package/dist/wire/disposition.d.ts.map +1 -1
  104. package/dist/wire/disposition.js +5 -16
  105. package/dist/wire/disposition.js.map +1 -1
  106. package/dist/wire/envelope.d.ts +31 -1
  107. package/dist/wire/envelope.d.ts.map +1 -1
  108. package/dist/wire/envelope.js +48 -1
  109. package/dist/wire/envelope.js.map +1 -1
  110. package/dist/wire/errors.d.ts +31 -1
  111. package/dist/wire/errors.d.ts.map +1 -1
  112. package/dist/wire/errors.js +36 -0
  113. package/dist/wire/errors.js.map +1 -1
  114. package/dist/wire/handshake-byte-bounds.d.ts.map +1 -1
  115. package/dist/wire/handshake-byte-bounds.js +1 -4
  116. package/dist/wire/handshake-byte-bounds.js.map +1 -1
  117. package/dist/wire/handshake.d.ts +12 -11
  118. package/dist/wire/handshake.d.ts.map +1 -1
  119. package/dist/wire/handshake.js +11 -15
  120. package/dist/wire/handshake.js.map +1 -1
  121. package/dist/wire/index.d.ts +15 -13
  122. package/dist/wire/index.d.ts.map +1 -1
  123. package/dist/wire/index.js +30 -9
  124. package/dist/wire/index.js.map +1 -1
  125. package/dist/wire/lifecycle-byte-bounds.d.ts +40 -0
  126. package/dist/wire/lifecycle-byte-bounds.d.ts.map +1 -0
  127. package/dist/wire/lifecycle-byte-bounds.js +148 -0
  128. package/dist/wire/lifecycle-byte-bounds.js.map +1 -0
  129. package/dist/wire/messaging-byte-bounds.d.ts +62 -0
  130. package/dist/wire/messaging-byte-bounds.d.ts.map +1 -0
  131. package/dist/wire/messaging-byte-bounds.js +581 -0
  132. package/dist/wire/messaging-byte-bounds.js.map +1 -0
  133. package/dist/wire/registry.d.ts +58 -107
  134. package/dist/wire/registry.d.ts.map +1 -1
  135. package/dist/wire/registry.js +45 -107
  136. package/dist/wire/registry.js.map +1 -1
  137. package/dist/wire/row-shapes.d.ts +82 -81
  138. package/dist/wire/row-shapes.d.ts.map +1 -1
  139. package/dist/wire/row-shapes.js +30 -3
  140. package/dist/wire/row-shapes.js.map +1 -1
  141. package/fixtures/behavior/messaging/adversarial-invariants.json +62 -183
  142. package/fixtures/manifest/invalid/contract-version-leading-zero-prerelease.json +1 -3
  143. package/fixtures/manifest/invalid/contract-version-range.json +1 -3
  144. package/fixtures/manifest/invalid/duplicate-signal-type.json +4 -4
  145. package/fixtures/manifest/invalid/icon-package-escape.json +20 -0
  146. package/fixtures/manifest/invalid/ipc-empty-entrypoint.json +1 -3
  147. package/fixtures/manifest/invalid/plugin-version-leading-zero-prerelease.json +1 -3
  148. package/fixtures/manifest/invalid/plugin-version-not-semver.json +1 -3
  149. package/fixtures/manifest/invalid/semver-empty-build-metadata.json +1 -3
  150. package/fixtures/manifest/invalid/stdio-missing-entrypoint.json +1 -3
  151. package/fixtures/manifest/invalid/user-authored-lifecycle.json +1 -3
  152. package/fixtures/manifest/valid/localized-product-metadata.json +25 -0
  153. package/fixtures/manifest/valid/minimal-builtin.json +1 -3
  154. package/fixtures/manifest/valid/protocol-intrinsic-lifecycle.json +1 -3
  155. package/fixtures/manifest/valid/semver-build-metadata.json +1 -3
  156. package/fixtures/manifest/valid/stdio-entrypoint.json +1 -3
  157. package/fixtures/messaging/valid/subscription-delivery.json +1 -1
  158. package/package.json +17 -4
  159. package/src/schemas/behavior-fixture.schema.json +800 -152
  160. package/src/schemas/catalog.schema.json +91 -0
  161. package/src/schemas/companion-bridge.schema.json +2256 -0
  162. package/src/schemas/docx-materialization.schema.json +302 -0
  163. package/src/schemas/manifest.schema.json +2196 -107
  164. package/src/schemas/messaging.schema.json +692 -41
  165. package/src/schemas/plugin-metadata.schema.json +62 -0
  166. package/src/schemas/signal.schema.json +68 -78
  167. package/dist/types/capability.d.ts +0 -4
  168. package/dist/types/capability.d.ts.map +0 -1
  169. package/dist/types/capability.js +0 -11
  170. package/dist/types/capability.js.map +0 -1
  171. package/dist/wire/grants.d.ts +0 -57
  172. package/dist/wire/grants.d.ts.map +0 -1
  173. package/dist/wire/grants.js +0 -59
  174. package/dist/wire/grants.js.map +0 -1
  175. package/dist/wire/signal-byte-bounds.d.ts +0 -97
  176. package/dist/wire/signal-byte-bounds.d.ts.map +0 -1
  177. package/dist/wire/signal-byte-bounds.js +0 -229
  178. package/dist/wire/signal-byte-bounds.js.map +0 -1
  179. package/fixtures/manifest/invalid/unknown-capability.json +0 -19
  180. package/fixtures/signals/invalid/destination-injection.json +0 -15
  181. package/fixtures/signals/invalid/non-utc-occurred-at.json +0 -12
  182. package/fixtures/signals/valid/feishu-meeting-artifact.json +0 -18
@@ -10,9 +10,13 @@
10
10
  {
11
11
  "id": "raw-thread-id-rejection",
12
12
  "invariant": "Plugins cannot address threads by raw threadId.",
13
+ "execution": {
14
+ "plane": "wire-admission",
15
+ "method": "messaging.send",
16
+ "verdictOracle": { "kind": "json-rpc-error", "code": -32602, "sideEffects": "behavior-expectation" }
17
+ },
13
18
  "given": {
14
19
  "caller": { "pluginInstanceId": "plugin-a" },
15
- "grants": ["messaging.send"],
16
20
  "handles": {},
17
21
  "state": { "threads": [{ "threadId": "thread-1" }] }
18
22
  },
@@ -40,9 +44,13 @@
40
44
  {
41
45
  "id": "system-audience-dual-rejection",
42
46
  "invariant": "Drafts cannot express the host-only system audience.",
47
+ "execution": {
48
+ "plane": "wire-admission",
49
+ "method": "messaging.send",
50
+ "verdictOracle": { "kind": "json-rpc-error", "code": -32602, "sideEffects": "behavior-expectation" }
51
+ },
43
52
  "given": {
44
53
  "caller": { "pluginInstanceId": "plugin-a" },
45
- "grants": ["messaging.send"],
46
54
  "handles": {
47
55
  "target": { "kind": "thread_handle", "token": "thread-handle-a", "ownerPluginInstanceId": "plugin-a", "threadId": "thread-1" }
48
56
  },
@@ -73,9 +81,13 @@
73
81
  {
74
82
  "id": "cross-instance-handle-rejection",
75
83
  "invariant": "A message handle issued to one plugin instance cannot authorize another.",
84
+ "execution": {
85
+ "plane": "plugin-to-host-wire",
86
+ "method": "messaging.appendElements",
87
+ "verdictOracle": { "kind": "behavior-expectation" }
88
+ },
76
89
  "given": {
77
90
  "caller": { "pluginInstanceId": "plugin-a" },
78
- "grants": ["messaging.appendElements"],
79
91
  "handles": {
80
92
  "foreignMessage": { "kind": "message_handle", "token": "message-handle-b", "ownerPluginInstanceId": "plugin-b", "threadId": "thread-1", "messageId": "message-1" }
81
93
  },
@@ -103,9 +115,13 @@
103
115
  {
104
116
  "id": "origin-forgery-rejection",
105
117
  "invariant": "A thread-handle send may only declare the caller's own plugin origin.",
118
+ "execution": {
119
+ "plane": "plugin-to-host-wire",
120
+ "method": "messaging.send",
121
+ "verdictOracle": { "kind": "behavior-expectation" }
122
+ },
106
123
  "given": {
107
124
  "caller": { "pluginInstanceId": "plugin-a" },
108
- "grants": ["messaging.send"],
109
125
  "handles": {
110
126
  "target": { "kind": "thread_handle", "token": "thread-handle-a", "ownerPluginInstanceId": "plugin-a", "threadId": "thread-1" }
111
127
  },
@@ -135,9 +151,13 @@
135
151
  {
136
152
  "id": "base-revision-conflict-zero-change",
137
153
  "invariant": "A stale baseRevision produces CONFLICT and no mutation.",
154
+ "execution": {
155
+ "plane": "plugin-to-host-wire",
156
+ "method": "messaging.appendElements",
157
+ "verdictOracle": { "kind": "behavior-expectation" }
158
+ },
138
159
  "given": {
139
160
  "caller": { "pluginInstanceId": "plugin-a" },
140
- "grants": ["messaging.appendElements"],
141
161
  "handles": {
142
162
  "message": { "kind": "message_handle", "token": "message-handle-a", "ownerPluginInstanceId": "plugin-a", "threadId": "thread-1", "messageId": "message-1" }
143
163
  },
@@ -165,9 +185,13 @@
165
185
  {
166
186
  "id": "stale-cursor-snapshot-roundtrip",
167
187
  "invariant": "A stale cursor reports stale and snapshot catch-up supplies an exact resume point.",
188
+ "execution": {
189
+ "plane": "plugin-to-host-wire",
190
+ "method": "messaging.read",
191
+ "verdictOracle": { "kind": "behavior-expectation" }
192
+ },
168
193
  "given": {
169
194
  "caller": { "pluginInstanceId": "plugin-a" },
170
- "grants": ["message.event.subscribe"],
171
195
  "handles": {
172
196
  "subscription": { "kind": "subscription", "token": "subscription-token-a", "ownerPluginInstanceId": "plugin-a", "threadId": "thread-1", "subscriptionId": "subscription-a" }
173
197
  },
@@ -189,9 +213,13 @@
189
213
  {
190
214
  "id": "cross-subscription-ack-rejection",
191
215
  "invariant": "Ack tokens are subscription-local and cannot cross subscriptions.",
216
+ "execution": {
217
+ "plane": "plugin-to-host-wire",
218
+ "method": "messaging.ack",
219
+ "verdictOracle": { "kind": "behavior-expectation" }
220
+ },
192
221
  "given": {
193
222
  "caller": { "pluginInstanceId": "plugin-a" },
194
- "grants": ["message.event.subscribe"],
195
223
  "handles": {
196
224
  "subscriptionA": { "kind": "subscription", "token": "ack-from-a", "ownerPluginInstanceId": "plugin-a", "threadId": "thread-1", "subscriptionId": "subscription-a" },
197
225
  "subscriptionB": { "kind": "subscription", "token": "subscription-token-b", "ownerPluginInstanceId": "plugin-a", "threadId": "thread-2", "subscriptionId": "subscription-b" }
@@ -214,9 +242,13 @@
214
242
  {
215
243
  "id": "reply-to-cross-thread-leakage",
216
244
  "invariant": "replyTo cannot reference a message from another thread.",
245
+ "execution": {
246
+ "plane": "plugin-to-host-wire",
247
+ "method": "messaging.send",
248
+ "verdictOracle": { "kind": "behavior-expectation" }
249
+ },
217
250
  "given": {
218
251
  "caller": { "pluginInstanceId": "plugin-a" },
219
- "grants": ["messaging.send"],
220
252
  "handles": {
221
253
  "target": { "kind": "thread_handle", "token": "thread-handle-a", "ownerPluginInstanceId": "plugin-a", "threadId": "thread-1" }
222
254
  },
@@ -247,9 +279,13 @@
247
279
  {
248
280
  "id": "epistemic-status-upgrade-rejection",
249
281
  "invariant": "Derived content cannot claim a stronger epistemic status than its source.",
282
+ "execution": {
283
+ "plane": "plugin-to-host-wire",
284
+ "method": "messaging.appendElements",
285
+ "verdictOracle": { "kind": "behavior-expectation" }
286
+ },
250
287
  "given": {
251
288
  "caller": { "pluginInstanceId": "plugin-a" },
252
- "grants": ["messaging.appendElements"],
253
289
  "handles": {
254
290
  "message": { "kind": "message_handle", "token": "message-handle-a", "ownerPluginInstanceId": "plugin-a", "threadId": "thread-1", "messageId": "message-1" }
255
291
  },
@@ -274,116 +310,18 @@
274
310
  ]
275
311
  }
276
312
  },
313
+
314
+
277
315
  {
278
- "id": "preset-l2-rejected",
279
- "invariant": "First-party presets are derived from L1 and cannot silently grant L2 capabilities.",
280
- "given": {
281
- "caller": { "pluginInstanceId": "first-party-plugin" },
282
- "grants": ["messaging.send"],
283
- "handles": {},
284
- "state": { "grantState": { "presetCapabilities": ["messaging.send"] } }
285
- },
286
- "when": {
287
- "operation": "applyGrantPreset",
288
- "input": { "presetKind": "first_party", "capabilities": ["onMessage"] }
289
- },
290
- "expect": {
291
- "status": "error",
292
- "errorCode": "PERMISSION",
293
- "sideEffects": [
294
- { "target": "grant_state", "assertion": "unchanged" }
295
- ]
296
- }
297
- },
298
- {
299
- "id": "preset-visible-revocable",
300
- "invariant": "A first-party L1 preset remains visible and independently revocable.",
301
- "given": {
302
- "caller": { "pluginInstanceId": "first-party-plugin" },
303
- "grants": ["messaging.send"],
304
- "handles": {},
305
- "state": { "grantState": { "messaging.send": { "visible": true, "granted": true } } }
306
- },
307
- "when": {
308
- "operation": "revokeGrant",
309
- "input": { "capability": "messaging.send" }
310
- },
311
- "expect": {
312
- "status": "success",
313
- "sideEffects": [
314
- { "target": "grant_state", "assertion": "state_equals", "value": { "capability": "messaging.send", "visible": true, "granted": false } }
315
- ]
316
- }
317
- },
318
- {
319
- "id": "whisper-target-beyond-default-empty-grant-rejected",
320
- "invariant": "The default whisper target grant is empty; messaging.send alone cannot add a target.",
321
- "given": {
322
- "caller": { "pluginInstanceId": "plugin-a" },
323
- "grants": ["messaging.send"],
324
- "handles": {
325
- "target": { "kind": "thread_handle", "token": "thread-handle-a", "ownerPluginInstanceId": "plugin-a", "threadId": "thread-1" }
326
- },
327
- "state": { "whisperGrantTargets": [] }
328
- },
329
- "when": {
330
- "operation": "send",
331
- "input": {
332
- "address": { "kind": "thread_handle", "handle": "thread-handle-a" },
333
- "draftAudience": { "kind": "whisper", "targets": ["cat-b"] },
334
- "idempotencyKey": "whisper-without-target-grant-1",
335
- "payload": {
336
- "provenance": { "epistemicStatus": "inference" },
337
- "elements": [{ "elementId": "text-1", "kind": "text", "payload": { "text": "blocked" } }]
338
- }
339
- }
340
- },
341
- "expect": {
342
- "status": "error",
343
- "errorCode": "PERMISSION",
344
- "sideEffects": [
345
- { "target": "messages", "assertion": "unchanged" },
346
- { "target": "output_events", "assertion": "none" },
347
- { "target": "idempotency_ledger", "assertion": "unchanged" }
348
- ]
349
- }
350
- },
351
- {
352
- "id": "append-without-grant-rejected",
353
- "invariant": "A valid message handle does not bypass the messaging.appendElements grant.",
354
- "given": {
355
- "caller": { "pluginInstanceId": "plugin-a" },
356
- "grants": [],
357
- "handles": {
358
- "message": { "kind": "message_handle", "token": "message-handle-a", "ownerPluginInstanceId": "plugin-a", "threadId": "thread-1", "messageId": "message-1" }
359
- },
360
- "state": { "messages": [{ "messageId": "message-1", "threadId": "thread-1", "revision": 1 }] }
361
- },
362
- "when": {
363
- "operation": "appendElements",
364
- "input": {
365
- "handle": { "kind": "message", "token": "message-handle-a" },
366
- "operationId": "append-without-grant-1",
367
- "baseRevision": 1,
368
- "elements": [{ "elementId": "text-2", "kind": "text", "payload": { "text": "blocked" } }]
369
- }
316
+ "id": "on-message-delivery",
317
+ "invariant": "A live instance receives its scoped message through the declared handler",
318
+ "execution": {
319
+ "plane": "host-to-plugin-delivery",
320
+ "method": "host.messaging.deliver",
321
+ "verdictOracle": { "kind": "behavior-expectation" }
370
322
  },
371
- "expect": {
372
- "status": "error",
373
- "errorCode": "PERMISSION",
374
- "sideEffects": [
375
- { "target": "messages", "assertion": "unchanged" },
376
- { "target": "output_events", "assertion": "none" },
377
- { "target": "idempotency_ledger", "assertion": "unchanged" }
378
- ]
379
- }
380
- },
381
- {
382
- "id": "denied-on-message-rejected",
383
- "invariant": "The Host cannot deliver an onMessage envelope without an explicit scoped L2 grant.",
384
323
  "given": {
385
324
  "caller": { "pluginInstanceId": "plugin-a" },
386
- "grants": [],
387
325
  "handles": {
388
326
  "target": { "kind": "thread_handle", "token": "thread-handle-a", "ownerPluginInstanceId": "plugin-a", "threadId": "thread-1" }
389
327
  },
@@ -397,60 +335,22 @@
397
335
  }
398
336
  },
399
337
  "expect": {
400
- "status": "error",
401
- "errorCode": "PERMISSION",
338
+ "status": "success",
402
339
  "sideEffects": [
403
340
  { "target": "messages", "assertion": "unchanged" },
404
341
  { "target": "output_events", "assertion": "none" }
405
342
  ]
406
343
  }
407
344
  },
408
- {
409
- "id": "permission-matrix-complete",
410
- "invariant": "The loopback policy matrix covers every signed capability and presets only L1 for first-party plugins.",
411
- "given": {
412
- "caller": { "pluginInstanceId": "policy-auditor" },
413
- "grants": [],
414
- "handles": {},
415
- "state": {}
416
- },
417
- "when": {
418
- "operation": "checkPermissionMatrix",
419
- "input": {
420
- "entries": [
421
- { "capability": "plugin.config.read", "layer": "L0", "firstPartyPreset": false },
422
- { "capability": "plugin.state.get", "layer": "L0", "firstPartyPreset": false },
423
- { "capability": "plugin.state.set", "layer": "L0", "firstPartyPreset": false },
424
- { "capability": "messaging.send", "layer": "L1", "firstPartyPreset": true },
425
- { "capability": "schedule.register", "layer": "L1", "firstPartyPreset": true },
426
- { "capability": "events.publish", "layer": "L1", "firstPartyPreset": true },
427
- { "capability": "messaging.appendElements", "layer": "L1", "firstPartyPreset": true },
428
- { "capability": "onMessage", "layer": "L2", "firstPartyPreset": false },
429
- { "capability": "message.event.subscribe", "layer": "L2", "firstPartyPreset": false },
430
- { "capability": "secret.read", "layer": "L2", "firstPartyPreset": false },
431
- { "capability": "thread.listMetadata", "layer": "L2", "firstPartyPreset": false },
432
- { "capability": "thread.readContent", "layer": "L2", "firstPartyPreset": false },
433
- { "capability": "memory.query", "layer": "L2", "firstPartyPreset": false },
434
- { "capability": "memory.append", "layer": "L2", "firstPartyPreset": false },
435
- { "capability": "memory.retrieve", "layer": "L2", "firstPartyPreset": false },
436
- { "capability": "windows.create", "layer": "L2", "firstPartyPreset": false },
437
- { "capability": "whisper.extend", "layer": "L2", "firstPartyPreset": false }
438
- ]
439
- }
440
- },
441
- "expect": {
442
- "status": "success",
443
- "sideEffects": [
444
- { "target": "permission_matrix", "assertion": "matches", "value": { "complete": true, "firstPartyPresetLayers": ["L1"], "defaultWhisperTargets": [] } }
445
- ]
446
- }
447
- },
448
345
  {
449
346
  "id": "delete-replay-events-preserves-canonical-messages",
450
347
  "invariant": "Deleting the replay transport buffer cannot delete canonical messages or threads.",
348
+ "execution": {
349
+ "plane": "host-control",
350
+ "verdictOracle": { "kind": "behavior-expectation" }
351
+ },
451
352
  "given": {
452
353
  "caller": { "pluginInstanceId": "host-retention" },
453
- "grants": ["message.event.subscribe"],
454
354
  "handles": {
455
355
  "subscription": { "kind": "subscription", "token": "subscription-token-a", "ownerPluginInstanceId": "host-retention", "threadId": "thread-1", "subscriptionId": "subscription-a" }
456
356
  },
@@ -471,36 +371,15 @@
471
371
  ]
472
372
  }
473
373
  },
474
- {
475
- "id": "snapshot-without-grant-rejected",
476
- "invariant": "A subscription identifier cannot bypass the message.event.subscribe grant for snapshots.",
477
- "given": {
478
- "caller": { "pluginInstanceId": "plugin-a" },
479
- "grants": [],
480
- "handles": {
481
- "subscription": { "kind": "subscription", "token": "subscription-token-a", "ownerPluginInstanceId": "plugin-a", "threadId": "thread-1", "subscriptionId": "subscription-a" }
482
- },
483
- "state": { "subscription": { "cursorSequence": 4 } }
484
- },
485
- "when": {
486
- "operation": "snapshot",
487
- "input": { "subscriptionId": "subscription-a" }
488
- },
489
- "expect": {
490
- "status": "error",
491
- "errorCode": "PERMISSION",
492
- "sideEffects": [
493
- { "target": "snapshot", "assertion": "none" },
494
- { "target": "subscription", "assertion": "unchanged" }
495
- ]
496
- }
497
- },
498
374
  {
499
375
  "id": "foreign-replay-delete-rejected",
500
376
  "invariant": "A caller cannot delete another plugin instance's subscription replay buffer.",
377
+ "execution": {
378
+ "plane": "host-control",
379
+ "verdictOracle": { "kind": "behavior-expectation" }
380
+ },
501
381
  "given": {
502
382
  "caller": { "pluginInstanceId": "plugin-b" },
503
- "grants": ["message.event.subscribe"],
504
383
  "handles": {
505
384
  "subscription": { "kind": "subscription", "token": "subscription-token-a", "ownerPluginInstanceId": "plugin-a", "threadId": "thread-1", "subscriptionId": "subscription-a" }
506
385
  },
@@ -7,9 +7,7 @@
7
7
  {
8
8
  "id": "echo",
9
9
  "name": "Echo",
10
- "resources": [],
11
- "capabilities": []
12
- }
10
+ "resources": []}
13
11
  ],
14
12
  "runtime": {
15
13
  "transport": "builtin"
@@ -7,9 +7,7 @@
7
7
  {
8
8
  "id": "echo",
9
9
  "name": "Echo",
10
- "resources": [],
11
- "capabilities": []
12
- }
10
+ "resources": []}
13
11
  ],
14
12
  "runtime": {
15
13
  "transport": "builtin"
@@ -7,9 +7,7 @@
7
7
  {
8
8
  "id": "meeting-intake",
9
9
  "name": "Meeting intake",
10
- "resources": [],
11
- "capabilities": ["events.publish"]
12
- }
10
+ "resources": []}
13
11
  ],
14
12
  "signals": {
15
13
  "provides": [
@@ -29,5 +27,7 @@
29
27
  }
30
28
  ]
31
29
  },
32
- "runtime": { "transport": "builtin" }
30
+ "runtime": {
31
+ "transport": "builtin"
32
+ }
33
33
  }
@@ -0,0 +1,20 @@
1
+ {
2
+ "pluginId": "com.example.icon-escape",
3
+ "version": "1.0.0",
4
+ "contractVersion": "0.1.0-beta.13",
5
+ "name": "Icon escape fixture",
6
+ "description": "Legacy description remains accepted.",
7
+ "icon": {
8
+ "type": "svg",
9
+ "src": "../outside.svg"
10
+ },
11
+ "features": [
12
+ {
13
+ "id": "main",
14
+ "name": "Main",
15
+ "resources": []}
16
+ ],
17
+ "runtime": {
18
+ "transport": "builtin"
19
+ }
20
+ }
@@ -7,9 +7,7 @@
7
7
  {
8
8
  "id": "echo",
9
9
  "name": "Echo",
10
- "resources": [],
11
- "capabilities": []
12
- }
10
+ "resources": []}
13
11
  ],
14
12
  "runtime": {
15
13
  "transport": "ipc",
@@ -7,9 +7,7 @@
7
7
  {
8
8
  "id": "echo",
9
9
  "name": "Echo",
10
- "resources": [],
11
- "capabilities": []
12
- }
10
+ "resources": []}
13
11
  ],
14
12
  "runtime": {
15
13
  "transport": "builtin"
@@ -7,9 +7,7 @@
7
7
  {
8
8
  "id": "echo",
9
9
  "name": "Echo",
10
- "resources": [],
11
- "capabilities": []
12
- }
10
+ "resources": []}
13
11
  ],
14
12
  "runtime": {
15
13
  "transport": "builtin"
@@ -7,9 +7,7 @@
7
7
  {
8
8
  "id": "echo",
9
9
  "name": "Echo",
10
- "resources": [],
11
- "capabilities": []
12
- }
10
+ "resources": []}
13
11
  ],
14
12
  "runtime": {
15
13
  "transport": "builtin"
@@ -7,9 +7,7 @@
7
7
  {
8
8
  "id": "echo",
9
9
  "name": "Echo",
10
- "resources": [],
11
- "capabilities": []
12
- }
10
+ "resources": []}
13
11
  ],
14
12
  "runtime": {
15
13
  "transport": "stdio"
@@ -7,9 +7,7 @@
7
7
  {
8
8
  "id": "notes",
9
9
  "name": "Notes",
10
- "resources": [],
11
- "capabilities": []
12
- }
10
+ "resources": []}
13
11
  ],
14
12
  "data": [
15
13
  {
@@ -0,0 +1,25 @@
1
+ {
2
+ "pluginId": "com.example.localized-metadata",
3
+ "version": "1.0.0",
4
+ "contractVersion": "0.1.0-beta.13",
5
+ "name": "Localized metadata fixture",
6
+ "description": {
7
+ "default": "Describe this plugin for agents and people.",
8
+ "translations": {
9
+ "zh-CN": "向 Agent 和用户介绍这个插件。"
10
+ }
11
+ },
12
+ "icon": {
13
+ "type": "svg",
14
+ "src": "assets/icon.svg"
15
+ },
16
+ "features": [
17
+ {
18
+ "id": "main",
19
+ "name": "Main",
20
+ "resources": []}
21
+ ],
22
+ "runtime": {
23
+ "transport": "builtin"
24
+ }
25
+ }
@@ -7,9 +7,7 @@
7
7
  {
8
8
  "id": "echo",
9
9
  "name": "Echo",
10
- "resources": [],
11
- "capabilities": []
12
- }
10
+ "resources": []}
13
11
  ],
14
12
  "runtime": {
15
13
  "transport": "builtin"
@@ -8,9 +8,7 @@
8
8
  {
9
9
  "id": "lifecycle-baseline",
10
10
  "name": "Lifecycle baseline",
11
- "resources": [],
12
- "capabilities": []
13
- }
11
+ "resources": []}
14
12
  ],
15
13
  "runtime": {
16
14
  "transport": "builtin"
@@ -7,9 +7,7 @@
7
7
  {
8
8
  "id": "echo",
9
9
  "name": "Echo",
10
- "resources": [],
11
- "capabilities": []
12
- }
10
+ "resources": []}
13
11
  ],
14
12
  "runtime": {
15
13
  "transport": "builtin"
@@ -7,9 +7,7 @@
7
7
  {
8
8
  "id": "echo",
9
9
  "name": "Echo",
10
- "resources": [],
11
- "capabilities": []
12
- }
10
+ "resources": []}
13
11
  ],
14
12
  "runtime": {
15
13
  "transport": "stdio",
@@ -18,7 +18,7 @@
18
18
  "audience": {
19
19
  "kind": "public"
20
20
  },
21
- "occurredAt": "2026-07-15T02:42:00Z",
21
+ "occurredAt": "2026-07-15T02:42:00.000Z",
22
22
  "payload": {
23
23
  "provenance": {
24
24
  "origin": {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@clowder-ai/plugin-contract",
3
- "version": "0.1.0-beta.9",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
- "description": "Clowder AI plugin contract — the single machine-readable truth source for plugin schema, types, capability table, and conformance fixtures (P15)",
5
+ "description": "Clowder AI plugin schemas, bidirectional protocol and conformance fixtures",
6
6
  "license": "MIT",
7
7
  "type": "module",
8
8
  "exports": {
@@ -14,11 +14,24 @@
14
14
  "types": "./dist/conformance/index.d.ts",
15
15
  "import": "./dist/conformance/index.js"
16
16
  },
17
+ "./docx-materialization": {
18
+ "types": "./dist/docx-materialization.d.ts",
19
+ "import": "./dist/docx-materialization.js"
20
+ },
21
+ "./variant": {
22
+ "types": "./dist/variant.d.ts",
23
+ "import": "./dist/variant.js"
24
+ },
17
25
  "./schemas/messaging": "./src/schemas/messaging.schema.json",
18
26
  "./schemas/manifest": "./src/schemas/manifest.schema.json",
27
+ "./schemas/catalog": "./src/schemas/catalog.schema.json",
28
+ "./schemas/plugin-metadata": "./src/schemas/plugin-metadata.schema.json",
19
29
  "./schemas/signals": "./src/schemas/signal.schema.json",
20
30
  "./schemas/physical-limb": "./src/schemas/physical-limb.schema.json",
21
- "./schemas/behavior-fixture": "./src/schemas/behavior-fixture.schema.json"
31
+ "./schemas/docx-materialization": "./src/schemas/docx-materialization.schema.json",
32
+ "./schemas/companion-bridge": "./src/schemas/companion-bridge.schema.json",
33
+ "./schemas/behavior-fixture": "./src/schemas/behavior-fixture.schema.json",
34
+ "./fixtures/behavior/messaging/adversarial-invariants": "./fixtures/behavior/messaging/adversarial-invariants.json"
22
35
  },
23
36
  "main": "./dist/index.js",
24
37
  "types": "./dist/index.d.ts",
@@ -35,7 +48,7 @@
35
48
  "generate:check": "node --import tsx src/codegen/generate-contract.ts --check",
36
49
  "build": "pnpm clean && tsc -p tsconfig.build.json && node --test scripts/conformance-public-boundary.test.mjs",
37
50
  "typecheck": "tsc --noEmit",
38
- "test": "node --import tsx --test src/**/*.test.ts src/**/**/*.test.ts",
51
+ "test": "node --import tsx --test \"src/**/*.test.ts\"",
39
52
  "conformance": "node --import tsx src/conformance/runner.ts",
40
53
  "lint": "tsc --noEmit",
41
54
  "clean": "rm -rf dist",