mirror of
https://github.com/different-ai/openwork
synced 2026-04-27 18:07:25 +02:00
183 lines
5.3 KiB
JavaScript
183 lines
5.3 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import test from "node:test";
|
|
|
|
import { startBridge } from "../dist/bridge.js";
|
|
|
|
function createLoggerStub() {
|
|
const base = {
|
|
child() {
|
|
return base;
|
|
},
|
|
debug() {},
|
|
info() {},
|
|
warn() {},
|
|
error() {},
|
|
};
|
|
return base;
|
|
}
|
|
|
|
test("bridge: routes sessions per peer directory binding within workspace", async () => {
|
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "opencodeRouter-multiws-"));
|
|
const wsA = path.join(dir, "ws-a");
|
|
const wsB = path.join(wsA, "project-b");
|
|
fs.mkdirSync(wsA, { recursive: true });
|
|
fs.mkdirSync(wsB, { recursive: true });
|
|
|
|
const dbPath = path.join(dir, "opencode-router.db");
|
|
const sent = [];
|
|
const created = [];
|
|
const prompted = [];
|
|
|
|
const slackAdapter = {
|
|
key: "slack:default",
|
|
name: "slack",
|
|
identityId: "default",
|
|
maxTextLength: 39_000,
|
|
async start() {},
|
|
async stop() {},
|
|
async sendText(peerId, text) {
|
|
sent.push({ peerId, text });
|
|
},
|
|
};
|
|
|
|
const clientFactory = (directory) => {
|
|
const dirLabel = directory;
|
|
return {
|
|
global: {
|
|
health: async () => ({ healthy: true, version: "test" }),
|
|
},
|
|
session: {
|
|
create: async () => {
|
|
created.push(dirLabel);
|
|
return { id: `session-${created.length}` };
|
|
},
|
|
prompt: async () => {
|
|
prompted.push(dirLabel);
|
|
return { parts: [{ type: "text", text: `pong:${path.basename(dirLabel)}` }] };
|
|
},
|
|
},
|
|
};
|
|
};
|
|
|
|
const bridge = await startBridge(
|
|
{
|
|
configPath: path.join(dir, "opencode-router.json"),
|
|
configFile: { version: 1 },
|
|
opencodeUrl: "http://127.0.0.1:4096",
|
|
opencodeDirectory: wsA,
|
|
telegramBots: [],
|
|
slackApps: [],
|
|
dataDir: dir,
|
|
dbPath,
|
|
logFile: path.join(dir, "opencode-router.log"),
|
|
toolUpdatesEnabled: false,
|
|
groupsEnabled: false,
|
|
permissionMode: "allow",
|
|
toolOutputLimit: 1200,
|
|
healthPort: undefined,
|
|
logLevel: "silent",
|
|
},
|
|
createLoggerStub(),
|
|
undefined,
|
|
{
|
|
clientFactory,
|
|
adapters: new Map([["slack:default", slackAdapter]]),
|
|
disableEventStream: true,
|
|
disableHealthServer: true,
|
|
},
|
|
);
|
|
|
|
// Bind peer A to ws-a
|
|
await bridge.dispatchInbound({ channel: "slack", identityId: "default", peerId: "D-A", text: `/dir ${wsA}`, raw: {} });
|
|
await bridge.dispatchInbound({ channel: "slack", identityId: "default", peerId: "D-A", text: "ping", raw: {} });
|
|
|
|
// Bind peer B to ws-b
|
|
await bridge.dispatchInbound({ channel: "slack", identityId: "default", peerId: "D-B", text: `/dir ${wsB}`, raw: {} });
|
|
await bridge.dispatchInbound({ channel: "slack", identityId: "default", peerId: "D-B", text: "ping", raw: {} });
|
|
|
|
// Ensure prompts were routed to different workspace subdirectories
|
|
assert.ok(prompted.includes(wsA));
|
|
assert.ok(prompted.includes(wsB));
|
|
|
|
// Ensure output includes per-directory pong
|
|
const output = sent.map((m) => `${m.peerId}:${m.text}`).join("\n");
|
|
assert.ok(output.includes("D-A:pong:ws-a"));
|
|
assert.ok(output.includes("D-B:pong:project-b"));
|
|
|
|
await bridge.stop();
|
|
});
|
|
|
|
test("bridge: rejects /dir outside workspace root", async () => {
|
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "opencodeRouter-multiws-"));
|
|
const wsA = path.join(dir, "ws-a");
|
|
const outside = path.join(dir, "outside");
|
|
fs.mkdirSync(wsA, { recursive: true });
|
|
fs.mkdirSync(outside, { recursive: true });
|
|
|
|
const dbPath = path.join(dir, "opencode-router.db");
|
|
const prompted = [];
|
|
const sent = [];
|
|
|
|
const slackAdapter = {
|
|
key: "slack:default",
|
|
name: "slack",
|
|
identityId: "default",
|
|
maxTextLength: 39_000,
|
|
async start() {},
|
|
async stop() {},
|
|
async sendText(peerId, text) {
|
|
sent.push({ peerId, text });
|
|
},
|
|
};
|
|
|
|
const clientFactory = (directory) => ({
|
|
global: { health: async () => ({ healthy: true, version: "test" }) },
|
|
session: {
|
|
create: async () => ({ id: "session-1" }),
|
|
prompt: async () => {
|
|
prompted.push(directory);
|
|
return { parts: [{ type: "text", text: "pong" }] };
|
|
},
|
|
},
|
|
});
|
|
|
|
const bridge = await startBridge(
|
|
{
|
|
configPath: path.join(dir, "opencode-router.json"),
|
|
configFile: { version: 1 },
|
|
opencodeUrl: "http://127.0.0.1:4096",
|
|
opencodeDirectory: wsA,
|
|
telegramBots: [],
|
|
slackApps: [],
|
|
dataDir: dir,
|
|
dbPath,
|
|
logFile: path.join(dir, "opencode-router.log"),
|
|
toolUpdatesEnabled: false,
|
|
groupsEnabled: false,
|
|
permissionMode: "allow",
|
|
toolOutputLimit: 1200,
|
|
healthPort: undefined,
|
|
logLevel: "silent",
|
|
},
|
|
createLoggerStub(),
|
|
undefined,
|
|
{
|
|
clientFactory,
|
|
adapters: new Map([["slack:default", slackAdapter]]),
|
|
disableEventStream: true,
|
|
disableHealthServer: true,
|
|
},
|
|
);
|
|
|
|
await bridge.dispatchInbound({ channel: "slack", identityId: "default", peerId: "D-OUT", text: `/dir ${outside}`, raw: {} });
|
|
await bridge.dispatchInbound({ channel: "slack", identityId: "default", peerId: "D-OUT", text: "ping", raw: {} });
|
|
|
|
assert.ok(sent.some((m) => m.text.includes("Directory must stay within workspace root")));
|
|
assert.ok(prompted.every((dirPath) => dirPath === wsA));
|
|
|
|
await bridge.stop();
|
|
});
|