superacli 1.1.0 → 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 (261) hide show
  1. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl +57 -0
  2. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl +57 -0
  3. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl +57 -0
  4. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl +57 -0
  5. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl +57 -0
  6. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl +57 -0
  7. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl +57 -0
  8. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl +57 -0
  9. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl +57 -0
  10. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl +57 -0
  11. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl +57 -0
  12. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl +57 -0
  13. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl +57 -0
  14. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl +57 -0
  15. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl +57 -0
  16. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl +57 -0
  17. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl +57 -0
  18. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl +57 -0
  19. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl +57 -0
  20. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl +57 -0
  21. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl +57 -0
  22. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl +58 -0
  23. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl +59 -0
  24. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl +60 -0
  25. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl +60 -0
  26. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl +60 -0
  27. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl +60 -0
  28. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl +60 -0
  29. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl +60 -0
  30. package/.beads/issues.jsonl +20 -17
  31. package/README.md +1 -1
  32. package/__tests__/adapter-schema.test.js +3 -0
  33. package/__tests__/aws-plugin.test.js +84 -0
  34. package/__tests__/az-plugin.test.js +84 -0
  35. package/__tests__/builtin-adapter.test.js +29 -0
  36. package/__tests__/cline-plugin.test.js +109 -0
  37. package/__tests__/cline-skill.test.js +49 -0
  38. package/__tests__/docker-plugin.test.js +3 -1
  39. package/__tests__/eza-plugin.test.js +81 -0
  40. package/__tests__/gcloud-plugin.test.js +86 -0
  41. package/__tests__/gh-plugin.test.js +86 -0
  42. package/__tests__/helm-plugin.test.js +81 -0
  43. package/__tests__/http-adapter.test.js +118 -0
  44. package/__tests__/just-plugin.test.js +82 -0
  45. package/__tests__/kubectl-plugin.test.js +83 -0
  46. package/__tests__/linear-plugin.test.js +81 -0
  47. package/__tests__/mcp-adapter.test.js +187 -0
  48. package/__tests__/nextest-plugin.test.js +82 -0
  49. package/__tests__/npm-plugin.test.js +81 -0
  50. package/__tests__/nullclaw-plugin.test.js +157 -0
  51. package/__tests__/openapi-adapter.test.js +199 -0
  52. package/__tests__/plugin-agency-agents.test.js +6 -6
  53. package/__tests__/plugin-nullclaw.test.js +78 -0
  54. package/__tests__/plugin-visual-explainer.test.js +62 -0
  55. package/__tests__/plugins-manager.test.js +59 -10
  56. package/__tests__/pnpm-plugin.test.js +81 -0
  57. package/__tests__/poetry-plugin.test.js +83 -0
  58. package/__tests__/process-adapter.test.js +124 -90
  59. package/__tests__/pulumi-plugin.test.js +81 -0
  60. package/__tests__/railway-plugin.test.js +84 -0
  61. package/__tests__/server-app.test.js +67 -0
  62. package/__tests__/server-config-service.test.js +79 -0
  63. package/__tests__/server-routes-ask.test.js +89 -0
  64. package/__tests__/server-routes-commands.test.js +55 -0
  65. package/__tests__/server-routes-config.test.js +87 -0
  66. package/__tests__/server-routes-jobs.test.js +53 -0
  67. package/__tests__/server-routes-misc.test.js +112 -0
  68. package/__tests__/server-storage-adapter.test.js +40 -0
  69. package/__tests__/server-storage-file.test.js +73 -0
  70. package/__tests__/server-storage-mongo.test.js +74 -0
  71. package/__tests__/shell-adapter.test.js +81 -22
  72. package/__tests__/stripe-plugin.test.js +3 -1
  73. package/__tests__/supabase-plugin.test.js +86 -0
  74. package/__tests__/terraform-plugin.test.js +83 -0
  75. package/__tests__/uv-plugin.test.js +81 -0
  76. package/__tests__/vercel-plugin.test.js +81 -0
  77. package/__tests__/watchexec-plugin.test.js +80 -0
  78. package/cli/adapter-schema.js +5 -0
  79. package/cli/adapters/process.js +53 -2
  80. package/cli/plugin-install-guidance.js +320 -0
  81. package/cli/plugins-manager.js +272 -212
  82. package/cli/skills.js +16 -5
  83. package/cli/supercli.js +26 -2
  84. package/docs/plugins.md +2 -0
  85. package/docs/skills/cline-non-interactive/SKILL.md +59 -0
  86. package/docs/skills-catalog.md +35 -0
  87. package/docs/visual-overview.md +21 -0
  88. package/jest.config.js +4 -1
  89. package/package.json +4 -3
  90. package/plugins/agency-agents/plugin.json +5 -0
  91. package/{cli/plugin-agency-agents.js → plugins/agency-agents/scripts/post-install.js} +13 -3
  92. package/plugins/aws/README.md +46 -0
  93. package/plugins/aws/plugin.json +42 -0
  94. package/plugins/az/README.md +46 -0
  95. package/plugins/az/plugin.json +42 -0
  96. package/plugins/clickup/plugin.json +38 -0
  97. package/plugins/clickup/scripts/post-install.js +107 -0
  98. package/plugins/clickup/scripts/post-uninstall.js +30 -0
  99. package/plugins/cline/README.md +48 -0
  100. package/plugins/cline/plugin.json +92 -0
  101. package/plugins/eza/README.md +40 -0
  102. package/plugins/eza/plugin.json +42 -0
  103. package/plugins/gcloud/README.md +46 -0
  104. package/plugins/gcloud/plugin.json +42 -0
  105. package/plugins/gh/README.md +46 -0
  106. package/plugins/gh/plugin.json +43 -0
  107. package/plugins/helm/README.md +42 -0
  108. package/plugins/helm/plugin.json +42 -0
  109. package/plugins/just/README.md +42 -0
  110. package/plugins/just/plugin.json +42 -0
  111. package/plugins/kubectl/README.md +46 -0
  112. package/plugins/kubectl/plugin.json +42 -0
  113. package/plugins/linear/README.md +60 -0
  114. package/plugins/linear/plugin.json +42 -0
  115. package/plugins/nextest/README.md +42 -0
  116. package/plugins/nextest/plugin.json +42 -0
  117. package/plugins/npm/README.md +46 -0
  118. package/plugins/npm/plugin.json +42 -0
  119. package/plugins/nullclaw/README.md +45 -0
  120. package/plugins/nullclaw/plugin.json +64 -0
  121. package/plugins/nullclaw/scripts/post-install.js +189 -0
  122. package/plugins/nullclaw/scripts/post-uninstall.js +25 -0
  123. package/plugins/openfang/plugin.json +37 -0
  124. package/plugins/openfang/scripts/post-install.js +163 -0
  125. package/plugins/openfang/scripts/post-uninstall.js +30 -0
  126. package/plugins/plugins.json +234 -0
  127. package/plugins/pnpm/README.md +46 -0
  128. package/plugins/pnpm/plugin.json +42 -0
  129. package/plugins/poetry/README.md +46 -0
  130. package/plugins/poetry/plugin.json +42 -0
  131. package/plugins/pulumi/README.md +46 -0
  132. package/plugins/pulumi/plugin.json +42 -0
  133. package/plugins/railway/README.md +58 -0
  134. package/plugins/railway/plugin.json +43 -0
  135. package/plugins/supabase/README.md +55 -0
  136. package/plugins/supabase/plugin.json +42 -0
  137. package/plugins/superpowers/plugin.json +22 -0
  138. package/plugins/superpowers/scripts/post-install.js +124 -0
  139. package/plugins/superpowers/scripts/post-uninstall.js +30 -0
  140. package/plugins/terraform/README.md +46 -0
  141. package/plugins/terraform/plugin.json +42 -0
  142. package/plugins/uv/README.md +46 -0
  143. package/plugins/uv/plugin.json +42 -0
  144. package/plugins/vercel/README.md +47 -0
  145. package/plugins/vercel/plugin.json +42 -0
  146. package/plugins/visual-explainer/plugin.json +15 -0
  147. package/plugins/visual-explainer/scripts/post-install.js +111 -0
  148. package/plugins/watchexec/README.md +40 -0
  149. package/plugins/watchexec/plugin.json +42 -0
  150. package/tests/test-aws-smoke.sh +56 -0
  151. package/tests/test-az-smoke.sh +56 -0
  152. package/tests/test-cline-smoke.sh +37 -0
  153. package/tests/test-eza-smoke.sh +33 -0
  154. package/tests/test-gcloud-smoke.sh +56 -0
  155. package/tests/test-gh-smoke.sh +56 -0
  156. package/tests/test-helm-smoke.sh +33 -0
  157. package/tests/test-just-smoke.sh +40 -0
  158. package/tests/test-kubectl-smoke.sh +37 -0
  159. package/tests/test-linear-smoke.sh +97 -0
  160. package/tests/test-nextest-smoke.sh +33 -0
  161. package/tests/test-npm-smoke.sh +32 -0
  162. package/tests/test-nullclaw-smoke.sh +51 -0
  163. package/tests/test-plugins-registry.js +110 -0
  164. package/tests/test-pnpm-smoke.sh +33 -0
  165. package/tests/test-poetry-smoke.sh +33 -0
  166. package/tests/test-pulumi-smoke.sh +33 -0
  167. package/tests/test-railway-smoke.sh +95 -0
  168. package/tests/test-supabase-smoke.sh +95 -0
  169. package/tests/test-terraform-smoke.sh +33 -0
  170. package/tests/test-uv-smoke.sh +33 -0
  171. package/tests/test-vercel-smoke.sh +55 -0
  172. package/tests/test-watchexec-smoke.sh +33 -0
  173. package/.beads/.br_history/issues.20260308_180927_477542428.jsonl +0 -12
  174. package/.beads/.br_history/issues.20260308_181032_020230108.jsonl +0 -12
  175. package/.beads/.br_history/issues.20260308_181032_180539413.jsonl +0 -12
  176. package/.beads/.br_history/issues.20260308_181032_372621506.jsonl +0 -12
  177. package/.beads/.br_history/issues.20260308_181032_565142225.jsonl +0 -12
  178. package/.beads/.br_history/issues.20260308_181311_336346464.jsonl +0 -12
  179. package/.beads/.br_history/issues.20260308_181444_039234498.jsonl +0 -13
  180. package/.beads/.br_history/issues.20260308_181503_794764403.jsonl +0 -13
  181. package/.beads/.br_history/issues.20260308_181503_950163105.jsonl +0 -13
  182. package/.beads/.br_history/issues.20260308_192031_852553505.jsonl +0 -13
  183. package/.beads/.br_history/issues.20260308_193552_846920518.jsonl +0 -14
  184. package/.beads/.br_history/issues.20260308_194054_394884833.jsonl +0 -14
  185. package/.beads/.br_history/issues.20260308_194209_440472460.jsonl +0 -15
  186. package/.beads/.br_history/issues.20260308_195319_099391899.jsonl +0 -15
  187. package/.beads/.br_history/issues.20260308_195324_176987204.jsonl +0 -16
  188. package/.beads/.br_history/issues.20260308_195436_929114019.jsonl +0 -16
  189. package/.beads/.br_history/issues.20260308_195437_055808298.jsonl +0 -17
  190. package/.beads/.br_history/issues.20260308_195437_304297399.jsonl +0 -18
  191. package/.beads/.br_history/issues.20260308_195437_556007332.jsonl +0 -19
  192. package/.beads/.br_history/issues.20260308_195444_987209695.jsonl +0 -20
  193. package/.beads/.br_history/issues.20260308_195445_133350193.jsonl +0 -20
  194. package/.beads/.br_history/issues.20260308_195445_400185615.jsonl +0 -20
  195. package/.beads/.br_history/issues.20260308_195445_689886334.jsonl +0 -20
  196. package/.beads/.br_history/issues.20260308_195445_949947727.jsonl +0 -20
  197. package/.beads/.br_history/issues.20260308_195745_580473297.jsonl +0 -20
  198. package/.beads/.br_history/issues.20260308_195745_725920532.jsonl +0 -20
  199. package/.beads/.br_history/issues.20260308_195745_968227911.jsonl +0 -20
  200. package/.beads/.br_history/issues.20260308_195746_224276322.jsonl +0 -20
  201. package/.beads/.br_history/issues.20260308_200018_386890807.jsonl +0 -20
  202. package/ref-btcbot/.env.example +0 -19
  203. package/ref-btcbot/README.md +0 -3
  204. package/ref-btcbot/docs/bot.md +0 -72
  205. package/ref-btcbot/docs/skills/btcbot.backtest/SKILL.md +0 -70
  206. package/ref-btcbot/docs/skills/btcbot.config/SKILL.md +0 -79
  207. package/ref-btcbot/docs/skills/btcbot.orders/SKILL.md +0 -60
  208. package/ref-btcbot/docs/skills/btcbot.positions/SKILL.md +0 -54
  209. package/ref-btcbot/docs/skills/btcbot.risk/SKILL.md +0 -69
  210. package/ref-btcbot/docs/skills/btcbot.run-loop/SKILL.md +0 -63
  211. package/ref-btcbot/docs/skills/btcbot.run-once/SKILL.md +0 -63
  212. package/ref-btcbot/docs/skills/btcbot.status/SKILL.md +0 -59
  213. package/ref-btcbot/examples/sample-candles.json +0 -52
  214. package/ref-btcbot/package.json +0 -18
  215. package/ref-btcbot/plugin/plugin.json +0 -146
  216. package/ref-btcbot/src/cli.js +0 -104
  217. package/ref-btcbot/src/config.js +0 -80
  218. package/ref-btcbot/src/core/bot-runner.js +0 -78
  219. package/ref-btcbot/src/core/exchange-factory.js +0 -19
  220. package/ref-btcbot/src/core/live-exchange.js +0 -12
  221. package/ref-btcbot/src/core/paper-exchange.js +0 -82
  222. package/ref-btcbot/src/core/risk-engine.js +0 -42
  223. package/ref-btcbot/src/core/state-repository.js +0 -47
  224. package/ref-btcbot/src/services/backtest-service.js +0 -44
  225. package/ref-btcbot/src/services/market-data.js +0 -32
  226. package/ref-btcbot/src/storage/json-store.js +0 -45
  227. package/ref-btcbot/src/strategy/hedge-strategy.js +0 -65
  228. package/ref-btcbot/src/strategy/indicators.js +0 -56
  229. package/ref-btcbot/src/web/api.js +0 -50
  230. package/ref-btcbot/src/web/app.js +0 -51
  231. package/ref-btcbot/src/web/index.html +0 -70
  232. package/ref-btcbot/src/web/server.js +0 -33
  233. /package/.beads/.br_history/{issues.20260308_180927_477542428.jsonl.meta.json → issues.20260308_235202_180577215.jsonl.meta.json} +0 -0
  234. /package/.beads/.br_history/{issues.20260308_181032_020230108.jsonl.meta.json → issues.20260308_235202_387414163.jsonl.meta.json} +0 -0
  235. /package/.beads/.br_history/{issues.20260308_181032_180539413.jsonl.meta.json → issues.20260308_235202_564422794.jsonl.meta.json} +0 -0
  236. /package/.beads/.br_history/{issues.20260308_181032_372621506.jsonl.meta.json → issues.20260308_235202_742600597.jsonl.meta.json} +0 -0
  237. /package/.beads/.br_history/{issues.20260308_181032_565142225.jsonl.meta.json → issues.20260308_235208_133360069.jsonl.meta.json} +0 -0
  238. /package/.beads/.br_history/{issues.20260308_181311_336346464.jsonl.meta.json → issues.20260308_235505_473406307.jsonl.meta.json} +0 -0
  239. /package/.beads/.br_history/{issues.20260308_181444_039234498.jsonl.meta.json → issues.20260308_235505_662360489.jsonl.meta.json} +0 -0
  240. /package/.beads/.br_history/{issues.20260308_181503_794764403.jsonl.meta.json → issues.20260308_235505_843935624.jsonl.meta.json} +0 -0
  241. /package/.beads/.br_history/{issues.20260308_181503_950163105.jsonl.meta.json → issues.20260308_235506_044530221.jsonl.meta.json} +0 -0
  242. /package/.beads/.br_history/{issues.20260308_192031_852553505.jsonl.meta.json → issues.20260309_002618_115728731.jsonl.meta.json} +0 -0
  243. /package/.beads/.br_history/{issues.20260308_193552_846920518.jsonl.meta.json → issues.20260309_003748_878174586.jsonl.meta.json} +0 -0
  244. /package/.beads/.br_history/{issues.20260308_194054_394884833.jsonl.meta.json → issues.20260309_004057_868755623.jsonl.meta.json} +0 -0
  245. /package/.beads/.br_history/{issues.20260308_194209_440472460.jsonl.meta.json → issues.20260309_004058_512842163.jsonl.meta.json} +0 -0
  246. /package/.beads/.br_history/{issues.20260308_195319_099391899.jsonl.meta.json → issues.20260309_004058_994445226.jsonl.meta.json} +0 -0
  247. /package/.beads/.br_history/{issues.20260308_195324_176987204.jsonl.meta.json → issues.20260309_004059_475988596.jsonl.meta.json} +0 -0
  248. /package/.beads/.br_history/{issues.20260308_195436_929114019.jsonl.meta.json → issues.20260309_161902_566857851.jsonl.meta.json} +0 -0
  249. /package/.beads/.br_history/{issues.20260308_195437_055808298.jsonl.meta.json → issues.20260309_170512_277017739.jsonl.meta.json} +0 -0
  250. /package/.beads/.br_history/{issues.20260308_195437_304297399.jsonl.meta.json → issues.20260309_170512_477876921.jsonl.meta.json} +0 -0
  251. /package/.beads/.br_history/{issues.20260308_195437_556007332.jsonl.meta.json → issues.20260309_170512_664382701.jsonl.meta.json} +0 -0
  252. /package/.beads/.br_history/{issues.20260308_195444_987209695.jsonl.meta.json → issues.20260309_170512_859400333.jsonl.meta.json} +0 -0
  253. /package/.beads/.br_history/{issues.20260308_195445_133350193.jsonl.meta.json → issues.20260309_212326_082771164.jsonl.meta.json} +0 -0
  254. /package/.beads/.br_history/{issues.20260308_195445_400185615.jsonl.meta.json → issues.20260309_212326_245619716.jsonl.meta.json} +0 -0
  255. /package/.beads/.br_history/{issues.20260308_195445_689886334.jsonl.meta.json → issues.20260309_212326_403198317.jsonl.meta.json} +0 -0
  256. /package/.beads/.br_history/{issues.20260308_195445_949947727.jsonl.meta.json → issues.20260309_212332_539197678.jsonl.meta.json} +0 -0
  257. /package/.beads/.br_history/{issues.20260308_195745_580473297.jsonl.meta.json → issues.20260309_212332_731373599.jsonl.meta.json} +0 -0
  258. /package/.beads/.br_history/{issues.20260308_195745_725920532.jsonl.meta.json → issues.20260309_212332_928710953.jsonl.meta.json} +0 -0
  259. /package/.beads/.br_history/{issues.20260308_195745_968227911.jsonl.meta.json → issues.20260309_213021_341505240.jsonl.meta.json} +0 -0
  260. /package/.beads/.br_history/{issues.20260308_195746_224276322.jsonl.meta.json → issues.20260309_213022_023136934.jsonl.meta.json} +0 -0
  261. /package/.beads/.br_history/{issues.20260308_200018_386890807.jsonl.meta.json → issues.20260309_213022_400050719.jsonl.meta.json} +0 -0
@@ -0,0 +1,84 @@
1
+ const fs = require("fs")
2
+ const os = require("os")
3
+ const path = require("path")
4
+ const { execSync } = require("child_process")
5
+
6
+ const CLI = path.join(__dirname, "..", "cli", "supercli.js")
7
+
8
+ function runNoServer(args, options = {}) {
9
+ try {
10
+ const env = { ...process.env }
11
+ delete env.SUPERCLI_SERVER
12
+ const out = execSync(`node ${CLI} ${args}`, {
13
+ encoding: "utf-8",
14
+ timeout: 15000,
15
+ env: { ...env, ...(options.env || {}) }
16
+ })
17
+ return { ok: true, output: out.trim(), code: 0 }
18
+ } catch (err) {
19
+ return {
20
+ ok: false,
21
+ output: (err.stdout || "").trim(),
22
+ stderr: (err.stderr || "").trim(),
23
+ code: err.status
24
+ }
25
+ }
26
+ }
27
+
28
+ function writeFakeAwsBinary(dir) {
29
+ const bin = path.join(dir, "aws")
30
+ fs.writeFileSync(bin, [
31
+ "#!/usr/bin/env node",
32
+ "const args = process.argv.slice(2);",
33
+ "if (args.includes('--version')) { console.log('aws-cli/2.0.0-test Python/3.11'); process.exit(0); }",
34
+ "if (args[0] === 'sts' && args[1] === 'get-caller-identity') {",
35
+ " console.log(JSON.stringify({ Account: '123456789012', Arn: 'arn:aws:iam::123456789012:user/mock', UserId: 'AIDTEST' }));",
36
+ " process.exit(0);",
37
+ "}",
38
+ "console.log(JSON.stringify({ ok: true, args }));"
39
+ ].join("\n"), "utf-8")
40
+ fs.chmodSync(bin, 0o755)
41
+ return bin
42
+ }
43
+
44
+ describe("aws plugin", () => {
45
+ const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-aws-"))
46
+ const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-aws-"))
47
+ writeFakeAwsBinary(fakeDir)
48
+ const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome }
49
+
50
+ beforeAll(() => {
51
+ runNoServer("plugins install ./plugins/aws --on-conflict replace --json", { env })
52
+ })
53
+
54
+ afterAll(() => {
55
+ runNoServer("plugins remove aws --json", { env })
56
+ fs.rmSync(fakeDir, { recursive: true, force: true })
57
+ fs.rmSync(tempHome, { recursive: true, force: true })
58
+ })
59
+
60
+ test("routes account identity wrapped command", () => {
61
+ const r = runNoServer("aws account identity --json", { env })
62
+ expect(r.ok).toBe(true)
63
+ const data = JSON.parse(r.output)
64
+ expect(data.command).toBe("aws.account.identity")
65
+ expect(data.data.Account).toBe("123456789012")
66
+ })
67
+
68
+ test("supports namespace passthrough", () => {
69
+ const r = runNoServer("aws s3api list-buckets", { env })
70
+ expect(r.ok).toBe(true)
71
+ const data = JSON.parse(r.output)
72
+ expect(data.command).toBe("aws.passthrough")
73
+ expect(data.data.args[0]).toBe("s3api")
74
+ expect(data.data.args[1]).toBe("list-buckets")
75
+ })
76
+
77
+ test("doctor reports aws dependency as healthy", () => {
78
+ const r = runNoServer("plugins doctor aws --json", { env })
79
+ expect(r.ok).toBe(true)
80
+ const data = JSON.parse(r.output)
81
+ expect(data.ok).toBe(true)
82
+ expect(data.checks.some(c => c.type === "binary" && c.binary === "aws" && c.ok === true)).toBe(true)
83
+ })
84
+ })
@@ -0,0 +1,84 @@
1
+ const fs = require("fs")
2
+ const os = require("os")
3
+ const path = require("path")
4
+ const { execSync } = require("child_process")
5
+
6
+ const CLI = path.join(__dirname, "..", "cli", "supercli.js")
7
+
8
+ function runNoServer(args, options = {}) {
9
+ try {
10
+ const env = { ...process.env }
11
+ delete env.SUPERCLI_SERVER
12
+ const out = execSync(`node ${CLI} ${args}`, {
13
+ encoding: "utf-8",
14
+ timeout: 15000,
15
+ env: { ...env, ...(options.env || {}) }
16
+ })
17
+ return { ok: true, output: out.trim(), code: 0 }
18
+ } catch (err) {
19
+ return {
20
+ ok: false,
21
+ output: (err.stdout || "").trim(),
22
+ stderr: (err.stderr || "").trim(),
23
+ code: err.status
24
+ }
25
+ }
26
+ }
27
+
28
+ function writeFakeAzBinary(dir) {
29
+ const bin = path.join(dir, "az")
30
+ fs.writeFileSync(bin, [
31
+ "#!/usr/bin/env node",
32
+ "const args = process.argv.slice(2);",
33
+ "if (args[0] === 'version') { console.log(JSON.stringify({ 'azure-cli': '2.0.0-test' })); process.exit(0); }",
34
+ "if (args[0] === 'account' && args[1] === 'show') {",
35
+ " console.log(JSON.stringify({ id: 'sub-123', name: 'mock-subscription', state: 'Enabled' }));",
36
+ " process.exit(0);",
37
+ "}",
38
+ "console.log(JSON.stringify({ ok: true, args }));"
39
+ ].join("\n"), "utf-8")
40
+ fs.chmodSync(bin, 0o755)
41
+ return bin
42
+ }
43
+
44
+ describe("az plugin", () => {
45
+ const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-az-"))
46
+ const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-az-"))
47
+ writeFakeAzBinary(fakeDir)
48
+ const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome }
49
+
50
+ beforeAll(() => {
51
+ runNoServer("plugins install ./plugins/az --on-conflict replace --json", { env })
52
+ })
53
+
54
+ afterAll(() => {
55
+ runNoServer("plugins remove az --json", { env })
56
+ fs.rmSync(fakeDir, { recursive: true, force: true })
57
+ fs.rmSync(tempHome, { recursive: true, force: true })
58
+ })
59
+
60
+ test("routes account show wrapped command", () => {
61
+ const r = runNoServer("az account show --json", { env })
62
+ expect(r.ok).toBe(true)
63
+ const data = JSON.parse(r.output)
64
+ expect(data.command).toBe("az.account.show")
65
+ expect(data.data.id).toBe("sub-123")
66
+ })
67
+
68
+ test("supports namespace passthrough", () => {
69
+ const r = runNoServer("az group list", { env })
70
+ expect(r.ok).toBe(true)
71
+ const data = JSON.parse(r.output)
72
+ expect(data.command).toBe("az.passthrough")
73
+ expect(data.data.args[0]).toBe("group")
74
+ expect(data.data.args[1]).toBe("list")
75
+ })
76
+
77
+ test("doctor reports az dependency as healthy", () => {
78
+ const r = runNoServer("plugins doctor az --json", { env })
79
+ expect(r.ok).toBe(true)
80
+ const data = JSON.parse(r.output)
81
+ expect(data.ok).toBe(true)
82
+ expect(data.checks.some(c => c.type === "binary" && c.binary === "az" && c.ok === true)).toBe(true)
83
+ })
84
+ })
@@ -0,0 +1,29 @@
1
+ const { execute } = require("../cli/adapters/builtin")
2
+
3
+ describe("builtin adapter", () => {
4
+ test("returns beads install steps", () => {
5
+ const result = execute({ adapterConfig: { builtin: "beads_install_steps" } })
6
+ expect(result.plugin).toBe("beads")
7
+ expect(result.install_steps).toContain("br --version")
8
+ })
9
+
10
+ test("returns gwc install steps", () => {
11
+ const result = execute({ adapterConfig: { builtin: "gwc_install_steps" } })
12
+ expect(result.plugin).toBe("gwc")
13
+ expect(result.install_steps).toContain("gws --version")
14
+ })
15
+
16
+ test("returns commiat install steps", () => {
17
+ const result = execute({ adapterConfig: { builtin: "commiat_install_steps" } })
18
+ expect(result.plugin).toBe("commiat")
19
+ expect(result.install_steps).toContain("commiat --version")
20
+ })
21
+
22
+ test("throws for unknown builtin action", () => {
23
+ expect(() => execute({ adapterConfig: { builtin: "unknown" } })).toThrow(/Unknown builtin action: unknown/)
24
+ })
25
+
26
+ test("throws for missing builtin action", () => {
27
+ expect(() => execute({ adapterConfig: {} })).toThrow(/Unknown builtin action: \(missing\)/)
28
+ })
29
+ })
@@ -0,0 +1,109 @@
1
+ const fs = require("fs")
2
+ const os = require("os")
3
+ const path = require("path")
4
+ const { execSync } = require("child_process")
5
+
6
+ const CLI = path.join(__dirname, "..", "cli", "supercli.js")
7
+
8
+ function runNoServer(args, options = {}) {
9
+ try {
10
+ const env = { ...process.env }
11
+ delete env.SUPERCLI_SERVER
12
+ const out = execSync(`node ${CLI} ${args}`, {
13
+ encoding: "utf-8",
14
+ timeout: 15000,
15
+ env: { ...env, ...(options.env || {}) }
16
+ })
17
+ return { ok: true, output: out.trim(), code: 0 }
18
+ } catch (err) {
19
+ return {
20
+ ok: false,
21
+ output: (err.stdout || "").trim(),
22
+ stderr: (err.stderr || "").trim(),
23
+ code: err.status
24
+ }
25
+ }
26
+ }
27
+
28
+ function writeFakeClineBinary(dir) {
29
+ const bin = path.join(dir, "cline")
30
+ fs.writeFileSync(bin, [
31
+ "#!/usr/bin/env node",
32
+ "const args = process.argv.slice(2);",
33
+ "if (args[0] === '--version') { console.log('cline 3.71.0-test'); process.exit(0); }",
34
+ "if (args.includes('--json') && (args.includes('-a') || args.includes('-p'))) {",
35
+ " const prompt = args[args.length - 1];",
36
+ " console.log(JSON.stringify({ type: 'task_started', taskId: 'task-123' }));",
37
+ " console.log(JSON.stringify({ type: 'say', say: 'task', text: prompt }));",
38
+ " console.log(JSON.stringify({ type: 'say', say: 'completion_result', text: 'done', partial: false }));",
39
+ " process.exit(0);",
40
+ "}",
41
+ "console.log(JSON.stringify({ ok: true, args }));"
42
+ ].join("\n"), "utf-8")
43
+ fs.chmodSync(bin, 0o755)
44
+ return bin
45
+ }
46
+
47
+ describe("cline plugin", () => {
48
+ const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-cline-"))
49
+ const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-cline-"))
50
+ writeFakeClineBinary(fakeDir)
51
+ const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome }
52
+
53
+ beforeAll(() => {
54
+ runNoServer("plugins install ./plugins/cline --on-conflict replace --json", { env })
55
+ })
56
+
57
+ afterAll(() => {
58
+ runNoServer("plugins remove cline --json", { env })
59
+ fs.rmSync(fakeDir, { recursive: true, force: true })
60
+ fs.rmSync(tempHome, { recursive: true, force: true })
61
+ })
62
+
63
+ test("routes cli version wrapped command", () => {
64
+ const r = runNoServer("cline cli version --json", { env })
65
+ expect(r.ok).toBe(true)
66
+ const data = JSON.parse(r.output)
67
+ expect(data.command).toBe("cline.cli.version")
68
+ expect(data.data.raw).toBe("cline 3.71.0-test")
69
+ })
70
+
71
+ test("streams act-mode task output with final summary", () => {
72
+ const r = runNoServer("cline task run --prompt \"List files with most LOC\" --cwd . --timeout 30 --json", { env })
73
+ expect(r.ok).toBe(true)
74
+ const lines = r.output.split("\n").filter(Boolean).map(line => JSON.parse(line))
75
+ expect(lines[0].stream).toBe(true)
76
+ expect(lines[0].command).toBe("cline.task.run")
77
+ expect(lines[0].data.type).toBe("task_started")
78
+ expect(lines[1].data.say).toBe("task")
79
+ expect(lines[2].data.say).toBe("completion_result")
80
+ expect(lines[3].stream).toBeUndefined()
81
+ expect(lines[3].data.streamed).toBe(true)
82
+ expect(lines[3].data.event_count).toBe(3)
83
+ })
84
+
85
+ test("streams plan-mode task output with final summary", () => {
86
+ const r = runNoServer("cline task plan --prompt \"Plan auth refactor\" --json", { env })
87
+ expect(r.ok).toBe(true)
88
+ const lines = r.output.split("\n").filter(Boolean).map(line => JSON.parse(line))
89
+ expect(lines[0].command).toBe("cline.task.plan")
90
+ expect(lines[3].data.last_event.say).toBe("completion_result")
91
+ })
92
+
93
+ test("supports namespace passthrough", () => {
94
+ const r = runNoServer("cline --help --json", { env })
95
+ expect(r.ok).toBe(true)
96
+ const data = JSON.parse(r.output)
97
+ expect(data.command).toBe("cline.passthrough")
98
+ expect(data.data.args).toContain("--help")
99
+ expect(data.data.args).toContain("--json")
100
+ })
101
+
102
+ test("doctor reports cline dependency as healthy", () => {
103
+ const r = runNoServer("plugins doctor cline --json", { env })
104
+ expect(r.ok).toBe(true)
105
+ const data = JSON.parse(r.output)
106
+ expect(data.ok).toBe(true)
107
+ expect(data.checks.some(c => c.type === "binary" && c.binary === "cline" && c.ok === true)).toBe(true)
108
+ })
109
+ })
@@ -0,0 +1,49 @@
1
+ const fs = require("fs")
2
+ const os = require("os")
3
+ const path = require("path")
4
+ const { execSync } = require("child_process")
5
+
6
+ const CLI = path.join(__dirname, "..", "cli", "supercli.js")
7
+
8
+ function runNoServer(args, options = {}) {
9
+ try {
10
+ const env = { ...process.env }
11
+ delete env.SUPERCLI_SERVER
12
+ const out = execSync(`node ${CLI} ${args}`, {
13
+ encoding: "utf-8",
14
+ timeout: 15000,
15
+ env: { ...env, ...(options.env || {}) }
16
+ })
17
+ return { ok: true, output: out.trim(), code: 0 }
18
+ } catch (err) {
19
+ return {
20
+ ok: false,
21
+ output: (err.stdout || "").trim(),
22
+ stderr: (err.stderr || "").trim(),
23
+ code: err.status
24
+ }
25
+ }
26
+ }
27
+
28
+ describe("cline local skill", () => {
29
+ const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-cline-skill-"))
30
+ const env = { ...process.env, SUPERCLI_HOME: tempHome }
31
+
32
+ afterAll(() => {
33
+ fs.rmSync(tempHome, { recursive: true, force: true })
34
+ })
35
+
36
+ test("syncs and resolves repo skill", () => {
37
+ const sync = runNoServer("skills sync --json", { env })
38
+ expect(sync.ok).toBe(true)
39
+
40
+ const list = runNoServer("skills list --catalog --provider repo --json", { env })
41
+ expect(list.ok).toBe(true)
42
+ const listData = JSON.parse(list.output)
43
+ expect(listData.skills.some(skill => skill.id === "repo:cline-non-interactive")).toBe(true)
44
+
45
+ const get = runNoServer("skills get repo:cline-non-interactive", { env })
46
+ expect(get.ok).toBe(true)
47
+ expect(get.output).toContain("supercli cline task run")
48
+ })
49
+ })
@@ -39,8 +39,9 @@ function writeFakeDockerBinary(dir) {
39
39
 
40
40
  describe("docker plugin", () => {
41
41
  const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-docker-"))
42
+ const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-docker-"))
42
43
  writeFakeDockerBinary(fakeDir)
43
- const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}` }
44
+ const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome }
44
45
 
45
46
  beforeAll(() => {
46
47
  runNoServer("plugins install ./plugins/docker --on-conflict replace --json", { env })
@@ -49,6 +50,7 @@ describe("docker plugin", () => {
49
50
  afterAll(() => {
50
51
  runNoServer("plugins remove docker --json", { env })
51
52
  fs.rmSync(fakeDir, { recursive: true, force: true })
53
+ fs.rmSync(tempHome, { recursive: true, force: true })
52
54
  })
53
55
 
54
56
  test("routes docker container ls to docker ps", () => {
@@ -0,0 +1,81 @@
1
+ const fs = require("fs")
2
+ const os = require("os")
3
+ const path = require("path")
4
+ const { execSync } = require("child_process")
5
+
6
+ const CLI = path.join(__dirname, "..", "cli", "supercli.js")
7
+
8
+ function runNoServer(args, options = {}) {
9
+ try {
10
+ const env = { ...process.env }
11
+ delete env.SUPERCLI_SERVER
12
+ const out = execSync(`node ${CLI} ${args}`, {
13
+ encoding: "utf-8",
14
+ timeout: 15000,
15
+ env: { ...env, ...(options.env || {}) }
16
+ })
17
+ return { ok: true, output: out.trim(), code: 0 }
18
+ } catch (err) {
19
+ return {
20
+ ok: false,
21
+ output: (err.stdout || "").trim(),
22
+ stderr: (err.stderr || "").trim(),
23
+ code: err.status
24
+ }
25
+ }
26
+ }
27
+
28
+ function writeFakeEzaBinary(dir) {
29
+ const bin = path.join(dir, "eza")
30
+ fs.writeFileSync(bin, [
31
+ "#!/usr/bin/env node",
32
+ "const args = process.argv.slice(2);",
33
+ "if (args[0] === '--version') { console.log('eza 0.23.4-test'); process.exit(0); }",
34
+ "console.log(JSON.stringify({ ok: true, args }));"
35
+ ].join("\n"), "utf-8")
36
+ fs.chmodSync(bin, 0o755)
37
+ return bin
38
+ }
39
+
40
+ describe("eza plugin", () => {
41
+ const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-eza-"))
42
+ const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-eza-"))
43
+ writeFakeEzaBinary(fakeDir)
44
+ const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome }
45
+
46
+ beforeAll(() => {
47
+ runNoServer("plugins install ./plugins/eza --on-conflict replace --json", { env })
48
+ })
49
+
50
+ afterAll(() => {
51
+ runNoServer("plugins remove eza --json", { env })
52
+ fs.rmSync(fakeDir, { recursive: true, force: true })
53
+ fs.rmSync(tempHome, { recursive: true, force: true })
54
+ })
55
+
56
+ test("routes cli version wrapped command", () => {
57
+ const r = runNoServer("eza cli version --json", { env })
58
+ expect(r.ok).toBe(true)
59
+ const data = JSON.parse(r.output)
60
+ expect(data.command).toBe("eza.cli.version")
61
+ expect(data.data.raw).toBe("eza 0.23.4-test")
62
+ })
63
+
64
+ test("supports namespace passthrough", () => {
65
+ const r = runNoServer("eza --oneline --color=never --json", { env })
66
+ expect(r.ok).toBe(true)
67
+ const data = JSON.parse(r.output)
68
+ expect(data.command).toBe("eza.passthrough")
69
+ expect(data.data.args).toContain("--oneline")
70
+ expect(data.data.args).toContain("--color=never")
71
+ expect(data.data.args).toContain("--json")
72
+ })
73
+
74
+ test("doctor reports eza dependency as healthy", () => {
75
+ const r = runNoServer("plugins doctor eza --json", { env })
76
+ expect(r.ok).toBe(true)
77
+ const data = JSON.parse(r.output)
78
+ expect(data.ok).toBe(true)
79
+ expect(data.checks.some(c => c.type === "binary" && c.binary === "eza" && c.ok === true)).toBe(true)
80
+ })
81
+ })
@@ -0,0 +1,86 @@
1
+ const fs = require("fs")
2
+ const os = require("os")
3
+ const path = require("path")
4
+ const { execSync } = require("child_process")
5
+
6
+ const CLI = path.join(__dirname, "..", "cli", "supercli.js")
7
+
8
+ function runNoServer(args, options = {}) {
9
+ try {
10
+ const env = { ...process.env }
11
+ delete env.SUPERCLI_SERVER
12
+ const out = execSync(`node ${CLI} ${args}`, {
13
+ encoding: "utf-8",
14
+ timeout: 15000,
15
+ env: { ...env, ...(options.env || {}) }
16
+ })
17
+ return { ok: true, output: out.trim(), code: 0 }
18
+ } catch (err) {
19
+ return {
20
+ ok: false,
21
+ output: (err.stdout || "").trim(),
22
+ stderr: (err.stderr || "").trim(),
23
+ code: err.status
24
+ }
25
+ }
26
+ }
27
+
28
+ function writeFakeGcloudBinary(dir) {
29
+ const bin = path.join(dir, "gcloud")
30
+ fs.writeFileSync(bin, [
31
+ "#!/usr/bin/env node",
32
+ "const args = process.argv.slice(2);",
33
+ "if (args.includes('--version')) { console.log('Google Cloud SDK 999.0.0-test'); process.exit(0); }",
34
+ "if (args[0] === 'auth' && args[1] === 'list' && args.includes('--format=json')) {",
35
+ " console.log(JSON.stringify([{ account: 'mock@example.com', status: 'ACTIVE' }]));",
36
+ " process.exit(0);",
37
+ "}",
38
+ "console.log(JSON.stringify({ ok: true, args }));"
39
+ ].join("\n"), "utf-8")
40
+ fs.chmodSync(bin, 0o755)
41
+ return bin
42
+ }
43
+
44
+ describe("gcloud plugin", () => {
45
+ const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-gcloud-"))
46
+ const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-gcloud-"))
47
+ writeFakeGcloudBinary(fakeDir)
48
+ const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome }
49
+
50
+ beforeAll(() => {
51
+ runNoServer("plugins install ./plugins/gcloud --on-conflict replace --json", { env })
52
+ })
53
+
54
+ afterAll(() => {
55
+ runNoServer("plugins remove gcloud --json", { env })
56
+ fs.rmSync(fakeDir, { recursive: true, force: true })
57
+ fs.rmSync(tempHome, { recursive: true, force: true })
58
+ })
59
+
60
+ test("routes account list wrapped command", () => {
61
+ const r = runNoServer("gcloud account list --json", { env })
62
+ expect(r.ok).toBe(true)
63
+ const data = JSON.parse(r.output)
64
+ expect(data.command).toBe("gcloud.account.list")
65
+ expect(Array.isArray(data.data)).toBe(true)
66
+ expect(data.data[0].account).toBe("mock@example.com")
67
+ })
68
+
69
+ test("supports namespace passthrough", () => {
70
+ const r = runNoServer("gcloud projects list --format=json", { env })
71
+ expect(r.ok).toBe(true)
72
+ const data = JSON.parse(r.output)
73
+ expect(data.command).toBe("gcloud.passthrough")
74
+ expect(data.data.args[0]).toBe("projects")
75
+ expect(data.data.args[1]).toBe("list")
76
+ expect(data.data.args).toContain("--format=json")
77
+ })
78
+
79
+ test("doctor reports gcloud dependency as healthy", () => {
80
+ const r = runNoServer("plugins doctor gcloud --json", { env })
81
+ expect(r.ok).toBe(true)
82
+ const data = JSON.parse(r.output)
83
+ expect(data.ok).toBe(true)
84
+ expect(data.checks.some(c => c.type === "binary" && c.binary === "gcloud" && c.ok === true)).toBe(true)
85
+ })
86
+ })
@@ -0,0 +1,86 @@
1
+ const fs = require("fs")
2
+ const os = require("os")
3
+ const path = require("path")
4
+ const { execSync } = require("child_process")
5
+
6
+ const CLI = path.join(__dirname, "..", "cli", "supercli.js")
7
+
8
+ function runNoServer(args, options = {}) {
9
+ try {
10
+ const env = { ...process.env }
11
+ delete env.SUPERCLI_SERVER
12
+ const out = execSync(`node ${CLI} ${args}`, {
13
+ encoding: "utf-8",
14
+ timeout: 15000,
15
+ env: { ...env, ...(options.env || {}) }
16
+ })
17
+ return { ok: true, output: out.trim(), code: 0 }
18
+ } catch (err) {
19
+ return {
20
+ ok: false,
21
+ output: (err.stdout || "").trim(),
22
+ stderr: (err.stderr || "").trim(),
23
+ code: err.status
24
+ }
25
+ }
26
+ }
27
+
28
+ function writeFakeGhBinary(dir) {
29
+ const bin = path.join(dir, "gh")
30
+ fs.writeFileSync(bin, [
31
+ "#!/usr/bin/env node",
32
+ "const args = process.argv.slice(2);",
33
+ "if (args.includes('--version')) { console.log('gh version 2.0.0-test'); process.exit(0); }",
34
+ "if (args[0] === 'auth' && args[1] === 'status' && args.includes('--json')) {",
35
+ " console.log(JSON.stringify({ hosts: [{ hostname: 'github.com', status: 'logged_in', active: true }] }));",
36
+ " process.exit(0);",
37
+ "}",
38
+ "console.log(JSON.stringify({ ok: true, args }));"
39
+ ].join("\n"), "utf-8")
40
+ fs.chmodSync(bin, 0o755)
41
+ return bin
42
+ }
43
+
44
+ describe("gh plugin", () => {
45
+ const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-gh-"))
46
+ const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-gh-"))
47
+ writeFakeGhBinary(fakeDir)
48
+ const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome }
49
+
50
+ beforeAll(() => {
51
+ runNoServer("plugins install ./plugins/gh --on-conflict replace --json", { env })
52
+ })
53
+
54
+ afterAll(() => {
55
+ runNoServer("plugins remove gh --json", { env })
56
+ fs.rmSync(fakeDir, { recursive: true, force: true })
57
+ fs.rmSync(tempHome, { recursive: true, force: true })
58
+ })
59
+
60
+ test("routes account status wrapped command", () => {
61
+ const r = runNoServer("gh account status --json", { env })
62
+ expect(r.ok).toBe(true)
63
+ const data = JSON.parse(r.output)
64
+ expect(data.command).toBe("gh.account.status")
65
+ expect(Array.isArray(data.data.hosts)).toBe(true)
66
+ expect(data.data.hosts[0].hostname).toBe("github.com")
67
+ })
68
+
69
+ test("supports namespace passthrough", () => {
70
+ const r = runNoServer("gh repo list --limit 1 --json name", { env })
71
+ expect(r.ok).toBe(true)
72
+ const data = JSON.parse(r.output)
73
+ expect(data.command).toBe("gh.passthrough")
74
+ expect(data.data.args[0]).toBe("repo")
75
+ expect(data.data.args[1]).toBe("list")
76
+ expect(data.data.args).toContain("--json")
77
+ })
78
+
79
+ test("doctor reports gh dependency as healthy", () => {
80
+ const r = runNoServer("plugins doctor gh --json", { env })
81
+ expect(r.ok).toBe(true)
82
+ const data = JSON.parse(r.output)
83
+ expect(data.ok).toBe(true)
84
+ expect(data.checks.some(c => c.type === "binary" && c.binary === "gh" && c.ok === true)).toBe(true)
85
+ })
86
+ })