@claudetools/cli 0.13.13 → 0.13.15

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 (368) hide show
  1. package/dist/__tests__/factories.d.ts +173 -0
  2. package/dist/__tests__/factories.d.ts.map +1 -0
  3. package/dist/__tests__/factories.js +150 -0
  4. package/dist/__tests__/factories.js.map +1 -0
  5. package/dist/__tests__/helpers.d.ts +36 -0
  6. package/dist/__tests__/helpers.d.ts.map +1 -0
  7. package/dist/__tests__/helpers.js +52 -0
  8. package/dist/__tests__/helpers.js.map +1 -0
  9. package/dist/analytics/index.d.ts +14 -0
  10. package/dist/analytics/index.d.ts.map +1 -0
  11. package/dist/analytics/index.js +259 -0
  12. package/dist/analytics/index.js.map +1 -0
  13. package/dist/analytics/session.d.ts +17 -0
  14. package/dist/analytics/session.d.ts.map +1 -0
  15. package/dist/analytics/session.js +130 -0
  16. package/dist/analytics/session.js.map +1 -0
  17. package/dist/analytics/token-tracker.d.ts +48 -0
  18. package/dist/analytics/token-tracker.d.ts.map +1 -0
  19. package/dist/analytics/token-tracker.js +269 -0
  20. package/dist/analytics/token-tracker.js.map +1 -0
  21. package/dist/analytics/tracker.d.ts +33 -0
  22. package/dist/analytics/tracker.d.ts.map +1 -0
  23. package/dist/analytics/tracker.js +210 -0
  24. package/dist/analytics/tracker.js.map +1 -0
  25. package/dist/api-keys/index.d.ts +15 -0
  26. package/dist/api-keys/index.d.ts.map +1 -0
  27. package/dist/api-keys/index.js +228 -0
  28. package/dist/api-keys/index.js.map +1 -0
  29. package/dist/auth/config.d.ts +15 -0
  30. package/dist/auth/config.d.ts.map +1 -0
  31. package/dist/auth/config.js +67 -0
  32. package/dist/auth/config.js.map +1 -0
  33. package/dist/auth/index.d.ts +8 -0
  34. package/dist/auth/index.d.ts.map +1 -0
  35. package/dist/auth/index.js +299 -0
  36. package/dist/auth/index.js.map +1 -0
  37. package/dist/auth/keychain.d.ts +21 -0
  38. package/dist/auth/keychain.d.ts.map +1 -0
  39. package/dist/auth/keychain.js +256 -0
  40. package/dist/auth/keychain.js.map +1 -0
  41. package/dist/billing/index.d.ts +7 -0
  42. package/dist/billing/index.d.ts.map +1 -0
  43. package/dist/billing/index.js +233 -0
  44. package/dist/billing/index.js.map +1 -0
  45. package/dist/cli.js +291 -43
  46. package/dist/cli.js.map +1 -1
  47. package/dist/commands/hook.d.ts +12 -0
  48. package/dist/commands/hook.d.ts.map +1 -0
  49. package/dist/commands/hook.js +190 -0
  50. package/dist/commands/hook.js.map +1 -0
  51. package/dist/commands/keys.d.ts +4 -0
  52. package/dist/commands/keys.d.ts.map +1 -0
  53. package/dist/commands/keys.js +43 -0
  54. package/dist/commands/keys.js.map +1 -0
  55. package/dist/commands/mcp.d.ts +4 -0
  56. package/dist/commands/mcp.d.ts.map +1 -0
  57. package/dist/commands/mcp.js +43 -0
  58. package/dist/commands/mcp.js.map +1 -0
  59. package/dist/commands/project.d.ts +4 -0
  60. package/dist/commands/project.d.ts.map +1 -0
  61. package/dist/commands/project.js +68 -0
  62. package/dist/commands/project.js.map +1 -0
  63. package/dist/commands/skill.d.ts +4 -0
  64. package/dist/commands/skill.d.ts.map +1 -0
  65. package/dist/commands/skill.js +37 -0
  66. package/dist/commands/skill.js.map +1 -0
  67. package/dist/commands/stacks.d.ts +4 -0
  68. package/dist/commands/stacks.d.ts.map +1 -0
  69. package/dist/commands/stacks.js +103 -0
  70. package/dist/commands/stacks.js.map +1 -0
  71. package/dist/commands/stats.d.ts +4 -0
  72. package/dist/commands/stats.d.ts.map +1 -0
  73. package/dist/commands/stats.js +6 -0
  74. package/dist/commands/stats.js.map +1 -0
  75. package/dist/commands/sync.d.ts +4 -0
  76. package/dist/commands/sync.d.ts.map +1 -0
  77. package/dist/commands/sync.js +60 -0
  78. package/dist/commands/sync.js.map +1 -0
  79. package/dist/commands/update.d.ts +4 -0
  80. package/dist/commands/update.d.ts.map +1 -0
  81. package/dist/commands/update.js +63 -0
  82. package/dist/commands/update.js.map +1 -0
  83. package/dist/daemon/client.d.ts +107 -0
  84. package/dist/daemon/client.d.ts.map +1 -0
  85. package/dist/daemon/client.js +250 -0
  86. package/dist/daemon/client.js.map +1 -0
  87. package/dist/daemon/health.d.ts +38 -0
  88. package/dist/daemon/health.d.ts.map +1 -0
  89. package/dist/daemon/health.js +212 -0
  90. package/dist/daemon/health.js.map +1 -0
  91. package/dist/daemon/index.d.ts +34 -0
  92. package/dist/daemon/index.d.ts.map +1 -0
  93. package/dist/daemon/index.js +197 -0
  94. package/dist/daemon/index.js.map +1 -0
  95. package/dist/daemon/protocol.d.ts +144 -0
  96. package/dist/daemon/protocol.d.ts.map +1 -0
  97. package/dist/daemon/protocol.js +5 -0
  98. package/dist/daemon/protocol.js.map +1 -0
  99. package/dist/gamification/index.d.ts +13 -0
  100. package/dist/gamification/index.d.ts.map +1 -0
  101. package/dist/gamification/index.js +120 -0
  102. package/dist/gamification/index.js.map +1 -0
  103. package/dist/gamification/types.d.ts +34 -0
  104. package/dist/gamification/types.d.ts.map +1 -0
  105. package/dist/gamification/types.js +5 -0
  106. package/dist/gamification/types.js.map +1 -0
  107. package/dist/hooks/index.d.ts +65 -0
  108. package/dist/hooks/index.d.ts.map +1 -0
  109. package/dist/hooks/index.js +403 -0
  110. package/dist/hooks/index.js.map +1 -0
  111. package/dist/lib/api.d.ts +29 -0
  112. package/dist/lib/api.d.ts.map +1 -0
  113. package/dist/lib/api.js +213 -0
  114. package/dist/lib/api.js.map +1 -0
  115. package/dist/lib/browser.d.ts +6 -0
  116. package/dist/lib/browser.d.ts.map +1 -0
  117. package/dist/lib/browser.js +14 -0
  118. package/dist/lib/browser.js.map +1 -0
  119. package/dist/lib/channel-config.d.ts +10 -0
  120. package/dist/lib/channel-config.d.ts.map +1 -0
  121. package/dist/lib/channel-config.js +48 -0
  122. package/dist/lib/channel-config.js.map +1 -0
  123. package/dist/lib/command-runner.d.ts +16 -0
  124. package/dist/lib/command-runner.d.ts.map +1 -0
  125. package/dist/lib/command-runner.js +59 -0
  126. package/dist/lib/command-runner.js.map +1 -0
  127. package/dist/lib/command-utils.d.ts +22 -0
  128. package/dist/lib/command-utils.d.ts.map +1 -0
  129. package/dist/lib/command-utils.js +88 -0
  130. package/dist/lib/command-utils.js.map +1 -0
  131. package/dist/lib/error-handler.d.ts +13 -0
  132. package/dist/lib/error-handler.d.ts.map +1 -0
  133. package/dist/lib/error-handler.js +70 -0
  134. package/dist/lib/error-handler.js.map +1 -0
  135. package/dist/lib/errors.d.ts +35 -0
  136. package/dist/lib/errors.d.ts.map +1 -0
  137. package/dist/lib/errors.js +70 -0
  138. package/dist/lib/errors.js.map +1 -0
  139. package/dist/lib/exit.d.ts +10 -0
  140. package/dist/lib/exit.d.ts.map +1 -0
  141. package/dist/lib/exit.js +21 -0
  142. package/dist/lib/exit.js.map +1 -0
  143. package/dist/lib/formatters.d.ts +65 -0
  144. package/dist/lib/formatters.d.ts.map +1 -0
  145. package/dist/lib/formatters.js +180 -0
  146. package/dist/lib/formatters.js.map +1 -0
  147. package/dist/lib/hybrid-data.d.ts +47 -0
  148. package/dist/lib/hybrid-data.d.ts.map +1 -0
  149. package/dist/lib/hybrid-data.js +326 -0
  150. package/dist/lib/hybrid-data.js.map +1 -0
  151. package/dist/lib/local-store.d.ts +113 -0
  152. package/dist/lib/local-store.d.ts.map +1 -0
  153. package/dist/lib/local-store.js +220 -0
  154. package/dist/lib/local-store.js.map +1 -0
  155. package/dist/lib/machine-id.d.ts +8 -0
  156. package/dist/lib/machine-id.d.ts.map +1 -0
  157. package/dist/lib/machine-id.js +39 -0
  158. package/dist/lib/machine-id.js.map +1 -0
  159. package/dist/lib/network.d.ts +15 -0
  160. package/dist/lib/network.d.ts.map +1 -0
  161. package/dist/lib/network.js +46 -0
  162. package/dist/lib/network.js.map +1 -0
  163. package/dist/lib/theme.d.ts +77 -0
  164. package/dist/lib/theme.d.ts.map +1 -0
  165. package/dist/lib/theme.js +137 -0
  166. package/dist/lib/theme.js.map +1 -0
  167. package/dist/lib/tool-availability.d.ts +13 -0
  168. package/dist/lib/tool-availability.d.ts.map +1 -0
  169. package/dist/lib/tool-availability.js +48 -0
  170. package/dist/lib/tool-availability.js.map +1 -0
  171. package/dist/lib/update-checker.d.ts +21 -0
  172. package/dist/lib/update-checker.d.ts.map +1 -0
  173. package/dist/lib/update-checker.js +110 -0
  174. package/dist/lib/update-checker.js.map +1 -0
  175. package/dist/lib/validation.d.ts +30 -0
  176. package/dist/lib/validation.d.ts.map +1 -0
  177. package/dist/lib/validation.js +82 -0
  178. package/dist/lib/validation.js.map +1 -0
  179. package/dist/lib/validators.d.ts +18 -0
  180. package/dist/lib/validators.d.ts.map +1 -0
  181. package/dist/lib/validators.js +30 -0
  182. package/dist/lib/validators.js.map +1 -0
  183. package/dist/marketplace/api.d.ts +24 -0
  184. package/dist/marketplace/api.d.ts.map +1 -0
  185. package/dist/marketplace/api.js +92 -0
  186. package/dist/marketplace/api.js.map +1 -0
  187. package/dist/marketplace/index.d.ts +13 -0
  188. package/dist/marketplace/index.d.ts.map +1 -0
  189. package/dist/marketplace/index.js +155 -0
  190. package/dist/marketplace/index.js.map +1 -0
  191. package/dist/marketplace/installer.d.ts +18 -0
  192. package/dist/marketplace/installer.d.ts.map +1 -0
  193. package/dist/marketplace/installer.js +184 -0
  194. package/dist/marketplace/installer.js.map +1 -0
  195. package/dist/mcp/api.d.ts +93 -0
  196. package/dist/mcp/api.d.ts.map +1 -0
  197. package/dist/mcp/api.js +106 -0
  198. package/dist/mcp/api.js.map +1 -0
  199. package/dist/mcp/config.d.ts +72 -0
  200. package/dist/mcp/config.d.ts.map +1 -0
  201. package/dist/mcp/config.js +156 -0
  202. package/dist/mcp/config.js.map +1 -0
  203. package/dist/mcp/index.d.ts +54 -0
  204. package/dist/mcp/index.d.ts.map +1 -0
  205. package/dist/mcp/index.js +381 -0
  206. package/dist/mcp/index.js.map +1 -0
  207. package/dist/mcp/prompt.clean.d.ts +25 -0
  208. package/dist/mcp/prompt.clean.d.ts.map +1 -0
  209. package/dist/mcp/prompt.clean.js +206 -0
  210. package/dist/mcp/prompt.clean.js.map +1 -0
  211. package/dist/mcp/prompt.d.ts +52 -0
  212. package/dist/mcp/prompt.d.ts.map +1 -0
  213. package/dist/mcp/prompt.js +210 -0
  214. package/dist/mcp/prompt.js.map +1 -0
  215. package/dist/mcp/secrets.clean.d.ts +18 -0
  216. package/dist/mcp/secrets.clean.d.ts.map +1 -0
  217. package/dist/mcp/secrets.clean.js +357 -0
  218. package/dist/mcp/secrets.clean.js.map +1 -0
  219. package/dist/mcp/secrets.d.ts +46 -0
  220. package/dist/mcp/secrets.d.ts.map +1 -0
  221. package/dist/mcp/secrets.js +339 -0
  222. package/dist/mcp/secrets.js.map +1 -0
  223. package/dist/memory/index.d.ts +14 -0
  224. package/dist/memory/index.d.ts.map +1 -0
  225. package/dist/memory/index.js +98 -0
  226. package/dist/memory/index.js.map +1 -0
  227. package/dist/onboard/agents-md-builder.d.ts.map +1 -1
  228. package/dist/onboard/agents-md-builder.js +45 -0
  229. package/dist/onboard/agents-md-builder.js.map +1 -1
  230. package/dist/onboard/claude-inference.d.ts.map +1 -1
  231. package/dist/onboard/claude-inference.js +15 -4
  232. package/dist/onboard/claude-inference.js.map +1 -1
  233. package/dist/onboard/context7-fetcher.d.ts +1 -1
  234. package/dist/onboard/context7-fetcher.d.ts.map +1 -1
  235. package/dist/onboard/context7-fetcher.js +50 -16
  236. package/dist/onboard/context7-fetcher.js.map +1 -1
  237. package/dist/onboard/docs-builder.d.ts.map +1 -1
  238. package/dist/onboard/docs-builder.js +523 -50
  239. package/dist/onboard/docs-builder.js.map +1 -1
  240. package/dist/onboard/index.d.ts.map +1 -1
  241. package/dist/onboard/index.js +74 -25
  242. package/dist/onboard/index.js.map +1 -1
  243. package/dist/onboard/stack-detector.d.ts.map +1 -1
  244. package/dist/onboard/stack-detector.js +5 -55
  245. package/dist/onboard/stack-detector.js.map +1 -1
  246. package/dist/project/constants.d.ts +21 -0
  247. package/dist/project/constants.d.ts.map +1 -0
  248. package/dist/project/constants.js +21 -0
  249. package/dist/project/constants.js.map +1 -0
  250. package/dist/project/format.d.ts +16 -0
  251. package/dist/project/format.d.ts.map +1 -0
  252. package/dist/project/format.js +40 -0
  253. package/dist/project/format.js.map +1 -0
  254. package/dist/project/git.d.ts +28 -0
  255. package/dist/project/git.d.ts.map +1 -0
  256. package/dist/project/git.js +93 -0
  257. package/dist/project/git.js.map +1 -0
  258. package/dist/project/index.d.ts +36 -0
  259. package/dist/project/index.d.ts.map +1 -0
  260. package/dist/project/index.js +272 -0
  261. package/dist/project/index.js.map +1 -0
  262. package/dist/project/mapper.d.ts +27 -0
  263. package/dist/project/mapper.d.ts.map +1 -0
  264. package/dist/project/mapper.js +64 -0
  265. package/dist/project/mapper.js.map +1 -0
  266. package/dist/project/storage.d.ts +71 -0
  267. package/dist/project/storage.d.ts.map +1 -0
  268. package/dist/project/storage.js +274 -0
  269. package/dist/project/storage.js.map +1 -0
  270. package/dist/project/sync-bridge.d.ts +33 -0
  271. package/dist/project/sync-bridge.d.ts.map +1 -0
  272. package/dist/project/sync-bridge.js +155 -0
  273. package/dist/project/sync-bridge.js.map +1 -0
  274. package/dist/project/types.d.ts +107 -0
  275. package/dist/project/types.d.ts.map +1 -0
  276. package/dist/project/types.js +77 -0
  277. package/dist/project/types.js.map +1 -0
  278. package/dist/publish/index.d.ts +4 -0
  279. package/dist/publish/index.d.ts.map +1 -0
  280. package/dist/publish/index.js +92 -0
  281. package/dist/publish/index.js.map +1 -0
  282. package/dist/setup.d.ts.map +1 -1
  283. package/dist/setup.js +29 -10
  284. package/dist/setup.js.map +1 -1
  285. package/dist/skills/index.d.ts +51 -0
  286. package/dist/skills/index.d.ts.map +1 -0
  287. package/dist/skills/index.js +509 -0
  288. package/dist/skills/index.js.map +1 -0
  289. package/dist/stacks/check.d.ts +2 -0
  290. package/dist/stacks/check.d.ts.map +1 -0
  291. package/dist/stacks/check.js +144 -0
  292. package/dist/stacks/check.js.map +1 -0
  293. package/dist/stacks/diff.d.ts +11 -0
  294. package/dist/stacks/diff.d.ts.map +1 -0
  295. package/dist/stacks/diff.js +123 -0
  296. package/dist/stacks/diff.js.map +1 -0
  297. package/dist/stacks/index.d.ts +17 -0
  298. package/dist/stacks/index.d.ts.map +1 -0
  299. package/dist/stacks/index.js +525 -0
  300. package/dist/stacks/index.js.map +1 -0
  301. package/dist/stacks/index.refactored.d.ts.map +1 -0
  302. package/dist/stacks/index.refactored.js.map +1 -0
  303. package/dist/stacks/io.d.ts +11 -0
  304. package/dist/stacks/io.d.ts.map +1 -0
  305. package/dist/stacks/io.js +179 -0
  306. package/dist/stacks/io.js.map +1 -0
  307. package/dist/stacks/rollback.d.ts +5 -0
  308. package/dist/stacks/rollback.d.ts.map +1 -0
  309. package/dist/stacks/rollback.js +162 -0
  310. package/dist/stacks/rollback.js.map +1 -0
  311. package/dist/stacks/types.d.ts +70 -0
  312. package/dist/stacks/types.d.ts.map +1 -0
  313. package/dist/stacks/types.js +6 -0
  314. package/dist/stacks/types.js.map +1 -0
  315. package/dist/stacks/utils.d.ts +9 -0
  316. package/dist/stacks/utils.d.ts.map +1 -0
  317. package/dist/stacks/utils.js +11 -0
  318. package/dist/stacks/utils.js.map +1 -0
  319. package/dist/start/index.d.ts +23 -0
  320. package/dist/start/index.d.ts.map +1 -0
  321. package/dist/start/index.js +386 -0
  322. package/dist/start/index.js.map +1 -0
  323. package/dist/sync/index.d.ts +49 -0
  324. package/dist/sync/index.d.ts.map +1 -0
  325. package/dist/sync/index.js +207 -0
  326. package/dist/sync/index.js.map +1 -0
  327. package/dist/sync-engine/__tests__/test-helpers.d.ts +14 -0
  328. package/dist/sync-engine/__tests__/test-helpers.d.ts.map +1 -0
  329. package/dist/sync-engine/__tests__/test-helpers.js +73 -0
  330. package/dist/sync-engine/__tests__/test-helpers.js.map +1 -0
  331. package/dist/sync-engine/client.d.ts +128 -0
  332. package/dist/sync-engine/client.d.ts.map +1 -0
  333. package/dist/sync-engine/client.js +289 -0
  334. package/dist/sync-engine/client.js.map +1 -0
  335. package/dist/sync-engine/health.d.ts +38 -0
  336. package/dist/sync-engine/health.d.ts.map +1 -0
  337. package/dist/sync-engine/health.js +259 -0
  338. package/dist/sync-engine/health.js.map +1 -0
  339. package/dist/sync-engine/index.d.ts +34 -0
  340. package/dist/sync-engine/index.d.ts.map +1 -0
  341. package/dist/sync-engine/index.js +197 -0
  342. package/dist/sync-engine/index.js.map +1 -0
  343. package/dist/sync-engine/protocol.d.ts +153 -0
  344. package/dist/sync-engine/protocol.d.ts.map +1 -0
  345. package/dist/sync-engine/protocol.js +5 -0
  346. package/dist/sync-engine/protocol.js.map +1 -0
  347. package/dist/tasks/index.d.ts +14 -0
  348. package/dist/tasks/index.d.ts.map +1 -0
  349. package/dist/tasks/index.js +109 -0
  350. package/dist/tasks/index.js.map +1 -0
  351. package/dist/team/index.d.ts +12 -0
  352. package/dist/team/index.d.ts.map +1 -0
  353. package/dist/team/index.js +151 -0
  354. package/dist/team/index.js.map +1 -0
  355. package/dist/updater.d.ts +5 -5
  356. package/dist/updater.d.ts.map +1 -1
  357. package/dist/updater.js +24 -88
  358. package/dist/updater.js.map +1 -1
  359. package/dist/usage/index.d.ts +10 -0
  360. package/dist/usage/index.d.ts.map +1 -0
  361. package/dist/usage/index.js +104 -0
  362. package/dist/usage/index.js.map +1 -0
  363. package/dist/webhooks/index.d.ts +7 -0
  364. package/dist/webhooks/index.d.ts.map +1 -0
  365. package/dist/webhooks/index.js +81 -0
  366. package/dist/webhooks/index.js.map +1 -0
  367. package/package.json +26 -15
  368. package/scripts/postinstall.js +282 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/webhooks/index.ts"],"names":[],"mappings":"AA0BA,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CA2BrD;AAED,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAC9B,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWxE;AAED,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BtE"}
@@ -0,0 +1,81 @@
1
+ import { runCommand } from '../lib/command-runner.js';
2
+ import { required, requireActiveTeam } from '../lib/validators.js';
3
+ import { emptyState } from '../lib/formatters.js';
4
+ export async function runWebhooksList() {
5
+ await runCommand(async (client, config) => {
6
+ const activeTeam = requireActiveTeam(config);
7
+ const { data } = await client.get(`/teams/${activeTeam}/webhooks`);
8
+ const webhooks = data?.webhooks || [];
9
+ if (webhooks.length === 0) {
10
+ emptyState('No webhooks configured.', 'Create one with: claudetools webhooks create <url>');
11
+ return;
12
+ }
13
+ console.log();
14
+ console.log(` Team Webhooks (${webhooks.length}):`);
15
+ console.log();
16
+ for (const webhook of webhooks) {
17
+ const statusDisplay = webhook.status === 'active' ? 'active' : 'inactive';
18
+ const createdDate = new Date(webhook.createdAt).toLocaleDateString();
19
+ console.log(` ${webhook.url}`);
20
+ console.log(` ID: ${webhook.id}`);
21
+ console.log(` Events: ${webhook.events.join(', ')}`);
22
+ console.log(` Status: ${statusDisplay} | Created: ${createdDate}`);
23
+ console.log();
24
+ }
25
+ });
26
+ }
27
+ export async function runWebhooksCreate(url, options) {
28
+ await runCommand(async (client, config) => {
29
+ const activeTeam = requireActiveTeam(config);
30
+ required(url, 'webhook URL');
31
+ const { data } = await client.post(`/teams/${activeTeam}/webhooks`, {
32
+ url,
33
+ events: options?.events || ['*'],
34
+ });
35
+ const result = required(data, 'webhook response');
36
+ console.log();
37
+ console.log(' Webhook created successfully!');
38
+ console.log();
39
+ console.log(` URL: ${result.webhook.url}`);
40
+ console.log(` ID: ${result.webhook.id}`);
41
+ console.log(` Events: ${result.webhook.events.join(', ')}`);
42
+ console.log();
43
+ console.log(' Signing Secret:');
44
+ console.log(` ${result.secret}`);
45
+ console.log();
46
+ console.log(' Store this secret securely - it will not be shown again.');
47
+ console.log();
48
+ });
49
+ }
50
+ export async function runWebhooksDelete(webhookId) {
51
+ await runCommand(async (client, config) => {
52
+ const activeTeam = requireActiveTeam(config);
53
+ required(webhookId, 'webhook ID');
54
+ await client.delete(`/teams/${activeTeam}/webhooks/${webhookId}`);
55
+ console.log();
56
+ console.log(' Webhook deleted successfully.');
57
+ console.log();
58
+ });
59
+ }
60
+ export async function runWebhooksTest(webhookId) {
61
+ await runCommand(async (client, config) => {
62
+ const activeTeam = requireActiveTeam(config);
63
+ required(webhookId, 'webhook ID');
64
+ const { data } = await client.post(`/teams/${activeTeam}/webhooks/${webhookId}/test`, {});
65
+ const testResult = required(data, 'test response');
66
+ console.log();
67
+ console.log(' Webhook test result:');
68
+ console.log();
69
+ console.log(` Status Code: ${testResult.statusCode}`);
70
+ console.log(` Latency: ${testResult.latencyMs}ms`);
71
+ console.log();
72
+ if (testResult.statusCode >= 200 && testResult.statusCode < 300) {
73
+ console.log(' Test successful!');
74
+ }
75
+ else {
76
+ console.log(' Test failed - check your webhook endpoint.');
77
+ }
78
+ console.log();
79
+ });
80
+ }
81
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/webhooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAwBlD,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;QACxC,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAE7C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CAAuB,UAAU,UAAU,WAAW,CAAC,CAAC;QACzF,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC;QAEtC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,UAAU,CAAC,yBAAyB,EAAE,oDAAoD,CAAC,CAAC;YAC5F,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,oBAAoB,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;YAC1E,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,kBAAkB,EAAE,CAAC;YAErE,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,WAAW,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,eAAe,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACxD,OAAO,CAAC,GAAG,CAAC,eAAe,aAAa,eAAe,WAAW,EAAE,CAAC,CAAC;YACtE,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAW,EACX,OAA+B;IAE/B,MAAM,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;QACxC,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC7C,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QAE7B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAChC,UAAU,UAAU,WAAW,EAC/B;YACE,GAAG;YACH,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,GAAG,CAAC;SACjC,CACF,CAAC;QAEF,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;QAElD,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,UAAU,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7D,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAC;QAC1E,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,SAAiB;IACvD,MAAM,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;QACxC,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC7C,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QAElC,MAAM,MAAM,CAAC,MAAM,CAAC,UAAU,UAAU,aAAa,SAAS,EAAE,CAAC,CAAC;QAElE,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,SAAiB;IACrD,MAAM,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;QACxC,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC7C,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QAElC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAChC,UAAU,UAAU,aAAa,SAAS,OAAO,EACjD,EAAE,CACH,CAAC;QAEF,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QAEnD,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,kBAAkB,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,cAAc,UAAU,CAAC,SAAS,IAAI,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,IAAI,UAAU,CAAC,UAAU,IAAI,GAAG,IAAI,UAAU,CAAC,UAAU,GAAG,GAAG,EAAE,CAAC;YAChE,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claudetools/cli",
3
- "version": "0.13.13",
3
+ "version": "0.13.15",
4
4
  "description": "AI agent project setup and documentation tools for Claude Code",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",
@@ -9,9 +9,21 @@
9
9
  },
10
10
  "files": [
11
11
  "dist",
12
+ "scripts",
13
+ "bin",
12
14
  "README.md",
13
15
  "LICENSE"
14
16
  ],
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "dev": "tsx src/cli.ts",
20
+ "test": "vitest run",
21
+ "test:watch": "vitest",
22
+ "typecheck": "tsc --noEmit",
23
+ "clean": "rm -rf dist",
24
+ "prepublishOnly": "npm run build && npm run typecheck",
25
+ "postinstall": "node scripts/postinstall.js"
26
+ },
15
27
  "keywords": [
16
28
  "claude",
17
29
  "claude-code",
@@ -31,24 +43,23 @@
31
43
  "access": "public"
32
44
  },
33
45
  "dependencies": {
34
- "@anthropic-ai/claude-agent-sdk": "^0.2.19",
46
+ "boxen": "^8.0.1",
35
47
  "chalk": "^5.6.2",
48
+ "cli-table3": "^0.6.5",
49
+ "open": "^11.0.0",
36
50
  "ora": "^9.0.0",
37
- "prompts": "^2.4.2"
51
+ "prompts": "^2.4.2",
52
+ "yaml": "^2.8.2"
53
+ },
54
+ "optionalDependencies": {
55
+ "keytar": "^7.9.0"
38
56
  },
39
57
  "devDependencies": {
40
- "@types/node": "^20.10.0",
58
+ "@types/node": "^22.19.7",
41
59
  "@types/prompts": "^2.4.9",
42
- "tsx": "^4.7.0",
43
- "typescript": "^5.3.0",
60
+ "@vitest/coverage-v8": "^4.0.18",
61
+ "tsx": "^4.19.0",
62
+ "typescript": "^5.9.3",
44
63
  "vitest": "^4.0.15"
45
- },
46
- "scripts": {
47
- "build": "tsc",
48
- "dev": "tsx src/cli.ts",
49
- "test": "vitest run",
50
- "test:watch": "vitest",
51
- "typecheck": "tsc --noEmit",
52
- "clean": "rm -rf dist"
53
64
  }
54
- }
65
+ }
@@ -0,0 +1,282 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Postinstall script for @claudetools/cli
4
+ *
5
+ * Checks whether the platform-specific sync engine binary was installed
6
+ * via optionalDependencies. If not (e.g. npm bug, unsupported platform,
7
+ * offline install), falls back to downloading the binary from GitHub.
8
+ */
9
+ import https from 'https';
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+ import crypto from 'crypto';
13
+ import { fileURLToPath } from 'url';
14
+
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = path.dirname(__filename);
17
+
18
+ const TRUSTED_DOMAINS = [
19
+ 'github.com',
20
+ 'objects.githubusercontent.com',
21
+ 'github-releases.githubusercontent.com',
22
+ ];
23
+ const MAX_REDIRECTS = 5;
24
+
25
+ const PLATFORM_MAP = {
26
+ 'darwin-arm64': '@claudetools/sync-darwin-arm64',
27
+ 'darwin-x64': '@claudetools/sync-darwin-x64',
28
+ 'linux-arm64': '@claudetools/sync-linux-arm64',
29
+ 'linux-x64': '@claudetools/sync-linux-x64',
30
+ 'win32-x64': '@claudetools/sync-win32-x64',
31
+ };
32
+
33
+ // Rust target triples used for GitHub release asset names
34
+ const RUST_TARGETS = {
35
+ 'darwin-arm64': 'aarch64-apple-darwin',
36
+ 'darwin-x64': 'x86_64-apple-darwin',
37
+ 'linux-arm64': 'aarch64-unknown-linux-musl',
38
+ 'linux-x64': 'x86_64-unknown-linux-musl',
39
+ 'win32-x64': 'x86_64-pc-windows-msvc',
40
+ };
41
+
42
+ const platformKey = `${process.platform}-${process.arch}`;
43
+ const packageName = PLATFORM_MAP[platformKey];
44
+ const binaryName = process.platform === 'win32' ? 'claudetools-sync.exe' : 'claudetools-sync';
45
+ const BIN_DIR = path.join(__dirname, '..', 'bin');
46
+
47
+ function tryResolveFromOptionalDep() {
48
+ if (!packageName) return null;
49
+
50
+ try {
51
+ // Try to resolve from node_modules
52
+ const modulePath = path.join(__dirname, '..', 'node_modules', packageName, 'bin', binaryName);
53
+ if (fs.existsSync(modulePath)) return modulePath;
54
+ } catch {
55
+ // Not installed — fall through to download
56
+ }
57
+ return null;
58
+ }
59
+
60
+ function getSyncVersion(packageJson) {
61
+ const optDeps = packageJson.optionalDependencies || {};
62
+ const platformPkg = PLATFORM_MAP[platformKey];
63
+ // Get version from optionalDependencies, fall back to CLI version
64
+ return optDeps[platformPkg] || packageJson.version;
65
+ }
66
+
67
+ function getDownloadUrl(version) {
68
+ const rustTarget = RUST_TARGETS[platformKey];
69
+ if (!rustTarget) return null;
70
+ const ext = process.platform === 'win32' ? '.exe' : '';
71
+ return `https://github.com/ClaudeTools/sync/releases/download/v${version}/claudetools-sync-${rustTarget}${ext}`;
72
+ }
73
+
74
+ function getChecksumsUrl(version) {
75
+ return `https://github.com/ClaudeTools/sync/releases/download/v${version}/checksums.sha256`;
76
+ }
77
+
78
+ function fetchToBuffer(url, redirectsLeft = MAX_REDIRECTS) {
79
+ if (redirectsLeft <= 0) {
80
+ return Promise.reject(new Error('Too many redirects'));
81
+ }
82
+
83
+ return new Promise((resolve, reject) => {
84
+ const parsedUrl = new URL(url);
85
+ if (parsedUrl.protocol !== 'https:') {
86
+ return reject(new Error(`Refusing non-HTTPS URL: ${url}`));
87
+ }
88
+ if (!TRUSTED_DOMAINS.includes(parsedUrl.hostname)) {
89
+ return reject(new Error(`Refusing redirect to untrusted domain: ${parsedUrl.hostname}`));
90
+ }
91
+
92
+ https.get(url, { headers: { 'User-Agent': 'claudetools-installer' } }, (response) => {
93
+ if (response.statusCode === 301 || response.statusCode === 302) {
94
+ const redirectUrl = response.headers.location;
95
+ if (!redirectUrl) {
96
+ return reject(new Error('Redirect with no Location header'));
97
+ }
98
+ return fetchToBuffer(redirectUrl, redirectsLeft - 1).then(resolve).catch(reject);
99
+ }
100
+
101
+ if (response.statusCode !== 200) {
102
+ return reject(new Error(`Fetch failed with status ${response.statusCode}`));
103
+ }
104
+
105
+ const chunks = [];
106
+ response.on('data', (chunk) => chunks.push(chunk));
107
+ response.on('end', () => resolve(Buffer.concat(chunks)));
108
+ response.on('error', reject);
109
+ }).on('error', reject);
110
+ });
111
+ }
112
+
113
+ function downloadFile(url, dest, redirectsLeft = MAX_REDIRECTS) {
114
+ if (redirectsLeft <= 0) {
115
+ return Promise.reject(new Error('Too many redirects'));
116
+ }
117
+
118
+ return new Promise((resolve, reject) => {
119
+ const parsedUrl = new URL(url);
120
+ if (parsedUrl.protocol !== 'https:') {
121
+ return reject(new Error(`Refusing non-HTTPS URL: ${url}`));
122
+ }
123
+ if (!TRUSTED_DOMAINS.includes(parsedUrl.hostname)) {
124
+ return reject(new Error(`Refusing redirect to untrusted domain: ${parsedUrl.hostname}`));
125
+ }
126
+
127
+ console.log(` Downloading from: ${url}`);
128
+
129
+ https.get(url, { headers: { 'User-Agent': 'claudetools-installer' } }, (response) => {
130
+ if (response.statusCode === 301 || response.statusCode === 302) {
131
+ const redirectUrl = response.headers.location;
132
+ if (!redirectUrl) {
133
+ return reject(new Error('Redirect with no Location header'));
134
+ }
135
+ return downloadFile(redirectUrl, dest, redirectsLeft - 1).then(resolve).catch(reject);
136
+ }
137
+
138
+ if (response.statusCode !== 200) {
139
+ return reject(new Error(`Download failed with status ${response.statusCode}`));
140
+ }
141
+
142
+ const file = fs.createWriteStream(dest);
143
+ response.pipe(file);
144
+
145
+ file.on('finish', () => {
146
+ file.close();
147
+ resolve();
148
+ });
149
+
150
+ file.on('error', (err) => {
151
+ response.destroy();
152
+ try { fs.unlinkSync(dest); } catch { /* already cleaned up */ }
153
+ reject(err);
154
+ });
155
+ }).on('error', reject);
156
+ });
157
+ }
158
+
159
+ function computeSha256(filePath) {
160
+ const fileBuffer = fs.readFileSync(filePath);
161
+ return crypto.createHash('sha256').update(fileBuffer).digest('hex');
162
+ }
163
+
164
+ async function verifyChecksum(version, binaryPath, assetFilename) {
165
+ const checksumsUrl = getChecksumsUrl(version);
166
+ console.log(' Verifying checksum...');
167
+
168
+ try {
169
+ const checksumsBuffer = await fetchToBuffer(checksumsUrl);
170
+ const checksumsText = checksumsBuffer.toString('utf8');
171
+
172
+ // Format: sha256hash filename
173
+ const expectedEntry = checksumsText
174
+ .split('\n')
175
+ .map((line) => line.trim())
176
+ .find((line) => line.endsWith(assetFilename));
177
+
178
+ if (!expectedEntry) {
179
+ console.warn(` Checksum entry not found for ${assetFilename}, skipping verification`);
180
+ return;
181
+ }
182
+
183
+ const expectedHash = expectedEntry.split(/\s+/)[0];
184
+ const actualHash = computeSha256(binaryPath);
185
+
186
+ if (actualHash !== expectedHash) {
187
+ try { fs.unlinkSync(binaryPath); } catch { /* best effort cleanup */ }
188
+ throw new Error(
189
+ `Checksum mismatch for ${assetFilename}:\n` +
190
+ ` Expected: ${expectedHash}\n` +
191
+ ` Actual: ${actualHash}`
192
+ );
193
+ }
194
+
195
+ console.log(' Checksum verified');
196
+ } catch (checksumError) {
197
+ // If the checksums file itself couldn't be fetched (404), abort to prevent unverified binary install
198
+ if (checksumError.message && checksumError.message.includes('status 404')) {
199
+ try { fs.unlinkSync(binaryPath); } catch { /* best effort cleanup */ }
200
+ throw new Error(
201
+ `Checksum file not found for version ${version}. ` +
202
+ 'Refusing to install unverified binary. ' +
203
+ 'This may indicate a misconfigured release. ' +
204
+ 'Install manually from: https://github.com/ClaudeTools/sync/releases'
205
+ );
206
+ }
207
+ // Re-throw checksum mismatch and other real errors
208
+ throw checksumError;
209
+ }
210
+ }
211
+
212
+ async function install() {
213
+ // Allow users to skip the download entirely
214
+ if (process.env.CLAUDETOOLS_SYNC_SKIP_DOWNLOAD === '1') {
215
+ console.log('CLAUDETOOLS_SYNC_SKIP_DOWNLOAD=1 — skipping sync engine install');
216
+ return;
217
+ }
218
+
219
+ // Warn if a proxy is detected
220
+ if (process.env.HTTP_PROXY || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.https_proxy) {
221
+ console.warn('claudetools: Proxy detected. Download may fail behind a proxy.');
222
+ console.warn('claudetools: Set CLAUDETOOLS_SYNC_SKIP_DOWNLOAD=1 and install manually if needed.');
223
+ }
224
+
225
+ if (!packageName) {
226
+ console.log(`Unsupported platform: ${platformKey} — skipping sync engine install`);
227
+ return;
228
+ }
229
+
230
+ // Step 1: Check if the optional dependency installed the binary
231
+ const resolvedBinary = tryResolveFromOptionalDep();
232
+ if (resolvedBinary) {
233
+ console.log(`Sync engine binary found via npm: ${resolvedBinary}`);
234
+ return;
235
+ }
236
+
237
+ // Step 2: Fallback — download from GitHub releases
238
+ console.log('Sync engine binary not found in optional dependencies, downloading...');
239
+
240
+ const packageJson = JSON.parse(
241
+ fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')
242
+ );
243
+ const syncVersion = getSyncVersion(packageJson);
244
+
245
+ if (!fs.existsSync(BIN_DIR)) {
246
+ fs.mkdirSync(BIN_DIR, { recursive: true });
247
+ }
248
+
249
+ const binPath = path.join(BIN_DIR, binaryName);
250
+ const tmpPath = `${binPath}.tmp`;
251
+ const downloadUrl = getDownloadUrl(syncVersion);
252
+
253
+ // Derive the asset filename from the URL for checksum lookup
254
+ const assetFilename = path.basename(new URL(downloadUrl).pathname);
255
+
256
+ try {
257
+ // Download to temp file first (atomic write pattern)
258
+ await downloadFile(downloadUrl, tmpPath);
259
+
260
+ // Verify checksum before finalizing
261
+ await verifyChecksum(syncVersion, tmpPath, assetFilename);
262
+
263
+ // Atomic rename from .tmp to final destination
264
+ fs.renameSync(tmpPath, binPath);
265
+
266
+ if (process.platform !== 'win32') {
267
+ fs.chmodSync(binPath, 0o755);
268
+ }
269
+
270
+ console.log(`Sync engine installed at: ${binPath}`);
271
+ } catch (downloadError) {
272
+ // Clean up temp file on any failure
273
+ try { fs.unlinkSync(tmpPath); } catch { /* already cleaned up */ }
274
+
275
+ console.warn(`Failed to download sync engine: ${downloadError.message}`);
276
+ console.warn('The CLI will still work, but sync features require the sync engine.');
277
+ console.warn('Install manually: https://github.com/ClaudeTools/sync/releases');
278
+ // Non-fatal — CLI should still be usable without sync engine
279
+ }
280
+ }
281
+
282
+ install();