@inharness-ai/claude4spec 1.0.21 → 1.0.23

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 (241) hide show
  1. package/.claude/skills/c4s-brief-implementer/SKILL.md +120 -53
  2. package/CHANGELOG.md +20 -0
  3. package/dist/bin/c4s/commands/agent.d.ts +18 -0
  4. package/dist/bin/c4s/commands/agent.js +102 -0
  5. package/dist/bin/c4s/commands/agent.js.map +1 -0
  6. package/dist/bin/c4s/commands/ask.d.ts +9 -8
  7. package/dist/bin/c4s/commands/ask.js +23 -31
  8. package/dist/bin/c4s/commands/ask.js.map +1 -1
  9. package/dist/bin/c4s/commands/catalog.d.ts +1 -1
  10. package/dist/bin/c4s/commands/catalog.js +2 -2
  11. package/dist/bin/c4s/commands/catalog.js.map +1 -1
  12. package/dist/bin/c4s/commands/describe.d.ts +1 -1
  13. package/dist/bin/c4s/commands/describe.js +2 -2
  14. package/dist/bin/c4s/commands/describe.js.map +1 -1
  15. package/dist/bin/c4s/commands/detail.d.ts +1 -1
  16. package/dist/bin/c4s/commands/detail.js +2 -2
  17. package/dist/bin/c4s/commands/detail.js.map +1 -1
  18. package/dist/bin/c4s/commands/element-list.d.ts +1 -1
  19. package/dist/bin/c4s/commands/element-list.js +2 -2
  20. package/dist/bin/c4s/commands/element-list.js.map +1 -1
  21. package/dist/bin/c4s/commands/find-references.js +1 -1
  22. package/dist/bin/c4s/commands/find-references.js.map +1 -1
  23. package/dist/bin/c4s/commands/inline-mention.d.ts +1 -1
  24. package/dist/bin/c4s/commands/inline-mention.js +2 -2
  25. package/dist/bin/c4s/commands/inline-mention.js.map +1 -1
  26. package/dist/bin/c4s/commands/list-slugs.d.ts +1 -1
  27. package/dist/bin/c4s/commands/list-slugs.js +2 -2
  28. package/dist/bin/c4s/commands/list-slugs.js.map +1 -1
  29. package/dist/bin/c4s/commands/list-tags.d.ts +1 -1
  30. package/dist/bin/c4s/commands/list-tags.js +2 -2
  31. package/dist/bin/c4s/commands/list-tags.js.map +1 -1
  32. package/dist/bin/c4s/commands/plugins.d.ts +9 -0
  33. package/dist/bin/c4s/commands/plugins.js +81 -0
  34. package/dist/bin/c4s/commands/plugins.js.map +1 -0
  35. package/dist/bin/c4s/commands/resolve.d.ts +1 -1
  36. package/dist/bin/c4s/commands/resolve.js +2 -2
  37. package/dist/bin/c4s/commands/resolve.js.map +1 -1
  38. package/dist/bin/c4s/commands/single-element.d.ts +1 -1
  39. package/dist/bin/c4s/commands/single-element.js +2 -2
  40. package/dist/bin/c4s/commands/single-element.js.map +1 -1
  41. package/dist/bin/c4s/commands/tagged-list-mixed.d.ts +1 -1
  42. package/dist/bin/c4s/commands/tagged-list-mixed.js +2 -2
  43. package/dist/bin/c4s/commands/tagged-list-mixed.js.map +1 -1
  44. package/dist/bin/c4s/commands/tagged-list.d.ts +1 -1
  45. package/dist/bin/c4s/commands/tagged-list.js +2 -2
  46. package/dist/bin/c4s/commands/tagged-list.js.map +1 -1
  47. package/dist/bin/c4s/context.d.ts +3 -3
  48. package/dist/bin/c4s/context.js +7 -4
  49. package/dist/bin/c4s/context.js.map +1 -1
  50. package/dist/bin/c4s/errors.d.ts +1 -1
  51. package/dist/bin/c4s/errors.js.map +1 -1
  52. package/dist/bin/c4s-mcp.js +6 -2
  53. package/dist/bin/c4s-mcp.js.map +1 -1
  54. package/dist/bin/c4s.js +19 -4
  55. package/dist/bin/c4s.js.map +1 -1
  56. package/dist/bin/gitignore.js +7 -11
  57. package/dist/bin/gitignore.js.map +1 -1
  58. package/dist/client/assets/{arc-Coa9fbDO.js → arc-C9oTB3b1.js} +1 -1
  59. package/dist/client/assets/{architectureDiagram-3BPJPVTR-VJZcRMEN.js → architectureDiagram-3BPJPVTR-Bno5ViqK.js} +1 -1
  60. package/dist/client/assets/{blockDiagram-GPEHLZMM-C7dU2lW1.js → blockDiagram-GPEHLZMM-CJYBoeWQ.js} +1 -1
  61. package/dist/client/assets/{c4Diagram-AAUBKEIU-CG_BBm_5.js → c4Diagram-AAUBKEIU-DaaqWE6s.js} +1 -1
  62. package/dist/client/assets/channel-Cei_E79M.js +1 -0
  63. package/dist/client/assets/{chunk-2J33WTMH-BnS95YpK.js → chunk-2J33WTMH-P_I0OPMy.js} +1 -1
  64. package/dist/client/assets/{chunk-4BX2VUAB-COr8w3X3.js → chunk-4BX2VUAB-CCySMlh5.js} +1 -1
  65. package/dist/client/assets/{chunk-55IACEB6-CxrIbZhB.js → chunk-55IACEB6-CEUyqKGF.js} +1 -1
  66. package/dist/client/assets/{chunk-727SXJPM-DRchPPRe.js → chunk-727SXJPM-CoTSYOVz.js} +1 -1
  67. package/dist/client/assets/{chunk-AQP2D5EJ-_SfN7mED.js → chunk-AQP2D5EJ-DB0nMxPr.js} +1 -1
  68. package/dist/client/assets/{chunk-FMBD7UC4-p2tIiP1D.js → chunk-FMBD7UC4-PG3m6-_a.js} +1 -1
  69. package/dist/client/assets/{chunk-ND2GUHAM-B1mbl2hP.js → chunk-ND2GUHAM-CBNk6IaV.js} +1 -1
  70. package/dist/client/assets/{chunk-QZHKN3VN-DBUpeqvS.js → chunk-QZHKN3VN-CLFa0WvN.js} +1 -1
  71. package/dist/client/assets/classDiagram-4FO5ZUOK-DUe_fAto.js +1 -0
  72. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DUe_fAto.js +1 -0
  73. package/dist/client/assets/{cose-bilkent-S5V4N54A-BBsY5aKD.js → cose-bilkent-S5V4N54A-BDwDDxHN.js} +1 -1
  74. package/dist/client/assets/{dagre-BM42HDAG-b-vu4RC9.js → dagre-BM42HDAG-DR-1e8N5.js} +1 -1
  75. package/dist/client/assets/{diagram-2AECGRRQ-j-DW9qSf.js → diagram-2AECGRRQ-C-tHgBWt.js} +1 -1
  76. package/dist/client/assets/{diagram-5GNKFQAL-DHX_WYWQ.js → diagram-5GNKFQAL-uLmoKaJL.js} +1 -1
  77. package/dist/client/assets/{diagram-KO2AKTUF-DxdQok_M.js → diagram-KO2AKTUF-8Fd-xuOy.js} +1 -1
  78. package/dist/client/assets/{diagram-LMA3HP47-BbTIX5c1.js → diagram-LMA3HP47-C1gniWsn.js} +1 -1
  79. package/dist/client/assets/{diagram-OG6HWLK6-BQ9ODAlH.js → diagram-OG6HWLK6-BMWjZbeC.js} +1 -1
  80. package/dist/client/assets/{erDiagram-TEJ5UH35-6lwAL1y9.js → erDiagram-TEJ5UH35-CIUO8hrR.js} +1 -1
  81. package/dist/client/assets/{flowDiagram-I6XJVG4X-ioSHb5-t.js → flowDiagram-I6XJVG4X-Ccw5YEf3.js} +1 -1
  82. package/dist/client/assets/{ganttDiagram-6RSMTGT7-CXFQp9Nj.js → ganttDiagram-6RSMTGT7-BAvlf8cY.js} +1 -1
  83. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-C1pVD_NQ.js → gitGraphDiagram-PVQCEYII-ChCkdYar.js} +1 -1
  84. package/dist/client/assets/{index-JaAxQJXh.js → index-BotCWOKC.js} +1 -1
  85. package/dist/client/assets/index-CtdzGyqj.js +805 -0
  86. package/dist/client/assets/{index-hz5T_W2e.js → index-DtpKHGD1.js} +1 -1
  87. package/dist/client/assets/{infoDiagram-5YYISTIA-C2Guev-g.js → infoDiagram-5YYISTIA-CZMGwNyB.js} +1 -1
  88. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-D3v8VBb2.js → ishikawaDiagram-YF4QCWOH-CubjZGk6.js} +1 -1
  89. package/dist/client/assets/{journeyDiagram-JHISSGLW-DX1AW_Ap.js → journeyDiagram-JHISSGLW-DzwOyVzB.js} +1 -1
  90. package/dist/client/assets/{kanban-definition-UN3LZRKU-CzXThvq2.js → kanban-definition-UN3LZRKU-CXznoTY9.js} +1 -1
  91. package/dist/client/assets/{linear-CVw4gl5i.js → linear-EDwTFRrU.js} +1 -1
  92. package/dist/client/assets/{mermaid.core-C29eoXRj.js → mermaid.core-Lae2097R.js} +4 -4
  93. package/dist/client/assets/{mindmap-definition-RKZ34NQL-DEEGVQVA.js → mindmap-definition-RKZ34NQL-DFjIW41g.js} +1 -1
  94. package/dist/client/assets/{pieDiagram-4H26LBE5-Dme-VM6m.js → pieDiagram-4H26LBE5-CZDLR1jd.js} +1 -1
  95. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-CURFNo24.js → quadrantDiagram-W4KKPZXB-CTGDzbqp.js} +1 -1
  96. package/dist/client/assets/{requirementDiagram-4Y6WPE33-DxMZWXME.js → requirementDiagram-4Y6WPE33-CeH0NbMv.js} +1 -1
  97. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-BW64D4_P.js → sankeyDiagram-5OEKKPKP-B6ZTjurV.js} +1 -1
  98. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-BATRPm8Q.js → sequenceDiagram-3UESZ5HK-DcTRztVx.js} +1 -1
  99. package/dist/client/assets/{stateDiagram-AJRCARHV-pgHVMnO3.js → stateDiagram-AJRCARHV-nUgRVZSA.js} +1 -1
  100. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-D9pJuQbI.js +1 -0
  101. package/dist/client/assets/{timeline-definition-PNZ67QCA-qBxJZPWd.js → timeline-definition-PNZ67QCA-CXm5n4rV.js} +1 -1
  102. package/dist/client/assets/{vennDiagram-CIIHVFJN-BZJK9hqJ.js → vennDiagram-CIIHVFJN-EmNJBYNd.js} +1 -1
  103. package/dist/client/assets/{wardley-L42UT6IY-BobtgEXg.js → wardley-L42UT6IY-MLrlp8H-.js} +1 -1
  104. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DuWfX_-P.js → wardleyDiagram-YWT4CUSO-5QoES25n.js} +1 -1
  105. package/dist/client/assets/{xychartDiagram-2RQKCTM6-DCw1iURo.js → xychartDiagram-2RQKCTM6-CbDEQbY0.js} +1 -1
  106. package/dist/client/index.html +1 -1
  107. package/dist/core/agent/run-agent.d.ts +61 -0
  108. package/dist/core/agent/run-agent.js +212 -0
  109. package/dist/core/agent/run-agent.js.map +1 -0
  110. package/dist/core/ask/run-ask.d.ts +1 -1
  111. package/dist/core/ask/run-ask.js +14 -5
  112. package/dist/core/ask/run-ask.js.map +1 -1
  113. package/dist/core/workspace/resolve.d.ts +2 -0
  114. package/dist/core/workspace/resolve.js +2 -1
  115. package/dist/core/workspace/resolve.js.map +1 -1
  116. package/dist/plugin-types/ambient.d.ts +30 -0
  117. package/dist/plugin-types/plugin-runtime.d.ts +172 -0
  118. package/dist/plugin-types/ui.d.ts +154 -0
  119. package/dist/server/config.d.ts +12 -0
  120. package/dist/server/config.js +26 -0
  121. package/dist/server/config.js.map +1 -1
  122. package/dist/server/core/plugin-host/__fixtures__/plugins.d.ts +14 -0
  123. package/dist/server/core/plugin-host/__fixtures__/plugins.js +56 -0
  124. package/dist/server/core/plugin-host/__fixtures__/plugins.js.map +1 -0
  125. package/dist/server/core/plugin-host/base-packages.d.ts +14 -0
  126. package/dist/server/core/plugin-host/base-packages.js +26 -0
  127. package/dist/server/core/plugin-host/base-packages.js.map +1 -0
  128. package/dist/server/core/plugin-host/cache-bust.d.ts +10 -0
  129. package/dist/server/core/plugin-host/cache-bust.js +21 -0
  130. package/dist/server/core/plugin-host/cache-bust.js.map +1 -0
  131. package/dist/server/core/plugin-host/cli-engine.d.ts +7 -2
  132. package/dist/server/core/plugin-host/cli-engine.js +11 -3
  133. package/dist/server/core/plugin-host/cli-engine.js.map +1 -1
  134. package/dist/server/core/plugin-host/cli-plugins.d.ts +23 -0
  135. package/dist/server/core/plugin-host/cli-plugins.js +49 -0
  136. package/dist/server/core/plugin-host/cli-plugins.js.map +1 -0
  137. package/dist/server/core/plugin-host/cross-cutting.d.ts +41 -4
  138. package/dist/server/core/plugin-host/cross-cutting.js +52 -4
  139. package/dist/server/core/plugin-host/cross-cutting.js.map +1 -1
  140. package/dist/server/core/plugin-host/frontend-assets.d.ts +100 -0
  141. package/dist/server/core/plugin-host/frontend-assets.js +262 -0
  142. package/dist/server/core/plugin-host/frontend-assets.js.map +1 -0
  143. package/dist/server/core/plugin-host/frontend-manifest.d.ts +33 -0
  144. package/dist/server/core/plugin-host/frontend-manifest.js +60 -0
  145. package/dist/server/core/plugin-host/frontend-manifest.js.map +1 -0
  146. package/dist/server/core/plugin-host/loader.d.ts +107 -0
  147. package/dist/server/core/plugin-host/loader.js +196 -0
  148. package/dist/server/core/plugin-host/loader.js.map +1 -0
  149. package/dist/server/core/plugin-host/manifest-adapter.d.ts +30 -0
  150. package/dist/server/core/plugin-host/manifest-adapter.js +119 -0
  151. package/dist/server/core/plugin-host/manifest-adapter.js.map +1 -0
  152. package/dist/server/core/plugin-host/overlay-loader.d.ts +60 -0
  153. package/dist/server/core/plugin-host/overlay-loader.js +243 -0
  154. package/dist/server/core/plugin-host/overlay-loader.js.map +1 -0
  155. package/dist/server/core/plugin-host/plugin-watcher.d.ts +41 -0
  156. package/dist/server/core/plugin-host/plugin-watcher.js +95 -0
  157. package/dist/server/core/plugin-host/plugin-watcher.js.map +1 -0
  158. package/dist/server/core/plugin-host/project-host.d.ts +8 -2
  159. package/dist/server/core/plugin-host/project-host.js +56 -6
  160. package/dist/server/core/plugin-host/project-host.js.map +1 -1
  161. package/dist/server/core/plugin-host/registry.d.ts +26 -2
  162. package/dist/server/core/plugin-host/registry.js +107 -2
  163. package/dist/server/core/plugin-host/registry.js.map +1 -1
  164. package/dist/server/core/plugin-host/runtime-shims.d.ts +26 -0
  165. package/dist/server/core/plugin-host/runtime-shims.js +96 -0
  166. package/dist/server/core/plugin-host/runtime-shims.js.map +1 -0
  167. package/dist/server/core/plugin-host/types.d.ts +105 -3
  168. package/dist/server/db/migrations/042_chat_thread_drop_context_type_check.sql +61 -0
  169. package/dist/server/external-skills/brief-implementer-template.d.ts +1 -1
  170. package/dist/server/external-skills/brief-implementer-template.js +5 -2
  171. package/dist/server/external-skills/brief-implementer-template.js.map +1 -1
  172. package/dist/server/external-skills/spec-reader-template.d.ts +1 -1
  173. package/dist/server/external-skills/spec-reader-template.js +14 -0
  174. package/dist/server/external-skills/spec-reader-template.js.map +1 -1
  175. package/dist/server/index.js +82 -1
  176. package/dist/server/index.js.map +1 -1
  177. package/dist/server/mcp/c4s-tools.d.ts +6 -1
  178. package/dist/server/mcp/c4s-tools.js +18 -13
  179. package/dist/server/mcp/c4s-tools.js.map +1 -1
  180. package/dist/server/plugin-runtime/index.d.ts +17 -0
  181. package/dist/server/plugin-runtime/index.js +16 -0
  182. package/dist/server/plugin-runtime/index.js.map +1 -0
  183. package/dist/server/plugin-runtime/ui.d.ts +15 -0
  184. package/dist/server/plugin-runtime/ui.js +15 -0
  185. package/dist/server/plugin-runtime/ui.js.map +1 -0
  186. package/dist/server/routes/agent-turn.d.ts +8 -1
  187. package/dist/server/routes/agent-turn.js +67 -39
  188. package/dist/server/routes/agent-turn.js.map +1 -1
  189. package/dist/server/routes/config.d.ts +8 -0
  190. package/dist/server/routes/config.js +41 -3
  191. package/dist/server/routes/config.js.map +1 -1
  192. package/dist/server/routes/plugins.d.ts +43 -0
  193. package/dist/server/routes/plugins.js +93 -0
  194. package/dist/server/routes/plugins.js.map +1 -0
  195. package/dist/server/routes/threads.js +21 -3
  196. package/dist/server/routes/threads.js.map +1 -1
  197. package/dist/server/serialization/registerAll.d.ts +4 -0
  198. package/dist/server/serialization/registerAll.js +4 -2
  199. package/dist/server/serialization/registerAll.js.map +1 -1
  200. package/dist/server/services/chat-context.d.ts +34 -0
  201. package/dist/server/services/chat-context.js +58 -15
  202. package/dist/server/services/chat-context.js.map +1 -1
  203. package/dist/server/services/chat.d.ts +6 -0
  204. package/dist/server/services/chat.js +18 -2
  205. package/dist/server/services/chat.js.map +1 -1
  206. package/dist/server/services/entity-writer.d.ts +2 -3
  207. package/dist/server/services/entity-writer.js.map +1 -1
  208. package/dist/server/services/skill-registry.d.ts +31 -2
  209. package/dist/server/services/skill-registry.js +73 -1
  210. package/dist/server/services/skill-registry.js.map +1 -1
  211. package/dist/server/workspace/context-cache.d.ts +9 -0
  212. package/dist/server/workspace/context-cache.js +14 -0
  213. package/dist/server/workspace/context-cache.js.map +1 -1
  214. package/dist/server/workspace/project-context.d.ts +3 -0
  215. package/dist/server/workspace/project-context.js +106 -4
  216. package/dist/server/workspace/project-context.js.map +1 -1
  217. package/dist/server/workspace/registry.d.ts +28 -1
  218. package/dist/server/workspace/registry.js +57 -1
  219. package/dist/server/workspace/registry.js.map +1 -1
  220. package/dist/server/workspace/types.d.ts +15 -0
  221. package/dist/shared/entities.d.ts +4 -1
  222. package/dist/shared/entities.js.map +1 -1
  223. package/dist/shared/plugin-host/frontend-manifest.d.ts +56 -0
  224. package/dist/shared/plugin-host/frontend-manifest.js +89 -0
  225. package/dist/shared/plugin-host/frontend-manifest.js.map +1 -0
  226. package/dist/shared/plugin-host/host-api.d.ts +60 -0
  227. package/dist/shared/plugin-host/host-api.js +67 -0
  228. package/dist/shared/plugin-host/host-api.js.map +1 -0
  229. package/dist/shared/plugin-host/manifest.d.ts +194 -0
  230. package/dist/shared/plugin-host/manifest.js +52 -0
  231. package/dist/shared/plugin-host/manifest.js.map +1 -0
  232. package/dist/shared/plugin-host/ui-kit-surface.d.ts +22 -0
  233. package/dist/shared/plugin-host/ui-kit-surface.js +25 -0
  234. package/dist/shared/plugin-host/ui-kit-surface.js.map +1 -0
  235. package/dist/shared/types.d.ts +5 -0
  236. package/package.json +18 -3
  237. package/dist/client/assets/channel-D5gzBvo7.js +0 -1
  238. package/dist/client/assets/classDiagram-4FO5ZUOK-CT-amIxa.js +0 -1
  239. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-CT-amIxa.js +0 -1
  240. package/dist/client/assets/index-DyAnw7YN.js +0 -798
  241. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-szm_LIuD.js +0 -1
@@ -0,0 +1,243 @@
1
+ /**
2
+ * M33 — project-local plugin overlay loader.
3
+ *
4
+ * The second of the two M33 tracks (the first being the process-global
5
+ * `loadWorkspacePlugins`). This one loads plugins committed into a repo at
6
+ * `<cwd>/.claude4spec/plugins/<pkg>/` and builds a per-`ProjectContext`
7
+ * `ProjectPluginOverlay`. Because a `git clone` brings this code with it,
8
+ * loading is gated by `trustProjectPlugins` — the CALLER decides trust and only
9
+ * invokes `loadProjectOverlay` when trusted; `enumerateOverlayPackages` is the
10
+ * code-free probe used to drive the trust prompt.
11
+ *
12
+ * Per package, each step is isolated in its own try/catch so one bad plugin is
13
+ * skipped — never failing the project build:
14
+ * 1. Resolve entry — package.json main/module/exports, else index.{js,mjs}.
15
+ * 2. Dynamic import — `import(pathToFileURL(entry))` (native ESM).
16
+ * 3. Validate+gate — shared with the workspace loader (hostApiVersion+engines).
17
+ * 4. Lower entities — `lowerEntityContribution`, enforcing within-overlay
18
+ * type uniqueness (second duplicate → PLUGIN_TYPE_CONFLICT, rejected).
19
+ */
20
+ import fs from 'node:fs';
21
+ import path from 'node:path';
22
+ import { pathToFileURL } from 'node:url';
23
+ import { entryCacheBust } from './cache-bust.js';
24
+ import { extractManifest, gateManifest, isValidManifestShape, } from './loader.js';
25
+ import { lowerEntityContribution, validateWritingStyle } from './manifest-adapter.js';
26
+ const defaultImporter = (specifier) => import(specifier);
27
+ /** Absolute path to a project's local plugins directory. */
28
+ export function projectPluginsDir(cwd) {
29
+ return path.join(cwd, '.claude4spec', 'plugins');
30
+ }
31
+ /**
32
+ * Package directory names under `<cwd>/.claude4spec/plugins/`. Pure FS read — no
33
+ * code runs — so it is safe to call before the trust decision (drives the prompt
34
+ * and the untrusted-layer diagnostics).
35
+ */
36
+ export function enumerateOverlayPackages(cwd) {
37
+ const dir = projectPluginsDir(cwd);
38
+ let entries;
39
+ try {
40
+ if (!fs.existsSync(dir))
41
+ return [];
42
+ entries = fs.readdirSync(dir, { withFileTypes: true });
43
+ }
44
+ catch {
45
+ return [];
46
+ }
47
+ return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
48
+ }
49
+ /** True when the project ships at least one local plugin package. */
50
+ export function hasProjectPlugins(cwd) {
51
+ return enumerateOverlayPackages(cwd).length > 0;
52
+ }
53
+ /**
54
+ * Resolve a package.json `exports` field to a relative entry path. Handles the
55
+ * common shapes: a bare string, the `"."` subpath, and a conditions object
56
+ * (`{ import, default, require, node }`) at either the top level or under `"."`.
57
+ * Returns the first string match (preferring ESM `import`/`default`), or
58
+ * undefined if no string entry is reachable (caller falls back to module/main).
59
+ * Exported so the workspace-tier frontend resolver reuses the same condition
60
+ * handling for a plugin's `exports['./frontend']` (see `frontend-assets.ts`).
61
+ */
62
+ export function resolveExportsEntry(exp) {
63
+ if (typeof exp === 'string')
64
+ return exp;
65
+ if (!exp || typeof exp !== 'object')
66
+ return undefined;
67
+ const obj = exp;
68
+ // Subpath map: drill into "." first, then treat the whole object as conditions.
69
+ const dot = obj['.'];
70
+ if (typeof dot === 'string')
71
+ return dot;
72
+ const conditions = (dot && typeof dot === 'object' ? dot : obj);
73
+ for (const key of ['import', 'module', 'default', 'node', 'require']) {
74
+ const v = conditions[key];
75
+ if (typeof v === 'string')
76
+ return v;
77
+ }
78
+ return undefined;
79
+ }
80
+ /** Resolve the ESM entry file of a package directory. Returns null if none found. */
81
+ function resolveEntry(pkgDir) {
82
+ const pkgJsonPath = path.join(pkgDir, 'package.json');
83
+ if (fs.existsSync(pkgJsonPath)) {
84
+ try {
85
+ const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
86
+ const rel = resolveExportsEntry(pkg.exports) ?? pkg.module ?? pkg.main;
87
+ if (rel) {
88
+ const abs = path.resolve(pkgDir, rel);
89
+ if (fs.existsSync(abs))
90
+ return abs;
91
+ }
92
+ }
93
+ catch {
94
+ /* fall through to index.* probing */
95
+ }
96
+ }
97
+ for (const candidate of ['index.js', 'index.mjs', 'index.cjs']) {
98
+ const abs = path.join(pkgDir, candidate);
99
+ if (fs.existsSync(abs))
100
+ return abs;
101
+ }
102
+ return null;
103
+ }
104
+ /**
105
+ * Load and validate the trusted project-local overlay for `cwd`. The caller must
106
+ * have already confirmed `trustProjectPlugins === true`; this function executes
107
+ * project-committed code.
108
+ */
109
+ export async function loadProjectOverlay(cwd, importer = defaultImporter) {
110
+ const records = [];
111
+ const modules = new Map();
112
+ const originByType = new Map();
113
+ const writingStyles = [];
114
+ // M33: non-entity capabilities of trusted project-local plugins. An
115
+ // entity-less plugin (commands/settings only) still produces these.
116
+ const settingsSections = [];
117
+ const commands = [];
118
+ const teardowns = [];
119
+ for (const pkg of enumerateOverlayPackages(cwd)) {
120
+ const pkgDir = path.join(projectPluginsDir(cwd), pkg);
121
+ const origin = path.join('.claude4spec', 'plugins', pkg);
122
+ const base = { package: pkg, status: 'loaded', layer: 'overlay', trust: 'trusted', origin };
123
+ const entry = resolveEntry(pkgDir);
124
+ if (!entry) {
125
+ const reason = 'no resolvable ESM entry (package.json main/module/exports or index.{js,mjs,cjs})';
126
+ console.warn(`[overlay-loader] PLUGIN_INVALID_MANIFEST ${pkg}: ${reason}`);
127
+ records.push({ ...base, status: 'failed', code: 'PLUGIN_INVALID_MANIFEST', reason });
128
+ continue;
129
+ }
130
+ let mod;
131
+ try {
132
+ mod = await importer(pathToFileURL(entry).href + entryCacheBust(entry));
133
+ }
134
+ catch (err) {
135
+ const reason = err.message;
136
+ console.warn(`[overlay-loader] PLUGIN_IMPORT_FAILED ${pkg}: ${reason}`);
137
+ records.push({ ...base, status: 'failed', code: 'PLUGIN_IMPORT_FAILED', reason });
138
+ continue;
139
+ }
140
+ const manifest = extractManifest(mod);
141
+ if (!isValidManifestShape(manifest)) {
142
+ const reason = 'package does not export a valid PluginManifest (manifest/default)';
143
+ console.warn(`[overlay-loader] PLUGIN_INVALID_MANIFEST ${pkg}: ${reason}`);
144
+ records.push({ ...base, status: 'failed', code: 'PLUGIN_INVALID_MANIFEST', reason });
145
+ continue;
146
+ }
147
+ const gate = gateManifest(manifest);
148
+ if (gate) {
149
+ console.warn(`[overlay-loader] ${gate.code} ${pkg}: ${gate.reason}`);
150
+ records.push({
151
+ ...base,
152
+ status: gate.status,
153
+ code: gate.code,
154
+ reason: gate.reason,
155
+ migration: gate.migration,
156
+ manifestName: manifest.name,
157
+ manifestVersion: manifest.version,
158
+ });
159
+ continue;
160
+ }
161
+ // Lower contributions (entities + styles) before committing — a throw on
162
+ // either fails the whole plugin atomically.
163
+ let lowered;
164
+ let styles;
165
+ try {
166
+ lowered = (manifest.contributes?.entities ?? []).map(lowerEntityContribution);
167
+ styles = (manifest.contributes?.writingStyles ?? []).map(validateWritingStyle);
168
+ }
169
+ catch (err) {
170
+ const reason = err.message;
171
+ console.warn(`[overlay-loader] PLUGIN_INVALID_MANIFEST ${pkg}: ${reason}`);
172
+ records.push({ ...base, status: 'failed', code: 'PLUGIN_INVALID_MANIFEST', reason });
173
+ continue;
174
+ }
175
+ // Enforce within-overlay (same-layer) type uniqueness.
176
+ const conflict = lowered.find((m) => modules.has(m.type));
177
+ if (conflict) {
178
+ const reason = `type "${conflict.type}" already provided by another project-local plugin (origin ${originByType.get(conflict.type)})`;
179
+ console.warn(`[overlay-loader] PLUGIN_TYPE_CONFLICT ${pkg}: ${reason}`);
180
+ records.push({ ...base, status: 'failed', code: 'PLUGIN_TYPE_CONFLICT', reason });
181
+ continue;
182
+ }
183
+ for (const m of lowered) {
184
+ modules.set(m.type, m);
185
+ originByType.set(m.type, origin);
186
+ }
187
+ writingStyles.push(...styles);
188
+ // M33: capture non-entity capabilities + teardown of this trusted plugin.
189
+ if ((manifest.contributes?.settings ?? []).length > 0) {
190
+ settingsSections.push({
191
+ name: manifest.name,
192
+ version: manifest.version,
193
+ fields: manifest.contributes.settings,
194
+ });
195
+ }
196
+ commands.push(...(manifest.contributes?.commands ?? []));
197
+ if (typeof manifest.onUnregister === 'function') {
198
+ const fn = manifest.onUnregister.bind(manifest);
199
+ teardowns.push(fn);
200
+ }
201
+ else {
202
+ console.warn(`[overlay-loader] plugin "${manifest.name}" — required slot onUnregister is missing; using a no-op teardown`);
203
+ }
204
+ records.push({
205
+ ...base,
206
+ manifestName: manifest.name,
207
+ manifestVersion: manifest.version,
208
+ contributedTypes: lowered.map((m) => m.type),
209
+ });
210
+ }
211
+ // Node's ESM registry caches modules by URL — a true unload is not possible.
212
+ // dispose() runs each plugin's `onUnregister` (M33 teardown) then
213
+ // drops the host-side references (mirrors clearMcpFactories); a rebuild
214
+ // re-imports (cached) fresh manifests. Stateful native handles, if a plugin
215
+ // opens any, are the plugin's own teardown responsibility.
216
+ const dispose = () => {
217
+ for (const teardown of teardowns) {
218
+ try {
219
+ teardown();
220
+ }
221
+ catch (err) {
222
+ console.warn(`[overlay-loader] onUnregister threw during dispose: ${err.message}`);
223
+ }
224
+ }
225
+ modules.clear();
226
+ originByType.clear();
227
+ };
228
+ // No capabilities at all ⇒ no overlay host layer, but a plugin may still have
229
+ // contributed writing styles — return those so the caller can push them.
230
+ // M33: an entity-less plugin with only settings/commands DOES produce
231
+ // an overlay so the host surfaces those capabilities (axis B).
232
+ if (modules.size === 0 && settingsSections.length === 0 && commands.length === 0) {
233
+ return { overlay: undefined, records, writingStyles, dispose };
234
+ }
235
+ const overlay = {
236
+ listLocal: () => Array.from(modules.values()),
237
+ origin: (type) => originByType.get(type) ?? '',
238
+ listSettings: () => settingsSections,
239
+ listCommands: () => commands,
240
+ };
241
+ return { overlay, records, writingStyles, dispose };
242
+ }
243
+ //# sourceMappingURL=overlay-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay-loader.js","sourceRoot":"","sources":["../../../../src/server/core/plugin-host/overlay-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * M33 — plugin-pool hot-reload watcher.
3
+ *
4
+ * The main `PagesWatcher` is rooted OUTSIDE `.claude4spec/`, so plugin sources
5
+ * are watched by this dedicated watcher instead. It is the *mechanism only* —
6
+ * the reload pipeline (cache-bust import → onUnregister old → register new →
7
+ * invalidate ProjectContext → broadcast) is supplied by the caller via
8
+ * `onReload`. There is deliberately no projection store (no `byPath` map, no
9
+ * SQLite): the live `PluginRegistry` (base) + `ProjectPluginOverlay` (overlay)
10
+ * ARE the index (divergence from M29 — only the watcher is reused).
11
+ *
12
+ * Two callers wire it differently:
13
+ * - overlay: one watcher per `ProjectContext` over `<cwd>/.claude4spec/plugins/`,
14
+ * mounted only behind the `trustProjectPlugins` gate; closed on dispose.
15
+ * - base: one process-global watcher over the resolved workspace package dirs.
16
+ */
17
+ export type PluginWatcherCallback = (changedPaths: string[]) => void;
18
+ export declare class PluginWatcher {
19
+ private readonly roots;
20
+ private readonly onReload;
21
+ private readonly debounceMs;
22
+ private watcher;
23
+ private timer;
24
+ private pending;
25
+ private suppressUntil;
26
+ /**
27
+ * @param roots absolute directories to watch (empty ⇒ `start()` is a no-op).
28
+ * @param onReload invoked (debounced) with the de-duplicated changed paths.
29
+ */
30
+ constructor(roots: string[], onReload: PluginWatcherCallback, debounceMs?: number);
31
+ start(): void;
32
+ /**
33
+ * Call BEFORE a reload-initiated write into a watched dir so the resulting
34
+ * chokidar event does not re-trigger the pipeline (reload → write → reload).
35
+ * Keyed by absolute path.
36
+ */
37
+ suppress(absPath: string): void;
38
+ private queue;
39
+ private flush;
40
+ close(): Promise<void>;
41
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * M33 — plugin-pool hot-reload watcher.
3
+ *
4
+ * The main `PagesWatcher` is rooted OUTSIDE `.claude4spec/`, so plugin sources
5
+ * are watched by this dedicated watcher instead. It is the *mechanism only* —
6
+ * the reload pipeline (cache-bust import → onUnregister old → register new →
7
+ * invalidate ProjectContext → broadcast) is supplied by the caller via
8
+ * `onReload`. There is deliberately no projection store (no `byPath` map, no
9
+ * SQLite): the live `PluginRegistry` (base) + `ProjectPluginOverlay` (overlay)
10
+ * ARE the index (divergence from M29 — only the watcher is reused).
11
+ *
12
+ * Two callers wire it differently:
13
+ * - overlay: one watcher per `ProjectContext` over `<cwd>/.claude4spec/plugins/`,
14
+ * mounted only behind the `trustProjectPlugins` gate; closed on dispose.
15
+ * - base: one process-global watcher over the resolved workspace package dirs.
16
+ */
17
+ import chokidar from 'chokidar';
18
+ import path from 'node:path';
19
+ const DEFAULT_DEBOUNCE_MS = 300;
20
+ const SUPPRESS_WINDOW_MS = 600;
21
+ export class PluginWatcher {
22
+ roots;
23
+ onReload;
24
+ debounceMs;
25
+ watcher = null;
26
+ timer = null;
27
+ pending = new Set();
28
+ suppressUntil = new Map();
29
+ /**
30
+ * @param roots absolute directories to watch (empty ⇒ `start()` is a no-op).
31
+ * @param onReload invoked (debounced) with the de-duplicated changed paths.
32
+ */
33
+ constructor(roots, onReload, debounceMs = DEFAULT_DEBOUNCE_MS) {
34
+ this.roots = roots;
35
+ this.onReload = onReload;
36
+ this.debounceMs = debounceMs;
37
+ }
38
+ start() {
39
+ if (this.roots.length === 0 || this.watcher)
40
+ return;
41
+ this.watcher = chokidar.watch(this.roots, {
42
+ ignoreInitial: true,
43
+ awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 },
44
+ });
45
+ const onEvent = (p) => this.queue(p);
46
+ this.watcher.on('add', onEvent);
47
+ this.watcher.on('change', onEvent);
48
+ this.watcher.on('unlink', onEvent);
49
+ this.watcher.on('addDir', onEvent);
50
+ this.watcher.on('unlinkDir', onEvent);
51
+ }
52
+ /**
53
+ * Call BEFORE a reload-initiated write into a watched dir so the resulting
54
+ * chokidar event does not re-trigger the pipeline (reload → write → reload).
55
+ * Keyed by absolute path.
56
+ */
57
+ suppress(absPath) {
58
+ this.suppressUntil.set(path.resolve(absPath), Date.now() + SUPPRESS_WINDOW_MS);
59
+ }
60
+ queue(absPath) {
61
+ const resolved = path.resolve(absPath);
62
+ const until = this.suppressUntil.get(resolved);
63
+ if (until && Date.now() < until) {
64
+ this.suppressUntil.delete(resolved);
65
+ return;
66
+ }
67
+ this.pending.add(resolved);
68
+ if (this.timer)
69
+ clearTimeout(this.timer);
70
+ this.timer = setTimeout(() => this.flush(), this.debounceMs);
71
+ }
72
+ flush() {
73
+ this.timer = null;
74
+ if (this.pending.size === 0)
75
+ return;
76
+ const paths = [...this.pending];
77
+ this.pending.clear();
78
+ try {
79
+ this.onReload(paths);
80
+ }
81
+ catch (err) {
82
+ console.warn('[plugin-watcher] onReload threw:', err.message);
83
+ }
84
+ }
85
+ async close() {
86
+ if (this.timer) {
87
+ clearTimeout(this.timer);
88
+ this.timer = null;
89
+ }
90
+ this.pending.clear();
91
+ await this.watcher?.close();
92
+ this.watcher = null;
93
+ }
94
+ }
95
+ //# sourceMappingURL=plugin-watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-watcher.js","sourceRoot":"","sources":["../../../../src/server/core/plugin-host/plugin-watcher.ts"],"names":[],"mappings":"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"}
@@ -5,22 +5,28 @@
5
5
  */
6
6
  import type { Database } from 'better-sqlite3';
7
7
  import type { McpServerInstance } from '@inharness-ai/agent-adapters';
8
- import type { BackendModule, MountContext, PluginRegistry, ProjectPluginHost } from './types.js';
8
+ import type { BackendModule, MountContext, PluginRegistry, ProjectPluginHost, ProjectPluginOverlay, ShadowedType } from './types.js';
9
9
  import type { PluginActivationState } from '../../../shared/plugin-host/types.js';
10
+ import type { PluginCommandContribution, PluginSettingsSection } from '../../../shared/plugin-host/manifest.js';
10
11
  import type { EntityDiff, RestoreContext, RestoreResult, SerializeContext, SnapshotData } from '../../serialization/types.js';
11
12
  export declare class ProjectPluginHostImpl implements ProjectPluginHost {
12
13
  private readonly registry;
14
+ private readonly overlay?;
13
15
  private activeTypes;
14
16
  private unknownTypes;
15
17
  private mcpServerFactories;
16
18
  private entityServices;
17
- constructor(registry: PluginRegistry, activeWhitelist: string[] | null | undefined);
19
+ private readonly overlayModules;
20
+ constructor(registry: PluginRegistry, activeWhitelist: string[] | null | undefined, overlay?: ProjectPluginOverlay | undefined);
18
21
  listAvailable(): BackendModule[];
19
22
  listEntities(): BackendModule[];
23
+ listSettings(): PluginSettingsSection[];
24
+ listCommands(): PluginCommandContribution[];
20
25
  getEntity(type: string): BackendModule | null;
21
26
  getAvailable(type: string): BackendModule | null;
22
27
  isActive(type: string): boolean;
23
28
  partition(): PluginActivationState;
29
+ shadowReport(): ShadowedType[];
24
30
  mountBackend(ctx: MountContext): void;
25
31
  registerMcpServer(name: string, factory: () => McpServerInstance): void;
26
32
  buildMcpServers(): Array<{
@@ -6,21 +6,33 @@
6
6
  import { diffEntity, restoreEntity, snapshotEntity } from '../../serialization/snapshot.js';
7
7
  export class ProjectPluginHostImpl {
8
8
  registry;
9
+ overlay;
9
10
  activeTypes = null; // null = all active
10
11
  unknownTypes = [];
11
12
  mcpServerFactories = new Map();
12
13
  entityServices = new Map();
13
- constructor(registry, activeWhitelist) {
14
+ // Project-local modules of THIS context, keyed by type. Empty when
15
+ // `overlay === undefined` (parity with the base-only case).
16
+ overlayModules = new Map();
17
+ constructor(registry, activeWhitelist, overlay) {
14
18
  this.registry = registry;
19
+ this.overlay = overlay;
20
+ // Effective pool = base ∪ overlay. Overlay wins on cross-layer collision
21
+ // (shadow) — `getAvailable`/`listAvailable` consult the overlay first.
22
+ for (const m of overlay?.listLocal() ?? []) {
23
+ this.overlayModules.set(m.type, m);
24
+ }
15
25
  if (activeWhitelist == null) {
16
26
  this.activeTypes = null;
17
27
  this.unknownTypes = [];
18
28
  return;
19
29
  }
30
+ // The whitelist is applied to the merged pool, not the base alone — an
31
+ // overlay type is activatable exactly like a base type.
20
32
  const active = new Set();
21
33
  const unknown = [];
22
34
  for (const type of activeWhitelist) {
23
- if (this.registry.getAvailable(type))
35
+ if (this.getAvailable(type))
24
36
  active.add(type);
25
37
  else
26
38
  unknown.push(type);
@@ -29,21 +41,49 @@ export class ProjectPluginHostImpl {
29
41
  this.unknownTypes = unknown;
30
42
  }
31
43
  listAvailable() {
32
- return this.registry.listAvailable();
44
+ // Merge base + overlay; overlay shadows a same-typed base module.
45
+ const merged = new Map();
46
+ for (const m of this.registry.listAvailable())
47
+ merged.set(m.type, m);
48
+ for (const [type, m] of this.overlayModules)
49
+ merged.set(type, m);
50
+ return Array.from(merged.values()).sort((a, b) => a.displayOrder - b.displayOrder);
33
51
  }
34
52
  listEntities() {
35
53
  return this.listAvailable().filter((m) => this.isActive(m.type));
36
54
  }
55
+ listSettings() {
56
+ // Axis B (pool + trust), NOT axis A: deliberately unfiltered by
57
+ // `config.entities`. Base records are always loaded+trusted; the overlay is
58
+ // only constructed on the trusted path, so its sections are trusted too.
59
+ // Overlay shadows base on a name collision (parity with type shadowing).
60
+ const byName = new Map();
61
+ for (const r of this.registry.listPluginRecords()) {
62
+ if (r.settings.length > 0) {
63
+ byName.set(r.name, { name: r.name, version: r.version, fields: r.settings });
64
+ }
65
+ }
66
+ for (const section of this.overlay?.listSettings() ?? []) {
67
+ byName.set(section.name, section);
68
+ }
69
+ return Array.from(byName.values());
70
+ }
71
+ listCommands() {
72
+ // Same two-axis rationale as listSettings(): pool + trust, not entities.
73
+ const base = this.registry.listPluginRecords().flatMap((r) => r.commands);
74
+ return [...base, ...(this.overlay?.listCommands() ?? [])];
75
+ }
37
76
  getEntity(type) {
38
77
  if (!this.isActive(type))
39
78
  return null;
40
- return this.registry.getAvailable(type);
79
+ return this.getAvailable(type);
41
80
  }
42
81
  getAvailable(type) {
43
- return this.registry.getAvailable(type);
82
+ // Overlay shadows base on cross-layer collision.
83
+ return this.overlayModules.get(type) ?? this.registry.getAvailable(type) ?? null;
44
84
  }
45
85
  isActive(type) {
46
- if (!this.registry.getAvailable(type))
86
+ if (!this.getAvailable(type))
47
87
  return false;
48
88
  if (this.activeTypes == null)
49
89
  return true;
@@ -56,6 +96,16 @@ export class ProjectPluginHostImpl {
56
96
  .map((m) => m.type);
57
97
  return { active, inactive, unknown: [...this.unknownTypes] };
58
98
  }
99
+ shadowReport() {
100
+ const out = [];
101
+ for (const type of this.overlayModules.keys()) {
102
+ // Cross-layer collision: the overlay type also exists in the base layer.
103
+ if (this.registry.getAvailable(type)) {
104
+ out.push({ type, overlayOrigin: this.overlay?.origin(type) ?? '' });
105
+ }
106
+ }
107
+ return out;
108
+ }
59
109
  mountBackend(ctx) {
60
110
  // A throwing plugin mount propagates — M31 turns it into a per-project
61
111
  // build failure (500 PROJECT_BUILD_FAILED), never a process crash.
@@ -1 +1 @@
1
- {"version":3,"file":"project-host.js","sourceRoot":"","sources":["../../../../src/server/core/plugin-host/project-host.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"project-host.js","sourceRoot":"","sources":["../../../../src/server/core/plugin-host/project-host.ts"],"names":[],"mappings":"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"}
@@ -3,12 +3,36 @@
3
3
  * singleton — the registry is immutable after `registerAllPlugins(registry)`
4
4
  * runs at process start, and `consolidate(config.entities)` is a pure factory
5
5
  * producing one ProjectPluginHost per project context.
6
+ *
7
+ * M33: the base layer is no longer process-immutable — the hot-reload
8
+ * pipeline mutates it via `registerPlugin` / `unregisterPlugin` and then
9
+ * invalidates dependent `ProjectContext`s (axis B). The registry additionally
10
+ * retains a per-plugin {@link RegisteredPluginRecord} so the host can surface
11
+ * non-entity capabilities (settings/commands) and the reload pipeline can call
12
+ * the old version's `onUnregister` before re-registering.
6
13
  */
7
- import type { BackendModule, PluginRegistry, ProjectPluginHost } from './types.js';
14
+ import type { BackendModule, PluginRegistry, ProjectPluginHost, ProjectPluginOverlay, RegisteredPluginRecord } from './types.js';
15
+ import type { PluginManifest, WritingStyleContribution } from '../../../shared/plugin-host/manifest.js';
8
16
  export declare class PluginRegistryImpl implements PluginRegistry {
9
17
  private modules;
18
+ private plugins;
10
19
  registerEntityModule(module: BackendModule): void;
20
+ /**
21
+ * Validate a manifest's shape and lower every contribution WITHOUT mutating
22
+ * the registry. Throws `PluginManifestError` on any structural problem (the
23
+ * loader/reload pipeline catches it). The hot-reload pipeline calls this
24
+ * BEFORE tearing the old version down, so a structurally-broken new version
25
+ * never leaves the pool missing a type ("old stays").
26
+ */
27
+ private validateAndLower;
28
+ validatePlugin(manifest: PluginManifest): void;
29
+ registerPlugin(manifest: PluginManifest): void;
30
+ unregisterPlugin(name: string): void;
31
+ listPluginRecords(): RegisteredPluginRecord[];
32
+ listWritingStyles(): WritingStyleContribution[];
11
33
  listAvailable(): BackendModule[];
12
34
  getAvailable(type: string): BackendModule | null;
13
- consolidate(activeWhitelist: string[] | null | undefined): ProjectPluginHost;
35
+ consolidate(config: {
36
+ entities?: string[];
37
+ } | null | undefined, overlay?: ProjectPluginOverlay): ProjectPluginHost;
14
38
  }