mirror of
https://github.com/different-ai/openwork
synced 2026-04-25 17:15:34 +02:00
feat(headless): bundle openwork server for openwrk (#338)
This commit is contained in:
@@ -29,7 +29,7 @@ The goal: make “agentic work” feel like a product, not a terminal.
|
||||
- `curl -fsSL https://raw.githubusercontent.com/different-ai/openwork/dev/packages/owpenbot/install.sh | bash`
|
||||
- run `owpenbot setup`, then `owpenbot whatsapp login`, then `owpenbot start`
|
||||
- full setup: [packages/owpenbot/README.md](./packages/owpenbot/README.md)
|
||||
- **Openwrk (CLI host)**: run OpenCode + OpenWork server without the desktop UI.
|
||||
- **Openwrk (CLI host)**: run OpenCode + OpenWork server without the desktop UI. Install with `npm install -g openwrk`.
|
||||
- docs: [packages/headless/README.md](./packages/headless/README.md)
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ npm install -g openwrk
|
||||
openwrk start --workspace /path/to/workspace --approval auto
|
||||
```
|
||||
|
||||
`openwrk` installs the OpenWork server dependency automatically. No extra install needed.
|
||||
|
||||
Or from source:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openwrk",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"description": "Headless OpenWork host orchestrator for OpenCode + OpenWork server + Owpenbot",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
@@ -36,7 +36,8 @@
|
||||
"access": "public"
|
||||
},
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "^1.1.31"
|
||||
"@opencode-ai/sdk": "^1.1.31",
|
||||
"openwork-server": "^0.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.10.2",
|
||||
|
||||
@@ -4,7 +4,9 @@ import { randomUUID } from "node:crypto";
|
||||
import { mkdir, stat, writeFile } from "node:fs/promises";
|
||||
import { createServer } from "node:net";
|
||||
import { hostname, networkInterfaces } from "node:os";
|
||||
import { join, resolve } from "node:path";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { access } from "node:fs/promises";
|
||||
import { createRequire } from "node:module";
|
||||
import { once } from "node:events";
|
||||
|
||||
import { createOpencodeClient } from "@opencode-ai/sdk/v2/client";
|
||||
@@ -158,6 +160,15 @@ async function fileExists(path: string): Promise<boolean> {
|
||||
}
|
||||
}
|
||||
|
||||
async function isExecutable(path: string): Promise<boolean> {
|
||||
try {
|
||||
await access(path);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureWorkspace(workspace: string): Promise<string> {
|
||||
const resolved = resolve(workspace);
|
||||
await mkdir(resolved, { recursive: true });
|
||||
@@ -292,11 +303,20 @@ function prefixStream(
|
||||
});
|
||||
}
|
||||
|
||||
function shouldUseBun(bin: string): boolean {
|
||||
if (!bin.endsWith(`${join("dist", "cli.js")}`)) return false;
|
||||
if (bin.includes("openwork-server")) return true;
|
||||
return bin.includes(`${join("packages", "server")}`);
|
||||
}
|
||||
|
||||
function resolveBinCommand(bin: string): { command: string; prefixArgs: string[] } {
|
||||
if (bin.endsWith(".ts")) {
|
||||
return { command: "bun", prefixArgs: [bin, "--"] };
|
||||
}
|
||||
if (bin.endsWith(".js")) {
|
||||
if (shouldUseBun(bin)) {
|
||||
return { command: "bun", prefixArgs: [bin, "--"] };
|
||||
}
|
||||
return { command: "node", prefixArgs: [bin, "--"] };
|
||||
}
|
||||
return { command: bin, prefixArgs: [] };
|
||||
@@ -309,6 +329,26 @@ function resolveBinPath(bin: string): string {
|
||||
return bin;
|
||||
}
|
||||
|
||||
async function resolveOpenworkServerBin(explicit?: string): Promise<string> {
|
||||
if (explicit) {
|
||||
return resolveBinPath(explicit);
|
||||
}
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
try {
|
||||
const pkgPath = require.resolve("openwork-server/package.json");
|
||||
const pkgDir = dirname(pkgPath);
|
||||
const cliPath = join(pkgDir, "dist", "cli.js");
|
||||
if (await isExecutable(cliPath)) {
|
||||
return cliPath;
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return "openwork-server";
|
||||
}
|
||||
|
||||
async function waitForHealthy(url: string, timeoutMs = 10_000, pollMs = 250): Promise<void> {
|
||||
const start = Date.now();
|
||||
let lastError: string | null = null;
|
||||
@@ -760,8 +800,8 @@ async function runStart(args: ParsedArgs) {
|
||||
const corsOrigins = parseList(corsValue);
|
||||
const connectHost = readFlag(args.flags, "connect-host");
|
||||
|
||||
const openworkServerBin = resolveBinPath(
|
||||
readFlag(args.flags, "openwork-server-bin") ?? process.env.OPENWORK_SERVER_BIN ?? "openwork-server",
|
||||
const openworkServerBin = await resolveOpenworkServerBin(
|
||||
readFlag(args.flags, "openwork-server-bin") ?? process.env.OPENWORK_SERVER_BIN,
|
||||
);
|
||||
const owpenbotBin = resolveBinPath(readFlag(args.flags, "owpenbot-bin") ?? process.env.OWPENBOT_BIN ?? "owpenbot");
|
||||
const owpenbotEnabled = readBool(args.flags, "owpenbot", true);
|
||||
|
||||
@@ -5,7 +5,14 @@ Filesystem-backed API for OpenWork remote clients. This package provides the Ope
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
pnpm --filter @different-ai/openwork-server dev -- \
|
||||
npm install -g openwork-server
|
||||
openwork-server --workspace /path/to/workspace --approval auto
|
||||
```
|
||||
|
||||
Or from source:
|
||||
|
||||
```bash
|
||||
pnpm --filter openwork-server dev -- \
|
||||
--workspace /path/to/workspace \
|
||||
--approval auto
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@different-ai/openwork-server",
|
||||
"name": "openwork-server",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"description": "Filesystem-backed API for OpenWork remote clients",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"openwork-server": "dist/cli.js"
|
||||
@@ -14,6 +14,30 @@
|
||||
"start": "bun dist/cli.js",
|
||||
"typecheck": "tsc -p tsconfig.json --noEmit"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/different-ai/openwork.git",
|
||||
"directory": "packages/server"
|
||||
},
|
||||
"homepage": "https://github.com/different-ai/openwork/tree/dev/packages/server",
|
||||
"bugs": {
|
||||
"url": "https://github.com/different-ai/openwork/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"openwork",
|
||||
"server",
|
||||
"opencode",
|
||||
"headless",
|
||||
"cli"
|
||||
],
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsonc-parser": "^3.2.1",
|
||||
"minimatch": "^10.0.1",
|
||||
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -88,6 +88,9 @@ importers:
|
||||
'@opencode-ai/sdk':
|
||||
specifier: ^1.1.31
|
||||
version: 1.1.39
|
||||
openwork-server:
|
||||
specifier: ^0.1.0
|
||||
version: link:../server
|
||||
devDependencies:
|
||||
'@types/node':
|
||||
specifier: ^22.10.2
|
||||
|
||||
Reference in New Issue
Block a user