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"