--- install scripts ---
### prepublishOnly
npm run test:run && npm run build:publish
--- package/package.json (excerpt) ---
{
"name": "@jacob-ebey/almostnode",
"version": "0.4.0",
"description": "Node.js in your browser. Just like that.",
"type": "module",
"license": "MIT",
"keywords": [
"node",
"browser",
"runtime",
"virtual-filesystem",
"sandbox",
"vite",
"nextjs",
"hmr",
"typescript"
],
"repository": {
"type": "git",
"url": "https://github.com/macaly/almostnode.git"
},
"homepage": "https://github.com/macaly/almostnode#readme",
"bugs": {
"url": "https://github.com/macaly/almostnode/issues"
},
"author": "",
"engines": {
"node": ">=20.0.0"
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.mjs"
},
"require": {
"types": "./dist/index.d.ts",
"default": "./dist/index.cjs"
}
},
"./vite": {
"import": {
"types": "./dist/vite-plugin.d.ts",
"default": "./dist/vite-plugin.mjs"
},
"require": {
"types": "./dist/vite-plugin.d.ts",
"default": "./dist/vite-plugin.cjs"
}
},
"./next": {
"import": {
"types": "./dist/next-plugin.d.ts",
"default": "./dist/next-plugin.mjs"
},
"require": {
"types": "./dist/next-plugin.d.ts",
"default": "./dist/next-plugin.cjs"
}
}
},
"files": [
"src",
"dist"
],
"sideE
--- package/src/agent-workbench-entry.ts (excerpt) ---
/**
* Agent Workbench Entry Point
*
* Architecture:
* - The entire app (chat UI + preview) runs inside almostnode's virtual Next.js
* - Chat page (/app/page.tsx) uses useChat from @ai-sdk/react (loaded from esm.sh)
* - API route (/pages/api/chat.ts) uses streamText with tool-calling
* - AI SDK packages (ai, @ai-sdk/openai, zod) are installed via PackageManager
* - Tools operate on VFS directly (read, write, replace, list, bash)
*/
import { VirtualFS } from './virtual-fs';
import { NextDevServer } from './frameworks/next-dev-server';
import { getServerBridge } from './server-bridge';
import { createAgentWorkbenchProject } from './agent-workbench-project';
import { initChildProcess, exec as cpExec } from './shims/child_process';
import { PackageManager } from './npm/index';
// ── Constants ──
const CORS_PROXY = new URLSearchParams(window.location.search).get('corsProxy') || 'https://almostnode-cors-proxy.langtail.workers.dev/?url=';
const PORT = 3004;
// ── Logging (outside React) ──
const logsEl = document.getElementById('logs') as HTMLDivElement;
function log(message: string, type: 'info' | 'error' | 'warn' | 'success' = 'info') {
const line = document.createElement('div');
const time = new Date().toLocaleTimeString();
line.textContent = `[${time}] ${message}`;
line.className = type;
logsEl.appendChild(line);
logsEl.scrollTop = logsEl.scrollHeight;
}
// ── Create __project__ module (VFS operations for the API route) ──
function createProjectModule
--- package/src/agent-workbench-project.ts (excerpt) ---
/**
* Agent Workbench - Virtual Project Seed
*
* Creates a Next.js project in VFS with:
* - Chat UI using useChat from @ai-sdk/react (App Router client page, loaded from esm.sh)
* - API route using streamText + Pages Router streaming (server, proven pattern)
* - Tools: read_file, write_file, replace_in_file, list_files, run_bash
*/
import { VirtualFS } from './virtual-fs';
const PACKAGE_JSON = {
name: 'agent-workbench-app',
version: '0.1.0',
private: true,
scripts: {
dev: 'next dev',
build: 'next build',
start: 'next start',
},
dependencies: {
next: '^14.0.0',
react: '^18.2.0',
'react-dom': '^18.2.0',
ai: '^6.0.0',
'@ai-sdk/react': '^3.0.0',
},
};
// ── API Route (/pages/api/chat.ts) — Pages Router for proven streaming ──
const API_ROUTE = `import { streamText, tool, stepCountIs, convertToModelMessages } from 'ai';
import { createOpenAI } from '@ai-sdk/openai';
import { z } from 'zod';
import { readFile, writeFile, existsSync, listFiles, statSync, mkdirSync, runCommand, log } from '__project__';
var CORS_PROXY = process.env.CORS_PROXY_URL || 'https://almostnode-cors-proxy.langtail.workers.dev/?url=';
var openai = createOpenAI({
apiKey: process.env.OPENAI_API_KEY || '',
fetch: function(url, init) {
var proxiedUrl = CORS_PROXY + encodeURIComponent(String(url));
return globalThis.fetch(proxiedUrl, init);
},
});
var SYSTEM_PROMPT = 'You are a frontend developer agent. You help users build and modify a Next.{
"name": "@jacob-ebey/almostnode",
"version": "0.4.0",
"description": "Node.js in your browser. Just like that.",
"type": "module",
"license": "MIT",
"keywords": [
"node",
"browser",
"runtime",
"virtual-filesystem",
"sandbox",
"vite",
"nextjs",
"hmr",
"typescript"
],
"repository": {
"type": "git",
"url": "https://github.com/macaly/almostnode.git"
},
"homepage": "https://github.com/macaly/almostnode#readme",
"bugs": {
"url": "https://github.com/macaly/almostnode/issues"
},
"author": "",
"engines": {
"node": ">=20.0.0"
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.mjs"
},
"require": {
"types": "./dist/index.d.ts",
"default": "./dist/index.cjs"
}
},
"./vite": {
"import": {
"types": "./dist/vite-plugin.d.ts",
"default": "./dist/vite-plugin.mjs"
},
"require": {
"types": "./dist/vite-plugin.d.ts",
"default": "./dist/vite-plugin.cjs"
}
},
"./next": {
"import": {
"types": "./dist/next-plugin.d.ts",
"default": "./dist/next-plugin.mjs"
},
"require": {
"types": "./dist/next-plugin.d.ts",
"default": "./dist/next-plugin.cjs"
}
}
},
"files": [
"src",
"dist"
],
"sideE
/**
* Agent Workbench - Virtual Project Seed
*
* Creates a Next.js project in VFS with:
* - Chat UI using useChat from @ai-sdk/react (App Router client page, loaded from esm.sh)
* - API route using streamText + Pages Router streaming (server, proven pattern)
* - Tools: read_file, write_file, replace_in_file, list_files, run_bash
*/
import { VirtualFS } from './virtual-fs';
const PACKAGE_JSON = {
name: 'agent-workbench-app',
version: '0.1.0',
private: true,
scripts: {
dev: 'next dev',
build: 'next build',
start: 'next start',
},
dependencies: {
next: '^14.0.0',
react: '^18.2.0',
'react-dom': '^18.2.0',
ai: '^6.0.0',
'@ai-sdk/react': '^3.0.0',
},
};
// ── API Route (/pages/api/chat.ts) — Pages Router for proven streaming ──
const API_ROUTE = `import { streamText, tool, stepCountIs, convertToModelMessages } from 'ai';
import { createOpenAI } from '@ai-sdk/openai';
import { z } from 'zod';
import { readFile, writeFile, existsSync, listFiles, statSync, mkdirSync, runCommand, log } from '__project__';
var CORS_PROXY = process.env.CORS_PROXY_URL || 'https://almostnode-cors-proxy.langtail.workers.dev/?url=';
var openai = createOpenAI({
apiKey: process.env.OPENAI_API_KEY || '',
fetch: function(url, init) {
var proxiedUrl = CORS_PROXY + encodeURIComponent(String(url));
return globalThis.fetch(proxiedUrl, init);
},
});
var SYSTEM_PROMPT = 'You are a frontend developer agent. You help users build and modify a Next.