@stigmer/server 3.15.3-dev.20260914100347 → 3.15.3-dev.20260916211208

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 (570) hide show
  1. package/README.md +3 -3
  2. package/dist/archive/content-store.d.ts +35 -0
  3. package/dist/archive/content-store.d.ts.map +1 -0
  4. package/dist/archive/content-store.js +98 -0
  5. package/dist/archive/content-store.js.map +1 -0
  6. package/dist/archive/inflate.d.ts +22 -0
  7. package/dist/archive/inflate.d.ts.map +1 -0
  8. package/dist/archive/inflate.js +75 -0
  9. package/dist/archive/inflate.js.map +1 -0
  10. package/dist/archive/limits.d.ts +33 -0
  11. package/dist/archive/limits.d.ts.map +1 -0
  12. package/dist/archive/limits.js +31 -0
  13. package/dist/archive/limits.js.map +1 -0
  14. package/dist/archive/open.d.ts +24 -0
  15. package/dist/archive/open.d.ts.map +1 -0
  16. package/dist/archive/open.js +93 -0
  17. package/dist/archive/open.js.map +1 -0
  18. package/dist/{domain/skill/storage → archive}/prefilter.d.ts +5 -0
  19. package/dist/archive/prefilter.d.ts.map +1 -0
  20. package/dist/archive/prefilter.js.map +1 -0
  21. package/dist/archive/write.d.ts +8 -0
  22. package/dist/archive/write.d.ts.map +1 -0
  23. package/dist/archive/write.js +44 -0
  24. package/dist/archive/write.js.map +1 -0
  25. package/dist/authorization/authorizer.d.ts +98 -0
  26. package/dist/authorization/authorizer.d.ts.map +1 -0
  27. package/dist/authorization/authorizer.js +156 -0
  28. package/dist/authorization/authorizer.js.map +1 -0
  29. package/dist/authorization/derived-tuples.d.ts +42 -0
  30. package/dist/authorization/derived-tuples.d.ts.map +1 -0
  31. package/dist/authorization/derived-tuples.js +240 -0
  32. package/dist/authorization/derived-tuples.js.map +1 -0
  33. package/dist/authorization/evaluator.d.ts +66 -0
  34. package/dist/authorization/evaluator.d.ts.map +1 -0
  35. package/dist/authorization/evaluator.js +153 -0
  36. package/dist/authorization/evaluator.js.map +1 -0
  37. package/dist/authorization/facts.d.ts +29 -0
  38. package/dist/authorization/facts.d.ts.map +1 -0
  39. package/dist/authorization/facts.js +17 -0
  40. package/dist/authorization/facts.js.map +1 -0
  41. package/dist/authorization/list-read-scope.d.ts +18 -0
  42. package/dist/authorization/list-read-scope.d.ts.map +1 -0
  43. package/dist/authorization/list-read-scope.js +155 -0
  44. package/dist/authorization/list-read-scope.js.map +1 -0
  45. package/dist/authorization/model/agent.d.ts +2 -0
  46. package/dist/authorization/model/agent.d.ts.map +1 -0
  47. package/dist/authorization/model/agent.js +42 -0
  48. package/dist/authorization/model/agent.js.map +1 -0
  49. package/dist/authorization/model/agent_channel.d.ts +2 -0
  50. package/dist/authorization/model/agent_channel.d.ts.map +1 -0
  51. package/dist/authorization/model/agent_channel.js +38 -0
  52. package/dist/authorization/model/agent_channel.js.map +1 -0
  53. package/dist/authorization/model/agent_execution.d.ts +2 -0
  54. package/dist/authorization/model/agent_execution.d.ts.map +1 -0
  55. package/dist/authorization/model/agent_execution.js +25 -0
  56. package/dist/authorization/model/agent_execution.js.map +1 -0
  57. package/dist/authorization/model/agent_instance.d.ts +2 -0
  58. package/dist/authorization/model/agent_instance.d.ts.map +1 -0
  59. package/dist/authorization/model/agent_instance.js +47 -0
  60. package/dist/authorization/model/agent_instance.js.map +1 -0
  61. package/dist/authorization/model/agent_share.d.ts +2 -0
  62. package/dist/authorization/model/agent_share.d.ts.map +1 -0
  63. package/dist/authorization/model/agent_share.js +29 -0
  64. package/dist/authorization/model/agent_share.js.map +1 -0
  65. package/dist/authorization/model/api_key.d.ts +2 -0
  66. package/dist/authorization/model/api_key.d.ts.map +1 -0
  67. package/dist/authorization/model/api_key.js +27 -0
  68. package/dist/authorization/model/api_key.js.map +1 -0
  69. package/dist/authorization/model/artifact.d.ts +2 -0
  70. package/dist/authorization/model/artifact.d.ts.map +1 -0
  71. package/dist/authorization/model/artifact.js +27 -0
  72. package/dist/authorization/model/artifact.js.map +1 -0
  73. package/dist/authorization/model/channel_app.d.ts +2 -0
  74. package/dist/authorization/model/channel_app.d.ts.map +1 -0
  75. package/dist/authorization/model/channel_app.js +28 -0
  76. package/dist/authorization/model/channel_app.js.map +1 -0
  77. package/dist/authorization/model/default-of.d.ts +38 -0
  78. package/dist/authorization/model/default-of.d.ts.map +1 -0
  79. package/dist/authorization/model/default-of.js +39 -0
  80. package/dist/authorization/model/default-of.js.map +1 -0
  81. package/dist/authorization/model/environment.d.ts +2 -0
  82. package/dist/authorization/model/environment.d.ts.map +1 -0
  83. package/dist/authorization/model/environment.js +33 -0
  84. package/dist/authorization/model/environment.js.map +1 -0
  85. package/dist/authorization/model/execution_context.d.ts +2 -0
  86. package/dist/authorization/model/execution_context.d.ts.map +1 -0
  87. package/dist/authorization/model/execution_context.js +19 -0
  88. package/dist/authorization/model/execution_context.js.map +1 -0
  89. package/dist/authorization/model/iam_policy.d.ts +2 -0
  90. package/dist/authorization/model/iam_policy.d.ts.map +1 -0
  91. package/dist/authorization/model/iam_policy.js +31 -0
  92. package/dist/authorization/model/iam_policy.js.map +1 -0
  93. package/dist/authorization/model/identity_account.d.ts +2 -0
  94. package/dist/authorization/model/identity_account.d.ts.map +1 -0
  95. package/dist/authorization/model/identity_account.js +25 -0
  96. package/dist/authorization/model/identity_account.js.map +1 -0
  97. package/dist/authorization/model/index.d.ts +36 -0
  98. package/dist/authorization/model/index.d.ts.map +1 -0
  99. package/dist/authorization/model/index.js +72 -0
  100. package/dist/authorization/model/index.js.map +1 -0
  101. package/dist/authorization/model/mcp_server.d.ts +2 -0
  102. package/dist/authorization/model/mcp_server.d.ts.map +1 -0
  103. package/dist/authorization/model/mcp_server.js +37 -0
  104. package/dist/authorization/model/mcp_server.js.map +1 -0
  105. package/dist/authorization/model/memory.d.ts +2 -0
  106. package/dist/authorization/model/memory.d.ts.map +1 -0
  107. package/dist/authorization/model/memory.js +26 -0
  108. package/dist/authorization/model/memory.js.map +1 -0
  109. package/dist/authorization/model/oauth_app.d.ts +2 -0
  110. package/dist/authorization/model/oauth_app.d.ts.map +1 -0
  111. package/dist/authorization/model/oauth_app.js +30 -0
  112. package/dist/authorization/model/oauth_app.js.map +1 -0
  113. package/dist/authorization/model/organization.d.ts +2 -0
  114. package/dist/authorization/model/organization.d.ts.map +1 -0
  115. package/dist/authorization/model/organization.js +54 -0
  116. package/dist/authorization/model/organization.js.map +1 -0
  117. package/dist/authorization/model/plugin.d.ts +2 -0
  118. package/dist/authorization/model/plugin.d.ts.map +1 -0
  119. package/dist/authorization/model/plugin.js +44 -0
  120. package/dist/authorization/model/plugin.js.map +1 -0
  121. package/dist/authorization/model/project.d.ts +2 -0
  122. package/dist/authorization/model/project.d.ts.map +1 -0
  123. package/dist/authorization/model/project.js +32 -0
  124. package/dist/authorization/model/project.js.map +1 -0
  125. package/dist/authorization/model/rewrite.d.ts +127 -0
  126. package/dist/authorization/model/rewrite.d.ts.map +1 -0
  127. package/dist/authorization/model/rewrite.js +82 -0
  128. package/dist/authorization/model/rewrite.js.map +1 -0
  129. package/dist/authorization/model/schedule.d.ts +2 -0
  130. package/dist/authorization/model/schedule.d.ts.map +1 -0
  131. package/dist/authorization/model/schedule.js +29 -0
  132. package/dist/authorization/model/schedule.js.map +1 -0
  133. package/dist/authorization/model/session.d.ts +2 -0
  134. package/dist/authorization/model/session.d.ts.map +1 -0
  135. package/dist/authorization/model/session.js +38 -0
  136. package/dist/authorization/model/session.js.map +1 -0
  137. package/dist/authorization/model/skill.d.ts +2 -0
  138. package/dist/authorization/model/skill.d.ts.map +1 -0
  139. package/dist/authorization/model/skill.js +38 -0
  140. package/dist/authorization/model/skill.js.map +1 -0
  141. package/dist/authorization/model/workflow.d.ts +2 -0
  142. package/dist/authorization/model/workflow.d.ts.map +1 -0
  143. package/dist/authorization/model/workflow.js +38 -0
  144. package/dist/authorization/model/workflow.js.map +1 -0
  145. package/dist/authorization/model/workflow_execution.d.ts +2 -0
  146. package/dist/authorization/model/workflow_execution.d.ts.map +1 -0
  147. package/dist/authorization/model/workflow_execution.js +32 -0
  148. package/dist/authorization/model/workflow_execution.js.map +1 -0
  149. package/dist/authorization/model/workflow_instance.d.ts +2 -0
  150. package/dist/authorization/model/workflow_instance.d.ts.map +1 -0
  151. package/dist/authorization/model/workflow_instance.js +92 -0
  152. package/dist/authorization/model/workflow_instance.js.map +1 -0
  153. package/dist/authorization/organization-directory.d.ts +13 -0
  154. package/dist/authorization/organization-directory.d.ts.map +1 -0
  155. package/dist/authorization/organization-directory.js +83 -0
  156. package/dist/authorization/organization-directory.js.map +1 -0
  157. package/dist/authorization/person.d.ts +42 -0
  158. package/dist/authorization/person.d.ts.map +1 -0
  159. package/dist/authorization/person.js +19 -0
  160. package/dist/authorization/person.js.map +1 -0
  161. package/dist/authorization/posture.d.ts +38 -0
  162. package/dist/authorization/posture.d.ts.map +1 -0
  163. package/dist/authorization/posture.js +7 -0
  164. package/dist/authorization/posture.js.map +1 -0
  165. package/dist/authorization/schedule-fire-caller.d.ts +12 -0
  166. package/dist/authorization/schedule-fire-caller.d.ts.map +1 -0
  167. package/dist/authorization/schedule-fire-caller.js +67 -0
  168. package/dist/authorization/schedule-fire-caller.js.map +1 -0
  169. package/dist/authorization/store-test-kit.d.ts +68 -0
  170. package/dist/authorization/store-test-kit.d.ts.map +1 -0
  171. package/dist/authorization/store-test-kit.js +311 -0
  172. package/dist/authorization/store-test-kit.js.map +1 -0
  173. package/dist/authorization/tuples.d.ts +115 -0
  174. package/dist/authorization/tuples.d.ts.map +1 -0
  175. package/dist/authorization/tuples.js +83 -0
  176. package/dist/authorization/tuples.js.map +1 -0
  177. package/dist/boot/compose.d.ts.map +1 -1
  178. package/dist/boot/compose.js +157 -32
  179. package/dist/boot/compose.js.map +1 -1
  180. package/dist/boot/inprocess.d.ts +12 -0
  181. package/dist/boot/inprocess.d.ts.map +1 -1
  182. package/dist/boot/inprocess.js +62 -20
  183. package/dist/boot/inprocess.js.map +1 -1
  184. package/dist/domain/agent/controller.d.ts.map +1 -1
  185. package/dist/domain/agent/controller.js +9 -0
  186. package/dist/domain/agent/controller.js.map +1 -1
  187. package/dist/domain/iampolicy/constants.d.ts +11 -0
  188. package/dist/domain/iampolicy/constants.d.ts.map +1 -1
  189. package/dist/domain/iampolicy/constants.js +11 -0
  190. package/dist/domain/iampolicy/constants.js.map +1 -1
  191. package/dist/domain/iampolicy/membership.d.ts +72 -1
  192. package/dist/domain/iampolicy/membership.d.ts.map +1 -1
  193. package/dist/domain/iampolicy/membership.js +141 -56
  194. package/dist/domain/iampolicy/membership.js.map +1 -1
  195. package/dist/domain/identityaccount/actor.d.ts +26 -0
  196. package/dist/domain/identityaccount/actor.d.ts.map +1 -0
  197. package/dist/domain/identityaccount/actor.js +17 -0
  198. package/dist/domain/identityaccount/actor.js.map +1 -0
  199. package/dist/domain/mcpserver/controller.d.ts.map +1 -1
  200. package/dist/domain/mcpserver/controller.js +9 -0
  201. package/dist/domain/mcpserver/controller.js.map +1 -1
  202. package/dist/domain/plugin/archive.d.ts +37 -0
  203. package/dist/domain/plugin/archive.d.ts.map +1 -0
  204. package/dist/domain/plugin/archive.js +50 -0
  205. package/dist/domain/plugin/archive.js.map +1 -0
  206. package/dist/domain/plugin/constants.d.ts +38 -0
  207. package/dist/domain/plugin/constants.d.ts.map +1 -0
  208. package/dist/domain/plugin/constants.js +46 -0
  209. package/dist/domain/plugin/constants.js.map +1 -0
  210. package/dist/domain/plugin/controller.d.ts +25 -0
  211. package/dist/domain/plugin/controller.d.ts.map +1 -0
  212. package/dist/domain/plugin/controller.js +493 -0
  213. package/dist/domain/plugin/controller.js.map +1 -0
  214. package/dist/domain/plugin/materialize/agent.d.ts +13 -0
  215. package/dist/domain/plugin/materialize/agent.d.ts.map +1 -0
  216. package/dist/domain/plugin/materialize/agent.js +128 -0
  217. package/dist/domain/plugin/materialize/agent.js.map +1 -0
  218. package/dist/domain/plugin/materialize/default-agent-instructions.d.ts +22 -0
  219. package/dist/domain/plugin/materialize/default-agent-instructions.d.ts.map +1 -0
  220. package/dist/domain/plugin/materialize/default-agent-instructions.js +31 -0
  221. package/dist/domain/plugin/materialize/default-agent-instructions.js.map +1 -0
  222. package/dist/domain/plugin/materialize/identity.d.ts +28 -0
  223. package/dist/domain/plugin/materialize/identity.d.ts.map +1 -0
  224. package/dist/domain/plugin/materialize/identity.js +40 -0
  225. package/dist/domain/plugin/materialize/identity.js.map +1 -0
  226. package/dist/domain/plugin/materialize/mcp-servers.d.ts +15 -0
  227. package/dist/domain/plugin/materialize/mcp-servers.d.ts.map +1 -0
  228. package/dist/domain/plugin/materialize/mcp-servers.js +131 -0
  229. package/dist/domain/plugin/materialize/mcp-servers.js.map +1 -0
  230. package/dist/domain/plugin/materialize/plan.d.ts +24 -0
  231. package/dist/domain/plugin/materialize/plan.d.ts.map +1 -0
  232. package/dist/domain/plugin/materialize/plan.js +77 -0
  233. package/dist/domain/plugin/materialize/plan.js.map +1 -0
  234. package/dist/domain/plugin/materialize/ports.d.ts +42 -0
  235. package/dist/domain/plugin/materialize/ports.d.ts.map +1 -0
  236. package/dist/domain/plugin/materialize/ports.js +2 -0
  237. package/dist/domain/plugin/materialize/ports.js.map +1 -0
  238. package/dist/domain/plugin/materialize/skills.d.ts +12 -0
  239. package/dist/domain/plugin/materialize/skills.d.ts.map +1 -0
  240. package/dist/domain/plugin/materialize/skills.js +44 -0
  241. package/dist/domain/plugin/materialize/skills.js.map +1 -0
  242. package/dist/domain/plugin/materialize/workflows.d.ts +15 -0
  243. package/dist/domain/plugin/materialize/workflows.d.ts.map +1 -0
  244. package/dist/domain/plugin/materialize/workflows.js +31 -0
  245. package/dist/domain/plugin/materialize/workflows.js.map +1 -0
  246. package/dist/domain/plugin/members.d.ts +42 -0
  247. package/dist/domain/plugin/members.d.ts.map +1 -0
  248. package/dist/domain/plugin/members.js +97 -0
  249. package/dist/domain/plugin/members.js.map +1 -0
  250. package/dist/domain/plugin/overlay/documents.d.ts +31 -0
  251. package/dist/domain/plugin/overlay/documents.d.ts.map +1 -0
  252. package/dist/domain/plugin/overlay/documents.js +38 -0
  253. package/dist/domain/plugin/overlay/documents.js.map +1 -0
  254. package/dist/domain/plugin/overlay/parse.d.ts +16 -0
  255. package/dist/domain/plugin/overlay/parse.d.ts.map +1 -0
  256. package/dist/domain/plugin/overlay/parse.js +79 -0
  257. package/dist/domain/plugin/overlay/parse.js.map +1 -0
  258. package/dist/domain/plugin/overlay/sanitize.d.ts +10 -0
  259. package/dist/domain/plugin/overlay/sanitize.d.ts.map +1 -0
  260. package/dist/domain/plugin/overlay/sanitize.js +101 -0
  261. package/dist/domain/plugin/overlay/sanitize.js.map +1 -0
  262. package/dist/domain/plugin/push.d.ts +133 -0
  263. package/dist/domain/plugin/push.d.ts.map +1 -0
  264. package/dist/domain/plugin/push.js +800 -0
  265. package/dist/domain/plugin/push.js.map +1 -0
  266. package/dist/domain/plugin/search-extractor.d.ts +3 -0
  267. package/dist/domain/plugin/search-extractor.d.ts.map +1 -0
  268. package/dist/domain/plugin/search-extractor.js +41 -0
  269. package/dist/domain/plugin/search-extractor.js.map +1 -0
  270. package/dist/domain/skill/constants.d.ts +6 -11
  271. package/dist/domain/skill/constants.d.ts.map +1 -1
  272. package/dist/domain/skill/constants.js +6 -11
  273. package/dist/domain/skill/constants.js.map +1 -1
  274. package/dist/domain/skill/controller.d.ts.map +1 -1
  275. package/dist/domain/skill/controller.js +33 -30
  276. package/dist/domain/skill/controller.js.map +1 -1
  277. package/dist/domain/skill/push.d.ts +9 -10
  278. package/dist/domain/skill/push.d.ts.map +1 -1
  279. package/dist/domain/skill/push.js +53 -122
  280. package/dist/domain/skill/push.js.map +1 -1
  281. package/dist/domain/skill/search-extractor.d.ts.map +1 -1
  282. package/dist/domain/skill/search-extractor.js.map +1 -1
  283. package/dist/domain/skill/storage/artifact-storage.d.ts +26 -29
  284. package/dist/domain/skill/storage/artifact-storage.d.ts.map +1 -1
  285. package/dist/domain/skill/storage/artifact-storage.js +6 -103
  286. package/dist/domain/skill/storage/artifact-storage.js.map +1 -1
  287. package/dist/domain/skill/storage/zip-gate.d.ts +1 -2
  288. package/dist/domain/skill/storage/zip-gate.d.ts.map +1 -1
  289. package/dist/domain/skill/storage/zip-gate.js +56 -126
  290. package/dist/domain/skill/storage/zip-gate.js.map +1 -1
  291. package/dist/domain/skill/version-resolution.d.ts +5 -5
  292. package/dist/domain/skill/version-resolution.d.ts.map +1 -1
  293. package/dist/domain/skill/version-resolution.js +34 -216
  294. package/dist/domain/skill/version-resolution.js.map +1 -1
  295. package/dist/domain/workflow/controller.d.ts.map +1 -1
  296. package/dist/domain/workflow/controller.js +30 -3
  297. package/dist/domain/workflow/controller.js.map +1 -1
  298. package/dist/domain/workflow/registry/data/task-kind-registry.json +1 -0
  299. package/dist/extensions/authorizer.d.ts +10 -5
  300. package/dist/extensions/authorizer.d.ts.map +1 -1
  301. package/dist/extensions/drivers.d.ts +4 -1
  302. package/dist/extensions/drivers.d.ts.map +1 -1
  303. package/dist/extensions/list-read-scope.d.ts +75 -11
  304. package/dist/extensions/list-read-scope.d.ts.map +1 -1
  305. package/dist/extensions/list-read-scope.js +40 -7
  306. package/dist/extensions/list-read-scope.js.map +1 -1
  307. package/dist/extensions/organization-directory.d.ts +13 -9
  308. package/dist/extensions/organization-directory.d.ts.map +1 -1
  309. package/dist/extensions/organization-directory.js.map +1 -1
  310. package/dist/extensions/resource-authorization.d.ts +33 -0
  311. package/dist/extensions/resource-authorization.d.ts.map +1 -1
  312. package/dist/extensions/schedule-fire-caller.d.ts +45 -18
  313. package/dist/extensions/schedule-fire-caller.d.ts.map +1 -1
  314. package/dist/extensions/schedule-fire-caller.js +12 -1
  315. package/dist/extensions/schedule-fire-caller.js.map +1 -1
  316. package/dist/index.d.ts +10 -0
  317. package/dist/index.d.ts.map +1 -1
  318. package/dist/index.js +8 -0
  319. package/dist/index.js.map +1 -1
  320. package/dist/pipeline/apiresource-labels.d.ts +23 -3
  321. package/dist/pipeline/apiresource-labels.d.ts.map +1 -1
  322. package/dist/pipeline/apiresource-labels.js +20 -0
  323. package/dist/pipeline/apiresource-labels.js.map +1 -1
  324. package/dist/pipeline/apiresource-meta.d.ts +21 -0
  325. package/dist/pipeline/apiresource-meta.d.ts.map +1 -1
  326. package/dist/pipeline/apiresource-meta.js +28 -0
  327. package/dist/pipeline/apiresource-meta.js.map +1 -1
  328. package/dist/pipeline/errors.d.ts.map +1 -1
  329. package/dist/pipeline/errors.js.map +1 -1
  330. package/dist/pipeline/steps/authorization-facts.d.ts +12 -0
  331. package/dist/pipeline/steps/authorization-facts.d.ts.map +1 -0
  332. package/dist/pipeline/steps/authorization-facts.js +100 -0
  333. package/dist/pipeline/steps/authorization-facts.js.map +1 -0
  334. package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
  335. package/dist/pipeline/steps/authorization-tuples.js +7 -26
  336. package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
  337. package/dist/pipeline/steps/delete.d.ts.map +1 -1
  338. package/dist/pipeline/steps/delete.js +1 -1
  339. package/dist/pipeline/steps/delete.js.map +1 -1
  340. package/dist/pipeline/steps/duplicate.d.ts.map +1 -1
  341. package/dist/pipeline/steps/duplicate.js.map +1 -1
  342. package/dist/pipeline/steps/guard-plugin-managed.d.ts +12 -0
  343. package/dist/pipeline/steps/guard-plugin-managed.d.ts.map +1 -0
  344. package/dist/pipeline/steps/guard-plugin-managed.js +96 -0
  345. package/dist/pipeline/steps/guard-plugin-managed.js.map +1 -0
  346. package/dist/pipeline/steps/guard-reserved-labels.d.ts +16 -2
  347. package/dist/pipeline/steps/guard-reserved-labels.d.ts.map +1 -1
  348. package/dist/pipeline/steps/guard-reserved-labels.js +11 -7
  349. package/dist/pipeline/steps/guard-reserved-labels.js.map +1 -1
  350. package/dist/pipeline/steps/helpers.d.ts.map +1 -1
  351. package/dist/pipeline/steps/helpers.js.map +1 -1
  352. package/dist/pipeline/steps/index-search.d.ts.map +1 -1
  353. package/dist/pipeline/steps/index-search.js.map +1 -1
  354. package/dist/pipeline/steps/load-existing.d.ts.map +1 -1
  355. package/dist/pipeline/steps/load-existing.js +1 -1
  356. package/dist/pipeline/steps/load-existing.js.map +1 -1
  357. package/dist/pipeline/steps/references.d.ts +16 -0
  358. package/dist/pipeline/steps/references.d.ts.map +1 -1
  359. package/dist/pipeline/steps/references.js +18 -0
  360. package/dist/pipeline/steps/references.js.map +1 -1
  361. package/dist/pipeline/steps/resolve-artifact-source.d.ts +35 -0
  362. package/dist/pipeline/steps/resolve-artifact-source.d.ts.map +1 -0
  363. package/dist/pipeline/steps/resolve-artifact-source.js +27 -0
  364. package/dist/pipeline/steps/resolve-artifact-source.js.map +1 -0
  365. package/dist/pipeline/steps/server-stamped-reserved-labels.d.ts.map +1 -1
  366. package/dist/pipeline/steps/server-stamped-reserved-labels.js.map +1 -1
  367. package/dist/pipeline/steps/shapes.d.ts +18 -0
  368. package/dist/pipeline/steps/shapes.d.ts.map +1 -1
  369. package/dist/pipeline/steps/shapes.js +29 -0
  370. package/dist/pipeline/steps/shapes.js.map +1 -1
  371. package/dist/pipeline/steps/slug.d.ts.map +1 -1
  372. package/dist/pipeline/steps/slug.js.map +1 -1
  373. package/dist/pipeline/steps/validate-visibility.d.ts +9 -0
  374. package/dist/pipeline/steps/validate-visibility.d.ts.map +1 -1
  375. package/dist/pipeline/steps/validate-visibility.js +6 -1
  376. package/dist/pipeline/steps/validate-visibility.js.map +1 -1
  377. package/dist/pipeline/steps/validation.d.ts.map +1 -1
  378. package/dist/pipeline/steps/validation.js.map +1 -1
  379. package/dist/pipeline/steps/version-archive.d.ts +63 -0
  380. package/dist/pipeline/steps/version-archive.d.ts.map +1 -0
  381. package/dist/pipeline/steps/version-archive.js +129 -0
  382. package/dist/pipeline/steps/version-archive.js.map +1 -0
  383. package/dist/pipeline/steps/version-history.d.ts +49 -0
  384. package/dist/pipeline/steps/version-history.d.ts.map +1 -0
  385. package/dist/pipeline/steps/version-history.js +229 -0
  386. package/dist/pipeline/steps/version-history.js.map +1 -0
  387. package/dist/pipeline/steps/visibility-gates.d.ts +8 -0
  388. package/dist/pipeline/steps/visibility-gates.d.ts.map +1 -1
  389. package/dist/pipeline/steps/visibility-gates.js +7 -2
  390. package/dist/pipeline/steps/visibility-gates.js.map +1 -1
  391. package/dist/query/search/registry.d.ts.map +1 -1
  392. package/dist/query/search/registry.js +2 -0
  393. package/dist/query/search/registry.js.map +1 -1
  394. package/dist/temporal/schedule/run-starter.d.ts +1 -1
  395. package/dist/temporal/schedule/run-starter.d.ts.map +1 -1
  396. package/dist/temporal/schedule/run-starter.js +14 -1
  397. package/dist/temporal/schedule/run-starter.js.map +1 -1
  398. package/package.json +5 -4
  399. package/src/archive/__tests__/archive.test.ts +233 -0
  400. package/src/{domain/skill → archive}/__tests__/prefilter.test.ts +1 -1
  401. package/src/archive/content-store.ts +132 -0
  402. package/src/archive/inflate.ts +107 -0
  403. package/src/archive/limits.ts +42 -0
  404. package/src/archive/open.ts +131 -0
  405. package/src/{domain/skill/storage → archive}/prefilter.ts +5 -0
  406. package/src/archive/write.ts +54 -0
  407. package/src/authorization/README.md +124 -0
  408. package/src/authorization/__tests__/authorizer.test.ts +719 -0
  409. package/src/authorization/__tests__/derived-tuples.test.ts +802 -0
  410. package/src/authorization/__tests__/drivers.ts +70 -0
  411. package/src/authorization/__tests__/evaluator.test.ts +359 -0
  412. package/src/authorization/__tests__/facts.test.ts +155 -0
  413. package/src/authorization/__tests__/fixtures/fga/agent-channel-owner.fga.yaml +112 -0
  414. package/src/authorization/__tests__/fixtures/fga/agent-share-owner.fga.yaml +109 -0
  415. package/src/authorization/__tests__/fixtures/fga/artifact-org-and-owner.fga.yaml +128 -0
  416. package/src/authorization/__tests__/fixtures/fga/blueprint-private-visibility.fga.yaml +410 -0
  417. package/src/authorization/__tests__/fixtures/fga/channel-app-owner.fga.yaml +125 -0
  418. package/src/authorization/__tests__/fixtures/fga/channel-participation.fga.yaml +201 -0
  419. package/src/authorization/__tests__/fixtures/fga/channel-session-visibility.fga.yaml +187 -0
  420. package/src/authorization/__tests__/fixtures/fga/cross-org-share-creation.fga.yaml +98 -0
  421. package/src/authorization/__tests__/fixtures/fga/default-instance-inheritance.fga.yaml +271 -0
  422. package/src/authorization/__tests__/fixtures/fga/memory-subject-only.fga.yaml +72 -0
  423. package/src/authorization/__tests__/fixtures/fga/org-admin-owner-inheritance.fga.yaml +328 -0
  424. package/src/authorization/__tests__/fixtures/fga/org-shared-environment.fga.yaml +144 -0
  425. package/src/authorization/__tests__/fixtures/fga/platform-visibility.fga.yaml +223 -0
  426. package/src/authorization/__tests__/fixtures/fga/provider-standing-viewer.fga.yaml +40 -0
  427. package/src/authorization/__tests__/fixtures/fga/public-visibility-setter.fga.yaml +52 -0
  428. package/src/authorization/__tests__/fixtures/fga/reserved-label-writer.fga.yaml +41 -0
  429. package/src/authorization/__tests__/fixtures/fga/schedule-owner.fga.yaml +113 -0
  430. package/src/authorization/__tests__/fixtures/fga/schedule-session-visibility.fga.yaml +214 -0
  431. package/src/authorization/__tests__/fixtures/fga/session-personal-resource.fga.yaml +117 -0
  432. package/src/authorization/__tests__/fixtures/fga/workflow-execution-sharing.fga.yaml +192 -0
  433. package/src/authorization/__tests__/list-read-scope.measure.test.ts +317 -0
  434. package/src/authorization/__tests__/list-read-scope.test.ts +796 -0
  435. package/src/authorization/__tests__/organization-directory.test.ts +236 -0
  436. package/src/authorization/__tests__/person.test.ts +114 -0
  437. package/src/authorization/__tests__/posture.test.ts +25 -0
  438. package/src/authorization/__tests__/schedule-fire-caller.test.ts +134 -0
  439. package/src/authorization/__tests__/store-tests.test.ts +306 -0
  440. package/src/authorization/__tests__/support.ts +101 -0
  441. package/src/authorization/__tests__/tuples.test.ts +62 -0
  442. package/src/authorization/__tests__/wire-permissions.test.ts +154 -0
  443. package/src/authorization/authorizer.ts +208 -0
  444. package/src/authorization/derived-tuples.ts +384 -0
  445. package/src/authorization/evaluator.ts +283 -0
  446. package/src/authorization/facts.ts +47 -0
  447. package/src/authorization/list-read-scope.ts +216 -0
  448. package/src/authorization/model/__tests__/registry.test.ts +317 -0
  449. package/src/authorization/model/agent.ts +64 -0
  450. package/src/authorization/model/agent_channel.ts +49 -0
  451. package/src/authorization/model/agent_execution.ts +33 -0
  452. package/src/authorization/model/agent_instance.ts +66 -0
  453. package/src/authorization/model/agent_share.ts +40 -0
  454. package/src/authorization/model/api_key.ts +28 -0
  455. package/src/authorization/model/artifact.ts +38 -0
  456. package/src/authorization/model/channel_app.ts +39 -0
  457. package/src/authorization/model/default-of.ts +99 -0
  458. package/src/authorization/model/environment.ts +48 -0
  459. package/src/authorization/model/execution_context.ts +20 -0
  460. package/src/authorization/model/iam_policy.ts +42 -0
  461. package/src/authorization/model/identity_account.ts +26 -0
  462. package/src/authorization/model/index.ts +108 -0
  463. package/src/authorization/model/mcp_server.ts +59 -0
  464. package/src/authorization/model/memory.ts +27 -0
  465. package/src/authorization/model/oauth_app.ts +42 -0
  466. package/src/authorization/model/organization.ts +55 -0
  467. package/src/authorization/model/plugin.ts +66 -0
  468. package/src/authorization/model/project.ts +47 -0
  469. package/src/authorization/model/rewrite.ts +213 -0
  470. package/src/authorization/model/schedule.ts +40 -0
  471. package/src/authorization/model/session.ts +50 -0
  472. package/src/authorization/model/skill.ts +60 -0
  473. package/src/authorization/model/workflow.ts +60 -0
  474. package/src/authorization/model/workflow_execution.ts +44 -0
  475. package/src/authorization/model/workflow_instance.ts +122 -0
  476. package/src/authorization/organization-directory.ts +114 -0
  477. package/src/authorization/person.ts +68 -0
  478. package/src/authorization/posture.ts +49 -0
  479. package/src/authorization/schedule-fire-caller.ts +91 -0
  480. package/src/authorization/store-test-kit.ts +454 -0
  481. package/src/authorization/tuples.ts +190 -0
  482. package/src/boot/compose.ts +175 -38
  483. package/src/boot/inprocess.ts +108 -30
  484. package/src/domain/agent/controller.ts +11 -0
  485. package/src/domain/iampolicy/__tests__/membership.test.ts +357 -3
  486. package/src/domain/iampolicy/constants.ts +12 -0
  487. package/src/domain/iampolicy/membership.ts +221 -66
  488. package/src/domain/identityaccount/actor.ts +44 -0
  489. package/src/domain/mcpserver/controller.ts +11 -0
  490. package/src/domain/plugin/__tests__/materialize.test.ts +303 -0
  491. package/src/domain/plugin/__tests__/overlay-parse.test.ts +85 -0
  492. package/src/domain/plugin/__tests__/plugin.test.ts +681 -0
  493. package/src/domain/plugin/__tests__/sanitize.test.ts +174 -0
  494. package/src/domain/plugin/archive.ts +89 -0
  495. package/src/domain/plugin/constants.ts +53 -0
  496. package/src/domain/plugin/controller.ts +913 -0
  497. package/src/domain/plugin/materialize/agent.ts +186 -0
  498. package/src/domain/plugin/materialize/default-agent-instructions.ts +59 -0
  499. package/src/domain/plugin/materialize/identity.ts +67 -0
  500. package/src/domain/plugin/materialize/mcp-servers.ts +175 -0
  501. package/src/domain/plugin/materialize/plan.ts +124 -0
  502. package/src/domain/plugin/materialize/ports.ts +53 -0
  503. package/src/domain/plugin/materialize/skills.ts +68 -0
  504. package/src/domain/plugin/materialize/workflows.ts +51 -0
  505. package/src/domain/plugin/members.ts +180 -0
  506. package/src/domain/plugin/overlay/documents.ts +78 -0
  507. package/src/domain/plugin/overlay/parse.ts +115 -0
  508. package/src/domain/plugin/overlay/sanitize.ts +149 -0
  509. package/src/domain/plugin/push.ts +1062 -0
  510. package/src/domain/plugin/search-extractor.ts +60 -0
  511. package/src/domain/skill/constants.ts +11 -14
  512. package/src/domain/skill/controller.ts +44 -36
  513. package/src/domain/skill/push.ts +61 -156
  514. package/src/domain/skill/search-extractor.ts +3 -1
  515. package/src/domain/skill/storage/artifact-storage.ts +23 -124
  516. package/src/domain/skill/storage/zip-gate.ts +58 -154
  517. package/src/domain/skill/version-resolution.ts +67 -269
  518. package/src/domain/workflow/controller.ts +38 -4
  519. package/src/domain/workflow/registry/data/task-kind-registry.json +1 -0
  520. package/src/extensions/__tests__/built-in-authorization-composed.test.ts +835 -0
  521. package/src/extensions/__tests__/composed-support.ts +32 -1
  522. package/src/extensions/__tests__/extension-composition.test.ts +35 -0
  523. package/src/extensions/__tests__/list-read-scope.test.ts +245 -3
  524. package/src/extensions/__tests__/role-reconciliation-composed.test.ts +209 -0
  525. package/src/extensions/__tests__/tier-truthfulness.test.ts +6 -14
  526. package/src/extensions/authorizer.ts +10 -5
  527. package/src/extensions/drivers.ts +4 -1
  528. package/src/extensions/list-read-scope.ts +116 -16
  529. package/src/extensions/organization-directory.ts +13 -9
  530. package/src/extensions/resource-authorization.ts +34 -0
  531. package/src/extensions/schedule-fire-caller.ts +49 -18
  532. package/src/index.ts +51 -1
  533. package/src/pipeline/__tests__/inherited-authorization-parent.test.ts +51 -0
  534. package/src/pipeline/__tests__/router-transport.test.ts +1 -3
  535. package/src/pipeline/apiresource-labels.ts +31 -3
  536. package/src/pipeline/apiresource-meta.ts +37 -0
  537. package/src/pipeline/errors.ts +5 -5
  538. package/src/pipeline/steps/__tests__/authorize-annotation-completeness.test.ts +1 -20
  539. package/src/pipeline/steps/__tests__/guard-memory-capture.test.ts +3 -9
  540. package/src/pipeline/steps/__tests__/guard-plugin-managed.test.ts +151 -0
  541. package/src/pipeline/steps/__tests__/guard-reserved-labels.test.ts +83 -8
  542. package/src/pipeline/steps/authorization-facts.ts +131 -0
  543. package/src/pipeline/steps/authorization-tuples.ts +7 -28
  544. package/src/pipeline/steps/delete.ts +11 -3
  545. package/src/pipeline/steps/duplicate.ts +8 -2
  546. package/src/pipeline/steps/guard-plugin-managed.ts +133 -0
  547. package/src/pipeline/steps/guard-reserved-labels.ts +29 -8
  548. package/src/pipeline/steps/helpers.ts +4 -1
  549. package/src/pipeline/steps/index-search.ts +28 -15
  550. package/src/pipeline/steps/load-existing.ts +12 -3
  551. package/src/pipeline/steps/references.ts +36 -2
  552. package/src/pipeline/steps/resolve-artifact-source.ts +66 -0
  553. package/src/pipeline/steps/server-stamped-reserved-labels.ts +2 -1
  554. package/src/pipeline/steps/shapes.ts +31 -0
  555. package/src/pipeline/steps/slug.ts +7 -2
  556. package/src/pipeline/steps/validate-visibility.ts +9 -2
  557. package/src/pipeline/steps/validation.ts +3 -1
  558. package/src/pipeline/steps/version-archive.ts +225 -0
  559. package/src/pipeline/steps/version-history.ts +362 -0
  560. package/src/pipeline/steps/visibility-gates.ts +12 -9
  561. package/src/query/README.md +1 -1
  562. package/src/query/search/__tests__/criteria.test.ts +6 -7
  563. package/src/query/search/__tests__/query-store.test.ts +9 -2
  564. package/src/query/search/__tests__/registry.test.ts +6 -4
  565. package/src/query/search/registry.ts +6 -1
  566. package/src/temporal/schedule/__tests__/run-starter.test.ts +86 -24
  567. package/src/temporal/schedule/run-starter.ts +31 -8
  568. package/dist/domain/skill/storage/prefilter.d.ts.map +0 -1
  569. package/dist/domain/skill/storage/prefilter.js.map +0 -1
  570. /package/dist/{domain/skill/storage → archive}/prefilter.js +0 -0
@@ -0,0 +1,1062 @@
1
+ /**
2
+ * Plugin push pipeline — the steps that turn a PushPluginRequest into an
3
+ * installed plugin, in two chains the controller runs back to back over
4
+ * one request context:
5
+ *
6
+ * plan: Authorize → ValidateProto → ResolveArtifactSource →
7
+ * GateAndHashArchive → ReadPluginPackage → BuildInitialPlugin →
8
+ * FindExistingBySlug → GenerateIDIfNeeded → ParseOverlayDocuments →
9
+ * SanitizePluginMetadata → PlanMaterialization →
10
+ * GuardPluginVisibility → ResolveConvergence
11
+ * install: CheckAndStoreArtifact → PopulatePluginFields →
12
+ * ArchiveCurrentPlugin → StorePlugin (INSTALLING) →
13
+ * MaterializeMembers → RemoveDroppedMembers →
14
+ * FinalizePluginStatus → StorePlugin → PluginPushAuthorizationTuples →
15
+ * IndexPluginSearch
16
+ *
17
+ * The split is the apply chain's shape (plan, then branch): when the plan
18
+ * chain finds the stored plugin already converged on this archive (same
19
+ * digest, READY, every member present and stamped with it) the controller
20
+ * returns the head and the install chain never runs, so a re-push writes
21
+ * nothing. Everything that can refuse — the archive, the package, the
22
+ * overlay, a reserved label, a held slug, a missing permission, the level
23
+ * — refuses in the plan chain BEFORE any write; the install chain's own
24
+ * failures are a child's, wrapped with the plugin's name, and leave a head
25
+ * that says FAILED so the next push of the same archive converges.
26
+ *
27
+ * Skill push is the precedent (domain/skill/push.ts): content addressing,
28
+ * repoint-never-duplicate, the audit tag as the single holder, non-
29
+ * transactional materialisation that a retry converges. What is a
30
+ * plugin's: the library reads the package, the plan is checked whole
31
+ * before the first child write, and every child is written through the
32
+ * in-process lane as the installing caller.
33
+ *
34
+ * Proven by __tests__/plugin.test.ts (composed-server round-trips) and the
35
+ * plugin conformance suite.
36
+ */
37
+ import { create } from "@bufbuild/protobuf";
38
+
39
+ import type { PluginFinding, PluginPackage } from "@stigmer/plugin-package";
40
+ import { readPluginPackage } from "@stigmer/plugin-package";
41
+ import { PluginSchema } from "@stigmer/protos/ai/stigmer/agentic/plugin/v1/api_pb";
42
+ import type { Plugin } from "@stigmer/protos/ai/stigmer/agentic/plugin/v1/api_pb";
43
+ import type { PushPluginRequestSchema } from "@stigmer/protos/ai/stigmer/agentic/plugin/v1/io_pb";
44
+ import {
45
+ PluginAuthorSchema,
46
+ PluginDialect,
47
+ PluginSpecSchema,
48
+ } from "@stigmer/protos/ai/stigmer/agentic/plugin/v1/spec_pb";
49
+ import {
50
+ PluginMaterializationSchema,
51
+ PluginState,
52
+ PluginStatusSchema,
53
+ PluginWarningSchema,
54
+ } from "@stigmer/protos/ai/stigmer/agentic/plugin/v1/status_pb";
55
+ import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
56
+ import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
57
+ import {
58
+ ApiResourceMetadataSchema,
59
+ ApiResourceMetadataVersionSchema,
60
+ } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
61
+ import { ApiResourceAuditSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/status_pb";
62
+ import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
63
+ import { Code, ConnectError } from "@connectrpc/connect";
64
+
65
+ import type { Logger } from "../../boot/logger.js";
66
+ import type { ContentAddressedArchiveStore } from "../../archive/content-store.js";
67
+ import type { Authorizer } from "../../extensions/authorizer.js";
68
+ import type { ResourceAuthorizationLifecycle } from "../../extensions/resource-authorization.js";
69
+ import {
70
+ defaultVisibilityFor,
71
+ getIdPrefix,
72
+ } from "../../pipeline/apiresource-meta.js";
73
+ import {
74
+ alreadyExistsError,
75
+ internalError,
76
+ invalidArgumentError,
77
+ } from "../../pipeline/errors.js";
78
+ import type { PipelineStep } from "../../pipeline/pipeline.js";
79
+ import type { RequestContext } from "../../pipeline/request-context.js";
80
+ import {
81
+ diffVisibilityShapes,
82
+ resolveResourceCreatedEvent,
83
+ } from "../../pipeline/steps/authorization-tuples.js";
84
+ import {
85
+ generateId,
86
+ setAuditFieldsForCreate,
87
+ setAuditFieldsForUpdate,
88
+ } from "../../pipeline/steps/defaults.js";
89
+ import { findResourceBySlug } from "../../pipeline/steps/helpers.js";
90
+ import { ARTIFACT_BYTES_KEY } from "../../pipeline/steps/resolve-artifact-source.js";
91
+ import { generateSlug } from "../../pipeline/steps/slug.js";
92
+ import { rejectUnsupportedVisibility } from "../../pipeline/steps/validate-visibility.js";
93
+ import { newArchiveCurrentVersionStep } from "../../pipeline/steps/version-archive.js";
94
+ import { requireOperatorMaySetPublic } from "../../pipeline/steps/visibility-gates.js";
95
+ import { ResourceNotFoundError } from "../../store/interface.js";
96
+ import type { Store } from "../../store/interface.js";
97
+ import { openPluginArchive } from "./archive.js";
98
+ import { VERSION_TAG_PATTERN } from "./constants.js";
99
+ import type { OpenedPluginArchive } from "./archive.js";
100
+ import type { PluginIdentity } from "./materialize/identity.js";
101
+ import { McpServerOverlayError } from "./materialize/mcp-servers.js";
102
+ import { planMaterialization } from "./materialize/plan.js";
103
+ import type { MaterializationPlan } from "./materialize/plan.js";
104
+ import type { PluginMaterializerProvider } from "./materialize/ports.js";
105
+ import {
106
+ droppedMembers,
107
+ findMembers,
108
+ membersConverge,
109
+ slugHolder,
110
+ } from "./members.js";
111
+ import type { Member } from "./members.js";
112
+ import { parseOverlays } from "./overlay/documents.js";
113
+ import type { ParsedOverlays } from "./overlay/documents.js";
114
+ import { OverlayParseError } from "./overlay/parse.js";
115
+ import { sanitizeOverlays } from "./overlay/sanitize.js";
116
+ import { pluginSearchExtractor } from "./search-extractor.js";
117
+
118
+ type PushDesc = typeof PushPluginRequestSchema;
119
+
120
+ // Context keys for the push operation.
121
+ export const PLUGIN_KEY = "plugin";
122
+ export const PLUGIN_ARCHIVE_KEY = "pluginArchive";
123
+ export const PLUGIN_PACKAGE_KEY = "pluginPackage";
124
+ export const PLUGIN_LIBRARY_WARNINGS_KEY = "pluginLibraryWarnings";
125
+ export const EXISTING_PLUGIN_KEY = "existingPlugin";
126
+ export const SHOULD_CREATE_PLUGIN_KEY = "shouldCreatePlugin";
127
+ export const PLUGIN_OVERLAYS_KEY = "pluginOverlays";
128
+ export const PLUGIN_PLAN_KEY = "pluginPlan";
129
+ export const EXISTING_MEMBERS_KEY = "pluginExistingMembers";
130
+ export const PLUGIN_CONVERGED_KEY = "pluginConverged";
131
+ export const ARTIFACT_STORAGE_KEY_KEY = "artifactStorageKey";
132
+
133
+ /**
134
+ * GateAndHashArchive — the ZIP gate over the shared archive plumbing:
135
+ * size ceiling, hash, prefilter, structural budgets, and the lazy reader
136
+ * the library reads through. Every gate failure is one InvalidArgument arm.
137
+ */
138
+ export function newGateAndHashArchiveStep(): PipelineStep<PushDesc> {
139
+ return {
140
+ name: "GateAndHashArchive",
141
+ execute(ctx: RequestContext<PushDesc>): void {
142
+ const bytes = ctx.get(ARTIFACT_BYTES_KEY) as Uint8Array;
143
+ let archive: OpenedPluginArchive;
144
+ try {
145
+ archive = openPluginArchive(bytes);
146
+ } catch (error) {
147
+ throw invalidArgumentError(
148
+ `failed to read plugin archive: ${error instanceof Error ? error.message : String(error)}`,
149
+ );
150
+ }
151
+ ctx.set(PLUGIN_ARCHIVE_KEY, archive);
152
+ },
153
+ };
154
+ }
155
+
156
+ /**
157
+ * ReadPluginPackage — the library reads the package; a refusal lists every
158
+ * problem in the sentences `stigmer validate -f` prints, so an author who
159
+ * skipped the offline check reads the same words here.
160
+ */
161
+ export function newReadPluginPackageStep(): PipelineStep<PushDesc> {
162
+ return {
163
+ name: "ReadPluginPackage",
164
+ execute(ctx: RequestContext<PushDesc>): void {
165
+ const archive = ctx.get(PLUGIN_ARCHIVE_KEY) as OpenedPluginArchive;
166
+ let outcome;
167
+ try {
168
+ outcome = readPluginPackage(archive.files);
169
+ } catch (error) {
170
+ // The reader's own throw: an entry that failed to inflate.
171
+ throw invalidArgumentError(
172
+ `failed to read plugin archive: ${error instanceof Error ? error.message : String(error)}`,
173
+ );
174
+ }
175
+ if (!outcome.ok) {
176
+ const count = outcome.errors.length;
177
+ throw invalidArgumentError(
178
+ `plugin cannot be installed, ${count} problem${count === 1 ? "" : "s"} found:\n` +
179
+ outcome.errors
180
+ .map((finding) => ` - ${finding.message}`)
181
+ .join("\n"),
182
+ );
183
+ }
184
+ ctx.set(PLUGIN_PACKAGE_KEY, outcome.plugin);
185
+ ctx.set(PLUGIN_LIBRARY_WARNINGS_KEY, outcome.warnings);
186
+ },
187
+ };
188
+ }
189
+
190
+ /**
191
+ * BuildInitialPlugin — the scaffold: org from the request, name and slug
192
+ * from the manifest. The id and every status field come later.
193
+ */
194
+ export function newBuildInitialPluginStep(): PipelineStep<PushDesc> {
195
+ return {
196
+ name: "BuildInitialPlugin",
197
+ execute(ctx: RequestContext<PushDesc>): void {
198
+ const pkg = ctx.get(PLUGIN_PACKAGE_KEY) as PluginPackage;
199
+ const slug = generateSlug(pkg.name);
200
+ if (slug === "") {
201
+ throw invalidArgumentError(`invalid plugin name: ${pkg.name}`);
202
+ }
203
+ const plugin = create(PluginSchema, {
204
+ apiVersion: "agentic.stigmer.ai/v1",
205
+ kind: "Plugin",
206
+ metadata: create(ApiResourceMetadataSchema, {
207
+ org: ctx.input.org,
208
+ name: pkg.name,
209
+ slug,
210
+ }),
211
+ spec: create(PluginSpecSchema, {}),
212
+ status: create(PluginStatusSchema, {}),
213
+ });
214
+ ctx.set(PLUGIN_KEY, plugin);
215
+ },
216
+ };
217
+ }
218
+
219
+ /** FindExistingBySlug — push is upsert-by-slug: an existing plugin's id is adopted. */
220
+ export function newFindExistingPluginBySlugStep(
221
+ store: Store,
222
+ ): PipelineStep<PushDesc> {
223
+ return {
224
+ name: "FindExistingBySlug",
225
+ async execute(ctx: RequestContext<PushDesc>): Promise<void> {
226
+ const plugin = ctx.get(PLUGIN_KEY) as Plugin;
227
+ let existing: Plugin | undefined;
228
+ try {
229
+ existing = await findResourceBySlug(
230
+ store,
231
+ ctx.apiResourceKind,
232
+ PluginSchema,
233
+ plugin.metadata!.slug,
234
+ plugin.metadata!.org,
235
+ );
236
+ } catch (error) {
237
+ throw internalError(error, "failed to search for existing plugin");
238
+ }
239
+ if (existing !== undefined) {
240
+ plugin.metadata!.id = existing.metadata!.id;
241
+ ctx.set(EXISTING_PLUGIN_KEY, existing);
242
+ ctx.set(SHOULD_CREATE_PLUGIN_KEY, false);
243
+ } else {
244
+ ctx.set(EXISTING_PLUGIN_KEY, undefined);
245
+ ctx.set(SHOULD_CREATE_PLUGIN_KEY, true);
246
+ }
247
+ },
248
+ };
249
+ }
250
+
251
+ /** GenerateIDIfNeeded — plg_{ulid} for new plugins; upgrades keep theirs. */
252
+ export function newGeneratePluginIdIfNeededStep(): PipelineStep<PushDesc> {
253
+ return {
254
+ name: "GenerateIDIfNeeded",
255
+ execute(ctx: RequestContext<PushDesc>): void {
256
+ const plugin = ctx.get(PLUGIN_KEY) as Plugin;
257
+ if (ctx.get(SHOULD_CREATE_PLUGIN_KEY) as boolean) {
258
+ plugin.metadata!.id = generateId(getIdPrefix(ctx.apiResourceKind));
259
+ }
260
+ },
261
+ };
262
+ }
263
+
264
+ /** ParseOverlayDocuments — the `ai.stigmer/` documents become protos, strictly. */
265
+ export function newParseOverlayDocumentsStep(): PipelineStep<PushDesc> {
266
+ return {
267
+ name: "ParseOverlayDocuments",
268
+ execute(ctx: RequestContext<PushDesc>): void {
269
+ const pkg = ctx.get(PLUGIN_PACKAGE_KEY) as PluginPackage;
270
+ try {
271
+ ctx.set(PLUGIN_OVERLAYS_KEY, parseOverlays(pkg.overlay, ctx.input.org));
272
+ } catch (error) {
273
+ if (error instanceof OverlayParseError) {
274
+ throw invalidArgumentError(error.message);
275
+ }
276
+ throw error;
277
+ }
278
+ },
279
+ };
280
+ }
281
+
282
+ /** SanitizePluginMetadata — what an overlay author may not say (overlay/sanitize.ts). */
283
+ export function newSanitizePluginMetadataStep(
284
+ authorizer: Authorizer,
285
+ ): PipelineStep<PushDesc> {
286
+ return {
287
+ name: "SanitizePluginMetadata",
288
+ async execute(ctx: RequestContext<PushDesc>): Promise<void> {
289
+ const pkg = ctx.get(PLUGIN_PACKAGE_KEY) as PluginPackage;
290
+ const overlays = ctx.get(PLUGIN_OVERLAYS_KEY) as ParsedOverlays;
291
+ await sanitizeOverlays(
292
+ overlays,
293
+ { pluginName: pkg.name },
294
+ authorizer,
295
+ ctx.callerIdentity,
296
+ );
297
+ },
298
+ };
299
+ }
300
+
301
+ /**
302
+ * The create permission each member kind's own chain will evaluate for the
303
+ * caller, checked here first so a missing one is a sentence before any
304
+ * write. MCP server create carries `is_skip_authorization` in its
305
+ * contract (mcpserver/v1/command.proto), so it has no row.
306
+ */
307
+ const MEMBER_CREATE_PERMISSIONS: ReadonlyMap<ApiResourceKind, IamPermission> =
308
+ new Map([
309
+ [ApiResourceKind.skill, IamPermission.can_create_skill],
310
+ [ApiResourceKind.agent, IamPermission.can_create_agent],
311
+ [ApiResourceKind.workflow, IamPermission.can_create_workflow],
312
+ ]);
313
+
314
+ /** The plugin as its members see it, from the head and the archive. */
315
+ export function identityOf(
316
+ plugin: Plugin,
317
+ digest: string,
318
+ visibility: ApiResourceVisibility,
319
+ ): PluginIdentity {
320
+ return {
321
+ org: plugin.metadata!.org,
322
+ id: plugin.metadata!.id,
323
+ slug: plugin.metadata!.slug,
324
+ name: plugin.metadata!.name,
325
+ digest,
326
+ visibility,
327
+ };
328
+ }
329
+
330
+ /** The level this push installs at: the request's, or the kind's default. */
331
+ export function requestedVisibility(
332
+ ctx: RequestContext<PushDesc>,
333
+ ): ApiResourceVisibility {
334
+ return ctx.input.visibility ===
335
+ ApiResourceVisibility.api_resource_visibility_unspecified
336
+ ? defaultVisibilityFor(ctx.apiResourceKind)
337
+ : ctx.input.visibility;
338
+ }
339
+
340
+ /**
341
+ * PlanMaterialization — everything the push will write, checked whole:
342
+ * every child slug against the organization (free, ours, or refused
343
+ * naming the holder), the caller's permission for every member kind, and
344
+ * the plugin's current members for the convergence and drop decisions.
345
+ */
346
+ export function newPlanMaterializationStep(
347
+ store: Store,
348
+ authorizer: Authorizer,
349
+ ): PipelineStep<PushDesc> {
350
+ return {
351
+ name: "PlanMaterialization",
352
+ async execute(ctx: RequestContext<PushDesc>): Promise<void> {
353
+ const plugin = ctx.get(PLUGIN_KEY) as Plugin;
354
+ const pkg = ctx.get(PLUGIN_PACKAGE_KEY) as PluginPackage;
355
+ const archive = ctx.get(PLUGIN_ARCHIVE_KEY) as OpenedPluginArchive;
356
+ const overlays = ctx.get(PLUGIN_OVERLAYS_KEY) as ParsedOverlays;
357
+ const identity = identityOf(
358
+ plugin,
359
+ archive.digest,
360
+ requestedVisibility(ctx),
361
+ );
362
+
363
+ let plan: MaterializationPlan;
364
+ try {
365
+ plan = planMaterialization(
366
+ pkg,
367
+ archive.files,
368
+ overlays,
369
+ identity,
370
+ ctx.input.message,
371
+ );
372
+ } catch (error) {
373
+ if (error instanceof McpServerOverlayError) {
374
+ throw invalidArgumentError(error.message);
375
+ }
376
+ throw error;
377
+ }
378
+
379
+ for (const member of plan.members) {
380
+ let holder;
381
+ try {
382
+ holder = await slugHolder(store, member, identity.org);
383
+ } catch (error) {
384
+ throw internalError(error, "failed to check a member slug");
385
+ }
386
+ if (!holder.held || holder.byPlugin === identity.id) {
387
+ continue;
388
+ }
389
+ const noun = memberNoun(member.kind);
390
+ if (holder.byPlugin === undefined) {
391
+ throw alreadyExistsError(
392
+ noun,
393
+ `'${member.slug}' exists in org '${identity.org}' and is not managed by a plugin; rename or delete it first`,
394
+ );
395
+ }
396
+ throw alreadyExistsError(
397
+ noun,
398
+ `'${member.slug}' is held by plugin '${await pluginSlugOf(store, holder.byPlugin)}'`,
399
+ );
400
+ }
401
+
402
+ const missing: string[] = [];
403
+ for (const kind of new Set(plan.members.map((member) => member.kind))) {
404
+ const permission = MEMBER_CREATE_PERMISSIONS.get(kind);
405
+ if (permission === undefined) {
406
+ continue;
407
+ }
408
+ let decision;
409
+ try {
410
+ decision = await authorizer.authorize(ctx.callerIdentity, {
411
+ permission,
412
+ resourceKind: ApiResourceKind.organization,
413
+ resourceId: identity.org,
414
+ });
415
+ } catch (error) {
416
+ throw internalError(
417
+ error,
418
+ "plugin install authorization could not be completed",
419
+ );
420
+ }
421
+ switch (decision.kind) {
422
+ case "allow":
423
+ break;
424
+ case "deny":
425
+ case "not-found":
426
+ missing.push(IamPermission[permission] ?? String(permission));
427
+ break;
428
+ case "unavailable":
429
+ throw internalError(
430
+ decision.cause,
431
+ "plugin install authorization could not be completed",
432
+ );
433
+ default: {
434
+ const exhaustive: never = decision;
435
+ throw internalError(
436
+ new Error(`unknown decision ${JSON.stringify(exhaustive)}`),
437
+ "plugin install authorization could not be completed",
438
+ );
439
+ }
440
+ }
441
+ }
442
+ if (missing.length > 0) {
443
+ throw new ConnectError(
444
+ `installing plugin '${identity.slug}' needs ${missing.join(", ")} in organization '${identity.org}'`,
445
+ Code.PermissionDenied,
446
+ );
447
+ }
448
+
449
+ let members: Member[];
450
+ try {
451
+ members = await findMembers(store, identity.id, identity.org);
452
+ } catch (error) {
453
+ throw internalError(error, "failed to list plugin members");
454
+ }
455
+ ctx.set(PLUGIN_PLAN_KEY, plan);
456
+ ctx.set(EXISTING_MEMBERS_KEY, members);
457
+ },
458
+ };
459
+ }
460
+
461
+ /**
462
+ * GuardPluginVisibility — the requested level must be one the plugin and
463
+ * every planned member kind support, and PUBLIC needs the operator grant
464
+ * (the one owner of that question, shared with every other create door).
465
+ * Each member's own chain will check again in-process; refusing here keeps
466
+ * the head from being written before the answer is known.
467
+ */
468
+ export function newGuardPluginVisibilityStep(
469
+ authorizer: Authorizer,
470
+ ): PipelineStep<PushDesc> {
471
+ return {
472
+ name: "GuardPluginVisibility",
473
+ async execute(ctx: RequestContext<PushDesc>): Promise<void> {
474
+ const level = requestedVisibility(ctx);
475
+ const plan = ctx.get(PLUGIN_PLAN_KEY) as MaterializationPlan;
476
+ rejectUnsupportedVisibility(ctx.apiResourceKind, level);
477
+ for (const kind of new Set(plan.members.map((member) => member.kind))) {
478
+ rejectUnsupportedVisibility(kind, level);
479
+ }
480
+ if (level !== ApiResourceVisibility.visibility_public) {
481
+ return;
482
+ }
483
+ if (ctx.callerIdentity.callerClass === "internal") {
484
+ return;
485
+ }
486
+ await requireOperatorMaySetPublic(authorizer, ctx.callerIdentity);
487
+ },
488
+ };
489
+ }
490
+
491
+ /**
492
+ * ResolveConvergence — the no-op decision: the stored plugin already IS
493
+ * this archive when its digest matches, it is READY, and every planned
494
+ * member exists stamped with the digest. Anything less installs.
495
+ */
496
+ export function newResolveConvergenceStep(): PipelineStep<PushDesc> {
497
+ return {
498
+ name: "ResolveConvergence",
499
+ execute(ctx: RequestContext<PushDesc>): void {
500
+ const existing = ctx.get(EXISTING_PLUGIN_KEY) as Plugin | undefined;
501
+ const archive = ctx.get(PLUGIN_ARCHIVE_KEY) as OpenedPluginArchive;
502
+ const plan = ctx.get(PLUGIN_PLAN_KEY) as MaterializationPlan;
503
+ const members = ctx.get(EXISTING_MEMBERS_KEY) as Member[];
504
+ const converged =
505
+ existing !== undefined &&
506
+ existing.status?.digest === archive.digest &&
507
+ existing.status.state === PluginState.READY &&
508
+ (existing.metadata?.visibility ??
509
+ ApiResourceVisibility.api_resource_visibility_unspecified) ===
510
+ requestedVisibility(ctx) &&
511
+ membersConverge(members, plan.members, archive.digest);
512
+ ctx.set(PLUGIN_CONVERGED_KEY, converged);
513
+ },
514
+ };
515
+ }
516
+
517
+ /** CheckAndStoreArtifact — content-addressed dedupe: same digest reuses the stored copy. */
518
+ export function newCheckAndStoreArtifactStep(
519
+ artifactStorage: ContentAddressedArchiveStore,
520
+ ): PipelineStep<PushDesc> {
521
+ return {
522
+ name: "CheckAndStoreArtifact",
523
+ async execute(ctx: RequestContext<PushDesc>): Promise<void> {
524
+ const bytes = ctx.get(ARTIFACT_BYTES_KEY) as Uint8Array;
525
+ const archive = ctx.get(PLUGIN_ARCHIVE_KEY) as OpenedPluginArchive;
526
+ let exists: boolean;
527
+ try {
528
+ exists = await artifactStorage.exists(archive.digest);
529
+ } catch (error) {
530
+ throw internalError(error, "failed to check artifact existence");
531
+ }
532
+ let storageKey: string;
533
+ if (exists) {
534
+ storageKey = artifactStorage.getStorageKey(archive.digest);
535
+ } else {
536
+ try {
537
+ storageKey = await artifactStorage.store(archive.digest, bytes);
538
+ } catch (error) {
539
+ throw internalError(error, "failed to store artifact");
540
+ }
541
+ }
542
+ ctx.set(ARTIFACT_STORAGE_KEY_KEY, storageKey);
543
+ },
544
+ };
545
+ }
546
+
547
+ /**
548
+ * PopulatePluginFields — the manifest into the spec, the archive identity
549
+ * and INSTALLING into the status, the level, the metadata.version chain,
550
+ * and the audit stamping discipline: creates stamp both slots; updates copy
551
+ * the loaded head's slot pointers and stamp spec_audit only (a push is a
552
+ * definition change; the helper sets a fresh spec_audit, never mutating
553
+ * the copied pointer, #540).
554
+ */
555
+ export function newPopulatePluginFieldsStep(): PipelineStep<PushDesc> {
556
+ return {
557
+ name: "PopulatePluginFields",
558
+ execute(ctx: RequestContext<PushDesc>): void {
559
+ const plugin = ctx.get(PLUGIN_KEY) as Plugin;
560
+ const pkg = ctx.get(PLUGIN_PACKAGE_KEY) as PluginPackage;
561
+ const archive = ctx.get(PLUGIN_ARCHIVE_KEY) as OpenedPluginArchive;
562
+ const storageKey = ctx.get(ARTIFACT_STORAGE_KEY_KEY) as string;
563
+ const shouldCreate = ctx.get(SHOULD_CREATE_PLUGIN_KEY) as boolean;
564
+ const existing = ctx.get(EXISTING_PLUGIN_KEY) as Plugin | undefined;
565
+
566
+ plugin.spec = create(PluginSpecSchema, {
567
+ name: pkg.name,
568
+ version: pkg.version ?? "",
569
+ description: pkg.description ?? "",
570
+ homepage: pkg.homepage ?? "",
571
+ repository: pkg.repository ?? "",
572
+ license: pkg.license ?? "",
573
+ keywords: [...pkg.keywords],
574
+ dialect: dialectOf(pkg.dialect),
575
+ });
576
+ if (pkg.author !== undefined) {
577
+ plugin.spec.author = create(PluginAuthorSchema, {
578
+ name: pkg.author.name ?? "",
579
+ email: pkg.author.email ?? "",
580
+ url: pkg.author.url ?? "",
581
+ });
582
+ }
583
+
584
+ plugin.metadata!.visibility = requestedVisibility(ctx);
585
+ plugin.metadata!.version = create(ApiResourceMetadataVersionSchema, {
586
+ id: archive.digest,
587
+ message: ctx.input.message,
588
+ previousVersionId: existing?.status?.digest ?? "",
589
+ });
590
+
591
+ const status = plugin.status!;
592
+ status.digest = archive.digest;
593
+ status.artifactStorageKey = storageKey;
594
+ status.state = PluginState.INSTALLING;
595
+ status.error = "";
596
+
597
+ if (shouldCreate) {
598
+ setAuditFieldsForCreate(PluginSchema, plugin, ctx.callerIdentity);
599
+ } else {
600
+ if (existing?.status?.audit !== undefined) {
601
+ status.audit ??= create(ApiResourceAuditSchema, {});
602
+ status.audit.specAudit = existing.status.audit.specAudit;
603
+ status.audit.statusAudit = existing.status.audit.statusAudit;
604
+ }
605
+ setAuditFieldsForUpdate(
606
+ PluginSchema,
607
+ plugin,
608
+ "spec_audit",
609
+ ctx.callerIdentity,
610
+ );
611
+ }
612
+ },
613
+ };
614
+ }
615
+
616
+ /**
617
+ * ArchiveCurrentPlugin — the shared versioning step bound to the plugin's
618
+ * digest and tag. The live tag IS the manifest version when it fits the
619
+ * tag pattern (the plan already warned when it does not), so the
620
+ * single-holder assignment and the getByReference ladder read one fact;
621
+ * the version is the manifest's word and is never cleared, so a failed
622
+ * tag assignment degrades to "reachable by digest" without touching the
623
+ * spec.
624
+ */
625
+ export function newArchiveCurrentPluginStep(
626
+ store: Store,
627
+ logger: Logger,
628
+ ): PipelineStep<PushDesc> {
629
+ return newArchiveCurrentVersionStep<typeof PluginSchema, PushDesc>(
630
+ store,
631
+ logger,
632
+ {
633
+ stepName: "ArchiveCurrentPlugin",
634
+ resourceKey: PLUGIN_KEY,
635
+ schema: PluginSchema,
636
+ noun: "plugin",
637
+ headHashOf: (plugin) => plugin.status?.digest ?? "",
638
+ clearHeadHash: (plugin) => {
639
+ plugin.status!.digest = "";
640
+ if (plugin.metadata?.version !== undefined) {
641
+ plugin.metadata.version.id = "";
642
+ }
643
+ },
644
+ liveTagOf: pluginLiveTag,
645
+ clearLiveTag: () => undefined,
646
+ },
647
+ );
648
+ }
649
+
650
+ /** The tag a plugin head claims: its manifest version when the pattern admits it. */
651
+ export function pluginLiveTag(plugin: Plugin): string {
652
+ const version = plugin.spec?.version ?? "";
653
+ return VERSION_TAG_PATTERN.test(version) ? version : "";
654
+ }
655
+
656
+ /** StorePlugin — persists the head; runs twice, before and after materialisation. */
657
+ export function newStorePluginStep(
658
+ store: Store,
659
+ stepName: string,
660
+ ): PipelineStep<PushDesc> {
661
+ return {
662
+ name: stepName,
663
+ async execute(ctx: RequestContext<PushDesc>): Promise<void> {
664
+ const plugin = ctx.get(PLUGIN_KEY) as Plugin;
665
+ try {
666
+ await store.saveResource(
667
+ ctx.apiResourceKind,
668
+ plugin.metadata!.id,
669
+ PluginSchema,
670
+ plugin,
671
+ );
672
+ } catch (error) {
673
+ throw internalError(error, "failed to save plugin");
674
+ }
675
+ },
676
+ };
677
+ }
678
+
679
+ /**
680
+ * MaterializeMembers — skills, MCP servers, the agent, workflows, each
681
+ * through the in-process lane as the installing caller, in the order
682
+ * references resolve. An existing member whose level differs from the
683
+ * plugin's is moved through its kind's updateVisibility afterwards (apply
684
+ * preserves a stored level by contract). A child failure records FAILED on
685
+ * the head, persists it, and fails the request with the plugin named.
686
+ */
687
+ export function newMaterializeMembersStep(
688
+ store: Store,
689
+ materializerProvider: PluginMaterializerProvider,
690
+ logger: Logger,
691
+ ): PipelineStep<PushDesc> {
692
+ return {
693
+ name: "MaterializeMembers",
694
+ async execute(ctx: RequestContext<PushDesc>): Promise<void> {
695
+ const plugin = ctx.get(PLUGIN_KEY) as Plugin;
696
+ const plan = ctx.get(PLUGIN_PLAN_KEY) as MaterializationPlan;
697
+ const materializer = materializerProvider();
698
+ const caller = ctx.callerIdentity;
699
+ const level = requestedVisibility(ctx);
700
+
701
+ const reconcileLevel = async (
702
+ kind: ApiResourceKind,
703
+ applied: {
704
+ readonly metadata?: {
705
+ readonly id: string;
706
+ readonly visibility: ApiResourceVisibility;
707
+ };
708
+ },
709
+ ): Promise<void> => {
710
+ const metadata = applied.metadata;
711
+ if (metadata !== undefined && metadata.visibility !== level) {
712
+ await materializer.updateVisibility(kind, metadata.id, level, caller);
713
+ }
714
+ };
715
+
716
+ const materialize = async <T>(
717
+ kind: ApiResourceKind,
718
+ slug: string,
719
+ write: () => Promise<T>,
720
+ ): Promise<T> => {
721
+ try {
722
+ return await write();
723
+ } catch (error) {
724
+ throw await recordFailure(store, ctx, plugin, kind, slug, error);
725
+ }
726
+ };
727
+
728
+ for (const skill of plan.skills) {
729
+ const pushed = await materialize(
730
+ ApiResourceKind.skill,
731
+ skill.slug,
732
+ () => materializer.pushSkill(skill.request, caller),
733
+ );
734
+ await materialize(ApiResourceKind.skill, skill.slug, () =>
735
+ reconcileLevel(ApiResourceKind.skill, pushed),
736
+ );
737
+ }
738
+ for (const server of plan.mcpServers) {
739
+ const applied = await materialize(
740
+ ApiResourceKind.mcp_server,
741
+ server.slug,
742
+ () => materializer.applyMcpServer(server.resource, caller),
743
+ );
744
+ await materialize(ApiResourceKind.mcp_server, server.slug, () =>
745
+ reconcileLevel(ApiResourceKind.mcp_server, applied),
746
+ );
747
+ }
748
+ if (plan.agent !== undefined) {
749
+ const agent = plan.agent;
750
+ const applied = await materialize(
751
+ ApiResourceKind.agent,
752
+ agent.slug,
753
+ () => materializer.applyAgent(agent.resource, caller),
754
+ );
755
+ await materialize(ApiResourceKind.agent, agent.slug, () =>
756
+ reconcileLevel(ApiResourceKind.agent, applied),
757
+ );
758
+ }
759
+ for (const workflow of plan.workflows) {
760
+ const applied = await materialize(
761
+ ApiResourceKind.workflow,
762
+ workflow.slug,
763
+ () => materializer.applyWorkflow(workflow.resource, caller),
764
+ );
765
+ await materialize(ApiResourceKind.workflow, workflow.slug, () =>
766
+ reconcileLevel(ApiResourceKind.workflow, applied),
767
+ );
768
+ }
769
+
770
+ logger.info("Materialized plugin members", {
771
+ pluginId: plugin.metadata!.id,
772
+ skills: plan.skills.length,
773
+ mcpServers: plan.mcpServers.length,
774
+ agents: plan.agent === undefined ? 0 : 1,
775
+ workflows: plan.workflows.length,
776
+ });
777
+ },
778
+ };
779
+ }
780
+
781
+ /**
782
+ * RemoveDroppedMembers — an upgrade whose archive no longer names a member
783
+ * deletes it through the member's own delete chain (agent first, so a
784
+ * workflow or a user's own resource still referencing it is judged by
785
+ * that chain, then the rest in reverse materialisation order).
786
+ */
787
+ export function newRemoveDroppedMembersStep(
788
+ store: Store,
789
+ materializerProvider: PluginMaterializerProvider,
790
+ logger: Logger,
791
+ ): PipelineStep<PushDesc> {
792
+ return {
793
+ name: "RemoveDroppedMembers",
794
+ async execute(ctx: RequestContext<PushDesc>): Promise<void> {
795
+ const plugin = ctx.get(PLUGIN_KEY) as Plugin;
796
+ const plan = ctx.get(PLUGIN_PLAN_KEY) as MaterializationPlan;
797
+ const existing = ctx.get(EXISTING_MEMBERS_KEY) as Member[];
798
+ const dropped = droppedMembers(existing, plan.members);
799
+ if (dropped.length === 0) {
800
+ return;
801
+ }
802
+ const materializer = materializerProvider();
803
+ for (const member of orderForDeletion(dropped)) {
804
+ try {
805
+ await materializer.deleteByKind(
806
+ member.kind,
807
+ member.id,
808
+ ctx.callerIdentity,
809
+ );
810
+ } catch (error) {
811
+ throw await recordFailure(
812
+ store,
813
+ ctx,
814
+ plugin,
815
+ member.kind,
816
+ member.slug,
817
+ error,
818
+ "remove",
819
+ );
820
+ }
821
+ }
822
+ logger.info("Removed members the new archive dropped", {
823
+ pluginId: plugin.metadata!.id,
824
+ dropped: dropped.map(
825
+ (member) => `${ApiResourceKind[member.kind]}:${member.slug}`,
826
+ ),
827
+ });
828
+ },
829
+ };
830
+ }
831
+
832
+ /** Cascade order: the agent first (it references the rest), then reverse materialisation order. */
833
+ export function orderForDeletion(members: readonly Member[]): Member[] {
834
+ const rank = new Map<ApiResourceKind, number>([
835
+ [ApiResourceKind.agent, 0],
836
+ [ApiResourceKind.workflow, 1],
837
+ [ApiResourceKind.mcp_server, 2],
838
+ [ApiResourceKind.skill, 3],
839
+ ]);
840
+ return [...members].sort(
841
+ (a, b) => (rank.get(a.kind) ?? 9) - (rank.get(b.kind) ?? 9),
842
+ );
843
+ }
844
+
845
+ /**
846
+ * FinalizePluginStatus — the install receipt: counts, every warning (the
847
+ * library's and the plan's), READY.
848
+ */
849
+ export function newFinalizePluginStatusStep(): PipelineStep<PushDesc> {
850
+ return {
851
+ name: "FinalizePluginStatus",
852
+ execute(ctx: RequestContext<PushDesc>): void {
853
+ const plugin = ctx.get(PLUGIN_KEY) as Plugin;
854
+ const plan = ctx.get(PLUGIN_PLAN_KEY) as MaterializationPlan;
855
+ const libraryWarnings = ctx.get(
856
+ PLUGIN_LIBRARY_WARNINGS_KEY,
857
+ ) as readonly PluginFinding[];
858
+ const status = plugin.status!;
859
+ status.state = PluginState.READY;
860
+ status.error = "";
861
+ status.materialized = create(PluginMaterializationSchema, {
862
+ skills: plan.skills.length,
863
+ mcpServers: plan.mcpServers.length,
864
+ agents: plan.agent === undefined ? 0 : 1,
865
+ workflows: plan.workflows.length,
866
+ });
867
+ status.warnings = [
868
+ ...libraryWarnings.map((finding) =>
869
+ create(PluginWarningSchema, {
870
+ kind: finding.kind,
871
+ message: finding.message,
872
+ path: finding.path ?? "",
873
+ }),
874
+ ),
875
+ ...plan.warnings,
876
+ ];
877
+ },
878
+ };
879
+ }
880
+
881
+ /**
882
+ * PluginPushAuthorizationTuples — the tuple-lifecycle splice for the push
883
+ * lane, the skill push's shape: a genuine create fires the creation event;
884
+ * a re-push diffs the stored level against the pushed head.
885
+ */
886
+ export function newPluginPushAuthorizationTuplesStep(
887
+ lifecycle: ResourceAuthorizationLifecycle | undefined,
888
+ logger: Logger,
889
+ ): PipelineStep<PushDesc> {
890
+ return {
891
+ name: "PluginPushAuthorizationTuples",
892
+ async execute(ctx: RequestContext<PushDesc>): Promise<void> {
893
+ if (lifecycle === undefined) {
894
+ return;
895
+ }
896
+ const plugin = ctx.get(PLUGIN_KEY) as Plugin;
897
+ if (ctx.get(SHOULD_CREATE_PLUGIN_KEY) as boolean) {
898
+ const event = resolveResourceCreatedEvent(
899
+ ctx.apiResourceKind,
900
+ plugin,
901
+ ctx.callerIdentity,
902
+ logger,
903
+ );
904
+ if (event === undefined) {
905
+ return;
906
+ }
907
+ try {
908
+ await lifecycle.onResourceCreated(event);
909
+ } catch (error) {
910
+ throw internalError(error, "failed to create authorization tuples");
911
+ }
912
+ return;
913
+ }
914
+ const existing = ctx.get(EXISTING_PLUGIN_KEY) as Plugin | undefined;
915
+ const oldLevel =
916
+ existing?.metadata?.visibility ??
917
+ ApiResourceVisibility.api_resource_visibility_unspecified;
918
+ const newLevel =
919
+ plugin.metadata?.visibility ??
920
+ ApiResourceVisibility.api_resource_visibility_unspecified;
921
+ const { shapesToCreate, shapesToDelete } = diffVisibilityShapes(
922
+ ctx.apiResourceKind,
923
+ oldLevel,
924
+ newLevel,
925
+ );
926
+ if (shapesToCreate.length === 0 && shapesToDelete.length === 0) {
927
+ return;
928
+ }
929
+ try {
930
+ await lifecycle.onVisibilityChanged({
931
+ kind: ctx.apiResourceKind,
932
+ resourceId: plugin.metadata?.id ?? "",
933
+ orgId: plugin.metadata?.org ?? "",
934
+ shapesToCreate,
935
+ shapesToDelete,
936
+ });
937
+ } catch (error) {
938
+ throw internalError(error, "failed to update visibility tuples");
939
+ }
940
+ },
941
+ };
942
+ }
943
+
944
+ /** IndexPluginSearch — search-index upsert, best-effort by contract. */
945
+ export function newIndexPluginSearchStep(
946
+ store: Store,
947
+ logger: Logger,
948
+ ): PipelineStep<PushDesc> {
949
+ return {
950
+ name: "IndexPluginSearch",
951
+ async execute(ctx: RequestContext<PushDesc>): Promise<void> {
952
+ const plugin = ctx.get(PLUGIN_KEY) as Plugin;
953
+ const entry = pluginSearchExtractor.getSearchIndexEntry(plugin);
954
+ if (entry === undefined) {
955
+ return;
956
+ }
957
+ try {
958
+ await store.upsertSearchIndex(
959
+ ctx.apiResourceKind,
960
+ plugin.metadata!.id,
961
+ entry,
962
+ );
963
+ } catch (error) {
964
+ logger.warn(
965
+ "IndexPluginSearch: failed to update search index (best-effort)",
966
+ {
967
+ id: plugin.metadata?.id ?? "",
968
+ error: error instanceof Error ? error.message : String(error),
969
+ },
970
+ );
971
+ }
972
+ },
973
+ };
974
+ }
975
+
976
+ // ─── helpers ─────────────────────────────────────────────────────────────
977
+
978
+ const MEMBER_NOUNS: ReadonlyMap<ApiResourceKind, string> = new Map([
979
+ [ApiResourceKind.skill, "skill"],
980
+ [ApiResourceKind.mcp_server, "MCP server"],
981
+ [ApiResourceKind.agent, "agent"],
982
+ [ApiResourceKind.workflow, "workflow"],
983
+ ]);
984
+
985
+ function memberNoun(kind: ApiResourceKind): string {
986
+ return MEMBER_NOUNS.get(kind) ?? ApiResourceKind[kind] ?? String(kind);
987
+ }
988
+
989
+ /** The holding plugin's slug for a refusal; a dangling id names itself. */
990
+ async function pluginSlugOf(store: Store, pluginId: string): Promise<string> {
991
+ try {
992
+ const plugin = await store.getResource(
993
+ ApiResourceKind.plugin,
994
+ pluginId,
995
+ PluginSchema,
996
+ );
997
+ return plugin.metadata?.slug ?? pluginId;
998
+ } catch (error) {
999
+ if (error instanceof ResourceNotFoundError) {
1000
+ return pluginId;
1001
+ }
1002
+ throw internalError(error, "failed to load the holding plugin");
1003
+ }
1004
+ }
1005
+
1006
+ /**
1007
+ * A child failed: the head records FAILED with one sentence and is
1008
+ * persisted before the request fails, so `get plugin` tells the truth and
1009
+ * the next push of the same archive re-materialises.
1010
+ */
1011
+ async function recordFailure(
1012
+ store: Store,
1013
+ ctx: RequestContext<PushDesc>,
1014
+ plugin: Plugin,
1015
+ kind: ApiResourceKind,
1016
+ slug: string,
1017
+ error: unknown,
1018
+ verb: "materialize" | "remove" = "materialize",
1019
+ ): Promise<ConnectError> {
1020
+ const cause =
1021
+ error instanceof ConnectError
1022
+ ? error.rawMessage
1023
+ : error instanceof Error
1024
+ ? error.message
1025
+ : String(error);
1026
+ const sentence = `failed to ${verb} ${memberNoun(kind)} '${slug}' from plugin '${plugin.metadata?.slug ?? ""}': ${cause}`;
1027
+ const status = plugin.status!;
1028
+ status.state = PluginState.FAILED;
1029
+ status.error = sentence;
1030
+ try {
1031
+ await store.saveResource(
1032
+ ctx.apiResourceKind,
1033
+ plugin.metadata!.id,
1034
+ PluginSchema,
1035
+ plugin,
1036
+ );
1037
+ } catch {
1038
+ // The original failure is the one the caller must hear; a second
1039
+ // failure persisting the receipt would only hide it.
1040
+ }
1041
+ if (error instanceof ConnectError) {
1042
+ return new ConnectError(sentence, error.code, undefined, undefined, error);
1043
+ }
1044
+ return internalError(error, sentence);
1045
+ }
1046
+
1047
+ function dialectOf(dialect: PluginPackage["dialect"]): PluginDialect {
1048
+ switch (dialect) {
1049
+ case "agent-plugins":
1050
+ return PluginDialect.AGENT_PLUGINS;
1051
+ case "claude":
1052
+ return PluginDialect.CLAUDE;
1053
+ case "cursor":
1054
+ return PluginDialect.CURSOR;
1055
+ case "codex":
1056
+ return PluginDialect.CODEX;
1057
+ default: {
1058
+ const exhaustive: never = dialect;
1059
+ throw new Error(`unknown dialect ${String(exhaustive)}`);
1060
+ }
1061
+ }
1062
+ }