superacli 1.0.1 → 1.1.2

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 (389) hide show
  1. package/.beads/.br_history/issues.20260308_200823_636718328.jsonl +20 -0
  2. package/.beads/.br_history/issues.20260308_200823_636718328.jsonl.meta.json +1 -0
  3. package/.beads/.br_history/issues.20260308_200827_033159453.jsonl +21 -0
  4. package/.beads/.br_history/issues.20260308_200827_033159453.jsonl.meta.json +1 -0
  5. package/.beads/.br_history/issues.20260308_200829_595900053.jsonl +22 -0
  6. package/.beads/.br_history/issues.20260308_200829_595900053.jsonl.meta.json +1 -0
  7. package/.beads/.br_history/issues.20260308_200834_079930100.jsonl +23 -0
  8. package/.beads/.br_history/issues.20260308_200834_079930100.jsonl.meta.json +1 -0
  9. package/.beads/.br_history/issues.20260308_200858_370924996.jsonl +24 -0
  10. package/.beads/.br_history/issues.20260308_200858_370924996.jsonl.meta.json +1 -0
  11. package/.beads/.br_history/issues.20260308_201031_019730855.jsonl +24 -0
  12. package/.beads/.br_history/issues.20260308_201031_019730855.jsonl.meta.json +1 -0
  13. package/.beads/.br_history/issues.20260308_201031_578974884.jsonl +24 -0
  14. package/.beads/.br_history/issues.20260308_201031_578974884.jsonl.meta.json +1 -0
  15. package/.beads/.br_history/issues.20260308_201054_780345548.jsonl +24 -0
  16. package/.beads/.br_history/issues.20260308_201054_780345548.jsonl.meta.json +1 -0
  17. package/.beads/.br_history/issues.20260308_201054_896980019.jsonl +24 -0
  18. package/.beads/.br_history/issues.20260308_201054_896980019.jsonl.meta.json +1 -0
  19. package/.beads/.br_history/issues.20260308_201128_599819688.jsonl +24 -0
  20. package/.beads/.br_history/issues.20260308_201128_599819688.jsonl.meta.json +1 -0
  21. package/.beads/.br_history/issues.20260308_201128_710221699.jsonl +24 -0
  22. package/.beads/.br_history/issues.20260308_201128_710221699.jsonl.meta.json +1 -0
  23. package/.beads/.br_history/issues.20260308_201204_745649213.jsonl +24 -0
  24. package/.beads/.br_history/issues.20260308_201204_745649213.jsonl.meta.json +1 -0
  25. package/.beads/.br_history/issues.20260308_201338_908436144.jsonl +24 -0
  26. package/.beads/.br_history/issues.20260308_201338_908436144.jsonl.meta.json +1 -0
  27. package/.beads/.br_history/issues.20260308_201344_734860714.jsonl +25 -0
  28. package/.beads/.br_history/issues.20260308_201344_734860714.jsonl.meta.json +1 -0
  29. package/.beads/.br_history/issues.20260308_201630_819282295.jsonl +25 -0
  30. package/.beads/.br_history/issues.20260308_201630_819282295.jsonl.meta.json +1 -0
  31. package/.beads/.br_history/issues.20260308_203538_054279699.jsonl +25 -0
  32. package/.beads/.br_history/issues.20260308_203538_054279699.jsonl.meta.json +1 -0
  33. package/.beads/.br_history/issues.20260308_203547_597113070.jsonl +26 -0
  34. package/.beads/.br_history/issues.20260308_203547_597113070.jsonl.meta.json +1 -0
  35. package/.beads/.br_history/issues.20260308_203547_775139216.jsonl +27 -0
  36. package/.beads/.br_history/issues.20260308_203547_775139216.jsonl.meta.json +1 -0
  37. package/.beads/.br_history/issues.20260308_203547_950724773.jsonl +28 -0
  38. package/.beads/.br_history/issues.20260308_203547_950724773.jsonl.meta.json +1 -0
  39. package/.beads/.br_history/issues.20260308_203548_107684523.jsonl +29 -0
  40. package/.beads/.br_history/issues.20260308_203548_107684523.jsonl.meta.json +1 -0
  41. package/.beads/.br_history/issues.20260308_203548_310389993.jsonl +30 -0
  42. package/.beads/.br_history/issues.20260308_203548_310389993.jsonl.meta.json +1 -0
  43. package/.beads/.br_history/issues.20260308_203825_953337320.jsonl +31 -0
  44. package/.beads/.br_history/issues.20260308_203825_953337320.jsonl.meta.json +1 -0
  45. package/.beads/.br_history/issues.20260308_204056_071377736.jsonl +32 -0
  46. package/.beads/.br_history/issues.20260308_204056_071377736.jsonl.meta.json +1 -0
  47. package/.beads/.br_history/issues.20260308_205141_517616844.jsonl +32 -0
  48. package/.beads/.br_history/issues.20260308_205141_517616844.jsonl.meta.json +1 -0
  49. package/.beads/.br_history/issues.20260308_205141_648994024.jsonl +32 -0
  50. package/.beads/.br_history/issues.20260308_205141_648994024.jsonl.meta.json +1 -0
  51. package/.beads/.br_history/issues.20260308_205141_867598036.jsonl +32 -0
  52. package/.beads/.br_history/issues.20260308_205141_867598036.jsonl.meta.json +1 -0
  53. package/.beads/.br_history/issues.20260308_205142_094157355.jsonl +32 -0
  54. package/.beads/.br_history/issues.20260308_205142_094157355.jsonl.meta.json +1 -0
  55. package/.beads/.br_history/issues.20260308_205142_327315677.jsonl +32 -0
  56. package/.beads/.br_history/issues.20260308_205142_327315677.jsonl.meta.json +1 -0
  57. package/.beads/.br_history/issues.20260308_205142_545563822.jsonl +32 -0
  58. package/.beads/.br_history/issues.20260308_205142_545563822.jsonl.meta.json +1 -0
  59. package/.beads/.br_history/issues.20260308_205213_061989333.jsonl +32 -0
  60. package/.beads/.br_history/issues.20260308_205213_061989333.jsonl.meta.json +1 -0
  61. package/.beads/.br_history/issues.20260308_205213_181103364.jsonl +32 -0
  62. package/.beads/.br_history/issues.20260308_205213_181103364.jsonl.meta.json +1 -0
  63. package/.beads/.br_history/issues.20260308_205213_408872234.jsonl +32 -0
  64. package/.beads/.br_history/issues.20260308_205213_408872234.jsonl.meta.json +1 -0
  65. package/.beads/.br_history/issues.20260308_205213_616681652.jsonl +32 -0
  66. package/.beads/.br_history/issues.20260308_205213_616681652.jsonl.meta.json +1 -0
  67. package/.beads/.br_history/issues.20260308_205213_821507069.jsonl +32 -0
  68. package/.beads/.br_history/issues.20260308_205213_821507069.jsonl.meta.json +1 -0
  69. package/.beads/.br_history/issues.20260308_205214_026661112.jsonl +32 -0
  70. package/.beads/.br_history/issues.20260308_205214_026661112.jsonl.meta.json +1 -0
  71. package/.beads/.br_history/issues.20260308_205454_955250554.jsonl +32 -0
  72. package/.beads/.br_history/issues.20260308_205454_955250554.jsonl.meta.json +1 -0
  73. package/.beads/.br_history/issues.20260308_205556_337800392.jsonl +33 -0
  74. package/.beads/.br_history/issues.20260308_205556_337800392.jsonl.meta.json +1 -0
  75. package/.beads/.br_history/issues.20260308_205824_274686694.jsonl +33 -0
  76. package/.beads/.br_history/issues.20260308_205824_274686694.jsonl.meta.json +1 -0
  77. package/.beads/.br_history/issues.20260308_210240_583768328.jsonl +34 -0
  78. package/.beads/.br_history/issues.20260308_210240_583768328.jsonl.meta.json +1 -0
  79. package/.beads/.br_history/issues.20260308_212223_641541494.jsonl +34 -0
  80. package/.beads/.br_history/issues.20260308_212223_641541494.jsonl.meta.json +1 -0
  81. package/.beads/.br_history/issues.20260308_212227_735550996.jsonl +35 -0
  82. package/.beads/.br_history/issues.20260308_212227_735550996.jsonl.meta.json +1 -0
  83. package/.beads/.br_history/issues.20260308_212232_547298548.jsonl +36 -0
  84. package/.beads/.br_history/issues.20260308_212232_547298548.jsonl.meta.json +1 -0
  85. package/.beads/.br_history/issues.20260308_212528_843628125.jsonl +37 -0
  86. package/.beads/.br_history/issues.20260308_212528_843628125.jsonl.meta.json +1 -0
  87. package/.beads/.br_history/issues.20260308_212529_094530502.jsonl +38 -0
  88. package/.beads/.br_history/issues.20260308_212529_094530502.jsonl.meta.json +1 -0
  89. package/.beads/.br_history/issues.20260308_212529_331000853.jsonl +39 -0
  90. package/.beads/.br_history/issues.20260308_212529_331000853.jsonl.meta.json +1 -0
  91. package/.beads/.br_history/issues.20260308_212529_587925652.jsonl +40 -0
  92. package/.beads/.br_history/issues.20260308_212529_587925652.jsonl.meta.json +1 -0
  93. package/.beads/.br_history/issues.20260308_212804_927764103.jsonl +41 -0
  94. package/.beads/.br_history/issues.20260308_212804_927764103.jsonl.meta.json +1 -0
  95. package/.beads/.br_history/issues.20260308_212805_153673453.jsonl +42 -0
  96. package/.beads/.br_history/issues.20260308_212805_153673453.jsonl.meta.json +1 -0
  97. package/.beads/.br_history/issues.20260308_212805_415982363.jsonl +43 -0
  98. package/.beads/.br_history/issues.20260308_212805_415982363.jsonl.meta.json +1 -0
  99. package/.beads/.br_history/issues.20260308_212805_657497741.jsonl +44 -0
  100. package/.beads/.br_history/issues.20260308_212805_657497741.jsonl.meta.json +1 -0
  101. package/.beads/.br_history/issues.20260308_212805_952838724.jsonl +45 -0
  102. package/.beads/.br_history/issues.20260308_212805_952838724.jsonl.meta.json +1 -0
  103. package/.beads/.br_history/issues.20260308_212806_325433779.jsonl +46 -0
  104. package/.beads/.br_history/issues.20260308_212806_325433779.jsonl.meta.json +1 -0
  105. package/.beads/.br_history/issues.20260308_212806_584685598.jsonl +47 -0
  106. package/.beads/.br_history/issues.20260308_212806_584685598.jsonl.meta.json +1 -0
  107. package/.beads/.br_history/issues.20260308_212806_827817208.jsonl +48 -0
  108. package/.beads/.br_history/issues.20260308_212806_827817208.jsonl.meta.json +1 -0
  109. package/.beads/.br_history/issues.20260308_212807_111320451.jsonl +49 -0
  110. package/.beads/.br_history/issues.20260308_212807_111320451.jsonl.meta.json +1 -0
  111. package/.beads/.br_history/issues.20260308_212807_409545536.jsonl +50 -0
  112. package/.beads/.br_history/issues.20260308_212807_409545536.jsonl.meta.json +1 -0
  113. package/.beads/.br_history/issues.20260308_212807_625063294.jsonl +51 -0
  114. package/.beads/.br_history/issues.20260308_212807_625063294.jsonl.meta.json +1 -0
  115. package/.beads/.br_history/issues.20260308_212807_843906551.jsonl +52 -0
  116. package/.beads/.br_history/issues.20260308_212807_843906551.jsonl.meta.json +1 -0
  117. package/.beads/.br_history/issues.20260308_212808_100304073.jsonl +53 -0
  118. package/.beads/.br_history/issues.20260308_212808_100304073.jsonl.meta.json +1 -0
  119. package/.beads/.br_history/issues.20260308_212808_324723976.jsonl +54 -0
  120. package/.beads/.br_history/issues.20260308_212808_324723976.jsonl.meta.json +1 -0
  121. package/.beads/.br_history/issues.20260308_212808_557513104.jsonl +55 -0
  122. package/.beads/.br_history/issues.20260308_212808_557513104.jsonl.meta.json +1 -0
  123. package/.beads/.br_history/issues.20260308_212808_788048322.jsonl +56 -0
  124. package/.beads/.br_history/issues.20260308_212808_788048322.jsonl.meta.json +1 -0
  125. package/.beads/.br_history/issues.20260308_213702_613249728.jsonl +57 -0
  126. package/.beads/.br_history/issues.20260308_213702_613249728.jsonl.meta.json +1 -0
  127. package/.beads/.br_history/issues.20260308_213715_115792063.jsonl +57 -0
  128. package/.beads/.br_history/issues.20260308_213715_115792063.jsonl.meta.json +1 -0
  129. package/.beads/.br_history/issues.20260308_213715_462220666.jsonl +57 -0
  130. package/.beads/.br_history/issues.20260308_213715_462220666.jsonl.meta.json +1 -0
  131. package/.beads/.br_history/issues.20260308_213727_191258923.jsonl +57 -0
  132. package/.beads/.br_history/issues.20260308_213727_191258923.jsonl.meta.json +1 -0
  133. package/.beads/.br_history/issues.20260308_213727_684383652.jsonl +57 -0
  134. package/.beads/.br_history/issues.20260308_213727_684383652.jsonl.meta.json +1 -0
  135. package/.beads/.br_history/issues.20260308_213735_751882991.jsonl +57 -0
  136. package/.beads/.br_history/issues.20260308_213735_751882991.jsonl.meta.json +1 -0
  137. package/.beads/.br_history/issues.20260308_222052_279844960.jsonl +57 -0
  138. package/.beads/.br_history/issues.20260308_222052_279844960.jsonl.meta.json +1 -0
  139. package/.beads/.br_history/issues.20260308_222056_873282114.jsonl +57 -0
  140. package/.beads/.br_history/issues.20260308_222056_873282114.jsonl.meta.json +1 -0
  141. package/.beads/.br_history/issues.20260308_222103_402410761.jsonl +57 -0
  142. package/.beads/.br_history/issues.20260308_222103_402410761.jsonl.meta.json +1 -0
  143. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl +57 -0
  144. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl.meta.json +1 -0
  145. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl +57 -0
  146. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl.meta.json +1 -0
  147. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl +57 -0
  148. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl.meta.json +1 -0
  149. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl +57 -0
  150. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl.meta.json +1 -0
  151. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl +57 -0
  152. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl.meta.json +1 -0
  153. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl +57 -0
  154. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl.meta.json +1 -0
  155. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl +57 -0
  156. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl.meta.json +1 -0
  157. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl +57 -0
  158. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl.meta.json +1 -0
  159. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl +57 -0
  160. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl.meta.json +1 -0
  161. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl +57 -0
  162. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl.meta.json +1 -0
  163. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl +57 -0
  164. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl.meta.json +1 -0
  165. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl +57 -0
  166. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl.meta.json +1 -0
  167. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl +57 -0
  168. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl.meta.json +1 -0
  169. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl +57 -0
  170. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl.meta.json +1 -0
  171. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl +57 -0
  172. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl.meta.json +1 -0
  173. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl +57 -0
  174. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl.meta.json +1 -0
  175. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl +57 -0
  176. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl.meta.json +1 -0
  177. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl +57 -0
  178. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl.meta.json +1 -0
  179. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl +57 -0
  180. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl.meta.json +1 -0
  181. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl +57 -0
  182. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl.meta.json +1 -0
  183. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl +57 -0
  184. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl.meta.json +1 -0
  185. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl +58 -0
  186. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl.meta.json +1 -0
  187. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl +59 -0
  188. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl.meta.json +1 -0
  189. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl +60 -0
  190. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl.meta.json +1 -0
  191. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl +60 -0
  192. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl.meta.json +1 -0
  193. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl +60 -0
  194. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl.meta.json +1 -0
  195. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl +60 -0
  196. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl.meta.json +1 -0
  197. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl +60 -0
  198. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl.meta.json +1 -0
  199. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl +60 -0
  200. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl.meta.json +1 -0
  201. package/.beads/config.yaml +4 -0
  202. package/.beads/issues.jsonl +60 -0
  203. package/.beads/metadata.json +4 -0
  204. package/README.md +226 -43
  205. package/__tests__/adapter-schema.test.js +119 -0
  206. package/__tests__/ask.test.js +327 -0
  207. package/__tests__/aws-plugin.test.js +84 -0
  208. package/__tests__/az-plugin.test.js +84 -0
  209. package/__tests__/builtin-adapter.test.js +29 -0
  210. package/__tests__/cline-plugin.test.js +109 -0
  211. package/__tests__/cline-skill.test.js +49 -0
  212. package/__tests__/config.test.js +297 -0
  213. package/__tests__/docker-plugin.test.js +95 -0
  214. package/__tests__/executor.test.js +303 -0
  215. package/__tests__/eza-plugin.test.js +81 -0
  216. package/__tests__/gcloud-plugin.test.js +86 -0
  217. package/__tests__/gh-plugin.test.js +86 -0
  218. package/__tests__/helm-plugin.test.js +81 -0
  219. package/__tests__/help-json.test.js +19 -0
  220. package/__tests__/http-adapter.test.js +118 -0
  221. package/__tests__/just-plugin.test.js +82 -0
  222. package/__tests__/kubectl-plugin.test.js +83 -0
  223. package/__tests__/linear-plugin.test.js +81 -0
  224. package/__tests__/mcp-adapter.test.js +187 -0
  225. package/__tests__/mcp-local.test.js +105 -0
  226. package/__tests__/namespace-passthrough.test.js +69 -0
  227. package/__tests__/nextest-plugin.test.js +82 -0
  228. package/__tests__/npm-plugin.test.js +81 -0
  229. package/__tests__/nullclaw-plugin.test.js +157 -0
  230. package/__tests__/openapi-adapter.test.js +199 -0
  231. package/__tests__/plan-runtime.test.js +43 -0
  232. package/__tests__/planner.test.js +47 -0
  233. package/__tests__/plugin-agency-agents.test.js +62 -0
  234. package/__tests__/plugin-nullclaw.test.js +78 -0
  235. package/__tests__/plugin-visual-explainer.test.js +62 -0
  236. package/__tests__/plugins-command.test.js +220 -0
  237. package/__tests__/plugins-manager.test.js +353 -0
  238. package/__tests__/plugins-registry.test.js +114 -0
  239. package/__tests__/plugins-store.test.js +115 -0
  240. package/__tests__/pnpm-plugin.test.js +81 -0
  241. package/__tests__/poetry-plugin.test.js +83 -0
  242. package/__tests__/process-adapter.test.js +143 -0
  243. package/__tests__/pulumi-plugin.test.js +81 -0
  244. package/__tests__/railway-plugin.test.js +84 -0
  245. package/__tests__/server-app.test.js +67 -0
  246. package/__tests__/server-config-service.test.js +79 -0
  247. package/__tests__/server-routes-ask.test.js +89 -0
  248. package/__tests__/server-routes-commands.test.js +55 -0
  249. package/__tests__/server-routes-config.test.js +87 -0
  250. package/__tests__/server-routes-jobs.test.js +53 -0
  251. package/__tests__/server-routes-misc.test.js +112 -0
  252. package/__tests__/server-storage-adapter.test.js +40 -0
  253. package/__tests__/server-storage-file.test.js +73 -0
  254. package/__tests__/server-storage-mongo.test.js +74 -0
  255. package/__tests__/shell-adapter.test.js +90 -0
  256. package/__tests__/skills-catalog.test.js +98 -0
  257. package/__tests__/skills.test.js +442 -0
  258. package/__tests__/stripe-plugin.test.js +81 -0
  259. package/__tests__/supabase-plugin.test.js +86 -0
  260. package/__tests__/terraform-plugin.test.js +83 -0
  261. package/__tests__/uv-plugin.test.js +81 -0
  262. package/__tests__/vercel-plugin.test.js +81 -0
  263. package/__tests__/watchexec-plugin.test.js +80 -0
  264. package/cli/adapter-schema.js +108 -0
  265. package/cli/adapters/builtin.js +43 -0
  266. package/cli/adapters/process.js +262 -0
  267. package/cli/adapters/shell.js +82 -0
  268. package/cli/config.js +12 -9
  269. package/cli/executor.js +6 -1
  270. package/cli/help-json.js +3 -1
  271. package/cli/namespace-passthrough.js +38 -0
  272. package/cli/plugin-install-guidance.js +320 -0
  273. package/cli/plugins-command.js +138 -0
  274. package/cli/plugins-manager.js +552 -0
  275. package/cli/plugins-registry.js +80 -0
  276. package/cli/plugins-store.js +56 -0
  277. package/cli/skills-catalog.js +237 -0
  278. package/cli/skills.js +180 -6
  279. package/cli/supercli.js +150 -58
  280. package/docs/docs.html +224 -0
  281. package/docs/feature-gaps.md +16 -0
  282. package/docs/index.html +164 -0
  283. package/docs/plugin-examples.md +397 -0
  284. package/docs/plugin-harness-guide.md +452 -0
  285. package/docs/plugins.md +44 -0
  286. package/docs/skills/cline-non-interactive/SKILL.md +59 -0
  287. package/docs/skills-catalog.md +81 -0
  288. package/docs/supported-harnesses.md +277 -0
  289. package/docs/visual-overview.md +21 -0
  290. package/jest.config.js +25 -0
  291. package/package.json +9 -3
  292. package/plugins/agency-agents/plugin.json +15 -0
  293. package/plugins/agency-agents/scripts/post-install.js +122 -0
  294. package/plugins/aws/README.md +46 -0
  295. package/plugins/aws/plugin.json +42 -0
  296. package/plugins/az/README.md +46 -0
  297. package/plugins/az/plugin.json +42 -0
  298. package/plugins/beads/plugin.json +202 -0
  299. package/plugins/clickup/plugin.json +38 -0
  300. package/plugins/clickup/scripts/post-install.js +107 -0
  301. package/plugins/clickup/scripts/post-uninstall.js +30 -0
  302. package/plugins/cline/README.md +48 -0
  303. package/plugins/cline/plugin.json +92 -0
  304. package/plugins/commiat/plugin.json +36 -0
  305. package/plugins/docker/MANIFEST.md +39 -0
  306. package/plugins/docker/README.md +35 -0
  307. package/plugins/docker/examples/build-image.sh +7 -0
  308. package/plugins/docker/examples/inspect-container.sh +6 -0
  309. package/plugins/docker/examples/list-containers.sh +4 -0
  310. package/plugins/docker/examples/multi-step-workflow.sh +10 -0
  311. package/plugins/docker/examples/run-container.sh +7 -0
  312. package/plugins/docker/plugin.json +266 -0
  313. package/plugins/eza/README.md +40 -0
  314. package/plugins/eza/plugin.json +42 -0
  315. package/plugins/gcloud/README.md +46 -0
  316. package/plugins/gcloud/plugin.json +42 -0
  317. package/plugins/gh/README.md +46 -0
  318. package/plugins/gh/plugin.json +43 -0
  319. package/plugins/gwc/plugin.json +35 -0
  320. package/plugins/helm/README.md +42 -0
  321. package/plugins/helm/plugin.json +42 -0
  322. package/plugins/just/README.md +42 -0
  323. package/plugins/just/plugin.json +42 -0
  324. package/plugins/kubectl/README.md +46 -0
  325. package/plugins/kubectl/plugin.json +42 -0
  326. package/plugins/linear/README.md +60 -0
  327. package/plugins/linear/plugin.json +42 -0
  328. package/plugins/nextest/README.md +42 -0
  329. package/plugins/nextest/plugin.json +42 -0
  330. package/plugins/npm/README.md +46 -0
  331. package/plugins/npm/plugin.json +42 -0
  332. package/plugins/nullclaw/README.md +45 -0
  333. package/plugins/nullclaw/plugin.json +64 -0
  334. package/plugins/nullclaw/scripts/post-install.js +189 -0
  335. package/plugins/nullclaw/scripts/post-uninstall.js +25 -0
  336. package/plugins/openfang/plugin.json +37 -0
  337. package/plugins/openfang/scripts/post-install.js +163 -0
  338. package/plugins/openfang/scripts/post-uninstall.js +30 -0
  339. package/plugins/plugins.json +295 -0
  340. package/plugins/pnpm/README.md +46 -0
  341. package/plugins/pnpm/plugin.json +42 -0
  342. package/plugins/poetry/README.md +46 -0
  343. package/plugins/poetry/plugin.json +42 -0
  344. package/plugins/pulumi/README.md +46 -0
  345. package/plugins/pulumi/plugin.json +42 -0
  346. package/plugins/railway/README.md +58 -0
  347. package/plugins/railway/plugin.json +43 -0
  348. package/plugins/stripe/README.md +49 -0
  349. package/plugins/stripe/plugin.json +52 -0
  350. package/plugins/supabase/README.md +55 -0
  351. package/plugins/supabase/plugin.json +42 -0
  352. package/plugins/superpowers/plugin.json +22 -0
  353. package/plugins/superpowers/scripts/post-install.js +124 -0
  354. package/plugins/superpowers/scripts/post-uninstall.js +30 -0
  355. package/plugins/terraform/README.md +46 -0
  356. package/plugins/terraform/plugin.json +42 -0
  357. package/plugins/uv/README.md +46 -0
  358. package/plugins/uv/plugin.json +42 -0
  359. package/plugins/vercel/README.md +47 -0
  360. package/plugins/vercel/plugin.json +42 -0
  361. package/plugins/visual-explainer/plugin.json +15 -0
  362. package/plugins/visual-explainer/scripts/post-install.js +111 -0
  363. package/plugins/watchexec/README.md +40 -0
  364. package/plugins/watchexec/plugin.json +42 -0
  365. package/tests/test-aws-smoke.sh +56 -0
  366. package/tests/test-az-smoke.sh +56 -0
  367. package/tests/test-cli.js +116 -2
  368. package/tests/test-cline-smoke.sh +37 -0
  369. package/tests/test-eza-smoke.sh +33 -0
  370. package/tests/test-gcloud-smoke.sh +56 -0
  371. package/tests/test-gh-smoke.sh +56 -0
  372. package/tests/test-helm-smoke.sh +33 -0
  373. package/tests/test-just-smoke.sh +40 -0
  374. package/tests/test-kubectl-smoke.sh +37 -0
  375. package/tests/test-linear-smoke.sh +97 -0
  376. package/tests/test-nextest-smoke.sh +33 -0
  377. package/tests/test-npm-smoke.sh +32 -0
  378. package/tests/test-nullclaw-smoke.sh +51 -0
  379. package/tests/test-plugins-registry.js +212 -0
  380. package/tests/test-pnpm-smoke.sh +33 -0
  381. package/tests/test-poetry-smoke.sh +33 -0
  382. package/tests/test-pulumi-smoke.sh +33 -0
  383. package/tests/test-railway-smoke.sh +95 -0
  384. package/tests/test-stripe-smoke.sh +55 -0
  385. package/tests/test-supabase-smoke.sh +95 -0
  386. package/tests/test-terraform-smoke.sh +33 -0
  387. package/tests/test-uv-smoke.sh +33 -0
  388. package/tests/test-vercel-smoke.sh +55 -0
  389. package/tests/test-watchexec-smoke.sh +33 -0
@@ -0,0 +1,552 @@
1
+ const fs = require("fs")
2
+ const path = require("path")
3
+ const os = require("os")
4
+ const { spawnSync } = require("child_process")
5
+ const { SUPPORTED_ADAPTERS } = require("./adapter-schema")
6
+ const { getRegistryPlugin } = require("./plugins-registry")
7
+ const { getPluginInstallGuidance } = require("./plugin-install-guidance")
8
+ const {
9
+ readPluginsLock,
10
+ writePluginsLock,
11
+ listInstalledPlugins
12
+ } = require("./plugins-store")
13
+
14
+ const BUNDLED_PLUGINS = {
15
+ beads: path.resolve(__dirname, "..", "plugins", "beads", "plugin.json"),
16
+ gwc: path.resolve(__dirname, "..", "plugins", "gwc", "plugin.json"),
17
+ docker: path.resolve(__dirname, "..", "plugins", "docker", "plugin.json"),
18
+ "agency-agents": path.resolve(__dirname, "..", "plugins", "agency-agents", "plugin.json"),
19
+ "visual-explainer": path.resolve(__dirname, "..", "plugins", "visual-explainer", "plugin.json")
20
+ }
21
+
22
+ function validateNodeHook(hook, kind) {
23
+ if (!hook) return null
24
+ if (!hook.script || typeof hook.script !== "string") {
25
+ throw Object.assign(new Error(`Invalid plugin manifest: ${kind}.script must be a string`), {
26
+ code: 85,
27
+ type: "invalid_argument",
28
+ recoverable: false
29
+ })
30
+ }
31
+
32
+ const runtime = hook.runtime || "node"
33
+ if (runtime !== "node") {
34
+ throw Object.assign(new Error(`Invalid plugin manifest: ${kind}.runtime must be 'node'`), {
35
+ code: 85,
36
+ type: "invalid_argument",
37
+ recoverable: false
38
+ })
39
+ }
40
+
41
+ const timeoutMs = hook.timeout_ms === undefined ? 15000 : Number(hook.timeout_ms)
42
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 15000) {
43
+ throw Object.assign(new Error(`Invalid plugin manifest: ${kind}.timeout_ms must be a positive number <= 15000`), {
44
+ code: 85,
45
+ type: "invalid_argument",
46
+ recoverable: false
47
+ })
48
+ }
49
+
50
+ return {
51
+ script: hook.script,
52
+ runtime,
53
+ timeout_ms: timeoutMs
54
+ }
55
+ }
56
+
57
+ function commandKey(cmd) {
58
+ return `${cmd.namespace}.${cmd.resource}.${cmd.action}`
59
+ }
60
+
61
+ function resolveManifestPath(ref) {
62
+ const base = BUNDLED_PLUGINS[ref] || path.resolve(ref)
63
+ if (!fs.existsSync(base)) return null
64
+ const st = fs.statSync(base)
65
+ if (st.isDirectory()) return path.join(base, "plugin.json")
66
+ return base
67
+ }
68
+
69
+ function parseManifestFile(manifestPath) {
70
+ let raw
71
+ try {
72
+ raw = JSON.parse(fs.readFileSync(manifestPath, "utf-8"))
73
+ } catch (err) {
74
+ throw Object.assign(new Error(`Invalid plugin manifest at ${manifestPath}: ${err.message}`), {
75
+ code: 85,
76
+ type: "invalid_argument",
77
+ recoverable: false
78
+ })
79
+ }
80
+ if (!raw.name || !Array.isArray(raw.commands)) {
81
+ throw Object.assign(new Error("Invalid plugin manifest: missing name or commands"), {
82
+ code: 85,
83
+ type: "invalid_argument",
84
+ recoverable: false
85
+ })
86
+ }
87
+ return raw
88
+ }
89
+
90
+ function resolveRepoManifestPath(baseDir, manifestPath) {
91
+ const relative = manifestPath || "plugin.json"
92
+ const candidate = path.resolve(baseDir, relative)
93
+ const normalizedBase = path.resolve(baseDir) + path.sep
94
+ if (!candidate.startsWith(normalizedBase)) {
95
+ throw Object.assign(new Error(`Invalid manifest path '${relative}'`), {
96
+ code: 85,
97
+ type: "invalid_argument",
98
+ recoverable: false
99
+ })
100
+ }
101
+ return candidate
102
+ }
103
+
104
+ function noCleanup() {
105
+ return undefined
106
+ }
107
+
108
+ function loadManifestFromGit(repo, options = {}) {
109
+ if (!repo || typeof repo !== "string") {
110
+ throw Object.assign(new Error("Missing git repo URL/path for plugin install"), {
111
+ code: 85,
112
+ type: "invalid_argument",
113
+ recoverable: false
114
+ })
115
+ }
116
+
117
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-plugin-"))
118
+ const args = ["clone", "--depth", "1"]
119
+ if (options.ref) args.push("--branch", String(options.ref), "--single-branch")
120
+ args.push(repo, tmpDir)
121
+ const clone = spawnSync("git", args, { encoding: "utf-8", timeout: 15000 })
122
+
123
+ if (clone.error) {
124
+ fs.rmSync(tmpDir, { recursive: true, force: true })
125
+ const suggestion = clone.error.code === "ENOENT" ? ["Install git and retry"] : []
126
+ throw Object.assign(new Error(`Failed to clone plugin repo '${repo}': ${clone.error.message}`), {
127
+ code: 105,
128
+ type: "integration_error",
129
+ recoverable: true,
130
+ suggestions: suggestion
131
+ })
132
+ }
133
+ if (clone.status !== 0) {
134
+ fs.rmSync(tmpDir, { recursive: true, force: true })
135
+ throw Object.assign(new Error(`Failed to clone plugin repo '${repo}': ${(clone.stderr || "").trim() || `exit ${clone.status}`}`), {
136
+ code: 105,
137
+ type: "integration_error",
138
+ recoverable: true
139
+ })
140
+ }
141
+
142
+ const manifestPath = resolveRepoManifestPath(tmpDir, options.manifestPath)
143
+ if (!fs.existsSync(manifestPath)) {
144
+ fs.rmSync(tmpDir, { recursive: true, force: true })
145
+ throw Object.assign(new Error(`Plugin manifest not found in repo: ${options.manifestPath || "plugin.json"}`), {
146
+ code: 92,
147
+ type: "resource_not_found",
148
+ recoverable: false
149
+ })
150
+ }
151
+
152
+ return {
153
+ manifest: parseManifestFile(manifestPath),
154
+ manifestPath,
155
+ resolvedFrom: {
156
+ type: "git",
157
+ repo,
158
+ ref: options.ref || null,
159
+ manifest_path: options.manifestPath || "plugin.json"
160
+ },
161
+ cleanup: () => fs.rmSync(tmpDir, { recursive: true, force: true })
162
+ }
163
+ }
164
+
165
+ function resolveRegistrySource(name) {
166
+ const entry = getRegistryPlugin(name)
167
+ if (!entry) return null
168
+
169
+ const source = entry.source || {}
170
+ const sourceType = source.type || "bundled"
171
+ if (sourceType === "git") {
172
+ return {
173
+ type: "git",
174
+ repo: source.repo,
175
+ ref: source.ref,
176
+ manifestPath: source.manifest_path
177
+ }
178
+ }
179
+
180
+ const manifestPath = source.manifest_path || `plugins/${entry.name}/plugin.json`
181
+ return {
182
+ type: "path",
183
+ manifestPath: path.resolve(__dirname, "..", manifestPath)
184
+ }
185
+ }
186
+
187
+ function loadPluginManifest(ref, options = {}) {
188
+ if (options.git) {
189
+ return loadManifestFromGit(options.git, {
190
+ ref: options.ref,
191
+ manifestPath: options.manifestPath
192
+ })
193
+ }
194
+
195
+ const directManifestPath = resolveManifestPath(ref)
196
+ if (directManifestPath && fs.existsSync(directManifestPath)) {
197
+ return {
198
+ manifest: parseManifestFile(directManifestPath),
199
+ manifestPath: directManifestPath,
200
+ resolvedFrom: {
201
+ type: "path",
202
+ manifest_path: directManifestPath
203
+ },
204
+ cleanup: noCleanup
205
+ }
206
+ }
207
+
208
+ const registrySource = resolveRegistrySource(ref)
209
+ if (!registrySource) {
210
+ throw Object.assign(new Error(`Plugin '${ref}' not found`), {
211
+ code: 92,
212
+ type: "resource_not_found",
213
+ recoverable: false,
214
+ suggestions: ["Run: dcli plugins explore"]
215
+ })
216
+ }
217
+
218
+ if (registrySource.type === "git") {
219
+ return loadManifestFromGit(registrySource.repo, {
220
+ ref: registrySource.ref,
221
+ manifestPath: registrySource.manifestPath
222
+ })
223
+ }
224
+
225
+ if (!registrySource.manifestPath || !fs.existsSync(registrySource.manifestPath)) {
226
+ throw Object.assign(new Error(`Plugin manifest not found for '${ref}'`), {
227
+ code: 92,
228
+ type: "resource_not_found",
229
+ recoverable: false
230
+ })
231
+ }
232
+
233
+ return {
234
+ manifest: parseManifestFile(registrySource.manifestPath),
235
+ manifestPath: registrySource.manifestPath,
236
+ resolvedFrom: {
237
+ type: "registry",
238
+ name: ref,
239
+ manifest_path: registrySource.manifestPath
240
+ },
241
+ cleanup: noCleanup
242
+ }
243
+ }
244
+
245
+ function parsePostInstallResult(stdout) {
246
+ const text = (stdout || "").trim()
247
+ if (!text) return null
248
+ try {
249
+ return JSON.parse(text)
250
+ } catch {
251
+ return { raw: text }
252
+ }
253
+ }
254
+
255
+ function resolveHookScriptPath(manifestDir, script, kind) {
256
+ const scriptPath = path.resolve(manifestDir, script)
257
+ const normalizedBase = path.resolve(manifestDir) + path.sep
258
+ if (!scriptPath.startsWith(normalizedBase)) {
259
+ throw Object.assign(new Error(`Invalid ${kind} script path '${script}'`), {
260
+ code: 85,
261
+ type: "invalid_argument",
262
+ recoverable: false
263
+ })
264
+ }
265
+ if (!fs.existsSync(scriptPath)) {
266
+ throw Object.assign(new Error(`${kind} script not found: ${script}`), {
267
+ code: 92,
268
+ type: "resource_not_found",
269
+ recoverable: false
270
+ })
271
+ }
272
+ return scriptPath
273
+ }
274
+
275
+ function runNodeHook(pluginName, kind, hook, scriptPath, env = {}) {
276
+ const result = spawnSync("node", [scriptPath], {
277
+ encoding: "utf-8",
278
+ timeout: hook.timeout_ms,
279
+ env: {
280
+ ...process.env,
281
+ ...env,
282
+ SUPERCLI_PLUGIN_NAME: pluginName,
283
+ SUPERCLI_PLUGIN_DIR: path.dirname(scriptPath)
284
+ }
285
+ })
286
+
287
+ if (result.error) {
288
+ throw Object.assign(new Error(`${kind} hook failed for '${pluginName}': ${result.error.message}`), {
289
+ code: 105,
290
+ type: "integration_error",
291
+ recoverable: true
292
+ })
293
+ }
294
+ if (result.status !== 0) {
295
+ throw Object.assign(new Error(`${kind} hook failed for '${pluginName}': ${(result.stderr || "").trim() || `exit ${result.status}`}`), {
296
+ code: 105,
297
+ type: "integration_error",
298
+ recoverable: true
299
+ })
300
+ }
301
+
302
+ return parsePostInstallResult(result.stdout)
303
+ }
304
+
305
+ function runPostInstall(manifest, manifestPath) {
306
+ const hook = validateNodeHook(manifest.post_install, "post_install")
307
+ if (!hook) return null
308
+ const manifestDir = path.dirname(manifestPath)
309
+ const scriptPath = resolveHookScriptPath(manifestDir, hook.script, "post-install")
310
+ return runNodeHook(manifest.name, "Post-install", hook, scriptPath)
311
+ }
312
+
313
+ function serializeHook(manifestPath, hook, kind) {
314
+ const validHook = validateNodeHook(hook, kind)
315
+ if (!validHook) return null
316
+ const manifestDir = path.dirname(manifestPath)
317
+ const scriptPath = resolveHookScriptPath(manifestDir, validHook.script, kind.replace(/_/g, "-"))
318
+ return {
319
+ runtime: validHook.runtime,
320
+ timeout_ms: validHook.timeout_ms,
321
+ script_path: scriptPath,
322
+ script_name: path.basename(scriptPath),
323
+ script_source: fs.readFileSync(scriptPath, "utf-8")
324
+ }
325
+ }
326
+
327
+ function runStoredHook(pluginName, kind, storedHook) {
328
+ if (!storedHook) return null
329
+ const runtime = storedHook.runtime || "node"
330
+ if (runtime !== "node") {
331
+ throw Object.assign(new Error(`Unsupported stored ${kind} runtime '${runtime}' for '${pluginName}'`), {
332
+ code: 85,
333
+ type: "invalid_argument",
334
+ recoverable: false
335
+ })
336
+ }
337
+
338
+ if (storedHook.script_path && fs.existsSync(storedHook.script_path)) {
339
+ return runNodeHook(pluginName, `Post-${kind}`, {
340
+ runtime,
341
+ timeout_ms: Number(storedHook.timeout_ms) || 15000
342
+ }, storedHook.script_path)
343
+ }
344
+
345
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-plugin-hook-"))
346
+ try {
347
+ const scriptName = storedHook.script_name || `${kind}.js`
348
+ const scriptPath = path.join(tmpDir, scriptName)
349
+ fs.writeFileSync(scriptPath, storedHook.script_source || "")
350
+ return runNodeHook(pluginName, `Post-${kind}`, {
351
+ runtime,
352
+ timeout_ms: Number(storedHook.timeout_ms) || 15000
353
+ }, scriptPath)
354
+ } finally {
355
+ fs.rmSync(tmpDir, { recursive: true, force: true })
356
+ }
357
+ }
358
+
359
+ function checkBinary(binary) {
360
+ const r = spawnSync(binary, ["--version"], { encoding: "utf-8", timeout: 5000 })
361
+ if (r.error) {
362
+ return {
363
+ binary,
364
+ ok: false,
365
+ message: r.error.code === "ENOENT" ? "not installed" : r.error.message
366
+ }
367
+ }
368
+ if (r.status !== 0) {
369
+ return {
370
+ binary,
371
+ ok: false,
372
+ message: (r.stderr || "").trim() || `exit ${r.status}`
373
+ }
374
+ }
375
+ return {
376
+ binary,
377
+ ok: true,
378
+ message: (r.stdout || "").trim() || "ok"
379
+ }
380
+ }
381
+
382
+ function doctorPlugin(name) {
383
+ const plugin = getPlugin(name)
384
+ if (!plugin) {
385
+ throw Object.assign(new Error(`Plugin '${name}' is not installed`), {
386
+ code: 92,
387
+ type: "resource_not_found",
388
+ recoverable: false,
389
+ suggestions: ["Run: dcli plugins list"]
390
+ })
391
+ }
392
+
393
+ const checks = []
394
+ for (const check of (plugin.checks || [])) {
395
+ if (check && check.type === "binary" && check.name) {
396
+ checks.push({ type: "binary", ...checkBinary(check.name) })
397
+ }
398
+ }
399
+
400
+ const adapterCounts = {}
401
+ let unsafeCommands = 0
402
+ for (const cmd of (plugin.commands || [])) {
403
+ const adapter = cmd.adapter || "(missing)"
404
+ adapterCounts[adapter] = (adapterCounts[adapter] || 0) + 1
405
+ if (!SUPPORTED_ADAPTERS.includes(adapter)) {
406
+ checks.push({ type: "policy", ok: false, message: `Command '${commandKey(cmd)}' uses unknown adapter '${adapter}'` })
407
+ }
408
+ const cfg = cmd.adapterConfig || {}
409
+ if (adapter === "shell") {
410
+ if (cfg.unsafe !== true) checks.push({ type: "policy", ok: false, message: `Shell command '${commandKey(cmd)}' must set adapterConfig.unsafe=true` })
411
+ else unsafeCommands += 1
412
+ if (cfg.non_interactive === false) {
413
+ checks.push({ type: "policy", ok: false, message: `Shell command '${commandKey(cmd)}' cannot disable non_interactive` })
414
+ }
415
+ }
416
+ }
417
+
418
+ return {
419
+ plugin: name,
420
+ ok: checks.every(c => c.ok),
421
+ commands: (plugin.commands || []).length,
422
+ adapter_counts: adapterCounts,
423
+ unsafe_commands: unsafeCommands,
424
+ checks,
425
+ install_guidance: getPluginInstallGuidance(name)
426
+ }
427
+ }
428
+
429
+ function doctorAllPlugins() {
430
+ const reports = listInstalledPlugins().map(p => doctorPlugin(p.name))
431
+ return {
432
+ plugins: reports,
433
+ ok: reports.every(r => r.ok),
434
+ total_plugins: reports.length,
435
+ failing_plugins: reports.filter(r => !r.ok).map(r => r.plugin)
436
+ }
437
+ }
438
+
439
+ function installPlugin(ref, options = {}) {
440
+ const onConflict = options.onConflict || "fail"
441
+ if (!["fail", "skip", "replace"].includes(onConflict)) {
442
+ throw Object.assign(new Error("Invalid --on-conflict. Use: fail, skip, replace"), {
443
+ code: 85,
444
+ type: "invalid_argument",
445
+ recoverable: false
446
+ })
447
+ }
448
+
449
+ const loaded = loadPluginManifest(ref, options)
450
+ try {
451
+ const manifest = loaded.manifest
452
+ const lock = readPluginsLock()
453
+ const existing = lock.installed[manifest.name]
454
+ const currentCommands = Array.isArray(options.currentCommands) ? options.currentCommands : []
455
+
456
+ const existingByKey = {}
457
+ for (const cmd of currentCommands) existingByKey[commandKey(cmd)] = true
458
+
459
+ const ownerByKey = {}
460
+ for (const [pluginName, plugin] of Object.entries(lock.installed)) {
461
+ for (const cmd of (plugin.commands || [])) ownerByKey[commandKey(cmd)] = pluginName
462
+ }
463
+
464
+ const existingKeysForSamePlugin = new Set((existing && existing.commands ? existing.commands : []).map(commandKey))
465
+ const conflicts = []
466
+ const installedCommands = []
467
+
468
+ for (const cmd of manifest.commands) {
469
+ const key = commandKey(cmd)
470
+ const owner = ownerByKey[key]
471
+ if ((!existingByKey[key] && !owner) || existingKeysForSamePlugin.has(key)) {
472
+ installedCommands.push(cmd)
473
+ continue
474
+ }
475
+ if (onConflict === "skip") {
476
+ conflicts.push({ key, owner, action: "skipped" })
477
+ continue
478
+ }
479
+ if (onConflict === "replace") {
480
+ if (owner) {
481
+ lock.installed[owner].commands = (lock.installed[owner].commands || []).filter(c => commandKey(c) !== key)
482
+ conflicts.push({ key, owner, action: "replaced" })
483
+ installedCommands.push(cmd)
484
+ continue
485
+ }
486
+ conflicts.push({ key, owner: "base", action: "blocked" })
487
+ continue
488
+ }
489
+ conflicts.push({ key, owner, action: "blocked" })
490
+ }
491
+
492
+ if (onConflict === "fail" && conflicts.length > 0) {
493
+ throw Object.assign(new Error(`Plugin install conflict for: ${conflicts.map(c => c.key).join(", ")}`), {
494
+ code: 85,
495
+ type: "invalid_argument",
496
+ recoverable: false,
497
+ suggestions: ["Retry with --on-conflict skip", "Retry with --on-conflict replace"]
498
+ })
499
+ }
500
+
501
+ lock.installed[manifest.name] = {
502
+ name: manifest.name,
503
+ version: manifest.version || "0.0.0",
504
+ description: manifest.description || "",
505
+ source: manifest.source || ref,
506
+ resolved_from: loaded.resolvedFrom,
507
+ installed_at: new Date().toISOString(),
508
+ commands: installedCommands,
509
+ checks: manifest.checks || [],
510
+ lifecycle_hooks: {
511
+ post_uninstall: serializeHook(loaded.manifestPath, manifest.post_uninstall, "post_uninstall")
512
+ }
513
+ }
514
+
515
+ const postInstall = runPostInstall(manifest, loaded.manifestPath)
516
+ writePluginsLock(lock)
517
+ return {
518
+ plugin: manifest.name,
519
+ version: manifest.version || "0.0.0",
520
+ installed_commands: installedCommands.length,
521
+ conflicts,
522
+ post_install: postInstall
523
+ }
524
+ } finally {
525
+ if (typeof loaded.cleanup === "function") loaded.cleanup()
526
+ }
527
+ }
528
+
529
+ function removePlugin(name) {
530
+ const lock = readPluginsLock()
531
+ const plugin = lock.installed[name]
532
+ if (!plugin) return false
533
+ runStoredHook(name, "uninstall", plugin.lifecycle_hooks && plugin.lifecycle_hooks.post_uninstall)
534
+ delete lock.installed[name]
535
+ writePluginsLock(lock)
536
+ return true
537
+ }
538
+
539
+ function getPlugin(name) {
540
+ const lock = readPluginsLock()
541
+ return lock.installed[name] || null
542
+ }
543
+
544
+ module.exports = {
545
+ installPlugin,
546
+ removePlugin,
547
+ getPlugin,
548
+ listInstalledPlugins,
549
+ getPluginInstallGuidance,
550
+ doctorPlugin,
551
+ doctorAllPlugins
552
+ }
@@ -0,0 +1,80 @@
1
+ const fs = require("fs")
2
+ const path = require("path")
3
+
4
+ const REGISTRY_FILE = path.resolve(__dirname, "..", "plugins", "plugins.json")
5
+
6
+ function invalid(message) {
7
+ return Object.assign(new Error(message), {
8
+ code: 85,
9
+ type: "invalid_argument",
10
+ recoverable: false
11
+ })
12
+ }
13
+
14
+ function readRegistry() {
15
+ if (!fs.existsSync(REGISTRY_FILE)) {
16
+ return { version: 1, plugins: [] }
17
+ }
18
+
19
+ let parsed
20
+ try {
21
+ parsed = JSON.parse(fs.readFileSync(REGISTRY_FILE, "utf-8"))
22
+ } catch (err) {
23
+ throw invalid(`Invalid plugin registry at ${REGISTRY_FILE}: ${err.message}`)
24
+ }
25
+
26
+ if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.plugins)) {
27
+ throw invalid("Invalid plugin registry: expected object with plugins array")
28
+ }
29
+
30
+ return parsed
31
+ }
32
+
33
+ function normalizePlugin(entry) {
34
+ return {
35
+ name: entry.name,
36
+ description: entry.description || "",
37
+ tags: Array.isArray(entry.tags) ? entry.tags.map(t => String(t)) : [],
38
+ source: entry.source && typeof entry.source === "object" ? entry.source : {}
39
+ }
40
+ }
41
+
42
+ function listRegistryPlugins(filters = {}) {
43
+ const registry = readRegistry()
44
+ const nameQuery = (filters.name || "").toLowerCase().trim()
45
+ const tagQueries = (filters.tags || [])
46
+ .map(t => String(t || "").toLowerCase().trim())
47
+ .filter(Boolean)
48
+
49
+ return registry.plugins
50
+ .map(normalizePlugin)
51
+ .filter(entry => {
52
+ if (nameQuery) {
53
+ const text = `${entry.name} ${entry.description}`.toLowerCase()
54
+ if (!text.includes(nameQuery)) return false
55
+ }
56
+
57
+ if (tagQueries.length > 0) {
58
+ const tags = entry.tags.map(t => t.toLowerCase())
59
+ const anyMatch = tagQueries.some(q => tags.includes(q))
60
+ if (!anyMatch) return false
61
+ }
62
+
63
+ return true
64
+ })
65
+ }
66
+
67
+ function getRegistryPlugin(name) {
68
+ const lower = String(name || "").toLowerCase()
69
+ if (!lower) return null
70
+ const registry = readRegistry()
71
+ const found = registry.plugins.find(p => String(p.name || "").toLowerCase() === lower)
72
+ return found ? normalizePlugin(found) : null
73
+ }
74
+
75
+ module.exports = {
76
+ REGISTRY_FILE,
77
+ readRegistry,
78
+ listRegistryPlugins,
79
+ getRegistryPlugin
80
+ }
@@ -0,0 +1,56 @@
1
+ const fs = require("fs")
2
+ const os = require("os")
3
+ const path = require("path")
4
+
5
+ const DCLI_DIR = path.join(os.homedir(), ".dcli")
6
+ const PLUGINS_FILE = path.join(DCLI_DIR, "plugins.lock.json")
7
+
8
+ function ensureDir() {
9
+ if (!fs.existsSync(DCLI_DIR)) fs.mkdirSync(DCLI_DIR, { recursive: true })
10
+ }
11
+
12
+ function emptyLock() {
13
+ return { version: 1, installed: {} }
14
+ }
15
+
16
+ function readPluginsLock() {
17
+ try {
18
+ if (!fs.existsSync(PLUGINS_FILE)) return emptyLock()
19
+ const parsed = JSON.parse(fs.readFileSync(PLUGINS_FILE, "utf-8"))
20
+ if (!parsed || typeof parsed !== "object") return emptyLock()
21
+ if (!parsed.installed || typeof parsed.installed !== "object") parsed.installed = {}
22
+ return parsed
23
+ } catch {
24
+ return emptyLock()
25
+ }
26
+ }
27
+
28
+ function writePluginsLock(lock) {
29
+ ensureDir()
30
+ fs.writeFileSync(PLUGINS_FILE, JSON.stringify(lock, null, 2))
31
+ return lock
32
+ }
33
+
34
+ function listInstalledPlugins() {
35
+ const lock = readPluginsLock()
36
+ return Object.values(lock.installed)
37
+ }
38
+
39
+ function getInstalledPluginCommands() {
40
+ const lock = readPluginsLock()
41
+ const commands = []
42
+ for (const plugin of Object.values(lock.installed)) {
43
+ for (const cmd of (plugin.commands || [])) {
44
+ commands.push(cmd)
45
+ }
46
+ }
47
+ return commands
48
+ }
49
+
50
+ module.exports = {
51
+ PLUGINS_FILE,
52
+ readPluginsLock,
53
+ writePluginsLock,
54
+ listInstalledPlugins,
55
+ getInstalledPluginCommands
56
+ }