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,46 +0,0 @@
1
- /* @vitest-environment node */
2
-
3
- import { describe, expect, it } from 'vitest'
4
- import { __test, matchesExactTokens, tokenize } from './searchText'
5
-
6
- describe('searchText', () => {
7
- it('tokenize lowercases and splits on punctuation', () => {
8
- expect(tokenize('Minimax Usage /minimax-usage')).toEqual([
9
- 'minimax',
10
- 'usage',
11
- 'minimax',
12
- 'usage',
13
- ])
14
- })
15
-
16
- it('matchesExactTokens requires at least one query token to prefix-match', () => {
17
- const queryTokens = tokenize('Remind Me')
18
- expect(matchesExactTokens(queryTokens, ['Remind Me', '/remind-me', 'Short summary'])).toBe(true)
19
- // "Reminder" starts with "remind", so it matches with prefix matching
20
- expect(matchesExactTokens(queryTokens, ['Reminder tool', '/reminder', 'Short summary'])).toBe(
21
- true,
22
- )
23
- // Matches because "remind" token is present
24
- expect(matchesExactTokens(queryTokens, ['Remind tool', '/remind', 'Short summary'])).toBe(true)
25
- // No matching tokens at all
26
- expect(matchesExactTokens(queryTokens, ['Other tool', '/other', 'Short summary'])).toBe(false)
27
- })
28
-
29
- it('matchesExactTokens supports prefix matching for partial queries', () => {
30
- // "go" should match "gohome" because "gohome" starts with "go"
31
- expect(matchesExactTokens(['go'], ['GoHome', '/gohome', 'Navigate home'])).toBe(true)
32
- // "pad" should match "padel"
33
- expect(matchesExactTokens(['pad'], ['Padel', '/padel', 'Tennis-like sport'])).toBe(true)
34
- // "xyz" should not match anything
35
- expect(matchesExactTokens(['xyz'], ['GoHome', '/gohome', 'Navigate home'])).toBe(false)
36
- })
37
-
38
- it('matchesExactTokens ignores empty inputs', () => {
39
- expect(matchesExactTokens([], ['text'])).toBe(false)
40
- expect(matchesExactTokens(['token'], [' ', null, undefined])).toBe(false)
41
- })
42
-
43
- it('normalize uses lowercase', () => {
44
- expect(__test.normalize('AbC')).toBe('abc')
45
- })
46
- })
@@ -1,27 +0,0 @@
1
- const WORD_RE = /[a-z0-9]+/g
2
-
3
- function normalize(value: string) {
4
- return value.toLowerCase()
5
- }
6
-
7
- export function tokenize(value: string): string[] {
8
- if (!value) return []
9
- return normalize(value).match(WORD_RE) ?? []
10
- }
11
-
12
- export function matchesExactTokens(
13
- queryTokens: string[],
14
- parts: Array<string | null | undefined>,
15
- ): boolean {
16
- if (queryTokens.length === 0) return false
17
- const text = parts.filter((part) => Boolean(part?.trim())).join(' ')
18
- if (!text) return false
19
- const textTokens = tokenize(text)
20
- if (textTokens.length === 0) return false
21
- // Require at least one token to prefix-match, allowing vector similarity to determine relevance
22
- return queryTokens.some((queryToken) =>
23
- textTokens.some((textToken) => textToken.includes(queryToken)),
24
- )
25
- }
26
-
27
- export const __test = { normalize, tokenize, matchesExactTokens }
@@ -1,34 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { buildSkillSummaryBackfillPatch } from './skillBackfill'
3
-
4
- describe('skill backfill', () => {
5
- it('produces summary + parsed patch from block scalar', () => {
6
- const patch = buildSkillSummaryBackfillPatch({
7
- readmeText: `---\ndescription: >\n Hello\n world.\n---\nBody`,
8
- currentSummary: '>',
9
- currentParsed: { frontmatter: { description: '>' } },
10
- })
11
- expect(patch.summary).toBe('Hello world.')
12
- expect(patch.parsed?.frontmatter.description).toBe('Hello world.')
13
- })
14
-
15
- it('does not set summary when description is not a string', () => {
16
- const patch = buildSkillSummaryBackfillPatch({
17
- readmeText: `---\ndescription:\n - a\n---\nBody`,
18
- currentSummary: 'Old',
19
- currentParsed: { frontmatter: {} },
20
- })
21
- expect(patch.summary).toBeUndefined()
22
- expect(patch.parsed?.frontmatter.description).toEqual(['a'])
23
- })
24
-
25
- it('keeps legacy summary when unchanged and still updates parsed', () => {
26
- const patch = buildSkillSummaryBackfillPatch({
27
- readmeText: `---\ndescription: Hello\n---\nBody`,
28
- currentSummary: 'Hello',
29
- currentParsed: { frontmatter: { description: 'nope' } },
30
- })
31
- expect(patch.summary).toBeUndefined()
32
- expect(patch.parsed?.frontmatter.description).toBe('Hello')
33
- })
34
- })
@@ -1,67 +0,0 @@
1
- import {
2
- getFrontmatterMetadata,
3
- getFrontmatterValue,
4
- type ParsedSkillFrontmatter,
5
- parseFrontmatter,
6
- parsePilotbotMetadata,
7
- } from './skills'
8
-
9
- export type ParsedSkillData = {
10
- frontmatter: ParsedSkillFrontmatter
11
- metadata?: unknown
12
- pilotbot?: unknown
13
- }
14
-
15
- export type SkillSummaryBackfillPatch = {
16
- summary?: string
17
- parsed?: ParsedSkillData
18
- }
19
-
20
- export function buildSkillSummaryBackfillPatch(args: {
21
- readmeText: string
22
- currentSummary?: string
23
- currentParsed?: ParsedSkillData
24
- }): SkillSummaryBackfillPatch {
25
- const frontmatter = parseFrontmatter(args.readmeText)
26
- const summary = getFrontmatterValue(frontmatter, 'description') ?? undefined
27
- const metadata = getFrontmatterMetadata(frontmatter)
28
- const pilotbot = parsePilotbotMetadata(frontmatter)
29
- const parsed: ParsedSkillData = { frontmatter, metadata, pilotbot }
30
-
31
- const patch: SkillSummaryBackfillPatch = {}
32
- if (summary && summary !== args.currentSummary) {
33
- patch.summary = summary
34
- }
35
- if (!deepEqual(parsed, args.currentParsed)) {
36
- patch.parsed = parsed
37
- }
38
- return patch
39
- }
40
-
41
- function deepEqual(a: unknown, b: unknown): boolean {
42
- if (a === b) return true
43
- if (!a || !b) return a === b
44
- if (typeof a !== typeof b) return false
45
- if (Array.isArray(a) || Array.isArray(b)) {
46
- if (!Array.isArray(a) || !Array.isArray(b)) return false
47
- if (a.length !== b.length) return false
48
- for (let i = 0; i < a.length; i++) {
49
- if (!deepEqual(a[i], b[i])) return false
50
- }
51
- return true
52
- }
53
- if (typeof a === 'object' && typeof b === 'object') {
54
- const aObj = a as Record<string, unknown>
55
- const bObj = b as Record<string, unknown>
56
- const aKeys = Object.keys(aObj).sort()
57
- const bKeys = Object.keys(bObj).sort()
58
- if (aKeys.length !== bKeys.length) return false
59
- for (let i = 0; i < aKeys.length; i++) {
60
- if (aKeys[i] !== bKeys[i]) return false
61
- const key = aKeys[i] as string
62
- if (!deepEqual(aObj[key], bObj[key])) return false
63
- }
64
- return true
65
- }
66
- return false
67
- }
@@ -1,28 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { __test } from './skillPublish'
3
-
4
- describe('skillPublish', () => {
5
- it('merges github source into metadata', () => {
6
- const merged = __test.mergeSourceIntoMetadata(
7
- { pilotbot: { emoji: 'x' } },
8
- {
9
- kind: 'github',
10
- url: 'https://github.com/a/b',
11
- repo: 'a/b',
12
- ref: 'main',
13
- commit: '0123456789012345678901234567890123456789',
14
- path: 'skills/demo',
15
- importedAt: 123,
16
- },
17
- )
18
- expect((merged as Record<string, unknown>).pilotbot).toEqual({ emoji: 'x' })
19
- const source = (merged as Record<string, unknown>).source
20
- expect(source).toEqual(
21
- expect.objectContaining({
22
- kind: 'github',
23
- repo: 'a/b',
24
- path: 'skills/demo',
25
- }),
26
- )
27
- })
28
- })
@@ -1,284 +0,0 @@
1
- import { ConvexError } from 'convex/values'
2
- import semver from 'semver'
3
- import { api, internal } from '../_generated/api'
4
- import type { Doc, Id } from '../_generated/dataModel'
5
- import type { ActionCtx, MutationCtx } from '../_generated/server'
6
- import { getSkillBadgeMap, isSkillHighlighted } from './badges'
7
- import { generateChangelogForPublish } from './changelog'
8
- import { generateEmbedding } from './embeddings'
9
- import type { PublicUser } from './public'
10
- import {
11
- buildEmbeddingText,
12
- getFrontmatterMetadata,
13
- hashSkillFiles,
14
- isTextFile,
15
- parseFrontmatter,
16
- parsePilotbotMetadata,
17
- sanitizePath,
18
- } from './skills'
19
- import type { WebhookSkillPayload } from './webhooks'
20
-
21
- const MAX_TOTAL_BYTES = 50 * 1024 * 1024
22
- const MAX_FILES_FOR_EMBEDDING = 40
23
-
24
- export type PublishResult = {
25
- skillId: Id<'skills'>
26
- versionId: Id<'skillVersions'>
27
- embeddingId: Id<'skillEmbeddings'>
28
- }
29
-
30
- export type PublishVersionArgs = {
31
- slug: string
32
- displayName: string
33
- version: string
34
- changelog: string
35
- tags?: string[]
36
- forkOf?: { slug: string; version?: string }
37
- source?: {
38
- kind: 'github'
39
- url: string
40
- repo: string
41
- ref: string
42
- commit: string
43
- path: string
44
- importedAt: number
45
- }
46
- files: Array<{
47
- path: string
48
- size: number
49
- storageId: Id<'_storage'>
50
- sha256: string
51
- contentType?: string
52
- }>
53
- }
54
-
55
- export async function publishVersionForUser(
56
- ctx: ActionCtx,
57
- userId: Id<'users'>,
58
- args: PublishVersionArgs,
59
- ): Promise<PublishResult> {
60
- const version = args.version.trim()
61
- const slug = args.slug.trim().toLowerCase()
62
- const displayName = args.displayName.trim()
63
- if (!slug || !displayName) throw new ConvexError('Slug and display name required')
64
- if (!/^[a-z0-9][a-z0-9-]*$/.test(slug)) {
65
- throw new ConvexError('Slug must be lowercase and url-safe')
66
- }
67
- if (!semver.valid(version)) {
68
- throw new ConvexError('Version must be valid semver')
69
- }
70
- const suppliedChangelog = args.changelog.trim()
71
- const changelogSource = suppliedChangelog ? ('user' as const) : ('auto' as const)
72
-
73
- const sanitizedFiles = args.files.map((file) => ({
74
- ...file,
75
- path: sanitizePath(file.path),
76
- }))
77
- if (sanitizedFiles.some((file) => !file.path)) {
78
- throw new ConvexError('Invalid file paths')
79
- }
80
- const safeFiles = sanitizedFiles.map((file) => ({
81
- ...file,
82
- path: file.path as string,
83
- }))
84
- if (safeFiles.some((file) => !isTextFile(file.path, file.contentType ?? undefined))) {
85
- throw new ConvexError('Only text-based files are allowed')
86
- }
87
-
88
- const totalBytes = safeFiles.reduce((sum, file) => sum + file.size, 0)
89
- if (totalBytes > MAX_TOTAL_BYTES) {
90
- throw new ConvexError('Skill bundle exceeds 50MB limit')
91
- }
92
-
93
- const readmeFile = safeFiles.find(
94
- (file) => file.path?.toLowerCase() === 'skill.md' || file.path?.toLowerCase() === 'skills.md',
95
- )
96
- if (!readmeFile) throw new ConvexError('SKILL.md is required')
97
-
98
- const readmeText = await fetchText(ctx, readmeFile.storageId)
99
- const frontmatter = parseFrontmatter(readmeText)
100
- const pilotbot = parsePilotbotMetadata(frontmatter)
101
- const metadata = mergeSourceIntoMetadata(getFrontmatterMetadata(frontmatter), args.source)
102
-
103
- const otherFiles = [] as Array<{ path: string; content: string }>
104
- for (const file of safeFiles) {
105
- if (!file.path || file.path.toLowerCase().endsWith('.md')) continue
106
- if (!isTextFile(file.path, file.contentType ?? undefined)) continue
107
- const content = await fetchText(ctx, file.storageId)
108
- otherFiles.push({ path: file.path, content })
109
- if (otherFiles.length >= MAX_FILES_FOR_EMBEDDING) break
110
- }
111
-
112
- const embeddingText = buildEmbeddingText({
113
- frontmatter,
114
- readme: readmeText,
115
- otherFiles,
116
- })
117
-
118
- const fingerprintPromise = hashSkillFiles(
119
- safeFiles.map((file) => ({ path: file.path, sha256: file.sha256 })),
120
- )
121
-
122
- const changelogPromise =
123
- changelogSource === 'user'
124
- ? Promise.resolve(suppliedChangelog)
125
- : generateChangelogForPublish(ctx, {
126
- slug,
127
- version,
128
- readmeText,
129
- files: safeFiles.map((file) => ({ path: file.path, sha256: file.sha256 })),
130
- })
131
-
132
- const embeddingPromise = generateEmbedding(embeddingText)
133
-
134
- const [fingerprint, changelogText, embedding] = await Promise.all([
135
- fingerprintPromise,
136
- changelogPromise,
137
- embeddingPromise.catch((error) => {
138
- throw new ConvexError(formatEmbeddingError(error))
139
- }),
140
- ])
141
-
142
- const publishResult = (await ctx.runMutation(internal.skills.insertVersion, {
143
- userId,
144
- slug,
145
- displayName,
146
- version,
147
- changelog: changelogText,
148
- changelogSource,
149
- tags: args.tags?.map((tag) => tag.trim()).filter(Boolean),
150
- fingerprint,
151
- forkOf: args.forkOf
152
- ? {
153
- slug: args.forkOf.slug.trim().toLowerCase(),
154
- version: args.forkOf.version?.trim() || undefined,
155
- }
156
- : undefined,
157
- files: safeFiles.map((file) => ({
158
- ...file,
159
- path: file.path,
160
- })),
161
- parsed: {
162
- frontmatter,
163
- metadata,
164
- pilotbot,
165
- },
166
- embedding,
167
- })) as PublishResult
168
-
169
- const owner = (await ctx.runQuery(internal.users.getByIdInternal, {
170
- userId,
171
- })) as Doc<'users'> | null
172
- const ownerHandle = owner?.handle ?? owner?.displayName ?? owner?.name ?? 'unknown'
173
-
174
- void ctx.scheduler
175
- .runAfter(0, internal.githubBackupsNode.backupSkillForPublishInternal, {
176
- slug,
177
- version,
178
- displayName,
179
- ownerHandle,
180
- files: safeFiles,
181
- publishedAt: Date.now(),
182
- })
183
- .catch((error) => {
184
- console.error('GitHub backup scheduling failed', error)
185
- })
186
-
187
- void schedulePublishWebhook(ctx, {
188
- slug,
189
- version,
190
- displayName,
191
- })
192
-
193
- return publishResult
194
- }
195
-
196
- function mergeSourceIntoMetadata(metadata: unknown, source: PublishVersionArgs['source']) {
197
- if (!source) return metadata === undefined ? undefined : metadata
198
- const sourceValue = {
199
- kind: source.kind,
200
- url: source.url,
201
- repo: source.repo,
202
- ref: source.ref,
203
- commit: source.commit,
204
- path: source.path,
205
- importedAt: source.importedAt,
206
- }
207
-
208
- if (!metadata) return { source: sourceValue }
209
- if (typeof metadata !== 'object' || Array.isArray(metadata)) return { source: sourceValue }
210
- return { ...(metadata as Record<string, unknown>), source: sourceValue }
211
- }
212
-
213
- export const __test = {
214
- mergeSourceIntoMetadata,
215
- }
216
-
217
- export async function queueHighlightedWebhook(ctx: MutationCtx, skillId: Id<'skills'>) {
218
- const skill = await ctx.db.get(skillId)
219
- if (!skill) return
220
- const owner = await ctx.db.get(skill.ownerUserId)
221
- const latestVersion = skill.latestVersionId ? await ctx.db.get(skill.latestVersionId) : null
222
-
223
- const badges = await getSkillBadgeMap(ctx, skillId)
224
- const payload: WebhookSkillPayload = {
225
- slug: skill.slug,
226
- displayName: skill.displayName,
227
- summary: skill.summary ?? undefined,
228
- version: latestVersion?.version ?? undefined,
229
- ownerHandle: owner?.handle ?? owner?.name ?? undefined,
230
- highlighted: isSkillHighlighted({ badges }),
231
- tags: Object.keys(skill.tags ?? {}),
232
- }
233
-
234
- await ctx.scheduler.runAfter(0, internal.webhooks.sendDiscordWebhook, {
235
- event: 'skill.highlighted',
236
- skill: payload,
237
- })
238
- }
239
-
240
- export async function fetchText(
241
- ctx: { storage: { get: (id: Id<'_storage'>) => Promise<Blob | null> } },
242
- storageId: Id<'_storage'>,
243
- ) {
244
- const blob = await ctx.storage.get(storageId)
245
- if (!blob) throw new Error('File missing in storage')
246
- return blob.text()
247
- }
248
-
249
- function formatEmbeddingError(error: unknown) {
250
- if (error instanceof Error) {
251
- if (error.message.includes('OPENAI_API_KEY')) {
252
- return 'OPENAI_API_KEY is not configured.'
253
- }
254
- if (error.message.startsWith('Embedding failed')) {
255
- return error.message
256
- }
257
- }
258
- return 'Embedding failed. Please try again.'
259
- }
260
-
261
- async function schedulePublishWebhook(
262
- ctx: ActionCtx,
263
- params: { slug: string; version: string; displayName: string },
264
- ) {
265
- const result = (await ctx.runQuery(api.skills.getBySlug, {
266
- slug: params.slug,
267
- })) as { skill: Doc<'skills'>; owner: PublicUser | null } | null
268
- if (!result?.skill) return
269
-
270
- const payload: WebhookSkillPayload = {
271
- slug: result.skill.slug,
272
- displayName: result.skill.displayName || params.displayName,
273
- summary: result.skill.summary ?? undefined,
274
- version: params.version,
275
- ownerHandle: result.owner?.handle ?? result.owner?.name ?? undefined,
276
- highlighted: isSkillHighlighted(result.skill),
277
- tags: Object.keys(result.skill.tags ?? {}),
278
- }
279
-
280
- await ctx.scheduler.runAfter(0, internal.webhooks.sendDiscordWebhook, {
281
- event: 'skill.publish',
282
- skill: payload,
283
- })
284
- }
@@ -1,80 +0,0 @@
1
- import type { Doc, Id } from '../_generated/dataModel'
2
- import type { MutationCtx } from '../_generated/server'
3
- import { toDayKey } from './leaderboards'
4
-
5
- type SkillStatDeltas = {
6
- downloads?: number
7
- stars?: number
8
- installsCurrent?: number
9
- installsAllTime?: number
10
- }
11
-
12
- export function applySkillStatDeltas(skill: Doc<'skills'>, deltas: SkillStatDeltas) {
13
- const currentDownloads =
14
- typeof skill.statsDownloads === 'number' ? skill.statsDownloads : skill.stats.downloads
15
- const currentStars = typeof skill.statsStars === 'number' ? skill.statsStars : skill.stats.stars
16
- const currentInstallsCurrent =
17
- typeof skill.statsInstallsCurrent === 'number'
18
- ? skill.statsInstallsCurrent
19
- : (skill.stats.installsCurrent ?? 0)
20
- const currentInstallsAllTime =
21
- typeof skill.statsInstallsAllTime === 'number'
22
- ? skill.statsInstallsAllTime
23
- : (skill.stats.installsAllTime ?? 0)
24
-
25
- const nextDownloads = Math.max(0, currentDownloads + (deltas.downloads ?? 0))
26
- const nextStars = Math.max(0, currentStars + (deltas.stars ?? 0))
27
- const nextInstallsCurrent = Math.max(0, currentInstallsCurrent + (deltas.installsCurrent ?? 0))
28
- const nextInstallsAllTime = Math.max(0, currentInstallsAllTime + (deltas.installsAllTime ?? 0))
29
-
30
- return {
31
- statsDownloads: nextDownloads,
32
- statsStars: nextStars,
33
- statsInstallsCurrent: nextInstallsCurrent,
34
- statsInstallsAllTime: nextInstallsAllTime,
35
- stats: {
36
- ...skill.stats,
37
- downloads: nextDownloads,
38
- stars: nextStars,
39
- installsCurrent: nextInstallsCurrent,
40
- installsAllTime: nextInstallsAllTime,
41
- },
42
- }
43
- }
44
-
45
- export async function bumpDailySkillStats(
46
- ctx: MutationCtx,
47
- params: {
48
- skillId: Id<'skills'>
49
- now: number
50
- downloads?: number
51
- installs?: number
52
- },
53
- ) {
54
- const downloads = params.downloads ?? 0
55
- const installs = params.installs ?? 0
56
- if (downloads === 0 && installs === 0) return
57
-
58
- const day = toDayKey(params.now)
59
- const existing = await ctx.db
60
- .query('skillDailyStats')
61
- .withIndex('by_skill_day', (q) => q.eq('skillId', params.skillId).eq('day', day))
62
- .unique()
63
-
64
- if (existing) {
65
- await ctx.db.patch(existing._id, {
66
- downloads: Math.max(0, existing.downloads + downloads),
67
- installs: Math.max(0, existing.installs + installs),
68
- updatedAt: params.now,
69
- })
70
- return
71
- }
72
-
73
- await ctx.db.insert('skillDailyStats', {
74
- skillId: params.skillId,
75
- day,
76
- downloads: Math.max(0, downloads),
77
- installs: Math.max(0, installs),
78
- updatedAt: params.now,
79
- })
80
- }