mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-04-25 00:16:29 +02:00
feat(x): add headless server runner and Dockerfile for agent core
This commit is contained in:
parent
601f5af978
commit
33f526ba53
5 changed files with 187 additions and 0 deletions
36
apps/x/DOCKER.md
Normal file
36
apps/x/DOCKER.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# Running Rowboat (Headless) in Docker
|
||||
|
||||
You can run the core agent logic of Rowboat in a Docker container, suitable for server environments or always-on agents.
|
||||
|
||||
## Build
|
||||
|
||||
From the `apps/x` directory:
|
||||
|
||||
```bash
|
||||
docker build -t rowboat-agent .
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
You need to mount a volume for the data directory (`~/.rowboat`) to persist your knowledge graph and credentials.
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name rowboat \
|
||||
-v $(pwd)/rowboat-data:/data/.rowboat \
|
||||
rowboat-agent
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The agent uses the configuration files in your data volume (`/data/.rowboat/config/`).
|
||||
If you are starting fresh, you may need to manually populate `models.json` or `config.json` in that volume, as there is no UI to guide you through onboarding in this headless mode.
|
||||
|
||||
### Environment Variables
|
||||
|
||||
You can inject API keys via environment variables which Rowboat will pick up (if configured to read them):
|
||||
|
||||
- `OPENAI_API_KEY`
|
||||
- `ANTHROPIC_API_KEY`
|
||||
- `GOOGLE_API_KEY`
|
||||
```
|
||||
52
apps/x/Dockerfile
Normal file
52
apps/x/Dockerfile
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
FROM node:22-slim
|
||||
|
||||
# Install system dependencies if needed (e.g. for native modules)
|
||||
RUN apt-get update && apt-get install -y \
|
||||
python3 \
|
||||
make \
|
||||
g++ \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Enable pnpm
|
||||
RUN corepack enable
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy workspace config
|
||||
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
|
||||
|
||||
# Copy packages
|
||||
COPY apps/server ./apps/server
|
||||
COPY packages/core ./packages/core
|
||||
COPY packages/shared ./packages/shared
|
||||
# Note: we skip apps/main, apps/renderer, apps/preload as they are Electron-specific
|
||||
|
||||
# Install dependencies (skipping Electron devDeps if possible, but they are in root)
|
||||
# We might need to ignore scripts or optional deps
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# Build dependencies in order
|
||||
WORKDIR /app/packages/shared
|
||||
RUN npm run build
|
||||
|
||||
WORKDIR /app/packages/core
|
||||
RUN npm run build
|
||||
|
||||
WORKDIR /app/apps/server
|
||||
RUN npm run build
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Set environment to production
|
||||
ENV NODE_ENV=production
|
||||
|
||||
# The app uses ~/.rowboat for storage by default.
|
||||
# In Docker, we should probably mount a volume or set HOME.
|
||||
# Let's verify if we need to override the path via env var, but the code hardcodes path.join(homedir(), ".rowboat")
|
||||
# So setting HOME=/data should work, provided we create the dir.
|
||||
ENV HOME=/data
|
||||
RUN mkdir -p /data/.rowboat
|
||||
|
||||
VOLUME /data/.rowboat
|
||||
|
||||
CMD ["node", "apps/server/dist/main.js"]
|
||||
21
apps/x/apps/server/package.json
Normal file
21
apps/x/apps/server/package.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "@x/server",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "dist/main.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "node dist/main.js",
|
||||
"dev": "tsx src/main.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@x/core": "workspace:*",
|
||||
"@x/shared": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tsx": "^4.19.1",
|
||||
"typescript": "^5.6.3",
|
||||
"@types/node": "^22.7.5"
|
||||
}
|
||||
}
|
||||
67
apps/x/apps/server/src/main.ts
Normal file
67
apps/x/apps/server/src/main.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import { init as initGmailSync } from "@x/core/dist/knowledge/sync_gmail.js";
|
||||
import { init as initCalendarSync } from "@x/core/dist/knowledge/sync_calendar.js";
|
||||
import { init as initFirefliesSync } from "@x/core/dist/knowledge/sync_fireflies.js";
|
||||
import { init as initGranolaSync } from "@x/core/dist/knowledge/granola/sync.js";
|
||||
import { init as initGraphBuilder } from "@x/core/dist/knowledge/build_graph.js";
|
||||
import { init as initPreBuiltRunner } from "@x/core/dist/pre_built/runner.js";
|
||||
import { init as initAgentRunner } from "@x/core/dist/agent-schedule/runner.js";
|
||||
import { initConfigs } from "@x/core/dist/config/initConfigs.js";
|
||||
import { startWorkspaceWatcher } from "@x/core/dist/workspace/watcher.js";
|
||||
|
||||
async function main() {
|
||||
console.log("Rowboat Headless Server starting...");
|
||||
|
||||
// Initialize all config files
|
||||
await initConfigs();
|
||||
console.log("Configs initialized.");
|
||||
|
||||
// Start workspace watcher (optional in headless, but good for reactivity if files change)
|
||||
// We need to import it from core if possible, or reimplement the watcher start logic if it was only in main.ts
|
||||
// Looking at main.ts imports: import { startWorkspaceWatcher } from "./ipc.js";
|
||||
// Wait, startWorkspaceWatcher in main.ts came from "./ipc.js". I need to find the real core watcher.
|
||||
// I saw "rowboat-workspace/apps/x/packages/core/src/workspace/watcher.ts" in grep results.
|
||||
// So I can import it directly.
|
||||
|
||||
// Note: The main.ts version wrapped it. I will try to use the core one directly if available.
|
||||
// Let's assume the side-effects are safe.
|
||||
|
||||
// Start services
|
||||
console.log("Starting Gmail sync...");
|
||||
initGmailSync();
|
||||
|
||||
console.log("Starting Calendar sync...");
|
||||
initCalendarSync();
|
||||
|
||||
console.log("Starting Fireflies sync...");
|
||||
initFirefliesSync();
|
||||
|
||||
console.log("Starting Granola sync...");
|
||||
initGranolaSync();
|
||||
|
||||
console.log("Starting Graph Builder...");
|
||||
initGraphBuilder();
|
||||
|
||||
console.log("Starting Pre-built Runner...");
|
||||
initPreBuiltRunner();
|
||||
|
||||
console.log("Starting Agent Runner...");
|
||||
initAgentRunner();
|
||||
|
||||
console.log("Rowboat Headless Server is running. Press Ctrl+C to stop.");
|
||||
|
||||
// Keep process alive
|
||||
process.stdin.resume();
|
||||
|
||||
const cleanup = () => {
|
||||
console.log("Stopping Rowboat Headless Server...");
|
||||
process.exit(0);
|
||||
};
|
||||
|
||||
process.on("SIGINT", cleanup);
|
||||
process.on("SIGTERM", cleanup);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error("Fatal error:", err);
|
||||
process.exit(1);
|
||||
});
|
||||
11
apps/x/apps/server/tsconfig.json
Normal file
11
apps/x/apps/server/tsconfig.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"target": "ES2022"
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue