Commit 782eb235 authored by edy's avatar edy

fix(desktop): inject workspace path into workspace entry env

parent 94996437
...@@ -69,7 +69,10 @@ import { ...@@ -69,7 +69,10 @@ import {
buildProjectModelRuntime, buildProjectModelRuntime,
materializeProjectModelRuntime materializeProjectModelRuntime
} from "./services/project-model-runtime.js"; } from "./services/project-model-runtime.js";
import { buildWorkspaceEntryLobsterEnv } from "./services/workspace-entry-lobster-env.js"; import {
buildWorkspaceEntryLobsterEnv,
buildWorkspaceEntryWorkspacePathEnv
} from "./services/workspace-entry-lobster-env.js";
import { import {
refreshProjectContextAfterExecution, refreshProjectContextAfterExecution,
shouldRefreshProjectContextAfterExecution shouldRefreshProjectContextAfterExecution
...@@ -832,6 +835,11 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc ...@@ -832,6 +835,11 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
return buildWorkspaceEntryLobsterEnv(await secretManager.getApiKey()); return buildWorkspaceEntryLobsterEnv(await secretManager.getApiKey());
}; };
const prepareWorkspaceEntryWorkspacePathEnv = async (): Promise<Record<string, string>> => {
const config = await configService.load();
return buildWorkspaceEntryWorkspacePathEnv(config.workspacePath);
};
const resolveConfiguredChatModel = async (config?: AppConfig) => { const resolveConfiguredChatModel = async (config?: AppConfig) => {
const nextConfig = config ?? await getEffectiveConfig(); const nextConfig = config ?? await getEffectiveConfig();
const baseUrl = nextConfig.expertModelConfig.copywriting.baseUrl.trim(); const baseUrl = nextConfig.expertModelConfig.copywriting.baseUrl.trim();
...@@ -1998,6 +2006,7 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc ...@@ -1998,6 +2006,7 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
try { try {
if (preparedExecution.decision.kind === "workspace-entry") { if (preparedExecution.decision.kind === "workspace-entry") {
const lobsterEnv = await prepareWorkspaceEntryLobsterEnv(); const lobsterEnv = await prepareWorkspaceEntryLobsterEnv();
const workspacePathEnv = await prepareWorkspaceEntryWorkspacePathEnv();
const projectModelEnv = await prepareProjectModelRuntime( const projectModelEnv = await prepareProjectModelRuntime(
preparedExecution.sessionState.projectId, preparedExecution.sessionState.projectId,
preparedExecution.sessionState.projectRoot preparedExecution.sessionState.projectRoot
...@@ -2010,7 +2019,8 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc ...@@ -2010,7 +2019,8 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
attachments: preparedExecution.attachments, attachments: preparedExecution.attachments,
extraEnv: { extraEnv: {
...projectModelEnv, ...projectModelEnv,
...lobsterEnv ...lobsterEnv,
...workspacePathEnv
} }
}); });
if ("handoff" in result) { if ("handoff" in result) {
...@@ -2142,6 +2152,7 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc ...@@ -2142,6 +2152,7 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
try { try {
if (decision.kind === "workspace-entry") { if (decision.kind === "workspace-entry") {
const lobsterEnv = await prepareWorkspaceEntryLobsterEnv(); const lobsterEnv = await prepareWorkspaceEntryLobsterEnv();
const workspacePathEnv = await prepareWorkspaceEntryWorkspacePathEnv();
const projectModelEnv = await prepareProjectModelRuntime(project.id, projectRoot); const projectModelEnv = await prepareProjectModelRuntime(project.id, projectRoot);
const result = await projectWorkspaceExecutor.execute({ const result = await projectWorkspaceExecutor.execute({
sessionId, sessionId,
...@@ -2151,7 +2162,8 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc ...@@ -2151,7 +2162,8 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
attachments: [], attachments: [],
extraEnv: { extraEnv: {
...projectModelEnv, ...projectModelEnv,
...lobsterEnv ...lobsterEnv,
...workspacePathEnv
} }
}); });
if ("handoff" in result) { if ("handoff" in result) {
...@@ -2473,6 +2485,7 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc ...@@ -2473,6 +2485,7 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
void (async () => { void (async () => {
try { try {
const lobsterEnv = await prepareWorkspaceEntryLobsterEnv(); const lobsterEnv = await prepareWorkspaceEntryLobsterEnv();
const workspacePathEnv = await prepareWorkspaceEntryWorkspacePathEnv();
const projectModelEnv = await prepareProjectModelRuntime( const projectModelEnv = await prepareProjectModelRuntime(
preparedExecution.sessionState.projectId, preparedExecution.sessionState.projectId,
preparedExecution.sessionState.projectRoot preparedExecution.sessionState.projectRoot
...@@ -2485,7 +2498,8 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc ...@@ -2485,7 +2498,8 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
attachments: preparedExecution.attachments, attachments: preparedExecution.attachments,
extraEnv: { extraEnv: {
...projectModelEnv, ...projectModelEnv,
...lobsterEnv ...lobsterEnv,
...workspacePathEnv
} }
}, { }, {
onStarted: (runId) => { onStarted: (runId) => {
......
const LOBSTER_KEY_REQUIRED_MESSAGE = "请先绑定龙虾密钥"; const LOBSTER_KEY_REQUIRED_MESSAGE = "请先绑定龙虾密钥";
const WORKSPACE_PATH_REQUIRED_MESSAGE = "请先设置工作目录";
export function buildWorkspaceEntryLobsterEnv(apiKey: string | undefined): Record<string, string> { export function buildWorkspaceEntryLobsterEnv(apiKey: string | undefined): Record<string, string> {
const lobsterKey = apiKey?.trim(); const lobsterKey = apiKey?.trim();
...@@ -11,3 +12,14 @@ export function buildWorkspaceEntryLobsterEnv(apiKey: string | undefined): Recor ...@@ -11,3 +12,14 @@ export function buildWorkspaceEntryLobsterEnv(apiKey: string | undefined): Recor
OPENCLAW_EMPLOYEE_API_KEY: lobsterKey OPENCLAW_EMPLOYEE_API_KEY: lobsterKey
}; };
} }
export function buildWorkspaceEntryWorkspacePathEnv(workspacePathInput: string | undefined): Record<string, string> {
const workspacePath = workspacePathInput?.trim();
if (!workspacePath) {
throw new Error(WORKSPACE_PATH_REQUIRED_MESSAGE);
}
return {
QJCLAW_WORKSPACE_PATH: workspacePath
};
}
import { mkdir, rm, writeFile } from "node:fs/promises"; import { mkdir, rm, writeFile } from "node:fs/promises";
import path from "node:path"; import path from "node:path";
import { fileURLToPath } from "node:url"; import { fileURLToPath } from "node:url";
import { buildWorkspaceEntryLobsterEnv } from "../../apps/desktop/src/main/services/workspace-entry-lobster-env.js"; import {
buildWorkspaceEntryLobsterEnv,
buildWorkspaceEntryWorkspacePathEnv
} from "../../apps/desktop/src/main/services/workspace-entry-lobster-env.js";
function assert(condition: unknown, message: string): asserts condition { function assert(condition: unknown, message: string): asserts condition {
if (!condition) { if (!condition) {
...@@ -21,6 +24,18 @@ function assertThrowsMissingKey(input: string | undefined): void { ...@@ -21,6 +24,18 @@ function assertThrowsMissingKey(input: string | undefined): void {
throw new Error("Missing-key path did not throw."); throw new Error("Missing-key path did not throw.");
} }
function assertThrowsMissingWorkspacePath(input: string | undefined): void {
try {
buildWorkspaceEntryWorkspacePathEnv(input);
} catch (error) {
assert(error instanceof Error, "Missing-workspace-path path should throw an Error.");
assert(error.message === "请先设置工作目录", "Missing-workspace-path error message changed.");
return;
}
throw new Error("Missing-workspace-path path did not throw.");
}
async function main(): Promise<void> { async function main(): Promise<void> {
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
...@@ -36,13 +51,22 @@ async function main(): Promise<void> { ...@@ -36,13 +51,22 @@ async function main(): Promise<void> {
assert(env.OPENCLAW_EMPLOYEE_API_KEY === "lobster-secret", "Compatibility env var should use the trimmed key."); assert(env.OPENCLAW_EMPLOYEE_API_KEY === "lobster-secret", "Compatibility env var should use the trimmed key.");
assert(Object.keys(env).length === 2, "Workspace-entry lobster env should expose only the two expected variables."); assert(Object.keys(env).length === 2, "Workspace-entry lobster env should expose only the two expected variables.");
const workspacePathEnv = buildWorkspaceEntryWorkspacePathEnv(" /tmp/qjc-workspace ");
assert(workspacePathEnv.QJCLAW_WORKSPACE_PATH === "/tmp/qjc-workspace", "Workspace path env var should use the trimmed path.");
assert(Object.keys(workspacePathEnv).length === 1, "Workspace-entry workspace path env should expose only the expected variable.");
assertThrowsMissingKey(undefined); assertThrowsMissingKey(undefined);
assertThrowsMissingKey(""); assertThrowsMissingKey("");
assertThrowsMissingKey(" "); assertThrowsMissingKey(" ");
assertThrowsMissingWorkspacePath(undefined);
assertThrowsMissingWorkspacePath("");
assertThrowsMissingWorkspacePath(" ");
await writeFile(resultPath, JSON.stringify({ await writeFile(resultPath, JSON.stringify({
ok: true, ok: true,
envKeys: Object.keys(env) envKeys: Object.keys(env),
workspacePathEnvKeys: Object.keys(workspacePathEnv),
workspacePath: workspacePathEnv.QJCLAW_WORKSPACE_PATH
}, null, 2), "utf8"); }, null, 2), "utf8");
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment