diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml new file mode 100644 index 0000000..bde0c91 --- /dev/null +++ b/.github/workflows/npm-publish.yml @@ -0,0 +1,63 @@ +name: Publish to NPM + +on: + release: + types: [created] + workflow_dispatch: + inputs: + version: + description: 'Version type (patch, minor, major)' + required: true + default: 'patch' + type: choice + options: + - patch + - minor + - major + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + registry-url: 'https://registry.npmjs.org' + + - name: Install dependencies + run: npm ci + + - name: Run tests + run: npm test + + - name: Generate static files + run: npm run generate + + - name: Update version (manual trigger) + if: github.event_name == 'workflow_dispatch' + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + npm version ${{ github.event.inputs.version }} -m "chore: bump version to %s" + git push + + - name: Publish to NPM + run: npm publish + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + + - name: Create GitHub Release (manual trigger) + if: github.event_name == 'workflow_dispatch' + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v${{ steps.package-version.outputs.version }} + release_name: Release v${{ steps.package-version.outputs.version }} + draft: false + prerelease: false \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..a6b9c28 --- /dev/null +++ b/.npmignore @@ -0,0 +1,62 @@ +# Source files (only include built output) +.nuxt/ +node_modules/ +server/ +pages/ +components/ +composables/ +layouts/ +middleware/ +plugins/ +utils/ +assets/ +static/ +tests/ +coverage/ + +# Development files +.git/ +.github/ +.vscode/ +.idea/ +*.log +*.tmp +.DS_Store +.env +.env.* + +# Config files (except necessary ones) +.eslintrc* +.prettierrc* +.gitignore +.gitlab-ci.yml +.travis.yml +tsconfig.json +vitest.config.ts +nuxt.config.ts +tailwind.config.js +postcss.config.js + +# Documentation (keep essential docs) +docs/ +*.md +!README.md +!LICENSE + +# Build artifacts we don't need +.nitro/ +.cache/ +.output/ + +# Test files +*.test.ts +*.spec.ts +*.test.js +*.spec.js + +# Keep only what's needed for npm package +!dist/ +!cli.js +!package.json +!README.md +!LICENSE \ No newline at end of file diff --git a/app.vue b/app.vue index ec195ce..ca7e7f3 100644 --- a/app.vue +++ b/app.vue @@ -49,12 +49,14 @@ + \ No newline at end of file diff --git a/package.json b/package.json index 422e0e1..29ef4a8 100644 --- a/package.json +++ b/package.json @@ -1,22 +1,50 @@ { - "name": "nuxt-app", - "private": true, + "name": "contextmax", + "version": "1.0.0-rc.1", + "description": "Privacy-first, browser-based tool for creating precise context sets for LLMs", + "keywords": ["llm", "context", "ai", "developer-tools", "privacy", "browser-based"], + "author": "Galih Muhammad", + "license": "MPL-2.0", "type": "module", + "bin": { + "contextmax": "./cli.js" + }, + "files": [ + "dist/**/*", + "cli.js", + "README.md", + "LICENSE" + ], + "engines": { + "node": ">=18.0.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/galliani/contextmax.git" + }, + "bugs": { + "url": "https://github.com/galliani/contextmax/issues" + }, + "homepage": "https://github.com/galliani/contextmax#readme", "scripts": { "build": "nuxt build", "dev": "nuxt dev --inspect", "dev:clean": "rm -rf .nuxt && nuxt dev --inspect", "clean": "rm -rf .nuxt node_modules/.cache", "dev:fresh": "npm run clean && npm install && nuxt dev", + "postinstall": "nuxt prepare || true", + "prepare": "nuxt prepare", "generate": "nuxt generate", - "preview": "nuxt preview", - "deploy": "npm run generate && wrangler pages deploy dist", - "postinstall": "nuxt prepare", "test": "vitest run", "test:coverage": "vitest run --coverage", - "coverage:badge": "coverage-badges" + "coverage:badge": "coverage-badges", + "prepublishOnly": "npm run generate", + "start": "node cli.js" }, "dependencies": { + "open": "^10.0.0" + }, + "devDependencies": { "@huggingface/transformers": "^3.5.2", "@nuxt/content": "^3.5.1", "@nuxt/eslint": "^1.4.1", @@ -49,9 +77,6 @@ "typescript": "^5.8.3", "vue": "^3.5.15", "vue-router": "^4.5.1", - "web-tree-sitter": "^0.25.6" - }, - "devDependencies": { "@iconify-json/lucide": "^1.2.45", "@testing-library/vue": "^8.1.0", "@vitest/coverage-v8": "^3.2.0", diff --git a/server/tsconfig.json b/server/tsconfig.json deleted file mode 100644 index b9ed69c..0000000 --- a/server/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../.nuxt/tsconfig.server.json" -} diff --git a/test-npm-package.sh b/test-npm-package.sh new file mode 100755 index 0000000..ba6ea9d --- /dev/null +++ b/test-npm-package.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +echo "๐Ÿงช Testing ContextMax NPM Package Locally" +echo "========================================" + +# Colors for output +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Check if we're in the project directory +if [ ! -f "package.json" ]; then + echo -e "${RED}Error: package.json not found. Run this script from the project root.${NC}" + exit 1 +fi + +echo -e "\n${YELLOW}Step 1: Generating static files...${NC}" +npm run generate + +if [ $? -ne 0 ]; then + echo -e "${RED}Build failed!${NC}" + exit 1 +fi + +echo -e "\n${GREEN}โœ“ Static generation completed successfully${NC}" + +# Check if dist directory exists +if [ ! -d "dist" ]; then + echo -e "${RED}Error: dist directory not found after generation${NC}" + exit 1 +fi + +echo -e "\n${YELLOW}Step 2: Creating local package...${NC}" +npm pack + +# Get the package filename +PACKAGE_FILE=$(ls contextmax-*.tgz | head -n 1) + +if [ -z "$PACKAGE_FILE" ]; then + echo -e "${RED}Error: Package file not created${NC}" + exit 1 +fi + +echo -e "${GREEN}โœ“ Package created: $PACKAGE_FILE${NC}" + +# Create a temporary test directory +TEST_DIR="/tmp/contextmax-test-$(date +%s)" +mkdir -p "$TEST_DIR" + +echo -e "\n${YELLOW}Step 3: Testing installation in temporary directory...${NC}" +cd "$TEST_DIR" + +# Install the package +npm install "$OLDPWD/$PACKAGE_FILE" + +if [ $? -ne 0 ]; then + echo -e "${RED}Installation failed!${NC}" + exit 1 +fi + +echo -e "${GREEN}โœ“ Package installed successfully${NC}" + +echo -e "\n${YELLOW}Step 4: Testing CLI execution...${NC}" + +# Test the CLI +timeout 5s npx contextmax help + +if [ $? -eq 124 ]; then + echo -e "${YELLOW}Note: Server started successfully (timeout expected for testing)${NC}" +else + echo -e "${GREEN}โœ“ CLI executed successfully${NC}" +fi + +# Cleanup +cd "$OLDPWD" +rm -rf "$TEST_DIR" +rm -f "$PACKAGE_FILE" + +echo -e "\n${GREEN}โœ… All tests passed! Package is ready for publishing.${NC}" +echo -e "\nTo publish to npm:" +echo -e " 1. Make sure you're logged in: ${YELLOW}npm login${NC}" +echo -e " 2. Publish the package: ${YELLOW}npm publish${NC}" +echo -e "\nUsers will be able to install with:" +echo -e " ${YELLOW}npx contextmax${NC}" \ No newline at end of file diff --git a/utils/healthCheck.ts b/utils/healthCheck.ts new file mode 100644 index 0000000..6866438 --- /dev/null +++ b/utils/healthCheck.ts @@ -0,0 +1,131 @@ +export interface HealthCheckResult { + feature: string + available: boolean + error?: string +} + +export async function checkBrowserAPIs(): Promise { + const results: HealthCheckResult[] = [] + + // Check File System Access API + results.push({ + feature: 'File System Access API', + available: 'showOpenFilePicker' in window && + 'showDirectoryPicker' in window && + 'showSaveFilePicker' in window + }) + + // Check Origin Private File System (OPFS) + try { + if ('storage' in navigator && 'getDirectory' in navigator.storage) { + const root = await navigator.storage.getDirectory() + results.push({ + feature: 'Origin Private File System (OPFS)', + available: true + }) + } else { + results.push({ + feature: 'Origin Private File System (OPFS)', + available: false, + error: 'OPFS API not found' + }) + } + } catch (error) { + results.push({ + feature: 'Origin Private File System (OPFS)', + available: false, + error: error instanceof Error ? error.message : 'Unknown error' + }) + } + + // Check IndexedDB + try { + const testDB = await new Promise((resolve) => { + const request = indexedDB.open('contextmax-health-check', 1) + request.onsuccess = () => { + request.result.close() + indexedDB.deleteDatabase('contextmax-health-check') + resolve(true) + } + request.onerror = () => resolve(false) + }) + + results.push({ + feature: 'IndexedDB', + available: testDB + }) + } catch (error) { + results.push({ + feature: 'IndexedDB', + available: false, + error: error instanceof Error ? error.message : 'Unknown error' + }) + } + + // Check WebGPU (for AI acceleration) + results.push({ + feature: 'WebGPU (AI Acceleration)', + available: 'gpu' in navigator + }) + + // Check Web Workers + results.push({ + feature: 'Web Workers', + available: 'Worker' in window + }) + + // Check SharedArrayBuffer (for multi-threading) + results.push({ + feature: 'SharedArrayBuffer', + available: 'SharedArrayBuffer' in window + }) + + // Check Browser Type and Version + const userAgent = navigator.userAgent + const isChrome = userAgent.includes('Chrome') && !userAgent.includes('Edg') + const isEdge = userAgent.includes('Edg') + const isFirefox = userAgent.includes('Firefox') + const isSafari = userAgent.includes('Safari') && !userAgent.includes('Chrome') + + results.push({ + feature: 'Supported Browser', + available: isChrome || isEdge, + error: (!isChrome && !isEdge) ? + `ContextMax works best in Chrome or Edge. Current browser: ${ + isFirefox ? 'Firefox' : isSafari ? 'Safari' : 'Unknown' + }` : undefined + }) + + return results +} + +export function getHealthCheckSummary(results: HealthCheckResult[]): { + allPassed: boolean + criticalPassed: boolean + warnings: string[] + errors: string[] +} { + const critical = ['File System Access API', 'Origin Private File System (OPFS)', 'IndexedDB'] + const errors: string[] = [] + const warnings: string[] = [] + + results.forEach(result => { + if (!result.available) { + const message = `${result.feature}: ${result.error || 'Not available'}` + if (critical.includes(result.feature)) { + errors.push(message) + } else { + warnings.push(message) + } + } + }) + + return { + allPassed: results.every(r => r.available), + criticalPassed: results + .filter(r => critical.includes(r.feature)) + .every(r => r.available), + warnings, + errors + } +} \ No newline at end of file diff --git a/wrangler.toml b/wrangler.toml deleted file mode 100644 index fd0a93f..0000000 --- a/wrangler.toml +++ /dev/null @@ -1,15 +0,0 @@ -name = "contextmax" -compatibility_date = "2025-06-13" -pages_build_output_dir = "dist" - -[build] -command = "npm run generate" - -[build.environment_variables] -NODE_VERSION = "18" - -[env.production] -name = "contextmax-curator" - -[env.preview] -name = "contextmax-curator-preview"