Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

builds playground with yarn workspaces + branch release #38

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/branch-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Branch Release

on:
push

jobs:
branch_publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20' # Specify the Node.js version you want to use

- name: Install Dependencies
run: yarn install

- name: Build
run: yarn build

- name: Set Version from Branch
run: |
BRANCH_NAME=${GITHUB_REF#refs/heads/}
SHORT_SHA=$(git rev-parse --short HEAD)
BASE_VERSION="0.1.0" # Define a base version
VERSION="${BASE_VERSION}-${BRANCH_NAME}-${SHORT_SHA}"
yarn version --new-version $VERSION --no-git-tag-version

- name: Configure NPM Authentication
run: |
echo "@bitte-ai:registry=https://registry.npmjs.org/" > ~/.npmrc
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc

- name: Publish with npm
if: ${{ github.ref_name != 'main'}}
run: yarn publish --access public --tag beta
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Binary file removed bun.lockb
Binary file not shown.
65 changes: 33 additions & 32 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,25 @@
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"private": true,
"description": "Bitte AI Agent Builder and Playground",
"bin": {
"make-agent": "./dist/index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/mintbase/make-agent"
},
"repository": "git+https://github.com/BitteProtocol/make-agent",
"bugs": {
"url": "https://github.com/mintbase/make-agent/issues"
"url": "https://github.com/BitteProtocol/make-agent/issues"
},
"homepage": "https://github.com/mintbase/make-agent/repo#readme",
"homepage": "https://github.com/BitteProtocol/make-agent/repo#readme",
"workspaces": [
"src/playground",
"src/commands"
],
"scripts": {
"typecheck": "tsc --noEmit",
"dev": "bun run ./src/index.ts dev --port 3000",
"build": "bun run typecheck && bun build ./src/index.ts --outdir ./dist --target node --external=lightningcss",
"prepublishOnly": "bun run build",
"build-binary": "bun run typecheck && bun build ./src/index.ts --compile --outfile make-agent",
"dev": "tsup src/index.ts --watch --onSuccess 'node dist/index.js'",
"build": "tsup --config tsup.config.ts",
"prepublishOnly": "yarn build",
"lint": "prettier --check '{src,tests}/**/*.{js,ts}' && eslint . --ignore-pattern dist/",
"fmt": "prettier --write '{src,tests}/**/*.{js,ts}' && yarn lint --fix"
},
Expand All @@ -30,26 +32,8 @@
"agent",
"cli"
],
"author": "Micro",
"author": "Bitte Team",
"license": "MIT",
"devDependencies": {
"@types/bun": "latest",
"@types/cors": "^2.8.17",
"@types/express": "^5.0.0",
"@types/inquirer": "^9.0.7",
"@types/localtunnel": "^2.0.4",
"@types/node": "^22.7.2",
"@types/open": "^6.2.1",
"@typescript-eslint/eslint-plugin": "^8.15.0",
"ajv": "^8.17.1",
"ajv-draft-04": "^1.0.0",
"eslint": "^9.15.0",
"eslint-plugin-import": "^2.31.0",
"prettier": "^3.3.3"
},
"peerDependencies": {
"typescript": "^5.0.0"
},
"dependencies": {
"@apidevtools/swagger-parser": "^10.1.0",
"borsh": "^0.7.0",
Expand All @@ -68,7 +52,24 @@
"near-safe": "^0.9.6",
"open": "^10.1.0",
"tsup": "^8.3.5",
"vercel-url": "^0.2.1",
"vite": "^6.0.9"
"vercel-url": "^0.2.1"
},
"devDependencies": {
"@types/bun": "latest",
"@types/cors": "^2.8.17",
"@types/express": "^5.0.0",
"@types/inquirer": "^9.0.7",
"@types/localtunnel": "^2.0.4",
"@types/node": "^22.7.2",
"@types/open": "^6.2.1",
"@typescript-eslint/eslint-plugin": "^8.15.0",
"ajv": "^8.17.1",
"ajv-draft-04": "^1.0.0",
"eslint": "^9.15.0",
"eslint-plugin-import": "^2.31.0",
"prettier": "^3.3.3"
},
"peerDependencies": {
"typescript": "^5.0.0"
}
}
}
99 changes: 57 additions & 42 deletions src/commands/dev.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Command } from "commander";
import dotenv from 'dotenv';
import isPortReachable from 'is-port-reachable';
import path from "path";
import dotenv from "dotenv";
import isPortReachable from "is-port-reachable";

import { startDevServer } from "../services/dev-server";
import { startApiServer } from "../services/proxy";
import { createViteServer } from "../services/vite";
import { getDeployedUrl } from "../utils/deployed-url";
import { validateEnv } from "../utils/env";
import { validateAndParseOpenApiSpec } from "../utils/openapi";
Expand All @@ -15,14 +15,19 @@ validateEnv();

interface ApiConfig {
key: string;
url: string;
url: string;
serverPort: number;
}

interface PortConfig {
port: number;
serverPort: number;
}

interface ValidationResult {
pluginId: string;
accountId: string;
spec: any;
spec: unknown;
}

const DEFAULT_PORTS = {
Expand All @@ -32,7 +37,7 @@ const DEFAULT_PORTS = {

async function findAvailablePort(startPort: number): Promise<number> {
let port = startPort;
while (await isPortReachable(port, {host: 'localhost'})) {
while (await isPortReachable(port, {host: "localhost"})) {
port++;
}
return port;
Expand All @@ -47,10 +52,10 @@ const API_CONFIG: ApiConfig = {
async function fetchAndValidateSpec(url: string): Promise<ValidationResult> {
const pluginId = getHostname(url);
const specUrl = getSpecUrl(url);

const validation = await validateAndParseOpenApiSpec(specUrl);
const { isValid, accountId } = validation;

const specContent = await fetch(specUrl).then(res => res.text());
let spec = JSON.parse(specContent);

Expand All @@ -72,8 +77,8 @@ async function fetchAndValidateSpec(url: string): Promise<ValidationResult> {
};
}

async function setupPorts(options: { port?: string }) {
let port = parseInt(options.port || '') || 0;
async function setupPorts(options: { port?: string }): Promise<PortConfig> {
let port = parseInt(options.port || "") || 0;

if (port === 0) {
const detectedPort = await detectPort();
Expand All @@ -84,28 +89,9 @@ async function setupPorts(options: { port?: string }) {
}
}

const uiPort = await findAvailablePort(DEFAULT_PORTS.UI);
const serverPort = await findAvailablePort(DEFAULT_PORTS.SERVER);

return { port, uiPort, serverPort };
}

async function createViteConfiguration(uiPort: number, serverPort: number, localAgent: ValidationResult) {
return {
root: path.resolve(__dirname, "../playground"),
port: uiPort,
configFile: path.resolve(__dirname, "../playground/vite.config.ts"),
define: {
__APP_DATA__: JSON.stringify({
serverStartTime: new Date().toISOString(),
environment: "make-agent",
localAgent,
apiUrl: `http://localhost:${serverPort}/api/v1/chat`,
bitteApiKey: API_CONFIG.key,
bitteApiUrl: `http://localhost:${serverPort}/api/v1/chat`
})
}
};
return { port, serverPort };
}

export const devCommand = new Command()
Expand All @@ -115,28 +101,57 @@ export const devCommand = new Command()
.option("-t, --testnet", "Use Testnet instead of Mainnet", false)
.action(async (options) => {
try {
const { port, uiPort, serverPort } = await setupPorts(options);

// Setup ports for the servers
const { port, serverPort } = await setupPorts(options);

// Start API server
API_CONFIG.serverPort = serverPort;
const server = await startApiServer(API_CONFIG);
const apiServer = await startApiServer(API_CONFIG);

// Get and validate the deployed URL
const deployedUrl = getDeployedUrl(port);
if (!deployedUrl) {
throw new Error("Deployed URL could not be determined.");
}

// Fetch and validate the spec
const localAgent = await fetchAndValidateSpec(deployedUrl);
const viteConfig = await createViteConfiguration(uiPort, serverPort, localAgent);
const viteServer = createViteServer(viteConfig);
await viteServer.start();

process.on("SIGINT", async () => {
await viteServer.close();
server.close();
process.exit(0);
// Start the integrated dev server
const devServer = await startDevServer({
port,
apiPort: serverPort,
define: {
__APP_DATA__: JSON.stringify({
serverStartTime: new Date().toISOString(),
environment: "make-agent",
localAgent,
apiUrl: `http://localhost:${serverPort}/api/v1/chat`,
bitteApiKey: API_CONFIG.key,
bitteApiUrl: `http://localhost:${serverPort}/api/v1/chat`
})
}
});

// Handle cleanup
const cleanup = async (): Promise<void> => {
await new Promise(resolve => devServer.close(resolve));
await new Promise(resolve => apiServer.close(resolve));
process.exit(0);
};

process.on("SIGINT", cleanup);
process.on("SIGTERM", cleanup);

console.log(`
Development server is running:
- Main UI: http://localhost:${port}
- API Server: http://localhost:${serverPort}
Press Ctrl+C to stop
`);

} catch (error) {
console.error("Failed to start development server:", error);
process.exit(1);
}
});
});
2 changes: 1 addition & 1 deletion src/playground/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "my-vue-app",
"name": "bitte-ai-playground",
"private": true,
"version": "0.0.0",
"type": "module",
Expand Down
46 changes: 46 additions & 0 deletions src/services/dev-server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import express from "express";
import { Server } from "http";
import { createProxyMiddleware } from "http-proxy-middleware";
import path from "path";
import { createServer } from "vite";

interface DevServerConfig {
port: number;
apiPort: number;
define: Record<string, unknown>;
}

export async function startDevServer(config: DevServerConfig): Promise<Server> {
const app = express();

// API proxy setup
app.use("/api", createProxyMiddleware({
target: `http://localhost:${config.apiPort}`,
changeOrigin: true,
pathRewrite: {
"^/api": ""
}
}));

// Create Vite server
const vite = await createServer({
root: path.resolve(process.cwd(), "playground"),
server: {
middlewareMode: true,
hmr: {
port: config.port + 1
}
},
define: config.define
});

// Use Vite's middleware
app.use(vite.middlewares);

return new Promise((resolve) => {
const server = app.listen(config.port, () => {
console.log(`Development server running at http://localhost:${config.port}`);
resolve(server);
});
});
}
Loading
Loading