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,443 +0,0 @@
1
- 'use node'
2
-
3
- import { createPrivateKey, createSign } from 'node:crypto'
4
- import type { Id } from '../_generated/dataModel'
5
- import type { ActionCtx } from '../_generated/server'
6
-
7
- const GITHUB_API = 'https://api.github.com'
8
- const DEFAULT_REPO = 'pilotbot/souls'
9
- const DEFAULT_ROOT = 'souls'
10
- const META_FILENAME = '_meta.json'
11
- const USER_AGENT = 'pilothub/souls-backup'
12
-
13
- type BackupFile = {
14
- path: string
15
- size: number
16
- storageId: Id<'_storage'>
17
- sha256: string
18
- contentType?: string
19
- }
20
-
21
- type BackupParams = {
22
- slug: string
23
- version: string
24
- displayName: string
25
- ownerHandle: string
26
- files: BackupFile[]
27
- publishedAt: number
28
- }
29
-
30
- type RepoInfo = {
31
- default_branch?: string
32
- }
33
-
34
- type GitRef = {
35
- object: { sha: string }
36
- }
37
-
38
- type GitCommit = {
39
- sha: string
40
- tree: { sha: string }
41
- }
42
-
43
- type GitTreeEntry = {
44
- path?: string
45
- type?: string
46
- }
47
-
48
- type GitTree = {
49
- tree?: GitTreeEntry[]
50
- }
51
-
52
- type MetaFile = {
53
- owner: string
54
- slug: string
55
- displayName: string
56
- latest: {
57
- version: string
58
- publishedAt: number
59
- commit: string | null
60
- }
61
- history: Array<{
62
- version: string
63
- publishedAt: number
64
- commit: string
65
- }>
66
- }
67
-
68
- export type GitHubBackupContext = {
69
- token: string
70
- repo: string
71
- repoOwner: string
72
- repoName: string
73
- branch: string
74
- root: string
75
- }
76
-
77
- export function isGitHubSoulBackupConfigured() {
78
- return Boolean(
79
- process.env.GITHUB_APP_ID &&
80
- process.env.GITHUB_APP_PRIVATE_KEY &&
81
- process.env.GITHUB_APP_INSTALLATION_ID,
82
- )
83
- }
84
-
85
- export async function getGitHubSoulBackupContext(): Promise<GitHubBackupContext> {
86
- const repo = process.env.GITHUB_SOULS_REPO ?? DEFAULT_REPO
87
- const root = process.env.GITHUB_SOULS_ROOT ?? DEFAULT_ROOT
88
- const [repoOwner, repoName] = parseRepo(repo)
89
- const token = await createInstallationToken()
90
- const repoInfo = await githubGet<RepoInfo>(token, `/repos/${repoOwner}/${repoName}`)
91
- const branch = repoInfo.default_branch ?? 'main'
92
-
93
- return { token, repo, repoOwner, repoName, branch, root }
94
- }
95
-
96
- export async function fetchGitHubSoulMeta(
97
- context: GitHubBackupContext,
98
- ownerHandle: string,
99
- slug: string,
100
- ): Promise<MetaFile | null> {
101
- const soulRoot = buildSoulRoot(context.root, ownerHandle, slug)
102
- return fetchMetaFile(
103
- context.token,
104
- context.repoOwner,
105
- context.repoName,
106
- `${soulRoot}/${META_FILENAME}`,
107
- context.branch,
108
- )
109
- }
110
-
111
- export async function backupSoulToGitHub(
112
- ctx: ActionCtx,
113
- params: BackupParams,
114
- context?: GitHubBackupContext,
115
- ) {
116
- if (!isGitHubSoulBackupConfigured()) return
117
-
118
- const resolved = context ?? (await getGitHubSoulBackupContext())
119
- const soulRoot = buildSoulRoot(resolved.root, params.ownerHandle, params.slug)
120
- const ref = await githubGet<GitRef>(
121
- resolved.token,
122
- `/repos/${resolved.repoOwner}/${resolved.repoName}/git/ref/heads/${resolved.branch}`,
123
- )
124
- const baseCommitSha = ref.object.sha
125
- const baseCommit = await githubGet<GitCommit>(
126
- resolved.token,
127
- `/repos/${resolved.repoOwner}/${resolved.repoName}/git/commits/${baseCommitSha}`,
128
- )
129
- const baseTreeSha = baseCommit.tree.sha
130
- const existingTree = await githubGet<GitTree>(
131
- resolved.token,
132
- `/repos/${resolved.repoOwner}/${resolved.repoName}/git/trees/${baseTreeSha}?recursive=1`,
133
- )
134
-
135
- const prefix = `${soulRoot}/`
136
- const existingPaths = new Set(
137
- (existingTree.tree ?? [])
138
- .filter((entry) => entry.type === 'blob' && entry.path?.startsWith(prefix))
139
- .map((entry) => entry.path ?? ''),
140
- )
141
-
142
- const newPaths = new Set<string>()
143
- const treeEntries: Array<{
144
- path: string
145
- mode: '100644'
146
- type: 'blob'
147
- sha: string | null
148
- }> = []
149
-
150
- for (const file of params.files) {
151
- const content = await fetchStorageBase64(ctx, file.storageId)
152
- const blobSha = await createBlob(resolved.token, resolved.repoOwner, resolved.repoName, content)
153
- const path = `${soulRoot}/${file.path}`
154
- newPaths.add(path)
155
- treeEntries.push({ path, mode: '100644', type: 'blob', sha: blobSha })
156
- }
157
-
158
- const existingMeta = await fetchMetaFile(
159
- resolved.token,
160
- resolved.repoOwner,
161
- resolved.repoName,
162
- `${soulRoot}/${META_FILENAME}`,
163
- resolved.branch,
164
- )
165
- const metaPath = `${soulRoot}/${META_FILENAME}`
166
- const metaDraft = buildMetaFile(params, existingMeta, resolved.repo, baseCommitSha, null)
167
- const metaDraftContent = `${JSON.stringify(metaDraft, null, 2)}\n`
168
- const metaDraftSha = await createBlob(
169
- resolved.token,
170
- resolved.repoOwner,
171
- resolved.repoName,
172
- toBase64(metaDraftContent),
173
- )
174
- newPaths.add(metaPath)
175
- treeEntries.push({ path: metaPath, mode: '100644', type: 'blob', sha: metaDraftSha })
176
-
177
- for (const path of existingPaths) {
178
- if (newPaths.has(path)) continue
179
- treeEntries.push({ path, mode: '100644', type: 'blob', sha: null })
180
- }
181
-
182
- const newTree = await githubPost<{ sha: string }>(
183
- resolved.token,
184
- `/repos/${resolved.repoOwner}/${resolved.repoName}/git/trees`,
185
- {
186
- base_tree: baseTreeSha,
187
- tree: treeEntries,
188
- },
189
- )
190
-
191
- const commit = await githubPost<GitCommit>(
192
- resolved.token,
193
- `/repos/${resolved.repoOwner}/${resolved.repoName}/git/commits`,
194
- {
195
- message: `soul: ${params.slug} v${params.version}`,
196
- tree: newTree.sha,
197
- parents: [baseCommitSha],
198
- },
199
- )
200
-
201
- const metaFinal = buildMetaFile(params, existingMeta, resolved.repo, baseCommitSha, commit.sha)
202
- const metaFinalContent = `${JSON.stringify(metaFinal, null, 2)}\n`
203
- const metaFinalSha = await createBlob(
204
- resolved.token,
205
- resolved.repoOwner,
206
- resolved.repoName,
207
- toBase64(metaFinalContent),
208
- )
209
- const metaTree = await githubPost<{ sha: string }>(
210
- resolved.token,
211
- `/repos/${resolved.repoOwner}/${resolved.repoName}/git/trees`,
212
- {
213
- base_tree: commit.tree.sha,
214
- tree: [{ path: metaPath, mode: '100644', type: 'blob', sha: metaFinalSha }],
215
- },
216
- )
217
- const metaCommit = await githubPost<GitCommit>(
218
- resolved.token,
219
- `/repos/${resolved.repoOwner}/${resolved.repoName}/git/commits`,
220
- {
221
- message: `meta: ${params.slug} v${params.version}`,
222
- tree: metaTree.sha,
223
- parents: [commit.sha],
224
- },
225
- )
226
-
227
- await githubPatch(
228
- resolved.token,
229
- `/repos/${resolved.repoOwner}/${resolved.repoName}/git/refs/heads/${resolved.branch}`,
230
- {
231
- sha: metaCommit.sha,
232
- },
233
- )
234
- }
235
-
236
- function buildMetaFile(
237
- params: BackupParams,
238
- existing: MetaFile | null,
239
- repo: string,
240
- baseCommitSha: string,
241
- latestCommitSha: string | null,
242
- ): MetaFile {
243
- let history = [...(existing?.history ?? [])]
244
- if (existing?.latest?.version) {
245
- const previousCommit = existing.latest.commit ?? commitUrl(repo, baseCommitSha)
246
- const previous = {
247
- version: existing.latest.version,
248
- publishedAt: existing.latest.publishedAt,
249
- commit: previousCommit,
250
- }
251
- history = [previous, ...history.filter((entry) => entry.version !== previous.version)]
252
- }
253
-
254
- return {
255
- owner: normalizeOwner(params.ownerHandle),
256
- slug: params.slug,
257
- displayName: params.displayName,
258
- latest: {
259
- version: params.version,
260
- publishedAt: params.publishedAt,
261
- commit: latestCommitSha ? commitUrl(repo, latestCommitSha) : null,
262
- },
263
- history: history.slice(0, 200),
264
- }
265
- }
266
-
267
- async function fetchMetaFile(
268
- token: string,
269
- repoOwner: string,
270
- repoName: string,
271
- path: string,
272
- branch: string,
273
- ): Promise<MetaFile | null> {
274
- try {
275
- const response = await githubGet<{ content?: string }>(
276
- token,
277
- `/repos/${repoOwner}/${repoName}/contents/${encodePath(path)}?ref=${branch}`,
278
- )
279
- if (!response.content) return null
280
- const raw = fromBase64(response.content)
281
- return JSON.parse(raw) as MetaFile
282
- } catch (error) {
283
- if (isNotFoundError(error)) return null
284
- throw error
285
- }
286
- }
287
-
288
- async function fetchStorageBase64(ctx: ActionCtx, storageId: Id<'_storage'>) {
289
- const blob = await ctx.storage.get(storageId)
290
- if (!blob) throw new Error('File missing in storage')
291
- const buffer = Buffer.from(await blob.arrayBuffer())
292
- return buffer.toString('base64')
293
- }
294
-
295
- async function createInstallationToken() {
296
- const appId = process.env.GITHUB_APP_ID
297
- const installationId = process.env.GITHUB_APP_INSTALLATION_ID
298
- if (!appId || !installationId) {
299
- throw new Error('GitHub App credentials missing')
300
- }
301
- const jwt = createAppJwt(appId)
302
- const response = await fetch(`${GITHUB_API}/app/installations/${installationId}/access_tokens`, {
303
- method: 'POST',
304
- headers: buildHeaders(jwt, true),
305
- })
306
- if (!response.ok) {
307
- const message = await response.text()
308
- throw new Error(`GitHub App token failed: ${message}`)
309
- }
310
- const payload = (await response.json()) as { token?: string }
311
- if (!payload.token) throw new Error('GitHub App token missing')
312
- return payload.token
313
- }
314
-
315
- function createAppJwt(appId: string) {
316
- const privateKey = loadPrivateKey()
317
- const now = Math.floor(Date.now() / 1000)
318
- const header = { alg: 'RS256', typ: 'JWT' }
319
- const payload = { iat: now - 60, exp: now + 9 * 60, iss: appId }
320
- const encodedHeader = base64Url(JSON.stringify(header))
321
- const encodedPayload = base64Url(JSON.stringify(payload))
322
- const signingInput = `${encodedHeader}.${encodedPayload}`
323
- const sign = createSign('RSA-SHA256')
324
- sign.update(signingInput)
325
- sign.end()
326
- const signature = sign.sign(privateKey)
327
- return `${signingInput}.${base64Url(signature)}`
328
- }
329
-
330
- function loadPrivateKey() {
331
- const raw = process.env.GITHUB_APP_PRIVATE_KEY
332
- if (!raw) throw new Error('GITHUB_APP_PRIVATE_KEY is not configured')
333
- const normalized = raw.replace(/\\n/g, '\n')
334
- return createPrivateKey(normalized)
335
- }
336
-
337
- async function createBlob(token: string, repoOwner: string, repoName: string, content: string) {
338
- const result = await githubPost<{ sha: string }>(
339
- token,
340
- `/repos/${repoOwner}/${repoName}/git/blobs`,
341
- {
342
- content,
343
- encoding: 'base64',
344
- },
345
- )
346
- if (!result.sha) throw new Error('GitHub blob missing sha')
347
- return result.sha
348
- }
349
-
350
- async function githubGet<T>(token: string, path: string): Promise<T> {
351
- const response = await fetch(`${GITHUB_API}${path}`, {
352
- headers: buildHeaders(token),
353
- })
354
- if (!response.ok) {
355
- const message = await response.text()
356
- throw new Error(`GitHub GET ${path} failed: ${message}`)
357
- }
358
- return (await response.json()) as T
359
- }
360
-
361
- async function githubPost<T>(token: string, path: string, body: unknown): Promise<T> {
362
- const response = await fetch(`${GITHUB_API}${path}`, {
363
- method: 'POST',
364
- headers: buildHeaders(token),
365
- body: JSON.stringify(body),
366
- })
367
- if (!response.ok) {
368
- const message = await response.text()
369
- throw new Error(`GitHub POST ${path} failed: ${message}`)
370
- }
371
- return (await response.json()) as T
372
- }
373
-
374
- async function githubPatch(token: string, path: string, body: unknown) {
375
- const response = await fetch(`${GITHUB_API}${path}`, {
376
- method: 'PATCH',
377
- headers: buildHeaders(token),
378
- body: JSON.stringify(body),
379
- })
380
- if (!response.ok) {
381
- const message = await response.text()
382
- throw new Error(`GitHub PATCH ${path} failed: ${message}`)
383
- }
384
- }
385
-
386
- function buildHeaders(token: string, isAppJwt = false) {
387
- return {
388
- Authorization: `${isAppJwt ? 'Bearer' : 'token'} ${token}`,
389
- Accept: 'application/vnd.github+json',
390
- 'User-Agent': USER_AGENT,
391
- }
392
- }
393
-
394
- function parseRepo(repo: string) {
395
- const [owner, name] = repo.split('/')
396
- if (!owner || !name) throw new Error('GITHUB_SOULS_REPO must be owner/repo')
397
- return [owner, name] as const
398
- }
399
-
400
- function normalizeOwner(value: string) {
401
- const normalized = value
402
- .trim()
403
- .toLowerCase()
404
- .replace(/[^a-z0-9-]/g, '-')
405
- .replace(/-+/g, '-')
406
- .replace(/^-+|-+$/g, '')
407
- return normalized || 'unknown'
408
- }
409
-
410
- function commitUrl(repo: string, sha: string) {
411
- return `https://github.com/${repo}/commit/${sha}`
412
- }
413
-
414
- function buildSoulRoot(root: string, ownerHandle: string, slug: string) {
415
- const ownerSegment = normalizeOwner(ownerHandle)
416
- return `${root}/${ownerSegment}/${slug}`
417
- }
418
-
419
- function encodePath(path: string) {
420
- return path
421
- .split('/')
422
- .map((segment) => encodeURIComponent(segment))
423
- .join('/')
424
- }
425
-
426
- function base64Url(value: string | Buffer) {
427
- const buffer = typeof value === 'string' ? Buffer.from(value) : value
428
- return buffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '')
429
- }
430
-
431
- function toBase64(value: string) {
432
- return Buffer.from(value).toString('base64')
433
- }
434
-
435
- function fromBase64(value: string) {
436
- return Buffer.from(value, 'base64').toString('utf8')
437
- }
438
-
439
- function isNotFoundError(error: unknown) {
440
- return (
441
- error instanceof Error && (error.message.includes('404') || error.message.includes('Not Found'))
442
- )
443
- }
@@ -1,103 +0,0 @@
1
- import type { Id } from '../_generated/dataModel'
2
- import type { MutationCtx, QueryCtx } from '../_generated/server'
3
-
4
- const DAY_MS = 24 * 60 * 60 * 1000
5
- export const TRENDING_DAYS = 7
6
-
7
- type LeaderboardEntry = {
8
- skillId: Id<'skills'>
9
- score: number
10
- installs: number
11
- downloads: number
12
- }
13
-
14
- export function toDayKey(timestamp: number) {
15
- return Math.floor(timestamp / DAY_MS)
16
- }
17
-
18
- export function getTrendingRange(now: number) {
19
- const endDay = toDayKey(now)
20
- const startDay = endDay - (TRENDING_DAYS - 1)
21
- return { startDay, endDay }
22
- }
23
-
24
- export async function buildTrendingLeaderboard(
25
- ctx: QueryCtx | MutationCtx,
26
- params: { limit: number; now?: number },
27
- ) {
28
- const now = params.now ?? Date.now()
29
- const { startDay, endDay } = getTrendingRange(now)
30
- const rows = await ctx.db
31
- .query('skillDailyStats')
32
- .withIndex('by_day', (q) => q.gte('day', startDay).lte('day', endDay))
33
- .collect()
34
-
35
- const totals = new Map<Id<'skills'>, { installs: number; downloads: number }>()
36
- for (const row of rows) {
37
- const current = totals.get(row.skillId) ?? { installs: 0, downloads: 0 }
38
- current.installs += row.installs
39
- current.downloads += row.downloads
40
- totals.set(row.skillId, current)
41
- }
42
-
43
- const entries = Array.from(totals, ([skillId, totalsEntry]) => ({
44
- skillId,
45
- installs: totalsEntry.installs,
46
- downloads: totalsEntry.downloads,
47
- score: totalsEntry.installs,
48
- }))
49
-
50
- const items = topN(entries, params.limit, compareTrendingEntries).sort((a, b) =>
51
- compareTrendingEntries(b, a),
52
- )
53
-
54
- return { startDay, endDay, items }
55
- }
56
-
57
- function compareTrendingEntries(a: LeaderboardEntry, b: LeaderboardEntry) {
58
- if (a.score !== b.score) return a.score - b.score
59
- if (a.downloads !== b.downloads) return a.downloads - b.downloads
60
- return 0
61
- }
62
-
63
- function topN<T>(entries: T[], limit: number, compare: (a: T, b: T) => number) {
64
- if (entries.length <= limit) return entries.slice()
65
-
66
- const heap: T[] = []
67
- for (const entry of entries) {
68
- if (heap.length < limit) {
69
- heap.push(entry)
70
- siftUp(heap, heap.length - 1, compare)
71
- continue
72
- }
73
- if (compare(entry, heap[0]) <= 0) continue
74
- heap[0] = entry
75
- siftDown(heap, 0, compare)
76
- }
77
- return heap
78
- }
79
-
80
- function siftUp<T>(heap: T[], index: number, compare: (a: T, b: T) => number) {
81
- let current = index
82
- while (current > 0) {
83
- const parent = Math.floor((current - 1) / 2)
84
- if (compare(heap[current], heap[parent]) >= 0) break
85
- ;[heap[current], heap[parent]] = [heap[parent], heap[current]]
86
- current = parent
87
- }
88
- }
89
-
90
- function siftDown<T>(heap: T[], index: number, compare: (a: T, b: T) => number) {
91
- let current = index
92
- const length = heap.length
93
- while (true) {
94
- const left = current * 2 + 1
95
- const right = current * 2 + 2
96
- let smallest = current
97
- if (left < length && compare(heap[left], heap[smallest]) < 0) smallest = left
98
- if (right < length && compare(heap[right], heap[smallest]) < 0) smallest = right
99
- if (smallest === current) break
100
- ;[heap[current], heap[smallest]] = [heap[smallest], heap[current]]
101
- current = smallest
102
- }
103
- }
@@ -1,42 +0,0 @@
1
- import type { Doc } from '../_generated/dataModel'
2
-
3
- const FLAG_RULES: Array<{ flag: string; pattern: RegExp }> = [
4
- { flag: 'suspicious.keyword', pattern: /(malware|stealer|phish|phishing|keylogger)/i },
5
- { flag: 'suspicious.secrets', pattern: /(api[-_ ]?key|token|password|private key|secret)/i },
6
- { flag: 'suspicious.crypto', pattern: /(wallet|seed phrase|mnemonic|crypto)/i },
7
- { flag: 'suspicious.webhook', pattern: /(discord\.gg|webhook|hooks\.slack)/i },
8
- { flag: 'suspicious.script', pattern: /(curl[^\n]+\|\s*(sh|bash))/i },
9
- { flag: 'suspicious.url_shortener', pattern: /(bit\.ly|tinyurl\.com|t\.co|goo\.gl|is\.gd)/i },
10
- ]
11
-
12
- export function deriveModerationFlags({
13
- skill,
14
- parsed,
15
- files,
16
- }: {
17
- skill: Pick<Doc<'skills'>, 'slug' | 'displayName' | 'summary'>
18
- parsed: Doc<'skillVersions'>['parsed']
19
- files: Doc<'skillVersions'>['files']
20
- }) {
21
- const text = [
22
- skill.slug,
23
- skill.displayName,
24
- skill.summary ?? '',
25
- JSON.stringify(parsed?.frontmatter ?? {}),
26
- JSON.stringify(parsed?.metadata ?? {}),
27
- JSON.stringify((parsed as { pilotbot?: unknown } | undefined)?.pilotbot ?? {}),
28
- ...files.map((file) => file.path),
29
- ]
30
- .filter(Boolean)
31
- .join('\n')
32
-
33
- const flags = new Set<string>()
34
-
35
- for (const rule of FLAG_RULES) {
36
- if (rule.pattern.test(text)) {
37
- flags.add(rule.flag)
38
- }
39
- }
40
-
41
- return Array.from(flags)
42
- }
@@ -1,89 +0,0 @@
1
- import type { Doc } from '../_generated/dataModel'
2
-
3
- export type PublicUser = Pick<
4
- Doc<'users'>,
5
- '_id' | '_creationTime' | 'handle' | 'name' | 'displayName' | 'image' | 'bio'
6
- >
7
-
8
- export type PublicSkill = Pick<
9
- Doc<'skills'>,
10
- | '_id'
11
- | '_creationTime'
12
- | 'slug'
13
- | 'displayName'
14
- | 'summary'
15
- | 'ownerUserId'
16
- | 'canonicalSkillId'
17
- | 'forkOf'
18
- | 'latestVersionId'
19
- | 'tags'
20
- | 'badges'
21
- | 'stats'
22
- | 'createdAt'
23
- | 'updatedAt'
24
- >
25
-
26
- export type PublicSoul = Pick<
27
- Doc<'souls'>,
28
- | '_id'
29
- | '_creationTime'
30
- | 'slug'
31
- | 'displayName'
32
- | 'summary'
33
- | 'ownerUserId'
34
- | 'latestVersionId'
35
- | 'tags'
36
- | 'stats'
37
- | 'createdAt'
38
- | 'updatedAt'
39
- >
40
-
41
- export function toPublicUser(user: Doc<'users'> | null | undefined): PublicUser | null {
42
- if (!user || user.deletedAt) return null
43
- return {
44
- _id: user._id,
45
- _creationTime: user._creationTime,
46
- handle: user.handle,
47
- name: user.name,
48
- displayName: user.displayName,
49
- image: user.image,
50
- bio: user.bio,
51
- }
52
- }
53
-
54
- export function toPublicSkill(skill: Doc<'skills'> | null | undefined): PublicSkill | null {
55
- if (!skill || skill.softDeletedAt) return null
56
- return {
57
- _id: skill._id,
58
- _creationTime: skill._creationTime,
59
- slug: skill.slug,
60
- displayName: skill.displayName,
61
- summary: skill.summary,
62
- ownerUserId: skill.ownerUserId,
63
- canonicalSkillId: skill.canonicalSkillId,
64
- forkOf: skill.forkOf,
65
- latestVersionId: skill.latestVersionId,
66
- tags: skill.tags,
67
- badges: skill.badges,
68
- stats: skill.stats,
69
- createdAt: skill.createdAt,
70
- updatedAt: skill.updatedAt,
71
- }
72
- }
73
-
74
- export function toPublicSoul(soul: Doc<'souls'> | null | undefined): PublicSoul | null {
75
- if (!soul || soul.softDeletedAt) return null
76
- return {
77
- _id: soul._id,
78
- _creationTime: soul._creationTime,
79
- slug: soul.slug,
80
- displayName: soul.displayName,
81
- summary: soul.summary,
82
- ownerUserId: soul.ownerUserId,
83
- latestVersionId: soul.latestVersionId,
84
- tags: soul.tags,
85
- stats: soul.stats,
86
- createdAt: soul.createdAt,
87
- updatedAt: soul.updatedAt,
88
- }
89
- }