diff --git a/.env.test b/.env.test new file mode 100644 index 0000000..7641cff --- /dev/null +++ b/.env.test @@ -0,0 +1 @@ +OPENAI_API_KEY=sk-mockapikey1234 diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..ef77922 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,39 @@ +name: Build + +on: + push: + branches: [main] + pull_request: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: ~/.bun/install/cache + key: bun-${{ hashFiles('**/bun.lockb') }} + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Run linter + run: bun run lint + + - name: Run tests + run: bun test + + - name: Build project + run: bun run build diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..e569229 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,38 @@ +name: Release + +on: + release: + types: [published] + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Build + run: bun run build + + - name: Publish package + env: + NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + # Extract version from tag (remove 'v' prefix if present) + VERSION=${GITHUB_REF_NAME#v} + + # Update package.json version + bun x json -I -f package.json -e "this.version='$VERSION'" + + # Publish with appropriate tag + if [[ "${{ github.event.release.prerelease }}" == "true" ]]; then + bun publish --access public --tag canary + else + bun publish --access public + fi diff --git a/.gitignore b/.gitignore index 9b1ee42..3f5137a 100644 --- a/.gitignore +++ b/.gitignore @@ -118,7 +118,7 @@ out # Nuxt.js build / generate output .nuxt -dist +dist/ # Gatsby files diff --git a/biome.json b/biome.json index 17bcd95..8aed832 100644 --- a/biome.json +++ b/biome.json @@ -1,34 +1,35 @@ { - "$schema": "https://biomejs.dev/schemas/2.1.1/schema.json", - "vcs": { - "enabled": false, - "clientKind": "git", - "useIgnoreFile": false - }, - "files": { - "ignoreUnknown": false - }, - "formatter": { - "enabled": true, - "indentStyle": "space" - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true - } - }, - "javascript": { - "formatter": { - "quoteStyle": "single" - } - }, - "assist": { - "enabled": true, - "actions": { - "source": { - "organizeImports": "on" - } - } - } + "$schema": "https://biomejs.dev/schemas/2.1.1/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "includes": ["**", "!**/*.test.ts", "!tests", "!dist", "!node_modules"], + "ignoreUnknown": false + }, + "formatter": { + "enabled": true, + "indentStyle": "space" + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "single" + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "on" + } + } + } } diff --git a/migrations/meta/0000_snapshot.json b/migrations/meta/0000_snapshot.json index ea3e199..3b98b55 100644 --- a/migrations/meta/0000_snapshot.json +++ b/migrations/meta/0000_snapshot.json @@ -154,12 +154,8 @@ "name": "snippets_library_libraries_name_fk", "tableFrom": "snippets", "tableTo": "libraries", - "columnsFrom": [ - "library" - ], - "columnsTo": [ - "name" - ], + "columnsFrom": ["library"], + "columnsTo": ["name"], "onDelete": "cascade", "onUpdate": "no action" } @@ -179,4 +175,4 @@ "internal": { "indexes": {} } -} \ No newline at end of file +} diff --git a/migrations/meta/0001_snapshot.json b/migrations/meta/0001_snapshot.json index 1a3c16a..07cbdf8 100644 --- a/migrations/meta/0001_snapshot.json +++ b/migrations/meta/0001_snapshot.json @@ -153,13 +153,9 @@ "snippets_library_libraries_name_fk": { "name": "snippets_library_libraries_name_fk", "tableFrom": "snippets", - "columnsFrom": [ - "library" - ], + "columnsFrom": ["library"], "tableTo": "libraries", - "columnsTo": [ - "name" - ], + "columnsTo": ["name"], "onUpdate": "no action", "onDelete": "cascade" } @@ -179,4 +175,4 @@ "internal": { "indexes": {} } -} \ No newline at end of file +} diff --git a/migrations/meta/_journal.json b/migrations/meta/_journal.json index 61aeb00..68009aa 100644 --- a/migrations/meta/_journal.json +++ b/migrations/meta/_journal.json @@ -17,4 +17,4 @@ "breakpoints": true } ] -} \ No newline at end of file +} diff --git a/package.json b/package.json index a5f0762..a9aa49e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libcontext", - "version": "0.0.1", + "version": "0.0.0", "main": "./dist/index.js", "type": "module", "bin": { @@ -15,6 +15,7 @@ "scripts": { "dev": "bun src/index.ts", "inspect": "fastmcp inspect src/mcp/index.ts", + "lint": "bun biome check", "build": "bun build.ts", "db:push": "drizzle-kit push", "db:generate": "drizzle-kit generate", diff --git a/src/commands/list.ts b/src/commands/list.ts index d04f89c..78d7bbf 100644 --- a/src/commands/list.ts +++ b/src/commands/list.ts @@ -1,7 +1,7 @@ import { list as handler } from '@libcontext/handlers/list'; import type { Command } from '@libcontext/types'; -export const list: Command<{}> = { +export const list: Command = { command: 'list', description: 'List libraries added to the server', handler: async () => { diff --git a/src/db/migrations.ts b/src/db/migrations.ts index 9860f83..c6e4f6b 100644 --- a/src/db/migrations.ts +++ b/src/db/migrations.ts @@ -1,6 +1,6 @@ +import path from 'node:path'; import { rootPath } from '@libcontext/utils/package'; import { migrate as execute } from 'drizzle-orm/libsql/migrator'; -import path from 'path'; import { db } from './db'; import { library } from './schema'; diff --git a/src/db/settings.ts b/src/db/settings.ts index c169f2c..e4b9655 100644 --- a/src/db/settings.ts +++ b/src/db/settings.ts @@ -1,13 +1,14 @@ +import { mkdirSync } from 'node:fs'; import { name } from '@libcontext/constants'; import { paths } from '@libcontext/utils/paths'; -import { mkdirSync } from 'fs'; if (process.env.NODE_ENV !== 'test') { try { mkdirSync(paths.data, { recursive: true }); - } catch (e) { + } catch (error) { console.error( `Permission error to create data folder at "${paths.data}". Please, create this folder manually and make sure this app has write permission.`, + error, ); process.exit(1); } diff --git a/src/handlers/get.test.ts b/src/handlers/get.test.ts index eeab5a4..0e4a1e0 100644 --- a/src/handlers/get.test.ts +++ b/src/handlers/get.test.ts @@ -6,7 +6,7 @@ import { type GetOptions, get } from './get'; describe('get', () => { const lib = stubs.libraries['org1/repo1']; - const embed = mock(async (text: string) => + const embed = mock(async () => Array.from({ length: 1536 }, (_, i) => i * 0.001), ); let mocks: MockResult[] = []; diff --git a/src/handlers/get.ts b/src/handlers/get.ts index d9c3d99..453d323 100644 --- a/src/handlers/get.ts +++ b/src/handlers/get.ts @@ -8,8 +8,20 @@ export interface GetOptions { k: number; } -const similarity = async ({ name, topic, k }: GetOptions) => { - const vector = await embed(topic!); +const all = async ({ name, k }: GetOptions) => { + return await db + .select() + .from(snippet) + .where(eq(snippet.library, name)) + .limit(k); +}; + +const similarity = async ({ + name, + topic, + k, +}: GetOptions & { topic: string }) => { + const vector = await embed(topic); return db .select({ title: snippet.title, @@ -24,21 +36,14 @@ const similarity = async ({ name, topic, k }: GetOptions) => { .where(eq(snippet.library, name)); }; -const all = async ({ name, k }: GetOptions) => { - return await db - .select() - .from(snippet) - .where(eq(snippet.library, name)) - .limit(k); -}; - -export const get = async (options: GetOptions) => { +export const get = async ({ name, topic, k }: GetOptions) => { try { - const query = options.topic ? similarity : all; - const results = await query(options); + const results = topic + ? await similarity({ name, topic, k }) + : await all({ name, topic, k }); if (results.length === 0) { - return `No snippets found for library "${options.name}"${options.topic ? ` with topic: "${options.topic}"` : ''}`; + return `No snippets found for library "${name}"${topic ? ` with topic: "${topic}"` : ''}`; } const snippets = results.map( @@ -51,7 +56,7 @@ ${snippet.code} \`\`\``, ); return snippets.join('\n----------------------------------------\n'); - } catch (error) { + } catch (_error) { return 'Failed to retrieve snippets'; } }; diff --git a/src/types/index.d.ts b/src/types/index.d.ts index c741086..e2157b1 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -1,6 +1,6 @@ import type { Argv } from 'yargs'; -export interface Command { +export interface Command { command: string; description: string; builder?: (yargs: Argv) => Argv; diff --git a/src/utils/package.ts b/src/utils/package.ts index a62b585..2fc4126 100644 --- a/src/utils/package.ts +++ b/src/utils/package.ts @@ -1,6 +1,6 @@ -import fs, { readFileSync } from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; +import fs, { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); diff --git a/src/utils/paths.ts b/src/utils/paths.ts index 2f8a663..440937d 100644 --- a/src/utils/paths.ts +++ b/src/utils/paths.ts @@ -1,7 +1,7 @@ +import os from 'node:os'; +import path from 'node:path'; +import process from 'node:process'; import { name } from '@libcontext/constants'; -import os from 'os'; -import path from 'path'; -import process from 'process'; const homedir = os.homedir(); const tmpdir = os.tmpdir(); diff --git a/tsconfig.json b/tsconfig.json index 0455efa..9b99837 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,7 +24,7 @@ "noUnusedParameters": false, "noPropertyAccessFromIndexSignature": false, "paths": { - "@libcontext/*": ["./src/*"], - }, - }, + "@libcontext/*": ["./src/*"] + } + } }