pilothub 0.0.1 → 0.0.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 (388) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +36 -129
  3. package/dist/browserAuth.d.ts +20 -0
  4. package/dist/browserAuth.js +156 -0
  5. package/dist/browserAuth.js.map +1 -0
  6. package/dist/browserAuth.test.d.ts +1 -0
  7. package/dist/browserAuth.test.js +83 -0
  8. package/dist/browserAuth.test.js.map +1 -0
  9. package/dist/cli/buildInfo.d.ts +3 -0
  10. package/dist/cli/buildInfo.js +103 -0
  11. package/dist/cli/buildInfo.js.map +1 -0
  12. package/dist/cli/commands/auth.d.ts +9 -0
  13. package/dist/cli/commands/auth.js +75 -0
  14. package/dist/cli/commands/auth.js.map +1 -0
  15. package/dist/cli/commands/delete.d.ts +11 -0
  16. package/dist/cli/commands/delete.js +67 -0
  17. package/dist/cli/commands/delete.js.map +1 -0
  18. package/dist/cli/commands/delete.test.d.ts +1 -0
  19. package/dist/cli/commands/delete.test.js +52 -0
  20. package/dist/cli/commands/delete.test.js.map +1 -0
  21. package/dist/cli/commands/publish.d.ts +9 -0
  22. package/dist/cli/commands/publish.js +87 -0
  23. package/dist/cli/commands/publish.js.map +1 -0
  24. package/dist/cli/commands/publish.test.d.ts +1 -0
  25. package/dist/cli/commands/publish.test.js +104 -0
  26. package/dist/cli/commands/publish.test.js.map +1 -0
  27. package/dist/cli/commands/skills.d.ts +23 -0
  28. package/dist/cli/commands/skills.js +298 -0
  29. package/dist/cli/commands/skills.js.map +1 -0
  30. package/dist/cli/commands/skills.test.d.ts +1 -0
  31. package/dist/cli/commands/skills.test.js +156 -0
  32. package/dist/cli/commands/skills.test.js.map +1 -0
  33. package/dist/cli/commands/star.d.ts +8 -0
  34. package/dist/cli/commands/star.js +38 -0
  35. package/dist/cli/commands/star.js.map +1 -0
  36. package/dist/cli/commands/sync.d.ts +3 -0
  37. package/dist/cli/commands/sync.js +160 -0
  38. package/dist/cli/commands/sync.js.map +1 -0
  39. package/dist/cli/commands/sync.test.d.ts +1 -0
  40. package/dist/cli/commands/sync.test.js +277 -0
  41. package/dist/cli/commands/sync.test.js.map +1 -0
  42. package/dist/cli/commands/syncHelpers.d.ts +76 -0
  43. package/dist/cli/commands/syncHelpers.js +349 -0
  44. package/dist/cli/commands/syncHelpers.js.map +1 -0
  45. package/dist/cli/commands/syncHelpers.test.d.ts +1 -0
  46. package/dist/cli/commands/syncHelpers.test.js +22 -0
  47. package/dist/cli/commands/syncHelpers.test.js.map +1 -0
  48. package/dist/cli/commands/syncTypes.d.ts +24 -0
  49. package/dist/cli/commands/syncTypes.js +2 -0
  50. package/dist/cli/commands/syncTypes.js.map +1 -0
  51. package/dist/cli/commands/unstar.d.ts +8 -0
  52. package/dist/cli/commands/unstar.js +38 -0
  53. package/dist/cli/commands/unstar.js.map +1 -0
  54. package/dist/cli/helpStyle.d.ts +13 -0
  55. package/dist/cli/helpStyle.js +38 -0
  56. package/dist/cli/helpStyle.js.map +1 -0
  57. package/dist/cli/pilotbotConfig.d.ts +6 -0
  58. package/dist/cli/pilotbotConfig.js +110 -0
  59. package/dist/cli/pilotbotConfig.js.map +1 -0
  60. package/dist/cli/pilotbotConfig.test.d.ts +1 -0
  61. package/dist/cli/pilotbotConfig.test.js +133 -0
  62. package/dist/cli/pilotbotConfig.test.js.map +1 -0
  63. package/dist/cli/registry.d.ts +7 -0
  64. package/dist/cli/registry.js +42 -0
  65. package/dist/cli/registry.js.map +1 -0
  66. package/dist/cli/registry.test.d.ts +1 -0
  67. package/dist/cli/registry.test.js +48 -0
  68. package/dist/cli/registry.test.js.map +1 -0
  69. package/dist/cli/scanSkills.d.ts +7 -0
  70. package/dist/cli/scanSkills.js +75 -0
  71. package/dist/cli/scanSkills.js.map +1 -0
  72. package/dist/cli/scanSkills.test.d.ts +1 -0
  73. package/dist/cli/scanSkills.test.js +60 -0
  74. package/dist/cli/scanSkills.test.js.map +1 -0
  75. package/dist/cli/slug.d.ts +2 -0
  76. package/dist/cli/slug.js +16 -0
  77. package/dist/cli/slug.js.map +1 -0
  78. package/dist/cli/types.d.ts +15 -0
  79. package/dist/cli/types.js +2 -0
  80. package/dist/cli/types.js.map +1 -0
  81. package/dist/cli/ui.d.ts +7 -0
  82. package/dist/cli/ui.js +72 -0
  83. package/dist/cli/ui.js.map +1 -0
  84. package/dist/cli.d.ts +2 -0
  85. package/dist/cli.js +268 -0
  86. package/dist/cli.js.map +1 -0
  87. package/dist/config.d.ts +4 -0
  88. package/dist/config.js +38 -0
  89. package/dist/config.js.map +1 -0
  90. package/dist/discovery.d.ts +5 -0
  91. package/dist/discovery.js +21 -0
  92. package/dist/discovery.js.map +1 -0
  93. package/dist/discovery.test.d.ts +1 -0
  94. package/dist/discovery.test.js +46 -0
  95. package/dist/discovery.test.js.map +1 -0
  96. package/dist/http.d.ts +32 -0
  97. package/dist/http.js +261 -0
  98. package/dist/http.js.map +1 -0
  99. package/dist/http.test.d.ts +1 -0
  100. package/dist/http.test.js +135 -0
  101. package/dist/http.test.js.map +1 -0
  102. package/dist/schema/ark.js.map +1 -0
  103. package/dist/schema/index.js.map +1 -0
  104. package/dist/schema/routes.js.map +1 -0
  105. package/{packages/schema/dist → dist/schema}/schemas.d.ts +0 -39
  106. package/{packages/schema/dist → dist/schema}/schemas.js +0 -22
  107. package/dist/schema/schemas.js.map +1 -0
  108. package/dist/schema/textFiles.js.map +1 -0
  109. package/dist/schema/textFiles.test.d.ts +1 -0
  110. package/dist/schema/textFiles.test.js +20 -0
  111. package/dist/schema/textFiles.test.js.map +1 -0
  112. package/dist/skills.d.ts +43 -0
  113. package/dist/skills.js +163 -0
  114. package/dist/skills.js.map +1 -0
  115. package/dist/skills.test.d.ts +1 -0
  116. package/dist/skills.test.js +144 -0
  117. package/dist/skills.test.js.map +1 -0
  118. package/dist/types.d.ts +7 -0
  119. package/dist/types.js +2 -0
  120. package/dist/types.js.map +1 -0
  121. package/package.json +27 -70
  122. package/.env.local.example +0 -19
  123. package/.github/workflows/ci.yml +0 -40
  124. package/.oxlintrc.json +0 -3
  125. package/AGENTS.md +0 -45
  126. package/CHANGELOG.md +0 -138
  127. package/DEPRECATIONS.md +0 -7
  128. package/biome.json +0 -41
  129. package/convex/_generated/api.d.ts +0 -153
  130. package/convex/_generated/api.js +0 -23
  131. package/convex/_generated/dataModel.d.ts +0 -60
  132. package/convex/_generated/server.d.ts +0 -143
  133. package/convex/_generated/server.js +0 -93
  134. package/convex/auth.config.ts +0 -8
  135. package/convex/auth.ts +0 -19
  136. package/convex/comments.ts +0 -88
  137. package/convex/crons.ts +0 -34
  138. package/convex/devSeed.ts +0 -459
  139. package/convex/devSeedExtra.ts +0 -541
  140. package/convex/downloads.ts +0 -78
  141. package/convex/githubBackups.ts +0 -170
  142. package/convex/githubBackupsNode.ts +0 -183
  143. package/convex/githubImport.ts +0 -317
  144. package/convex/githubSoulBackups.ts +0 -170
  145. package/convex/githubSoulBackupsNode.ts +0 -186
  146. package/convex/http.ts +0 -194
  147. package/convex/httpApi.handlers.test.ts +0 -488
  148. package/convex/httpApi.test.ts +0 -70
  149. package/convex/httpApi.ts +0 -305
  150. package/convex/httpApiV1.handlers.test.ts +0 -584
  151. package/convex/httpApiV1.ts +0 -1172
  152. package/convex/leaderboards.ts +0 -39
  153. package/convex/lib/access.ts +0 -36
  154. package/convex/lib/apiTokenAuth.ts +0 -36
  155. package/convex/lib/badges.ts +0 -50
  156. package/convex/lib/changelog.test.ts +0 -34
  157. package/convex/lib/changelog.ts +0 -278
  158. package/convex/lib/embeddings.ts +0 -38
  159. package/convex/lib/githubBackup.ts +0 -443
  160. package/convex/lib/githubImport.test.ts +0 -247
  161. package/convex/lib/githubImport.ts +0 -425
  162. package/convex/lib/githubSoulBackup.ts +0 -443
  163. package/convex/lib/leaderboards.ts +0 -103
  164. package/convex/lib/moderation.ts +0 -42
  165. package/convex/lib/public.ts +0 -89
  166. package/convex/lib/searchText.test.ts +0 -46
  167. package/convex/lib/searchText.ts +0 -27
  168. package/convex/lib/skillBackfill.test.ts +0 -34
  169. package/convex/lib/skillBackfill.ts +0 -67
  170. package/convex/lib/skillPublish.test.ts +0 -28
  171. package/convex/lib/skillPublish.ts +0 -284
  172. package/convex/lib/skillStats.ts +0 -80
  173. package/convex/lib/skills.test.ts +0 -197
  174. package/convex/lib/skills.ts +0 -273
  175. package/convex/lib/soulChangelog.ts +0 -273
  176. package/convex/lib/soulPublish.ts +0 -236
  177. package/convex/lib/tokens.test.ts +0 -33
  178. package/convex/lib/tokens.ts +0 -51
  179. package/convex/lib/webhooks.test.ts +0 -91
  180. package/convex/lib/webhooks.ts +0 -112
  181. package/convex/maintenance.test.ts +0 -270
  182. package/convex/maintenance.ts +0 -840
  183. package/convex/rateLimits.ts +0 -50
  184. package/convex/schema.ts +0 -472
  185. package/convex/search.test.ts +0 -12
  186. package/convex/search.ts +0 -254
  187. package/convex/seed.test.ts +0 -37
  188. package/convex/seed.ts +0 -254
  189. package/convex/seedSouls.ts +0 -111
  190. package/convex/skillStatEvents.ts +0 -568
  191. package/convex/skills.ts +0 -1606
  192. package/convex/soulComments.ts +0 -88
  193. package/convex/soulDownloads.ts +0 -14
  194. package/convex/soulStars.ts +0 -71
  195. package/convex/souls.ts +0 -570
  196. package/convex/stars.ts +0 -108
  197. package/convex/statsMaintenance.ts +0 -205
  198. package/convex/telemetry.ts +0 -434
  199. package/convex/tokens.ts +0 -88
  200. package/convex/tsconfig.json +0 -7
  201. package/convex/uploads.ts +0 -20
  202. package/convex/users.ts +0 -122
  203. package/convex/webhooks.ts +0 -50
  204. package/convex.json +0 -3
  205. package/docs/README.md +0 -32
  206. package/docs/api.md +0 -51
  207. package/docs/architecture.md +0 -61
  208. package/docs/auth.md +0 -54
  209. package/docs/cli.md +0 -117
  210. package/docs/deploy.md +0 -78
  211. package/docs/diffing.md +0 -84
  212. package/docs/github-import.md +0 -171
  213. package/docs/http-api.md +0 -187
  214. package/docs/manual-testing.md +0 -64
  215. package/docs/mintlify.md +0 -43
  216. package/docs/quickstart.md +0 -120
  217. package/docs/skill-format.md +0 -58
  218. package/docs/soul-format.md +0 -37
  219. package/docs/spec.md +0 -177
  220. package/docs/telemetry.md +0 -91
  221. package/docs/troubleshooting.md +0 -49
  222. package/docs/webhook.md +0 -51
  223. package/e2e/menu-smoke.pw.test.ts +0 -49
  224. package/e2e/pilothub.e2e.test.ts +0 -494
  225. package/e2e/search-exact.pw.test.ts +0 -97
  226. package/packages/pilothub/LICENSE +0 -22
  227. package/packages/pilothub/README.md +0 -57
  228. package/packages/pilothub/package.json +0 -41
  229. package/packages/pilothub/src/browserAuth.test.ts +0 -96
  230. package/packages/pilothub/src/browserAuth.ts +0 -174
  231. package/packages/pilothub/src/cli/buildInfo.ts +0 -94
  232. package/packages/pilothub/src/cli/commands/auth.ts +0 -97
  233. package/packages/pilothub/src/cli/commands/delete.test.ts +0 -73
  234. package/packages/pilothub/src/cli/commands/delete.ts +0 -83
  235. package/packages/pilothub/src/cli/commands/publish.test.ts +0 -122
  236. package/packages/pilothub/src/cli/commands/publish.ts +0 -108
  237. package/packages/pilothub/src/cli/commands/skills.test.ts +0 -191
  238. package/packages/pilothub/src/cli/commands/skills.ts +0 -380
  239. package/packages/pilothub/src/cli/commands/star.ts +0 -46
  240. package/packages/pilothub/src/cli/commands/sync.test.ts +0 -310
  241. package/packages/pilothub/src/cli/commands/sync.ts +0 -200
  242. package/packages/pilothub/src/cli/commands/syncHelpers.test.ts +0 -26
  243. package/packages/pilothub/src/cli/commands/syncHelpers.ts +0 -427
  244. package/packages/pilothub/src/cli/commands/syncTypes.ts +0 -27
  245. package/packages/pilothub/src/cli/commands/unstar.ts +0 -48
  246. package/packages/pilothub/src/cli/helpStyle.ts +0 -45
  247. package/packages/pilothub/src/cli/pilotbotConfig.test.ts +0 -159
  248. package/packages/pilothub/src/cli/pilotbotConfig.ts +0 -147
  249. package/packages/pilothub/src/cli/registry.test.ts +0 -63
  250. package/packages/pilothub/src/cli/registry.ts +0 -43
  251. package/packages/pilothub/src/cli/scanSkills.test.ts +0 -64
  252. package/packages/pilothub/src/cli/scanSkills.ts +0 -84
  253. package/packages/pilothub/src/cli/slug.ts +0 -16
  254. package/packages/pilothub/src/cli/types.ts +0 -12
  255. package/packages/pilothub/src/cli/ui.ts +0 -75
  256. package/packages/pilothub/src/cli.ts +0 -311
  257. package/packages/pilothub/src/config.ts +0 -36
  258. package/packages/pilothub/src/discovery.test.ts +0 -75
  259. package/packages/pilothub/src/discovery.ts +0 -19
  260. package/packages/pilothub/src/http.test.ts +0 -156
  261. package/packages/pilothub/src/http.ts +0 -301
  262. package/packages/pilothub/src/schema/ark.ts +0 -29
  263. package/packages/pilothub/src/schema/index.ts +0 -5
  264. package/packages/pilothub/src/schema/routes.ts +0 -22
  265. package/packages/pilothub/src/schema/schemas.ts +0 -260
  266. package/packages/pilothub/src/schema/textFiles.test.ts +0 -23
  267. package/packages/pilothub/src/schema/textFiles.ts +0 -66
  268. package/packages/pilothub/src/skills.test.ts +0 -191
  269. package/packages/pilothub/src/skills.ts +0 -172
  270. package/packages/pilothub/src/types.ts +0 -10
  271. package/packages/pilothub/tsconfig.json +0 -14
  272. package/packages/schema/README.md +0 -3
  273. package/packages/schema/dist/ark.js.map +0 -1
  274. package/packages/schema/dist/index.js.map +0 -1
  275. package/packages/schema/dist/routes.js.map +0 -1
  276. package/packages/schema/dist/schemas.js.map +0 -1
  277. package/packages/schema/dist/textFiles.js.map +0 -1
  278. package/packages/schema/package.json +0 -26
  279. package/packages/schema/src/ark.ts +0 -29
  280. package/packages/schema/src/index.ts +0 -5
  281. package/packages/schema/src/routes.ts +0 -22
  282. package/packages/schema/src/schemas.test.ts +0 -123
  283. package/packages/schema/src/schemas.ts +0 -287
  284. package/packages/schema/src/textFiles.test.ts +0 -23
  285. package/packages/schema/src/textFiles.ts +0 -66
  286. package/packages/schema/tsconfig.json +0 -15
  287. package/pilothub +0 -46
  288. package/playwright.config.ts +0 -33
  289. package/public/.well-known/pilothub.json +0 -6
  290. package/public/api/v1/openapi.json +0 -379
  291. package/public/favicon.ico +0 -0
  292. package/public/logo192.png +0 -0
  293. package/public/logo512.png +0 -0
  294. package/public/manifest.json +0 -25
  295. package/public/og.png +0 -0
  296. package/public/og.svg +0 -98
  297. package/public/pilot-logo.png +0 -0
  298. package/public/pilot-mark.png +0 -0
  299. package/public/robots.txt +0 -3
  300. package/public/tanstack-circle-logo.png +0 -0
  301. package/public/tanstack-word-logo-white.svg +0 -1
  302. package/scripts/check-peer-deps.ts +0 -56
  303. package/scripts/docs-list.ts +0 -148
  304. package/scripts/run-playwright-local.sh +0 -14
  305. package/server/og/fetchSkillOgMeta.ts +0 -27
  306. package/server/og/fetchSoulOgMeta.ts +0 -27
  307. package/server/og/ogAssets.ts +0 -80
  308. package/server/og/skillOgSvg.test.ts +0 -59
  309. package/server/og/skillOgSvg.ts +0 -258
  310. package/server/og/soulOgSvg.ts +0 -209
  311. package/server/routes/og/skill.png.ts +0 -103
  312. package/server/routes/og/soul.png.ts +0 -111
  313. package/src/__tests__/skill-detail-page.test.tsx +0 -86
  314. package/src/__tests__/skills-index.test.tsx +0 -145
  315. package/src/__tests__/upload.route.test.tsx +0 -228
  316. package/src/components/AppProviders.tsx +0 -19
  317. package/src/components/ClientOnly.tsx +0 -18
  318. package/src/components/Footer.tsx +0 -29
  319. package/src/components/Header.tsx +0 -295
  320. package/src/components/InstallSwitcher.tsx +0 -53
  321. package/src/components/SkillCard.tsx +0 -36
  322. package/src/components/SkillDetailPage.tsx +0 -817
  323. package/src/components/SkillDiffCard.tsx +0 -485
  324. package/src/components/SoulCard.tsx +0 -19
  325. package/src/components/SoulDetailPage.tsx +0 -263
  326. package/src/components/UserBootstrap.tsx +0 -18
  327. package/src/components/ui/dropdown-menu.tsx +0 -67
  328. package/src/components/ui/toggle-group.tsx +0 -35
  329. package/src/convex/client.ts +0 -3
  330. package/src/lib/badges.ts +0 -29
  331. package/src/lib/diffing.test.ts +0 -163
  332. package/src/lib/diffing.ts +0 -106
  333. package/src/lib/gravatar.test.ts +0 -9
  334. package/src/lib/gravatar.ts +0 -158
  335. package/src/lib/og.test.ts +0 -142
  336. package/src/lib/og.ts +0 -156
  337. package/src/lib/publicUser.ts +0 -39
  338. package/src/lib/roles.ts +0 -19
  339. package/src/lib/site.test.ts +0 -130
  340. package/src/lib/site.ts +0 -84
  341. package/src/lib/theme-transition.test.ts +0 -134
  342. package/src/lib/theme-transition.ts +0 -134
  343. package/src/lib/theme.test.tsx +0 -88
  344. package/src/lib/theme.ts +0 -43
  345. package/src/lib/uploadFiles.jsdom.test.ts +0 -33
  346. package/src/lib/uploadFiles.test.ts +0 -123
  347. package/src/lib/uploadFiles.ts +0 -245
  348. package/src/lib/uploadUtils.test.ts +0 -78
  349. package/src/lib/uploadUtils.ts +0 -93
  350. package/src/lib/useAuthStatus.ts +0 -12
  351. package/src/lib/utils.test.ts +0 -9
  352. package/src/lib/utils.ts +0 -6
  353. package/src/logo.svg +0 -12
  354. package/src/routeTree.gen.ts +0 -345
  355. package/src/router.tsx +0 -17
  356. package/src/routes/$owner/$slug.tsx +0 -55
  357. package/src/routes/__root.tsx +0 -136
  358. package/src/routes/admin.tsx +0 -11
  359. package/src/routes/cli/auth.tsx +0 -168
  360. package/src/routes/dashboard.tsx +0 -97
  361. package/src/routes/import.tsx +0 -415
  362. package/src/routes/index.tsx +0 -252
  363. package/src/routes/management.tsx +0 -529
  364. package/src/routes/settings.tsx +0 -203
  365. package/src/routes/skills/index.tsx +0 -422
  366. package/src/routes/souls/$slug.tsx +0 -55
  367. package/src/routes/souls/index.tsx +0 -243
  368. package/src/routes/stars.tsx +0 -68
  369. package/src/routes/u/$handle.tsx +0 -307
  370. package/src/routes/upload/utils.ts +0 -81
  371. package/src/routes/upload.tsx +0 -499
  372. package/src/styles.css +0 -2718
  373. package/tsconfig.json +0 -24
  374. package/tsconfig.oxlint.json +0 -16
  375. package/vercel.json +0 -8
  376. package/vite.config.ts +0 -48
  377. package/vitest.config.ts +0 -47
  378. package/vitest.e2e.config.ts +0 -11
  379. package/vitest.setup.ts +0 -1
  380. /package/{packages/pilothub/bin → bin}/pilothub.js +0 -0
  381. /package/{packages/schema/dist → dist/schema}/ark.d.ts +0 -0
  382. /package/{packages/schema/dist → dist/schema}/ark.js +0 -0
  383. /package/{packages/schema/dist → dist/schema}/index.d.ts +0 -0
  384. /package/{packages/schema/dist → dist/schema}/index.js +0 -0
  385. /package/{packages/schema/dist → dist/schema}/routes.d.ts +0 -0
  386. /package/{packages/schema/dist → dist/schema}/routes.js +0 -0
  387. /package/{packages/schema/dist → dist/schema}/textFiles.d.ts +0 -0
  388. /package/{packages/schema/dist → dist/schema}/textFiles.js +0 -0
@@ -1,39 +0,0 @@
1
- import { v } from 'convex/values'
2
- import { internalMutation } from './_generated/server'
3
- import { buildTrendingLeaderboard } from './lib/leaderboards'
4
-
5
- const MAX_TRENDING_LIMIT = 200
6
- const KEEP_LEADERBOARD_ENTRIES = 3
7
-
8
- export const rebuildTrendingLeaderboardInternal = internalMutation({
9
- args: { limit: v.optional(v.number()) },
10
- handler: async (ctx, args) => {
11
- const limit = clampInt(args.limit ?? MAX_TRENDING_LIMIT, 1, MAX_TRENDING_LIMIT)
12
- const now = Date.now()
13
- const { startDay, endDay, items } = await buildTrendingLeaderboard(ctx, { limit, now })
14
-
15
- await ctx.db.insert('skillLeaderboards', {
16
- kind: 'trending',
17
- generatedAt: now,
18
- rangeStartDay: startDay,
19
- rangeEndDay: endDay,
20
- items,
21
- })
22
-
23
- const recent = await ctx.db
24
- .query('skillLeaderboards')
25
- .withIndex('by_kind', (q) => q.eq('kind', 'trending'))
26
- .order('desc')
27
- .take(KEEP_LEADERBOARD_ENTRIES + 5)
28
-
29
- for (const entry of recent.slice(KEEP_LEADERBOARD_ENTRIES)) {
30
- await ctx.db.delete(entry._id)
31
- }
32
-
33
- return { ok: true as const, count: items.length }
34
- },
35
- })
36
-
37
- function clampInt(value: number, min: number, max: number) {
38
- return Math.min(Math.max(value, min), max)
39
- }
@@ -1,36 +0,0 @@
1
- import { getAuthUserId } from '@convex-dev/auth/server'
2
- import { internal } from '../_generated/api'
3
- import type { Doc } from '../_generated/dataModel'
4
- import type { ActionCtx, MutationCtx, QueryCtx } from '../_generated/server'
5
-
6
- export type Role = 'admin' | 'moderator' | 'user'
7
-
8
- export async function requireUser(ctx: MutationCtx | QueryCtx) {
9
- const userId = await getAuthUserId(ctx)
10
- if (!userId) throw new Error('Unauthorized')
11
- const user = await ctx.db.get(userId)
12
- if (!user || user.deletedAt) throw new Error('User not found')
13
- return { userId, user }
14
- }
15
-
16
- export async function requireUserFromAction(ctx: ActionCtx) {
17
- const userId = await getAuthUserId(ctx)
18
- if (!userId) throw new Error('Unauthorized')
19
- const user = await ctx.runQuery(internal.users.getByIdInternal, { userId })
20
- if (!user || user.deletedAt) throw new Error('User not found')
21
- return { userId, user: user as Doc<'users'> }
22
- }
23
-
24
- export function assertRole(user: Doc<'users'>, allowed: Role[]) {
25
- if (!user.role || !allowed.includes(user.role as Role)) {
26
- throw new Error('Forbidden')
27
- }
28
- }
29
-
30
- export function assertAdmin(user: Doc<'users'>) {
31
- assertRole(user, ['admin'])
32
- }
33
-
34
- export function assertModerator(user: Doc<'users'>) {
35
- assertRole(user, ['admin', 'moderator'])
36
- }
@@ -1,36 +0,0 @@
1
- import { ConvexError } from 'convex/values'
2
- import { internal } from '../_generated/api'
3
- import type { Doc } from '../_generated/dataModel'
4
- import type { ActionCtx } from '../_generated/server'
5
- import { hashToken } from './tokens'
6
-
7
- type TokenAuthResult = { user: Doc<'users'>; userId: Doc<'users'>['_id'] }
8
-
9
- export async function requireApiTokenUser(
10
- ctx: ActionCtx,
11
- request: Request,
12
- ): Promise<TokenAuthResult> {
13
- const header = request.headers.get('authorization') ?? request.headers.get('Authorization')
14
- const token = parseBearerToken(header)
15
- if (!token) throw new ConvexError('Unauthorized')
16
-
17
- const tokenHash = await hashToken(token)
18
- const apiToken = await ctx.runQuery(internal.tokens.getByHashInternal, { tokenHash })
19
- if (!apiToken || apiToken.revokedAt) throw new ConvexError('Unauthorized')
20
-
21
- const user = await ctx.runQuery(internal.tokens.getUserForTokenInternal, {
22
- tokenId: apiToken._id,
23
- })
24
- if (!user || user.deletedAt) throw new ConvexError('Unauthorized')
25
-
26
- await ctx.runMutation(internal.tokens.touchInternal, { tokenId: apiToken._id })
27
- return { user, userId: user._id }
28
- }
29
-
30
- function parseBearerToken(header: string | null) {
31
- if (!header) return null
32
- const trimmed = header.trim()
33
- if (!trimmed.toLowerCase().startsWith('bearer ')) return null
34
- const token = trimmed.slice(7).trim()
35
- return token || null
36
- }
@@ -1,50 +0,0 @@
1
- import type { Doc, Id } from '../_generated/dataModel'
2
- import type { QueryCtx } from '../_generated/server'
3
-
4
- type BadgeKind = Doc<'skillBadges'>['kind']
5
-
6
- export type SkillBadgeMap = Partial<Record<BadgeKind, { byUserId: Id<'users'>; at: number }>>
7
-
8
- export type SkillBadgeSource = { badges?: SkillBadgeMap | null }
9
-
10
- type BadgeCtx = Pick<QueryCtx, 'db'>
11
-
12
- export function isSkillHighlighted(skill: SkillBadgeSource) {
13
- return Boolean(skill.badges?.highlighted)
14
- }
15
-
16
- export function isSkillOfficial(skill: SkillBadgeSource) {
17
- return Boolean(skill.badges?.official)
18
- }
19
-
20
- export function isSkillDeprecated(skill: SkillBadgeSource) {
21
- return Boolean(skill.badges?.deprecated)
22
- }
23
-
24
- export function buildBadgeMap(records: Doc<'skillBadges'>[]): SkillBadgeMap {
25
- return records.reduce<SkillBadgeMap>((acc, record) => {
26
- acc[record.kind] = { byUserId: record.byUserId, at: record.at }
27
- return acc
28
- }, {})
29
- }
30
-
31
- export async function getSkillBadgeMap(
32
- ctx: BadgeCtx,
33
- skillId: Id<'skills'>,
34
- ): Promise<SkillBadgeMap> {
35
- const records = await ctx.db
36
- .query('skillBadges')
37
- .withIndex('by_skill', (q) => q.eq('skillId', skillId))
38
- .collect()
39
- return buildBadgeMap(records)
40
- }
41
-
42
- export async function getSkillBadgeMaps(
43
- ctx: BadgeCtx,
44
- skillIds: Array<Id<'skills'>>,
45
- ): Promise<Map<Id<'skills'>, SkillBadgeMap>> {
46
- const entries = await Promise.all(
47
- skillIds.map(async (skillId) => [skillId, await getSkillBadgeMap(ctx, skillId)] as const),
48
- )
49
- return new Map(entries)
50
- }
@@ -1,34 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { __test } from './changelog'
3
-
4
- describe('changelog utils', () => {
5
- it('summarizes file diffs', () => {
6
- const diff = __test.summarizeFileDiff(
7
- [
8
- { path: 'a.txt', sha256: 'aaa' },
9
- { path: 'b.txt', sha256: 'bbb' },
10
- ],
11
- [
12
- { path: 'a.txt', sha256: 'aaa' },
13
- { path: 'b.txt', sha256: 'ccc' },
14
- { path: 'c.txt', sha256: 'ddd' },
15
- ],
16
- )
17
-
18
- expect(diff.added).toEqual(['c.txt'])
19
- expect(diff.removed).toEqual([])
20
- expect(diff.changed).toEqual(['b.txt'])
21
- expect(__test.formatDiffSummary(diff)).toBe('1 added, 1 changed')
22
- })
23
-
24
- it('generates a fallback initial release note', () => {
25
- const text = __test.generateFallback({
26
- slug: 'demo',
27
- version: '1.0.0',
28
- oldReadme: null,
29
- nextReadme: 'hi',
30
- fileDiff: null,
31
- })
32
- expect(text).toMatch(/Initial release/i)
33
- })
34
- })
@@ -1,278 +0,0 @@
1
- import { internal } from '../_generated/api'
2
- import type { Doc, Id } from '../_generated/dataModel'
3
- import type { ActionCtx } from '../_generated/server'
4
-
5
- const CHANGELOG_MODEL = process.env.OPENAI_CHANGELOG_MODEL ?? 'gpt-4.1'
6
- const MAX_README_CHARS = 8_000
7
- const MAX_PATHS_IN_PROMPT = 30
8
-
9
- type FileMeta = { path: string; sha256?: string }
10
-
11
- type FileDiffSummary = {
12
- added: string[]
13
- removed: string[]
14
- changed: string[]
15
- }
16
-
17
- function clampText(value: string, maxChars: number) {
18
- const trimmed = value.trim()
19
- if (trimmed.length <= maxChars) return trimmed
20
- return `${trimmed.slice(0, maxChars).trimEnd()}\n…`
21
- }
22
-
23
- function summarizeFileDiff(oldFiles: FileMeta[], nextFiles: FileMeta[]): FileDiffSummary {
24
- const oldByPath = new Map(oldFiles.map((f) => [f.path, f] as const))
25
- const nextByPath = new Map(nextFiles.map((f) => [f.path, f] as const))
26
-
27
- const added: string[] = []
28
- const removed: string[] = []
29
- const changed: string[] = []
30
-
31
- for (const [path, file] of nextByPath.entries()) {
32
- const prev = oldByPath.get(path)
33
- if (!prev) {
34
- added.push(path)
35
- continue
36
- }
37
- if (file.sha256 && prev.sha256 && file.sha256 !== prev.sha256) changed.push(path)
38
- }
39
- for (const path of oldByPath.keys()) {
40
- if (!nextByPath.has(path)) removed.push(path)
41
- }
42
-
43
- added.sort()
44
- removed.sort()
45
- changed.sort()
46
- return { added, removed, changed }
47
- }
48
-
49
- function formatDiffSummary(diff: FileDiffSummary) {
50
- const parts: string[] = []
51
- if (diff.added.length) parts.push(`${diff.added.length} added`)
52
- if (diff.changed.length) parts.push(`${diff.changed.length} changed`)
53
- if (diff.removed.length) parts.push(`${diff.removed.length} removed`)
54
- return parts.join(', ') || 'no file changes detected'
55
- }
56
-
57
- function pickPaths(values: string[]) {
58
- if (values.length <= MAX_PATHS_IN_PROMPT) return values
59
- return values.slice(0, MAX_PATHS_IN_PROMPT)
60
- }
61
-
62
- function extractResponseText(payload: unknown) {
63
- if (!payload || typeof payload !== 'object') return null
64
- const output = (payload as { output?: unknown }).output
65
- if (!Array.isArray(output)) return null
66
- const chunks: string[] = []
67
- for (const item of output) {
68
- if (!item || typeof item !== 'object') continue
69
- if ((item as { type?: unknown }).type !== 'message') continue
70
- const content = (item as { content?: unknown }).content
71
- if (!Array.isArray(content)) continue
72
- for (const part of content) {
73
- if (!part || typeof part !== 'object') continue
74
- if ((part as { type?: unknown }).type !== 'output_text') continue
75
- const text = (part as { text?: unknown }).text
76
- if (typeof text === 'string' && text.trim()) chunks.push(text)
77
- }
78
- }
79
- const joined = chunks.join('\n').trim()
80
- return joined || null
81
- }
82
-
83
- async function generateWithOpenAI(args: {
84
- slug: string
85
- version: string
86
- oldReadme: string | null
87
- nextReadme: string
88
- fileDiff: FileDiffSummary | null
89
- }) {
90
- const apiKey = process.env.OPENAI_API_KEY
91
- if (!apiKey) return null
92
-
93
- const oldReadme = args.oldReadme ? clampText(args.oldReadme, MAX_README_CHARS) : ''
94
- const nextReadme = clampText(args.nextReadme, MAX_README_CHARS)
95
-
96
- const fileDiff = args.fileDiff
97
- const diffSummary = fileDiff ? formatDiffSummary(fileDiff) : 'unknown'
98
- const changedPaths = fileDiff ? pickPaths(fileDiff.changed) : []
99
- const addedPaths = fileDiff ? pickPaths(fileDiff.added) : []
100
- const removedPaths = fileDiff ? pickPaths(fileDiff.removed) : []
101
-
102
- const input = [
103
- `Skill: ${args.slug}`,
104
- `Version: ${args.version}`,
105
- `File changes: ${diffSummary}`,
106
- changedPaths.length ? `Changed files (sample): ${changedPaths.join(', ')}` : null,
107
- addedPaths.length ? `Added files (sample): ${addedPaths.join(', ')}` : null,
108
- removedPaths.length ? `Removed files (sample): ${removedPaths.join(', ')}` : null,
109
- oldReadme ? `Previous SKILL.md:\n${oldReadme}` : null,
110
- `New SKILL.md:\n${nextReadme}`,
111
- ]
112
- .filter(Boolean)
113
- .join('\n\n')
114
-
115
- const response = await fetch('https://api.openai.com/v1/responses', {
116
- method: 'POST',
117
- headers: {
118
- 'Content-Type': 'application/json',
119
- Authorization: `Bearer ${apiKey}`,
120
- },
121
- body: JSON.stringify({
122
- model: CHANGELOG_MODEL,
123
- instructions:
124
- 'Write a concise changelog for this skill version. Audience: everyone. Output plain text. Prefer 2–6 bullet points. If it is a big change, include a short 1-line summary first, then bullets. Don’t mention that you are AI. Don’t invent details; only use the inputs.',
125
- input,
126
- max_output_tokens: 220,
127
- }),
128
- })
129
-
130
- if (!response.ok) return null
131
- const payload = (await response.json()) as unknown
132
- return extractResponseText(payload)
133
- }
134
-
135
- function generateFallback(args: {
136
- slug: string
137
- version: string
138
- oldReadme: string | null
139
- nextReadme: string
140
- fileDiff: FileDiffSummary | null
141
- }) {
142
- const lines: string[] = []
143
- if (!args.oldReadme) {
144
- lines.push(`- Initial release.`)
145
- return lines.join('\n')
146
- }
147
-
148
- const diff = args.fileDiff
149
- if (diff) {
150
- const parts: string[] = []
151
- if (diff.added.length) parts.push(`added ${diff.added.length}`)
152
- if (diff.changed.length) parts.push(`updated ${diff.changed.length}`)
153
- if (diff.removed.length) parts.push(`removed ${diff.removed.length}`)
154
- if (parts.length) lines.push(`- ${parts.join(', ')} file(s).`)
155
- }
156
-
157
- lines.push(`- Updated SKILL.md and bundle contents.`)
158
- return lines.join('\n')
159
- }
160
-
161
- export async function generateChangelogForPublish(
162
- ctx: ActionCtx,
163
- args: { slug: string; version: string; readmeText: string; files: FileMeta[] },
164
- ): Promise<string> {
165
- try {
166
- const skill = (await ctx.runQuery(internal.skills.getSkillBySlugInternal, {
167
- slug: args.slug,
168
- })) as Doc<'skills'> | null
169
- const previous: Doc<'skillVersions'> | null =
170
- skill?.latestVersionId && !skill.softDeletedAt
171
- ? ((await ctx.runQuery(internal.skills.getVersionByIdInternal, {
172
- versionId: skill.latestVersionId,
173
- })) as Doc<'skillVersions'> | null)
174
- : null
175
-
176
- const oldReadmeText: string | null = previous
177
- ? await readReadmeFromVersion(ctx, previous)
178
- : null
179
- const oldFiles = previous
180
- ? previous.files.map((file) => ({ path: file.path, sha256: file.sha256 }))
181
- : []
182
- const fileDiff = previous ? summarizeFileDiff(oldFiles, args.files) : null
183
-
184
- const ai = await generateWithOpenAI({
185
- slug: args.slug,
186
- version: args.version,
187
- oldReadme: oldReadmeText,
188
- nextReadme: args.readmeText,
189
- fileDiff,
190
- }).catch(() => null)
191
-
192
- return (
193
- ai ??
194
- generateFallback({
195
- slug: args.slug,
196
- version: args.version,
197
- oldReadme: oldReadmeText,
198
- nextReadme: args.readmeText,
199
- fileDiff,
200
- })
201
- )
202
- } catch {
203
- return '- Updated skill.'
204
- }
205
- }
206
-
207
- export async function generateChangelogPreview(
208
- ctx: ActionCtx,
209
- args: {
210
- slug: string
211
- version: string
212
- readmeText: string
213
- filePaths?: string[]
214
- },
215
- ): Promise<string> {
216
- try {
217
- const skill = (await ctx.runQuery(internal.skills.getSkillBySlugInternal, {
218
- slug: args.slug,
219
- })) as Doc<'skills'> | null
220
- const previous: Doc<'skillVersions'> | null =
221
- skill?.latestVersionId && !skill.softDeletedAt
222
- ? ((await ctx.runQuery(internal.skills.getVersionByIdInternal, {
223
- versionId: skill.latestVersionId,
224
- })) as Doc<'skillVersions'> | null)
225
- : null
226
-
227
- const oldReadmeText: string | null = previous
228
- ? await readReadmeFromVersion(ctx, previous)
229
- : null
230
- const fileDiff =
231
- previous && args.filePaths
232
- ? summarizeFileDiff(
233
- previous.files.map((file) => ({ path: file.path, sha256: file.sha256 })),
234
- args.filePaths.map((path) => ({ path })),
235
- )
236
- : null
237
-
238
- const ai = await generateWithOpenAI({
239
- slug: args.slug,
240
- version: args.version,
241
- oldReadme: oldReadmeText,
242
- nextReadme: args.readmeText,
243
- fileDiff,
244
- }).catch(() => null)
245
-
246
- return (
247
- ai ??
248
- generateFallback({
249
- slug: args.slug,
250
- version: args.version,
251
- oldReadme: oldReadmeText,
252
- nextReadme: args.readmeText,
253
- fileDiff,
254
- })
255
- )
256
- } catch {
257
- return '- Updated skill.'
258
- }
259
- }
260
-
261
- async function readReadmeFromVersion(ctx: ActionCtx, version: Doc<'skillVersions'>) {
262
- const readmeFile = version.files.find((file) => {
263
- const lower = file.path.toLowerCase()
264
- return lower === 'skill.md' || lower === 'skills.md'
265
- })
266
- if (!readmeFile) return null
267
- const blob = await ctx.storage.get(readmeFile.storageId as Id<'_storage'>)
268
- if (!blob) return null
269
- return blob.text()
270
- }
271
-
272
- export const __test = {
273
- clampText,
274
- extractResponseText,
275
- formatDiffSummary,
276
- summarizeFileDiff,
277
- generateFallback,
278
- }
@@ -1,38 +0,0 @@
1
- export const EMBEDDING_MODEL = 'text-embedding-3-small'
2
- export const EMBEDDING_DIMENSIONS = 1536
3
-
4
- function emptyEmbedding() {
5
- return Array.from({ length: EMBEDDING_DIMENSIONS }, () => 0)
6
- }
7
-
8
- export async function generateEmbedding(text: string) {
9
- const apiKey = process.env.OPENAI_API_KEY
10
- if (!apiKey) {
11
- console.warn('OPENAI_API_KEY is not configured; using zero embeddings')
12
- return emptyEmbedding()
13
- }
14
-
15
- const response = await fetch('https://api.openai.com/v1/embeddings', {
16
- method: 'POST',
17
- headers: {
18
- 'Content-Type': 'application/json',
19
- Authorization: `Bearer ${apiKey}`,
20
- },
21
- body: JSON.stringify({
22
- model: EMBEDDING_MODEL,
23
- input: text,
24
- }),
25
- })
26
-
27
- if (!response.ok) {
28
- const message = await response.text()
29
- throw new Error(`Embedding failed: ${message}`)
30
- }
31
-
32
- const payload = (await response.json()) as {
33
- data?: Array<{ embedding: number[] }>
34
- }
35
- const embedding = payload.data?.[0]?.embedding
36
- if (!embedding) throw new Error('Embedding missing from response')
37
- return embedding
38
- }