fixed members login and permissions issues
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { join, relative } from "path";
|
||||
import type { Subprocess } from "bun";
|
||||
import type { PiEvent, MessageCost } from "./types";
|
||||
import { readApiKeys } from "../server-settings/pi-mono";
|
||||
@@ -8,11 +9,10 @@ export type PiEventHandler = (event: PiEvent) => void;
|
||||
|
||||
type SandboxOptions = {
|
||||
userId: number;
|
||||
username: string;
|
||||
homeDir: string;
|
||||
};
|
||||
|
||||
const CONTAINER_HOME = '/home/officer';
|
||||
const CONTAINER_PI_CONFIG = '/home/officer/.pi/agent';
|
||||
|
||||
export async function spawnPi(
|
||||
cwd: string,
|
||||
model: string,
|
||||
@@ -25,21 +25,25 @@ export async function spawnPi(
|
||||
const storedKeys = await readApiKeys();
|
||||
const dockerPath = Bun.which('docker') ?? 'docker';
|
||||
const containerId = `officer-terminal-${sandbox.userId}`;
|
||||
const containerHome = `/home/${sandbox.username}`;
|
||||
const containerPiConfig = `${containerHome}/.pi/agent`;
|
||||
const piArgs = ['pi', '--mode', 'rpc', '--no-extensions', '--no-skills', '--no-prompt-templates', '--no-themes'];
|
||||
if (model) piArgs.push('--model', model);
|
||||
|
||||
// Build env flags: Pi config dir + all stored API keys
|
||||
const envFlags = [
|
||||
'-e', `PI_CODING_AGENT_DIR=${CONTAINER_PI_CONFIG}`,
|
||||
'-e', `HOME=${CONTAINER_HOME}`,
|
||||
'-e', `PI_CODING_AGENT_DIR=${containerPiConfig}`,
|
||||
'-e', `HOME=${containerHome}`,
|
||||
];
|
||||
for (const [key, value] of Object.entries(storedKeys)) {
|
||||
if (value?.trim()) envFlags.push('-e', `${key}=${value.trim()}`);
|
||||
}
|
||||
|
||||
const rel = relative(sandbox.homeDir, cwd);
|
||||
const workdir = rel && !rel.startsWith('..') ? join(containerHome, rel) : containerHome;
|
||||
proc = Bun.spawn([
|
||||
dockerPath, 'exec', '-i',
|
||||
'-w', CONTAINER_HOME,
|
||||
'-w', workdir,
|
||||
...envFlags,
|
||||
containerId,
|
||||
...piArgs,
|
||||
|
||||
@@ -4,6 +4,8 @@ import type { ClientMessage, ServerMessage, Message, PiEvent } from './types';
|
||||
import { sessionManager } from './session-manager';
|
||||
import * as storage from './storage';
|
||||
import * as piBridge from './pi-bridge';
|
||||
import { join, resolve } from 'path';
|
||||
import { homedir } from 'os';
|
||||
import { getHomeDir, getUserSettingsFile } from '../../../servers/data-path';
|
||||
import { logger } from './logger';
|
||||
|
||||
@@ -27,12 +29,27 @@ async function getUserDefaultModel(email: string): Promise<string | null> {
|
||||
type WSData = {
|
||||
userId: number;
|
||||
email: string;
|
||||
username: string;
|
||||
role: string;
|
||||
provider: string;
|
||||
};
|
||||
|
||||
const IDLE_TIMEOUT_MS = 60 * 60 * 1000; // 1 hour
|
||||
|
||||
const resolveRoot = (email: string, root?: string) => {
|
||||
if (!root || root === 'home') return getHomeDir(email);
|
||||
if (root === '~') return homedir();
|
||||
if (root === 'officer.dev') return resolve(process.cwd(), '..');
|
||||
return getHomeDir(email);
|
||||
};
|
||||
|
||||
const resolveCwd = (home: string, cwd?: string) => {
|
||||
if (!cwd || cwd === '~') return home;
|
||||
if (cwd.startsWith('~/')) return join(home, cwd.slice(2));
|
||||
if (cwd.startsWith('/')) return join(home, cwd.slice(1));
|
||||
return home;
|
||||
};
|
||||
|
||||
const wsToSessionMap = new WeakMap<any, string>();
|
||||
|
||||
function sendToClient(ws: ServerWebSocket<WSData> | null, msg: ServerMessage): void {
|
||||
@@ -220,9 +237,9 @@ function createEventHandler(sessionId: string, model: string, cwd: string) {
|
||||
|
||||
async function handleChat(
|
||||
ws: ServerWebSocket<WSData>,
|
||||
msg: { prompt: string; sessionId?: string; model?: string; cwd?: string; sandboxed?: boolean; groupSlug?: string; attachmentIds?: string[] }
|
||||
msg: { prompt: string; sessionId?: string; model?: string; cwd?: string; cwdRoot?: string; sandboxed?: boolean; groupSlug?: string; attachmentIds?: string[] }
|
||||
): Promise<void> {
|
||||
const { email, userId } = ws.data;
|
||||
const { email, username, userId } = ws.data;
|
||||
const sessionId = msg.sessionId || randomUUID();
|
||||
|
||||
// Use provided model, or fall back to user default, or use system default
|
||||
@@ -248,7 +265,9 @@ async function handleChat(
|
||||
userDefault,
|
||||
});
|
||||
|
||||
const cwd = msg.cwd || getHomeDir(email);
|
||||
const homeDir = getHomeDir(email);
|
||||
const rootDir = resolveRoot(email, msg.cwdRoot);
|
||||
const cwd = resolveCwd(rootDir, msg.cwd);
|
||||
const groupSlug = msg.groupSlug || null;
|
||||
|
||||
const sandboxed = msg.sandboxed ?? false;
|
||||
@@ -262,7 +281,7 @@ async function handleChat(
|
||||
if (!session.piProcess) {
|
||||
try {
|
||||
const onEvent = createEventHandler(sessionId, model, cwd);
|
||||
session.piProcess = await piBridge.spawnPi(cwd, model, onEvent, sandboxed ? { userId } : undefined);
|
||||
session.piProcess = await piBridge.spawnPi(cwd, model, onEvent, sandboxed ? { userId, username, homeDir } : undefined);
|
||||
logger.info('Spawned Pi process for session', { sessionId, model, cwd, sandboxed });
|
||||
} catch (err) {
|
||||
logger.error('Failed to spawn Pi process', { sessionId, model, error: String(err) });
|
||||
@@ -328,7 +347,8 @@ async function handleResume(
|
||||
// Spawn fresh Pi process if needed
|
||||
if (!session.piProcess) {
|
||||
try {
|
||||
const sandbox = session.sandboxed && session.userId ? { userId: session.userId } : undefined;
|
||||
const homeDir = getHomeDir(email);
|
||||
const sandbox = session.sandboxed && session.userId ? { userId: session.userId, username: ws.data.username, homeDir } : undefined;
|
||||
const onEvent = createEventHandler(sessionId, session.model, session.cwd);
|
||||
session.piProcess = await piBridge.spawnPi(session.cwd, session.model, onEvent, sandbox);
|
||||
logger.info('Spawned fresh Pi process for resumed session', { sessionId, model: session.model, sandboxed: session.sandboxed });
|
||||
|
||||
Reference in New Issue
Block a user