Skip to content

Commit

Permalink
feat: add building to single executable
Browse files Browse the repository at this point in the history
- add build script with compilation to binary
- update tsconfig for correct compilation
- bump bun version to 1.1.30 to make it work with compilation and running compiled version
- add sourcemaps to compiled file to make errors & stacktraces point to their original locations instead of the transpiled location
- add gh release action for building binary on push of version tag
- fix some type errors
- update readme to reflect build and distribution process
- add required bun version to package.json and readme.
- describe packages installation thoublesheeting for dynamic imports and bun --compile
  • Loading branch information
erik-balfe committed Oct 10, 2024
1 parent 5ec826f commit 9a8e493
Show file tree
Hide file tree
Showing 9 changed files with 289 additions and 33 deletions.
45 changes: 45 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Build and Release

on:
push:
tags:
- "v*.*.*"

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: latest

- name: Install dependencies
run: bun install

- name: Build project
run: bun run build

- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false

- name: Upload Release Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./dist/ai-console-agent
asset_name: ai-console-agent
asset_content_type: application/octet-stream
144 changes: 142 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ AI Console Agent is an advanced command-line tool that uses artificial intellige
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Usage](#usage)
- [Compilation and Distribution](#compilation-and-distribution)
- [Safety and Limitations](#safety-and-limitations)
- [Development Status](#development-status)
- [Contributing](#contributing)
Expand Down Expand Up @@ -71,6 +72,146 @@ bun run src/index.ts "Show me the disk usage of the current directory"

The agent will interpret your request, execute the necessary commands, and provide you with the results.

## Compilation and Distribution

### Prerequisites

This project requires Bun version 1.1.30 or later. To install Bun, follow the instructions at https://bun.sh/.


### Compilation Process

To compile the AI Console Agent into a standalone executable with source maps, follow these steps:

1. Ensure all project dependencies are installed:

```
bun install
```

2. Run the build script:

```
bun run build
```

3. Upon successful compilation, you'll see a message similar to:

```
Build completed successfully. Executable: /path/to/ai-console-agent/dist/ai-console-agent
```

4. The compiled executable will be created in the `dist` directory as `ai-console-agent`, along with source map files.

### Running the Compiled Executable

After successful compilation, run the AI Console Agent using:

```
./dist/ai-console-agent "Your command here"
```

This executable includes all necessary dependencies and can be distributed as a standalone program.

### Release Process for Developers

To create a new release:

1. Ensure all changes are committed and pushed to the main branch.

2. Update the version number in `package.json`.

3. Create a new tag with the version number:

```
git tag v1.0.0 # Replace with your version number
```

4. Push the tag to GitHub:

```
git push origin v1.0.0 # Replace with your version number
```

5. The GitHub Actions workflow will automatically:

- Build the project
- Create a new release
- Attach the compiled executable to the release

6. Once complete, you can find the new release on the GitHub repository's releases page.

### Troubleshooting Compilation

Compilation is done using Bun bundler that allows compiling TypeScript code into one executable file.
Read about it here: https://bun.sh/docs/bundler/executables

If you encounter errors related to missing packages during compilation, follow these steps:

1. Identify the missing packages from the error messages. Common missing packages might include:

- pg
- @xenova/transformers
- pgvector

2. Install these packages as dev dependencies:

```
bun add -d packageName1 packageName2 ...
```

For example:

```
bun add -d pg @xenova/transformers pgvector
```

3. Update your `package.json` to include these as dev dependencies:

```json
{
"devDependencies": {
"@types/bun": "latest",
"@xenova/transformers": "^2.17.2",
"pg": "^8.13.0",
"pgvector": "^0.2.0"
},
"dependencies": {
"chalk": "^5.3.0",
"dotenv": "^16.0.0",
"llamaindex": "^0.6.18"
}
}
```

4. Run the build process again:
```
bun run build
```

Note: This issue may occur if there are changes in the `llamaindex` package or its dependencies. Always check for updates and be prepared to add new dev dependencies as needed.

### Development Run

For development and testing purposes, you can run the project directly without compilation:

```
bun run src/index.ts "Your natural language command or question here"
```

This method works fine for development without requiring the additional setup needed for compilation.

### Keeping Dependencies Updated

To ensure the project remains up-to-date:

1. Periodically update the project dependencies:
```
bun update
```
2. After updating, perform a fresh compilation process to ensure compatibility with the latest versions.
3. Test the newly compiled executable thoroughly before distribution.

## Safety and Limitations

- The agent creates backups before modifying important files.
Expand All @@ -86,7 +227,6 @@ AI Console Agent is in early development. While functional, it may have bugs or
Upcoming features:

- Continuation of previous sessions and access to previous task context
- Compilation into a single, easy-to-distribute binary
- Enhanced learning and adaptation capabilities
- More advanced context-aware processing
- Comprehensive error handling and recovery system
Expand All @@ -105,4 +245,4 @@ If you encounter any problems or have any questions, please open an issue on the

## Version

Current version: 0.1.0
Current version: 0.2.0
60 changes: 60 additions & 0 deletions build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { spawnSync } from "child_process";
import fs from "fs";
import path from "path";

const PROJECT_ROOT = process.cwd();
const DIST_DIR = path.join(PROJECT_ROOT, "dist");
const MAIN_FILE = path.join(PROJECT_ROOT, "src", "index.ts");
const OUTPUT_FILE = path.join(DIST_DIR, "ai-console-agent");

async function build() {
checkBunVersion();

console.log("Starting build process...");

if (!fs.existsSync(DIST_DIR)) {
fs.mkdirSync(DIST_DIR);
}

console.log("Installing dependencies...");
spawnSync("bun", ["install"], { stdio: "inherit" });

console.log("Compiling project...");
const result = spawnSync(
"bun",
[
"build",
MAIN_FILE,
"--compile",
"--minify",
"--outfile",
OUTPUT_FILE,
"--target",
"bun",
"--format",
"esm",
],
{ stdio: "inherit" },
);

if (result.status !== 0) {
console.error("Compilation failed");
process.exit(1);
}

console.log(`Build completed successfully. Executable: ${OUTPUT_FILE}`);
}

function checkBunVersion() {
const result = spawnSync("bun", ["--version"], { encoding: "utf8" });
const version = result.stdout.trim();
const requiredVersion = "1.1.30";

if (version !== requiredVersion) {
console.warn(
`Warning: This project is tested with Bun version ${requiredVersion}. You are using ${version}.`,
);
}
}

build().catch(console.error);
Binary file modified bun.lockb
Binary file not shown.
14 changes: 12 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
{
"name": "ai-console-agent",
"version": "0.2.0",
"engines": {
"bun": "1.1.30"
},
"module": "index.ts",
"type": "module",
"scripts": {
"build": "bun run build.ts"
},
"devDependencies": {
"@types/bun": "latest"
"@types/bun": "latest",
"@xenova/transformers": "^2.17.2",
"pg": "^8.13.0",
"pgvector": "^0.2.0"
},
"peerDependencies": {
"typescript": "^5.0.0"
},
"dependencies": {
"chalk": "^5.3.0",
"dotenv": "^16.0.0",
"llamaindex": "0.6"
"llamaindex": "^0.6.18"
},
"trustedDependencies": [
"protobufjs"
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { MAX_INPUT_LENGTH } from "./constants";
config();

async function main() {
const { input } = parseArguments(process.argv);
const { input } = parseArguments(Bun.argv);

if (input) {
console.log(chalk.cyan(`Input: ${input}`));
Expand Down
11 changes: 8 additions & 3 deletions src/tools/executeCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,17 @@ export const executeCommandTool = new FunctionTool(
if (useTmux) {
result = await TmuxWrapper.run(command, interactions);
} else {
const { stdout, stderr } = await runShellCommand(command);
result = stdout + (stderr ? `\nError: ${stderr}` : "");
try {
const { stdout, stderr } = await runShellCommand(command, { shell: "bash" });
result = JSON.stringify({ stdout, stderr });
} catch (error) {
console.error(chalk.red("Error in tool executing command:"), error);
return { stderr: error instanceof Error ? error.message : String(error) };
}
}

console.log(
chalk.green(`Successfully completed command "${command}"`) + chalk.gray(`\nResult: "${result}"`),
chalk.green(`Successfully completed command "${command}"`) + chalk.gray(`\nResult:\n"${result}"`),
);
return result;
} catch (error: unknown) {
Expand Down
13 changes: 8 additions & 5 deletions src/utils/runShellCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ export async function runShellCommand(
): Promise<{ stdout: string; stderr: string }> {
try {
const { stdout, stderr } = await execAsync(command, options);
return { stdout, stderr };
return {
stdout: stdout.toString(),
stderr: stderr.toString(),
};
} catch (error: any) {
console.error(`Error executing command: ${command}`, error);
throw new Error(
`Failed to execute command safely: ${error instanceof Error ? error.message : String(error)}`,
);
return {
stderr: error instanceof Error ? error.message : String(error),
stdout: "",
};
}
}
33 changes: 13 additions & 20 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
{
"compilerOptions": {
// Enable latest features
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,

// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,

// Best practices
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,

// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
"noEmit": true,
"allowJs": true,
"ignoreDeprecations": "5.0",
"isolatedModules": true,
"resolveJsonModule": true,
"forceConsistentCasingInFileNames": true,
"strict": false,
"strictNullChecks": true,
"allowSyntheticDefaultImports": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}

0 comments on commit 9a8e493

Please sign in to comment.