diff --git a/convex/devSeed.ts b/convex/devSeed.ts index 1919052706..c3446c2ac8 100644 --- a/convex/devSeed.ts +++ b/convex/devSeed.ts @@ -3,7 +3,7 @@ import { internal } from './_generated/api' import type { ActionCtx } from './_generated/server' import { internalAction, internalMutation } from './_generated/server' import { EMBEDDING_DIMENSIONS } from './lib/embeddings' -import { parseMoltbotMetadata, parseFrontmatter } from './lib/skills' +import { parseFrontmatter, parseMoltbotMetadata } from './lib/skills' type SeedSkillSpec = { slug: string diff --git a/convex/devSeedExtra.ts b/convex/devSeedExtra.ts index d33eb6e86f..4f202abed0 100644 --- a/convex/devSeedExtra.ts +++ b/convex/devSeedExtra.ts @@ -11,7 +11,7 @@ import { internal } from './_generated/api' import type { Id } from './_generated/dataModel' import type { ActionCtx } from './_generated/server' import { internalAction, internalMutation } from './_generated/server' -import { parseMoltbotMetadata, parseFrontmatter } from './lib/skills' +import { parseFrontmatter, parseMoltbotMetadata } from './lib/skills' type SeedSkillSpec = { slug: string diff --git a/convex/http.ts b/convex/http.ts index d09ba078db..3a27c2a790 100644 --- a/convex/http.ts +++ b/convex/http.ts @@ -1,5 +1,5 @@ -import { ApiRoutes, LegacyApiRoutes } from 'molthub-schema' import { httpRouter } from 'convex/server' +import { ApiRoutes, LegacyApiRoutes } from 'molthub-schema' import { auth } from './auth' import { downloadZip } from './downloads' import { diff --git a/convex/lib/badges.ts b/convex/lib/badges.ts index 2d1c4eb235..37a899f81a 100644 --- a/convex/lib/badges.ts +++ b/convex/lib/badges.ts @@ -3,9 +3,7 @@ import type { QueryCtx } from '../_generated/server' type BadgeKind = Doc<'skillBadges'>['kind'] -export type SkillBadgeMap = Partial< - Record; at: number }> -> +export type SkillBadgeMap = Partial; at: number }>> export type SkillBadgeSource = { badges?: SkillBadgeMap | null } diff --git a/convex/lib/githubImport.ts b/convex/lib/githubImport.ts index 9d71256462..5282e74869 100644 --- a/convex/lib/githubImport.ts +++ b/convex/lib/githubImport.ts @@ -1,5 +1,5 @@ -import { TEXT_FILE_EXTENSION_SET } from 'molthub-schema' import { zipSync } from 'fflate' +import { TEXT_FILE_EXTENSION_SET } from 'molthub-schema' import semver from 'semver' import { parseFrontmatter } from './skills' diff --git a/convex/lib/skillBackfill.ts b/convex/lib/skillBackfill.ts index 99ab322dee..c911a4ba83 100644 --- a/convex/lib/skillBackfill.ts +++ b/convex/lib/skillBackfill.ts @@ -2,8 +2,8 @@ import { getFrontmatterMetadata, getFrontmatterValue, type ParsedSkillFrontmatter, - parseMoltbotMetadata, parseFrontmatter, + parseMoltbotMetadata, } from './skills' export type ParsedSkillData = { diff --git a/convex/lib/skillPublish.ts b/convex/lib/skillPublish.ts index 80fc388f91..de744ec4ad 100644 --- a/convex/lib/skillPublish.ts +++ b/convex/lib/skillPublish.ts @@ -3,17 +3,17 @@ import semver from 'semver' import { api, internal } from '../_generated/api' import type { Doc, Id } from '../_generated/dataModel' import type { ActionCtx, MutationCtx } from '../_generated/server' +import { getSkillBadgeMap, isSkillHighlighted } from './badges' import { generateChangelogForPublish } from './changelog' import { generateEmbedding } from './embeddings' -import { getSkillBadgeMap, isSkillHighlighted } from './badges' import type { PublicUser } from './public' import { buildEmbeddingText, getFrontmatterMetadata, hashSkillFiles, isTextFile, - parseMoltbotMetadata, parseFrontmatter, + parseMoltbotMetadata, sanitizePath, } from './skills' import type { WebhookSkillPayload } from './webhooks' @@ -166,9 +166,9 @@ export async function publishVersionForUser( embedding, })) as PublishResult - const owner = (await ctx.runQuery(internal.users.getByIdInternal, { userId })) as - | Doc<'users'> - | null + const owner = (await ctx.runQuery(internal.users.getByIdInternal, { + userId, + })) as Doc<'users'> | null const ownerHandle = owner?.handle ?? owner?.displayName ?? owner?.name ?? 'unknown' void ctx.scheduler diff --git a/convex/lib/skills.test.ts b/convex/lib/skills.test.ts index 3d99947544..f8254f4226 100644 --- a/convex/lib/skills.test.ts +++ b/convex/lib/skills.test.ts @@ -5,8 +5,8 @@ import { getFrontmatterValue, hashSkillFiles, isTextFile, - parseMoltbotMetadata, parseFrontmatter, + parseMoltbotMetadata, sanitizePath, } from './skills' diff --git a/convex/lib/skills.ts b/convex/lib/skills.ts index 55b9336f56..2dfe60cdc8 100644 --- a/convex/lib/skills.ts +++ b/convex/lib/skills.ts @@ -1,8 +1,8 @@ import { + isTextContentType, type MoltbotConfigSpec, type MoltbotSkillMetadata, MoltbotSkillMetadataSchema, - isTextContentType, type NixPluginSpec, parseArk, type SkillInstallSpec, diff --git a/convex/lib/soulPublish.ts b/convex/lib/soulPublish.ts index ecf146aa1e..a6150f94ff 100644 --- a/convex/lib/soulPublish.ts +++ b/convex/lib/soulPublish.ts @@ -171,9 +171,9 @@ export async function publishSoulVersionForUser( embedding, })) as PublishResult - const owner = (await ctx.runQuery(internal.users.getByIdInternal, { userId })) as - | Doc<'users'> - | null + const owner = (await ctx.runQuery(internal.users.getByIdInternal, { + userId, + })) as Doc<'users'> | null const ownerHandle = owner?.handle ?? owner?.name ?? userId void ctx.scheduler diff --git a/convex/maintenance.ts b/convex/maintenance.ts index 7bc4227a6b..7f048c5cbb 100644 --- a/convex/maintenance.ts +++ b/convex/maintenance.ts @@ -672,9 +672,10 @@ export const backfillSkillBadges: ReturnType = action({ handler: async (ctx, args): Promise => { const { user } = await requireUserFromAction(ctx) assertRole(user, ['admin']) - return ctx.runAction(internal.maintenance.backfillSkillBadgesInternal, args) as Promise< - BadgeBackfillActionResult - > + return ctx.runAction( + internal.maintenance.backfillSkillBadgesInternal, + args, + ) as Promise }, }) @@ -771,15 +772,12 @@ export async function backfillSkillBadgeTableInternalHandler( if (dryRun) continue for (const entry of entries) { - const result = await ctx.runMutation( - internal.maintenance.upsertSkillBadgeRecordInternal, - { - skillId: item.skillId, - kind: entry.kind, - byUserId: entry.byUserId, - at: entry.at, - }, - ) + const result = await ctx.runMutation(internal.maintenance.upsertSkillBadgeRecordInternal, { + skillId: item.skillId, + kind: entry.kind, + byUserId: entry.byUserId, + at: entry.at, + }) if (result.inserted) { totals.recordsInserted++ } @@ -814,9 +812,10 @@ export const backfillSkillBadgeTable: ReturnType = action({ handler: async (ctx, args): Promise => { const { user } = await requireUserFromAction(ctx) assertRole(user, ['admin']) - return ctx.runAction(internal.maintenance.backfillSkillBadgeTableInternal, args) as Promise< - SkillBadgeTableBackfillActionResult - > + return ctx.runAction( + internal.maintenance.backfillSkillBadgeTableInternal, + args, + ) as Promise }, }) diff --git a/convex/search.ts b/convex/search.ts index 3ce5148fac..37fbf7e195 100644 --- a/convex/search.ts +++ b/convex/search.ts @@ -2,10 +2,10 @@ import { v } from 'convex/values' import { internal } from './_generated/api' import type { Doc, Id } from './_generated/dataModel' import { action, internalQuery } from './_generated/server' -import { generateEmbedding } from './lib/embeddings' import { getSkillBadgeMaps, isSkillHighlighted, type SkillBadgeMap } from './lib/badges' -import { matchesExactTokens, tokenize } from './lib/searchText' +import { generateEmbedding } from './lib/embeddings' import { toPublicSkill, toPublicSoul } from './lib/public' +import { matchesExactTokens, tokenize } from './lib/searchText' type HydratedEntry = { embeddingId: Id<'skillEmbeddings'> @@ -79,7 +79,11 @@ export const searchSkills: ReturnType = action({ : hydratedWithBadges exactMatches = filtered.filter((entry) => - matchesExactTokens(queryTokens, [entry.skill.displayName, entry.skill.slug, entry.skill.summary]), + matchesExactTokens(queryTokens, [ + entry.skill.displayName, + entry.skill.slug, + entry.skill.summary, + ]), ) if (exactMatches.length >= limit || results.length < candidateLimit) { @@ -185,7 +189,11 @@ export const searchSouls: ReturnType = action({ ) exactMatches = hydrated.filter((entry) => - matchesExactTokens(queryTokens, [entry.soul.displayName, entry.soul.slug, entry.soul.summary]), + matchesExactTokens(queryTokens, [ + entry.soul.displayName, + entry.soul.slug, + entry.soul.summary, + ]), ) if (exactMatches.length >= limit || results.length < candidateLimit) { diff --git a/convex/skills.ts b/convex/skills.ts index 90c4397100..486f5d09f0 100644 --- a/convex/skills.ts +++ b/convex/skills.ts @@ -6,11 +6,11 @@ import type { Doc, Id } from './_generated/dataModel' import type { MutationCtx, QueryCtx } from './_generated/server' import { action, internalMutation, internalQuery, mutation, query } from './_generated/server' import { assertAdmin, assertModerator, requireUser, requireUserFromAction } from './lib/access' -import { toPublicSkill, toPublicUser } from './lib/public' import { getSkillBadgeMap, getSkillBadgeMaps, isSkillHighlighted } from './lib/badges' import { generateChangelogPreview as buildChangelogPreview } from './lib/changelog' import { buildTrendingLeaderboard } from './lib/leaderboards' import { deriveModerationFlags } from './lib/moderation' +import { toPublicSkill, toPublicUser } from './lib/public' import { fetchText, type PublishResult, @@ -321,8 +321,7 @@ export const listWithLatest = query({ const ordered = args.batch === 'highlighted' ? [...withBadges].sort( - (a, b) => - (b.badges?.highlighted?.at ?? 0) - (a.badges?.highlighted?.at ?? 0), + (a, b) => (b.badges?.highlighted?.at ?? 0) - (a.badges?.highlighted?.at ?? 0), ) : withBadges const limited = ordered.slice(0, limit) @@ -332,10 +331,14 @@ export const listWithLatest = query({ latestVersion: skill.latestVersionId ? await ctx.db.get(skill.latestVersionId) : null, })), ) - return items.filter((item): item is { - skill: NonNullable> - latestVersion: Doc<'skillVersions'> | null - } => Boolean(item.skill)) + return items.filter( + ( + item, + ): item is { + skill: NonNullable> + latestVersion: Doc<'skillVersions'> | null + } => Boolean(item.skill), + ) }, }) @@ -350,8 +353,9 @@ export const listForManagement = query({ const limit = clampInt(args.limit ?? 50, 1, MAX_LIST_BULK_LIMIT) const takeLimit = Math.min(limit * 5, MAX_LIST_TAKE) const entries = await ctx.db.query('skills').order('desc').take(takeLimit) - const filtered = (args.includeDeleted ? entries : entries.filter((skill) => !skill.softDeletedAt)) - .slice(0, limit) + const filtered = ( + args.includeDeleted ? entries : entries.filter((skill) => !skill.softDeletedAt) + ).slice(0, limit) return buildManagementSkillEntries(ctx, filtered) }, }) @@ -362,7 +366,10 @@ export const listRecentVersions = query({ const { user } = await requireUser(ctx) assertModerator(user) const limit = clampInt(args.limit ?? 20, 1, MAX_LIST_BULK_LIMIT) - const versions = await ctx.db.query('skillVersions').order('desc').take(limit * 2) + const versions = await ctx.db + .query('skillVersions') + .order('desc') + .take(limit * 2) const entries = versions.filter((version) => !version.softDeletedAt).slice(0, limit) const results: Array<{ diff --git a/convex/souls.ts b/convex/souls.ts index e306f9f7b1..e0e3ebdd75 100644 --- a/convex/souls.ts +++ b/convex/souls.ts @@ -93,7 +93,10 @@ export const listPublicPage = query({ .order('desc') .paginate({ cursor: args.cursor ?? null, numItems: limit }) - const items: Array<{ soul: NonNullable>; latestVersion: Doc<'soulVersions'> | null }> = [] + const items: Array<{ + soul: NonNullable> + latestVersion: Doc<'soulVersions'> | null + }> = [] for (const soul of page) { if (soul.softDeletedAt) continue diff --git a/e2e/molthub.e2e.test.ts b/e2e/molthub.e2e.test.ts index dd2db59551..4a111df497 100644 --- a/e2e/molthub.e2e.test.ts +++ b/e2e/molthub.e2e.test.ts @@ -4,13 +4,13 @@ import { spawnSync } from 'node:child_process' import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { unzipSync } from 'fflate' import { ApiRoutes, ApiV1SearchResponseSchema, ApiV1WhoamiResponseSchema, parseArk, } from 'molthub-schema' -import { unzipSync } from 'fflate' import { Agent, setGlobalDispatcher } from 'undici' import { describe, expect, it } from 'vitest' import { readGlobalConfig } from '../packages/molthub/src/config' diff --git a/packages/molthub/src/cli.ts b/packages/molthub/src/cli.ts index 4cbdd42c96..3db7f551a6 100644 --- a/packages/molthub/src/cli.ts +++ b/packages/molthub/src/cli.ts @@ -3,7 +3,6 @@ import { stat } from 'node:fs/promises' import { join, resolve } from 'node:path' import { Command } from 'commander' import { getCliBuildLabel, getCliVersion } from './cli/buildInfo.js' -import { resolveMoltbotDefaultWorkspace } from './cli/moltbotConfig.js' import { cmdLoginFlow, cmdLogout, cmdWhoami } from './cli/commands/auth.js' import { cmdDeleteSkill, cmdUndeleteSkill } from './cli/commands/delete.js' import { cmdPublish } from './cli/commands/publish.js' @@ -12,6 +11,7 @@ import { cmdStarSkill } from './cli/commands/star.js' import { cmdSync } from './cli/commands/sync.js' import { cmdUnstarSkill } from './cli/commands/unstar.js' import { configureCommanderHelp, styleEnvBlock, styleTitle } from './cli/helpStyle.js' +import { resolveMoltbotDefaultWorkspace } from './cli/moltbotConfig.js' import { DEFAULT_REGISTRY, DEFAULT_SITE } from './cli/registry.js' import type { GlobalOpts } from './cli/types.js' import { fail } from './cli/ui.js' diff --git a/src/components/SkillDetailPage.tsx b/src/components/SkillDetailPage.tsx index 9a6cfd30b3..7d89b37217 100644 --- a/src/components/SkillDetailPage.tsx +++ b/src/components/SkillDetailPage.tsx @@ -1,6 +1,6 @@ import { Link, useNavigate } from '@tanstack/react-router' -import type { MoltbotSkillMetadata, SkillInstallSpec } from 'molthub-schema' import { useAction, useMutation, useQuery } from 'convex/react' +import type { MoltbotSkillMetadata, SkillInstallSpec } from 'molthub-schema' import { useEffect, useMemo, useState } from 'react' import ReactMarkdown from 'react-markdown' import remarkGfm from 'remark-gfm' @@ -650,9 +650,7 @@ export function SkillDetailPage({ @{entry.user?.handle ?? entry.user?.name ?? 'user'}
{entry.comment.body}
- {isAuthenticated && - me && - (me._id === entry.comment.userId || isModerator(me)) ? ( + {isAuthenticated && me && (me._id === entry.comment.userId || isModerator(me)) ? (