feat: implement OpenClaw process owner and runtime path utilities

- Add OpenClawProcessOwner class to manage the lifecycle of the OpenClaw process.
- Introduce utility functions for managing OpenClaw runtime paths.
- Update session store to normalize agent session keys and migrate existing keys.
- Refactor main process to handle local provider API routing through a new dispatch function.
- Enhance token usage writer to utilize a new session key parsing function.
- Create agents management store to handle agent data and interactions.
- Update chat store to integrate agent selection and session management.
- Introduce AgentsSection component for displaying agent information in the UI.
- Refactor HomePage to support agent selection and display current agent.
- Update routing to reflect new agents page structure.
This commit is contained in:
duanshuwen
2026-04-17 21:32:06 +08:00
parent eca70425cf
commit e9f3a29886
33 changed files with 1526 additions and 2428 deletions

74
electron/utils/paths.ts Normal file
View File

@@ -0,0 +1,74 @@
import { app } from 'electron';
import { existsSync, mkdirSync, realpathSync } from 'node:fs';
import { homedir } from 'node:os';
import { join } from 'node:path';
export const OPENCLAW_CONFIG_DIR_NAME = '.openclaw';
export const OPENCLAW_RUNTIME_DIR_NAME = 'runtime';
export const OPENCLAW_PACKAGE_DIR_NAME = 'openclaw';
export const OPENCLAW_ENTRY_FILE_NAME = 'openclaw.mjs';
export interface OpenClawRuntimePaths {
configDir: string;
runtimeDir: string;
dir: string;
resolvedDir: string;
entryPath: string;
}
export function getOpenClawConfigDir(): string {
return join(homedir(), OPENCLAW_CONFIG_DIR_NAME);
}
export function getOpenClawRuntimeDir(): string {
return join(getOpenClawConfigDir(), OPENCLAW_RUNTIME_DIR_NAME);
}
export function getOpenClawDir(): string {
if (app.isPackaged) {
return join(process.resourcesPath, OPENCLAW_PACKAGE_DIR_NAME);
}
return join(app.getAppPath(), 'node_modules', OPENCLAW_PACKAGE_DIR_NAME);
}
export function getOpenClawResolvedDir(): string {
const dir = getOpenClawDir();
if (!existsSync(dir)) {
return dir;
}
try {
return realpathSync(dir);
} catch {
return dir;
}
}
export function getOpenClawEntryPath(): string {
return join(getOpenClawDir(), OPENCLAW_ENTRY_FILE_NAME);
}
export function ensureDir(dir: string): string {
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
}
return dir;
}
export function ensureOpenClawRuntimeLayout(
paths: OpenClawRuntimePaths = getOpenClawRuntimePaths(),
): OpenClawRuntimePaths {
ensureDir(paths.configDir);
ensureDir(paths.runtimeDir);
return paths;
}
export function getOpenClawRuntimePaths(): OpenClawRuntimePaths {
return {
configDir: getOpenClawConfigDir(),
runtimeDir: getOpenClawRuntimeDir(),
dir: getOpenClawDir(),
resolvedDir: getOpenClawResolvedDir(),
entryPath: getOpenClawEntryPath(),
};
}

View File

@@ -1,23 +1,12 @@
import { app } from 'electron';
import * as fs from 'fs';
import * as path from 'path';
import { parseSessionKey } from '@runtime/lib/agents';
export function getTranscriptFilePath(sessionKey: string): string {
let agentId: string;
let sessionId: string;
if (sessionKey.startsWith('agent:')) {
const parts = sessionKey.split(':');
agentId = parts[1] ?? 'default';
sessionId = parts.slice(2).join(':') || sessionKey;
} else if (sessionKey.startsWith('local:')) {
const parts = sessionKey.split(':');
agentId = parts[1] ?? 'local';
sessionId = parts.slice(2).join(':') || sessionKey;
} else {
agentId = 'default';
sessionId = sessionKey;
}
const parsed = parseSessionKey(sessionKey);
let agentId = parsed.isAgentSession ? parsed.agentId : 'default';
let sessionId = parsed.isAgentSession ? parsed.sessionId : sessionKey;
if (!sessionId) {
sessionId = 'unknown';