sensorium-mcp 3.0.71 → 3.0.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +48 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +123 -1
- package/dist/config.js.map +1 -1
- package/dist/dashboard/presets.d.ts.map +1 -1
- package/dist/dashboard/presets.js +0 -6
- package/dist/dashboard/presets.js.map +1 -1
- package/dist/dashboard/routes/claude.d.ts +12 -0
- package/dist/dashboard/routes/claude.d.ts.map +1 -0
- package/dist/dashboard/routes/claude.js +80 -0
- package/dist/dashboard/routes/claude.js.map +1 -0
- package/dist/dashboard/routes/copilot.d.ts +17 -0
- package/dist/dashboard/routes/copilot.d.ts.map +1 -0
- package/dist/dashboard/routes/copilot.js +153 -0
- package/dist/dashboard/routes/copilot.js.map +1 -0
- package/dist/dashboard/routes/threads.js +1 -1
- package/dist/dashboard/routes/threads.js.map +1 -1
- package/dist/dashboard/routes.d.ts.map +1 -1
- package/dist/dashboard/routes.js +9 -0
- package/dist/dashboard/routes.js.map +1 -1
- package/dist/dashboard/spa.html +11 -11
- package/dist/services/agent-spawn.service.d.ts +13 -27
- package/dist/services/agent-spawn.service.d.ts.map +1 -1
- package/dist/services/agent-spawn.service.js +30 -395
- package/dist/services/agent-spawn.service.js.map +1 -1
- package/dist/services/claude-spawn.service.d.ts +9 -0
- package/dist/services/claude-spawn.service.d.ts.map +1 -0
- package/dist/services/claude-spawn.service.js +113 -0
- package/dist/services/claude-spawn.service.js.map +1 -0
- package/dist/services/codex-spawn.service.d.ts +9 -0
- package/dist/services/codex-spawn.service.d.ts.map +1 -0
- package/dist/services/codex-spawn.service.js +106 -0
- package/dist/services/codex-spawn.service.js.map +1 -0
- package/dist/services/copilot-spawn.service.d.ts +10 -0
- package/dist/services/copilot-spawn.service.d.ts.map +1 -0
- package/dist/services/copilot-spawn.service.js +89 -0
- package/dist/services/copilot-spawn.service.js.map +1 -0
- package/dist/services/spawn-common.d.ts +55 -0
- package/dist/services/spawn-common.d.ts.map +1 -0
- package/dist/services/spawn-common.js +202 -0
- package/dist/services/spawn-common.js.map +1 -0
- package/dist/tools/defs/session-defs.d.ts.map +1 -1
- package/dist/tools/defs/session-defs.js +1 -3
- package/dist/tools/defs/session-defs.js.map +1 -1
- package/dist/tools/delegate-tool.js +1 -1
- package/dist/tools/delegate-tool.js.map +1 -1
- package/package.json +1 -1
- package/templates/plan-mode.default.md +2 -2
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude-specific spawn logic: CLI-path resolution and the Claude Code process
|
|
3
|
+
* launch (per-thread config dir, OAuth-token handling, git-bash discovery).
|
|
4
|
+
*/
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { copyFileSync, existsSync, mkdirSync, openSync, closeSync, unlinkSync } from "node:fs";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { getDefaultThreadModel, getDefaultWorkerModel, getClaudeCliPath, getClaudeOauthToken, getClaudeGitBashPath } from "../config.js";
|
|
10
|
+
import { log } from "../logger.js";
|
|
11
|
+
import { errorMessage } from "../utils.js";
|
|
12
|
+
import { PROCESS_BASE_DIR, THREAD_LOGS_DIR } from "./process.service.js";
|
|
13
|
+
import { buildClaudeMcpConfig } from "./mcp-config.service.js";
|
|
14
|
+
import { sanitizeSpawnEnv, resolveCliPath, resolveWindowsCliPath, parseSensoriumTransport, normalizeWorkingDirectory, registerSpawnedProcess, isStartupCleanupInProgress, concurrencyLimitError, } from "./spawn-common.js";
|
|
15
|
+
export const resolveClaudePath = () => {
|
|
16
|
+
const envCmd = process.env.CLAUDE_CLI_CMD ?? getClaudeCliPath();
|
|
17
|
+
if (envCmd)
|
|
18
|
+
return envCmd;
|
|
19
|
+
if (process.platform !== "win32")
|
|
20
|
+
return resolveCliPath("claude");
|
|
21
|
+
// On Windows `where claude` returns extensionless shim first, then .cmd, then .exe.
|
|
22
|
+
// The extensionless file cannot be spawned directly (ENOENT). Prefer .exe (real binary),
|
|
23
|
+
// fall back to .cmd (Volta/npm shim that needs shell:true), never use extensionless.
|
|
24
|
+
return resolveWindowsCliPath("claude");
|
|
25
|
+
};
|
|
26
|
+
export function spawnAgentProcess(claudePath, name, threadId, threadLifecycle, workingDirectory, memorySourceThreadId, threadType) {
|
|
27
|
+
if (isStartupCleanupInProgress())
|
|
28
|
+
return { error: "Server startup cleanup in progress - try again in a few seconds" };
|
|
29
|
+
const limitError = concurrencyLimitError();
|
|
30
|
+
if (limitError)
|
|
31
|
+
return limitError;
|
|
32
|
+
const transport = parseSensoriumTransport();
|
|
33
|
+
if (!transport)
|
|
34
|
+
return { error: `MCP_HTTP_PORT env var is not set or invalid (got: '${process.env.MCP_HTTP_PORT ?? ''}'). Claude threads require HTTP transport.` };
|
|
35
|
+
workingDirectory = normalizeWorkingDirectory(workingDirectory);
|
|
36
|
+
const safeName = name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
37
|
+
const logFilePath = join(THREAD_LOGS_DIR, `${safeName}_${threadId}_${new Date().toISOString().slice(0, 10)}.json`);
|
|
38
|
+
const effectiveConfigPath = buildClaudeMcpConfig(transport, threadId);
|
|
39
|
+
const claudeConfigDir = join(PROCESS_BASE_DIR, "claude-configs", String(threadId));
|
|
40
|
+
mkdirSync(claudeConfigDir, { recursive: true });
|
|
41
|
+
// When CLAUDE_CODE_OAUTH_TOKEN is set, skip credentials copy — the env var
|
|
42
|
+
// provides a long-lived setup-token that bypasses the broken OAuth refresh flow.
|
|
43
|
+
// Only copy settings.json (for preferences). Without this, expired credentials
|
|
44
|
+
// get copied on every restart, causing an infinite 401 → restart death loop.
|
|
45
|
+
const oauthToken = process.env.CLAUDE_CODE_OAUTH_TOKEN ?? getClaudeOauthToken();
|
|
46
|
+
const mainClaudeDir = join(homedir(), ".claude");
|
|
47
|
+
const sharedFiles = [...(oauthToken ? ["settings.json"] : [".credentials.json", "settings.json"]), "CLAUDE.md"];
|
|
48
|
+
// Remove stale credentials from previous runs so Claude doesn't try to use them
|
|
49
|
+
if (oauthToken) {
|
|
50
|
+
try {
|
|
51
|
+
const stale = join(claudeConfigDir, ".credentials.json");
|
|
52
|
+
if (existsSync(stale))
|
|
53
|
+
unlinkSync(stale);
|
|
54
|
+
}
|
|
55
|
+
catch { }
|
|
56
|
+
}
|
|
57
|
+
for (const shared of sharedFiles) {
|
|
58
|
+
const src = join(mainClaudeDir, shared);
|
|
59
|
+
const dst = join(claudeConfigDir, shared);
|
|
60
|
+
try {
|
|
61
|
+
if (existsSync(src))
|
|
62
|
+
copyFileSync(src, dst);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
log.debug(`[spawn] Failed to copy ${shared} for thread ${threadId}: ${errorMessage(err)}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// CLAUDE_CODE_OAUTH_TOKEN is on ENV_DENYLIST to avoid leaking to Copilot/Codex — pass explicitly only to Claude spawns
|
|
69
|
+
const spawnEnv = sanitizeSpawnEnv({ CLAUDE_CONFIG_DIR: claudeConfigDir, CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1", ...(oauthToken ? { CLAUDE_CODE_OAUTH_TOKEN: oauthToken } : {}), ...(memorySourceThreadId !== undefined ? { MEMORY_SOURCE_THREAD_ID: String(memorySourceThreadId) } : {}) });
|
|
70
|
+
if (process.platform === "win32" && !spawnEnv.CLAUDE_CODE_GIT_BASH_PATH) {
|
|
71
|
+
const configuredBash = getClaudeGitBashPath();
|
|
72
|
+
if (configuredBash)
|
|
73
|
+
spawnEnv.CLAUDE_CODE_GIT_BASH_PATH = configuredBash;
|
|
74
|
+
else
|
|
75
|
+
for (const candidate of [join(homedir(), "AppData", "Local", "Programs", "Git", "bin", "bash.exe"), "C:\\Program Files\\Git\\bin\\bash.exe", "C:\\Program Files (x86)\\Git\\bin\\bash.exe"])
|
|
76
|
+
if (existsSync(candidate)) {
|
|
77
|
+
spawnEnv.CLAUDE_CODE_GIT_BASH_PATH = candidate;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const claudeModel = threadType === "worker"
|
|
83
|
+
? (process.env.CLAUDE_WORKER_MODEL || getDefaultWorkerModel())
|
|
84
|
+
: (process.env.CLAUDE_MODEL || getDefaultThreadModel());
|
|
85
|
+
const sessionPrompt = `Start remote session with sensorium. Thread name = '${name}'. Use threadId=${threadId} when calling start_session.`;
|
|
86
|
+
// Send the child's stdout/stderr to a file descriptor the CHILD owns, not a
|
|
87
|
+
// pipe drained by this (ephemeral) server process. A pipe's only reader is
|
|
88
|
+
// this node process; when it dies on a self-update/restart the orphaned,
|
|
89
|
+
// detached child keeps writing, the ~64KB OS pipe buffer fills, and the next
|
|
90
|
+
// write() blocks the child's event loop forever — killing MCP polling, the
|
|
91
|
+
// API stream and any reconnect (the exact zombie we saw on thread 20869).
|
|
92
|
+
// A file fd is duplicated into the child at spawn and drained by the OS, so
|
|
93
|
+
// it survives our restarts. (64KB blocking is a PIPE phenomenon, not a file.)
|
|
94
|
+
const outFd = openSync(logFilePath, "a");
|
|
95
|
+
try {
|
|
96
|
+
const child = spawn(claudePath, ["--verbose", "--dangerously-skip-permissions", "--mcp-config", effectiveConfigPath, "--model", claudeModel, "-p", sessionPrompt, "--output-format", "stream-json"], { stdio: ["ignore", outFd, outFd], shell: process.platform === "win32" && /\.(cmd|bat)$/i.test(claudePath), detached: true, windowsHide: false, env: spawnEnv, cwd: workingDirectory || undefined });
|
|
97
|
+
return registerSpawnedProcess({ child, threadId, name, logFilePath, configPath: effectiveConfigPath, agentLabel: "Claude", memorySourceThreadId, threadType }, threadLifecycle);
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
// Parent no longer needs the fd — the child holds its own duplicated handle.
|
|
101
|
+
try {
|
|
102
|
+
closeSync(outFd);
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
log.debug(`[spawn] closeSync log fd failed for thread ${threadId}: ${errorMessage(err)}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
return { error: `Failed to spawn Claude process: ${errorMessage(err)}` };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=claude-spawn.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-spawn.service.js","sourceRoot":"","sources":["../../src/services/claude-spawn.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex-specific spawn logic: CLI/native-exe resolution (including Volta layout
|
|
3
|
+
* discovery on Windows) and the Codex `exec` process launch.
|
|
4
|
+
*/
|
|
5
|
+
import type { ThreadLifecycleService } from "./thread-lifecycle.service.js";
|
|
6
|
+
import { type SpawnResult } from "./spawn-common.js";
|
|
7
|
+
export declare const resolveCodexPath: () => string | null;
|
|
8
|
+
export declare function spawnCodexProcess(codexPath: string, name: string, threadId: number, threadLifecycle: ThreadLifecycleService, workingDirectory?: string, memorySourceThreadId?: number, threadType?: "worker" | "branch"): SpawnResult;
|
|
9
|
+
//# sourceMappingURL=codex-spawn.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-spawn.service.d.ts","sourceRoot":"","sources":["../../src/services/codex-spawn.service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAE5E,OAAO,EAQL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAK3B,eAAO,MAAM,gBAAgB,QAAO,MAAM,GAAG,IAC4C,CAAC;AAiC1F,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,sBAAsB,EAAE,gBAAgB,CAAC,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CA6BrO"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex-specific spawn logic: CLI/native-exe resolution (including Volta layout
|
|
3
|
+
* discovery on Windows) and the Codex `exec` process launch.
|
|
4
|
+
*/
|
|
5
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
6
|
+
import { existsSync, openSync, closeSync, readdirSync } from "node:fs";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { log } from "../logger.js";
|
|
10
|
+
import { errorMessage } from "../utils.js";
|
|
11
|
+
import { PROCESS_BASE_DIR, THREAD_LOGS_DIR } from "./process.service.js";
|
|
12
|
+
import { buildCodexMcpArgs } from "./mcp-config.service.js";
|
|
13
|
+
import { sanitizeSpawnEnv, resolveCliPath, resolveWindowsCliPath, parseSensoriumTransport, normalizeWorkingDirectory, registerSpawnedProcess, concurrencyLimitError, } from "./spawn-common.js";
|
|
14
|
+
const CODEX_HOME_DIR = join(PROCESS_BASE_DIR, "codex-home");
|
|
15
|
+
const DEFAULT_CODEX_MODEL = "";
|
|
16
|
+
export const resolveCodexPath = () => process.platform === "win32" ? resolveWindowsCliPath("codex") : resolveCliPath("codex");
|
|
17
|
+
const resolveCodexNodeExe = () => {
|
|
18
|
+
if (process.platform !== "win32")
|
|
19
|
+
return null;
|
|
20
|
+
try {
|
|
21
|
+
const localAppData = process.env.LOCALAPPDATA || join(homedir(), "AppData", "Local");
|
|
22
|
+
const voltaImage = join(localAppData, "Volta", "tools", "image");
|
|
23
|
+
const codexJs = join(voltaImage, "packages", "@openai", "codex", "node_modules", "@openai", "codex", "bin", "codex.js");
|
|
24
|
+
if (!existsSync(codexJs))
|
|
25
|
+
return null;
|
|
26
|
+
const voltaCmd = join(localAppData, "Volta", "bin", "volta.exe");
|
|
27
|
+
const nodePathResult = spawnSync(voltaCmd, ["run", "node", "-e", "process.stdout.write(process.execPath)"], { encoding: "utf-8", timeout: 5000, windowsHide: true });
|
|
28
|
+
if (nodePathResult.status === 0 && nodePathResult.stdout?.trim())
|
|
29
|
+
return { nodeExe: nodePathResult.stdout.trim(), codexJs };
|
|
30
|
+
const nodeDir = join(voltaImage, "node");
|
|
31
|
+
if (!existsSync(nodeDir))
|
|
32
|
+
return null;
|
|
33
|
+
const versions = readdirSync(nodeDir).filter((v) => /^\d+\.\d+\.\d+$/.test(v)).sort((a, b) => b.localeCompare(a, undefined, { numeric: true }));
|
|
34
|
+
for (const version of versions) {
|
|
35
|
+
const nodeExe = join(nodeDir, version, "node.exe");
|
|
36
|
+
if (existsSync(nodeExe))
|
|
37
|
+
return { nodeExe, codexJs };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
log.debug(`[spawn] Codex Node.exe resolution failed: ${err instanceof Error ? err.message : err}`);
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
};
|
|
45
|
+
const resolveCodexExe = () => {
|
|
46
|
+
if (process.platform !== "win32")
|
|
47
|
+
return null;
|
|
48
|
+
if (process.env.CODEX_EXE)
|
|
49
|
+
return process.env.CODEX_EXE;
|
|
50
|
+
try {
|
|
51
|
+
const localAppData = process.env.LOCALAPPDATA || join(homedir(), "AppData", "Local");
|
|
52
|
+
const nativeExe = join(localAppData, "Volta", "tools", "image", "packages", "@openai", "codex", "node_modules", "@openai", "codex", "node_modules", "@openai", "codex-win32-x64", "vendor", "x86_64-pc-windows-msvc", "codex", "codex.exe");
|
|
53
|
+
return existsSync(nativeExe) ? nativeExe : null;
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
log.debug(`[spawn] Codex native exe resolution failed: ${err instanceof Error ? err.message : err}`);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
export function spawnCodexProcess(codexPath, name, threadId, threadLifecycle, workingDirectory, memorySourceThreadId, threadType) {
|
|
61
|
+
const limitError = concurrencyLimitError();
|
|
62
|
+
if (limitError)
|
|
63
|
+
return limitError;
|
|
64
|
+
const transport = parseSensoriumTransport();
|
|
65
|
+
if (!transport)
|
|
66
|
+
return { error: `MCP_HTTP_PORT env var is not set or invalid (got: '${process.env.MCP_HTTP_PORT ?? ''}'). Codex threads require HTTP transport.` };
|
|
67
|
+
workingDirectory = normalizeWorkingDirectory(workingDirectory);
|
|
68
|
+
const safeName = name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
69
|
+
const logFilePath = join(THREAD_LOGS_DIR, `${safeName}_${threadId}_${new Date().toISOString().slice(0, 10)}.jsonl`);
|
|
70
|
+
const prompt = `You are an AUTONOMOUS AGENT running an INFINITE polling loop. You MUST NEVER STOP.\n\nStep 1: Call start_session(name='${name}', threadId=${threadId}, agentType='codex'). Use threadId=${threadId} for all subsequent calls.\nStep 2: Call remote_copilot_wait_for_instructions(threadId=${threadId}).\nStep 3: Read the response:\n - If it says "MANDATORY ACTION" or "No new instructions" - call remote_copilot_wait_for_instructions AGAIN immediately.\n - If you receive a task - complete it using your tools, then call remote_copilot_wait_for_instructions again.\nStep 4: GOTO Step 2. This loop NEVER ends. You are NEVER done.\n\nCRITICAL: "No new instructions" is NOT a signal to stop. It means "keep waiting". Always call the tool again.`;
|
|
71
|
+
const model = process.env.CODEX_MODEL || DEFAULT_CODEX_MODEL;
|
|
72
|
+
const mcpArgs = buildCodexMcpArgs(transport);
|
|
73
|
+
const cliArgs = ["exec", "--dangerously-bypass-approvals-and-sandbox", "--skip-git-repo-check", ...(model ? ["-m", model] : []), "--json", ...mcpArgs, "-"];
|
|
74
|
+
if (workingDirectory)
|
|
75
|
+
cliArgs.splice(1, 0, "-C", workingDirectory);
|
|
76
|
+
const spawnEnv = sanitizeSpawnEnv({ ...(memorySourceThreadId !== undefined ? { MEMORY_SOURCE_THREAD_ID: String(memorySourceThreadId) } : {}), ...(transport.secret ? { SENSORIUM_MCP_SECRET: transport.secret } : {}) });
|
|
77
|
+
try {
|
|
78
|
+
const nativeExe = resolveCodexExe();
|
|
79
|
+
const nodeExeResult = !nativeExe && process.platform === "win32" && /\.(cmd|bat)$/i.test(codexPath) ? resolveCodexNodeExe() : null;
|
|
80
|
+
// stdin stays a pipe (we write the prompt below); stdout/stderr go to a
|
|
81
|
+
// child-owned file fd so a server self-update/restart can't orphan the pipe
|
|
82
|
+
// and deadlock the detached child (see Claude spawn for the full why).
|
|
83
|
+
const outFd = openSync(logFilePath, "a");
|
|
84
|
+
try {
|
|
85
|
+
const child = nativeExe ? spawn(nativeExe, cliArgs, { stdio: ["pipe", outFd, outFd], shell: false, detached: true, windowsHide: false, env: spawnEnv, cwd: workingDirectory || undefined }) : nodeExeResult ? spawn(nodeExeResult.nodeExe, [nodeExeResult.codexJs, ...cliArgs], { stdio: ["pipe", outFd, outFd], shell: false, detached: true, windowsHide: false, env: spawnEnv, cwd: workingDirectory || undefined }) : spawn(codexPath, cliArgs, { stdio: ["pipe", outFd, outFd], shell: process.platform === "win32" && /\.(cmd|bat)$/i.test(codexPath), detached: true, windowsHide: false, env: spawnEnv, cwd: workingDirectory || undefined });
|
|
86
|
+
try {
|
|
87
|
+
child.stdin?.write(prompt + "\n");
|
|
88
|
+
child.stdin?.end();
|
|
89
|
+
}
|
|
90
|
+
catch { }
|
|
91
|
+
return registerSpawnedProcess({ child, threadId, name, logFilePath, configPath: CODEX_HOME_DIR, agentLabel: "Codex", memorySourceThreadId, threadType }, threadLifecycle);
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
try {
|
|
95
|
+
closeSync(outFd);
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
log.debug(`[spawn] closeSync log fd failed for thread ${threadId}: ${errorMessage(err)}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
return { error: `Failed to spawn Codex process: ${errorMessage(err)}` };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=codex-spawn.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-spawn.service.js","sourceRoot":"","sources":["../../src/services/codex-spawn.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copilot-specific spawn logic: CLI-path resolution, the isolated COPILOT_HOME /
|
|
3
|
+
* workspace setup, and the Copilot process launch driven by dashboard settings
|
|
4
|
+
* (model + optional BYOK / OpenRouter provider).
|
|
5
|
+
*/
|
|
6
|
+
import type { ThreadLifecycleService } from "./thread-lifecycle.service.js";
|
|
7
|
+
import { type SpawnResult } from "./spawn-common.js";
|
|
8
|
+
export declare const resolveCopilotPath: () => string | null;
|
|
9
|
+
export declare function spawnCopilotProcess(copilotPath: string, name: string, threadId: number, threadLifecycle: ThreadLifecycleService, workingDirectory?: string, memorySourceThreadId?: number, threadType?: "worker" | "branch"): SpawnResult;
|
|
10
|
+
//# sourceMappingURL=copilot-spawn.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copilot-spawn.service.d.ts","sourceRoot":"","sources":["../../src/services/copilot-spawn.service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAE5E,OAAO,EAQL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AA8B3B,eAAO,MAAM,kBAAkB,QAAO,MAAM,GAAG,IACyD,CAAC;AAEzG,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,sBAAsB,EAAE,gBAAgB,CAAC,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAqCzO"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copilot-specific spawn logic: CLI-path resolution, the isolated COPILOT_HOME /
|
|
3
|
+
* workspace setup, and the Copilot process launch driven by dashboard settings
|
|
4
|
+
* (model + optional BYOK / OpenRouter provider).
|
|
5
|
+
*/
|
|
6
|
+
import { spawn } from "node:child_process";
|
|
7
|
+
import { existsSync, mkdirSync, openSync, closeSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { getCopilotSpawnEnv } from "../config.js";
|
|
10
|
+
import { log } from "../logger.js";
|
|
11
|
+
import { errorMessage } from "../utils.js";
|
|
12
|
+
import { PROCESS_BASE_DIR, THREAD_LOGS_DIR } from "./process.service.js";
|
|
13
|
+
import { buildCopilotMcpConfig } from "./mcp-config.service.js";
|
|
14
|
+
import { sanitizeSpawnEnv, resolveCliPath, resolveWindowsCliPath, parseSensoriumTransport, normalizeWorkingDirectory, registerSpawnedProcess, concurrencyLimitError, } from "./spawn-common.js";
|
|
15
|
+
const COPILOT_HOME_DIR = "copilot-home";
|
|
16
|
+
// Provider env vars that BYOK controls. Listed so a spawn can explicitly unset
|
|
17
|
+
// any ambient values when BYOK is disabled — keeping the dashboard settings, not
|
|
18
|
+
// the OS environment, authoritative for the Copilot provider.
|
|
19
|
+
const COPILOT_PROVIDER_ENV_KEYS = [
|
|
20
|
+
"COPILOT_PROVIDER_BASE_URL",
|
|
21
|
+
"COPILOT_PROVIDER_TYPE",
|
|
22
|
+
"COPILOT_PROVIDER_API_KEY",
|
|
23
|
+
"COPILOT_PROVIDER_MODEL_ID",
|
|
24
|
+
"COPILOT_PROVIDER_WIRE_MODEL",
|
|
25
|
+
];
|
|
26
|
+
function writeCopilotInstructions(copilotHome) {
|
|
27
|
+
mkdirSync(copilotHome, { recursive: true });
|
|
28
|
+
writeFileSync(join(copilotHome, "copilot-instructions.md"), "You are a remote Copilot agent. Start remote session with sensorium. Pass agentType='copilot' to start_session.", "utf-8");
|
|
29
|
+
}
|
|
30
|
+
function ensureCopilotWorkspace(baseDir) {
|
|
31
|
+
const wsDir = join(baseDir, "copilot-workspace");
|
|
32
|
+
mkdirSync(wsDir, { recursive: true });
|
|
33
|
+
const ignoreFile = join(wsDir, ".copilotignore");
|
|
34
|
+
if (!existsSync(ignoreFile))
|
|
35
|
+
writeFileSync(ignoreFile, "*\n", "utf-8");
|
|
36
|
+
return wsDir;
|
|
37
|
+
}
|
|
38
|
+
export const resolveCopilotPath = () => process.platform === "win32" ? resolveWindowsCliPath("copilot") : resolveCliPath("copilot", /\.exe$/i);
|
|
39
|
+
export function spawnCopilotProcess(copilotPath, name, threadId, threadLifecycle, workingDirectory, memorySourceThreadId, threadType) {
|
|
40
|
+
const limitError = concurrencyLimitError();
|
|
41
|
+
if (limitError)
|
|
42
|
+
return limitError;
|
|
43
|
+
const transport = parseSensoriumTransport();
|
|
44
|
+
if (!transport)
|
|
45
|
+
return { error: `MCP_HTTP_PORT env var is not set or invalid (got: '${process.env.MCP_HTTP_PORT ?? ''}'). Copilot threads require HTTP transport.` };
|
|
46
|
+
workingDirectory = normalizeWorkingDirectory(workingDirectory) || ensureCopilotWorkspace(PROCESS_BASE_DIR);
|
|
47
|
+
const copilotHomeDir = join(PROCESS_BASE_DIR, COPILOT_HOME_DIR);
|
|
48
|
+
buildCopilotMcpConfig(transport, copilotHomeDir);
|
|
49
|
+
writeCopilotInstructions(copilotHomeDir);
|
|
50
|
+
const safeName = name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
51
|
+
const logFilePath = join(THREAD_LOGS_DIR, `${safeName}_${threadId}_${new Date().toISOString().slice(0, 10)}.json`);
|
|
52
|
+
try {
|
|
53
|
+
const sessionPrompt = `Start remote session with sensorium. Thread name = '${name}'. Use threadId=${threadId} when calling start_session.`;
|
|
54
|
+
// Copilot model + BYOK provider config come from dashboard settings. Settings
|
|
55
|
+
// drive both the model and (optionally) a BYOK provider; provider vars the
|
|
56
|
+
// settings don't supply are explicitly unset so ambient env can't silently
|
|
57
|
+
// keep BYOK on.
|
|
58
|
+
const copilotEnv = getCopilotSpawnEnv();
|
|
59
|
+
const model = copilotEnv.COPILOT_MODEL;
|
|
60
|
+
const providerEnv = {};
|
|
61
|
+
for (const k of COPILOT_PROVIDER_ENV_KEYS)
|
|
62
|
+
providerEnv[k] = copilotEnv[k];
|
|
63
|
+
const spawnEnv = sanitizeSpawnEnv({
|
|
64
|
+
COPILOT_HOME: copilotHomeDir,
|
|
65
|
+
COPILOT_MODEL: model,
|
|
66
|
+
...providerEnv,
|
|
67
|
+
...(memorySourceThreadId !== undefined ? { MEMORY_SOURCE_THREAD_ID: String(memorySourceThreadId) } : {}),
|
|
68
|
+
});
|
|
69
|
+
// File fd owned by the child (see Claude spawn) — survives this server's
|
|
70
|
+
// self-update/restart without deadlocking the orphaned child.
|
|
71
|
+
const outFd = openSync(logFilePath, "a");
|
|
72
|
+
try {
|
|
73
|
+
const child = spawn(copilotPath, ["-p", sessionPrompt, "--allow-all-tools", "--model", model, "--autopilot"], { stdio: ["ignore", outFd, outFd], shell: process.platform === "win32" && /\.(cmd|bat)$/i.test(copilotPath), detached: true, windowsHide: false, env: spawnEnv, cwd: workingDirectory || undefined });
|
|
74
|
+
return registerSpawnedProcess({ child, threadId, name, logFilePath, configPath: copilotHomeDir, agentLabel: "Copilot", memorySourceThreadId, threadType }, threadLifecycle);
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
try {
|
|
78
|
+
closeSync(outFd);
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
log.debug(`[spawn] closeSync log fd failed for thread ${threadId}: ${errorMessage(err)}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
return { error: `Failed to spawn Copilot process: ${errorMessage(err)}` };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=copilot-spawn.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copilot-spawn.service.js","sourceRoot":"","sources":["../../src/services/copilot-spawn.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared spawn infrastructure used by the per-agent spawn modules
|
|
3
|
+
* (claude-spawn / copilot-spawn / codex-spawn).
|
|
4
|
+
*
|
|
5
|
+
* Holds the pieces that are agent-agnostic: env sanitization, CLI-path
|
|
6
|
+
* resolution helpers, MCP transport parsing, process registration/exit
|
|
7
|
+
* bookkeeping, and the startup-cleanup guard. Keeping these here lets each
|
|
8
|
+
* agent module stay focused on its own CLI invocation without duplicating the
|
|
9
|
+
* lifecycle plumbing.
|
|
10
|
+
*/
|
|
11
|
+
import { type ChildProcess } from "node:child_process";
|
|
12
|
+
import { type ThreadLifecycleService } from "./thread-lifecycle.service.js";
|
|
13
|
+
import type { SensoriumTransport } from "./mcp-config.service.js";
|
|
14
|
+
/** Result shape shared by every spawn function. */
|
|
15
|
+
export type SpawnResult = {
|
|
16
|
+
pid: number;
|
|
17
|
+
logFile: string;
|
|
18
|
+
} | {
|
|
19
|
+
error: string;
|
|
20
|
+
};
|
|
21
|
+
export declare const sanitizeSpawnEnv: (extra?: Record<string, string | undefined>) => NodeJS.ProcessEnv;
|
|
22
|
+
export declare const resolveCliPath: (name: string, prefer?: RegExp) => string | null;
|
|
23
|
+
/** On Windows: prefer .exe, fall back to .cmd, refuse extensionless shims (e.g. Volta). */
|
|
24
|
+
export declare function resolveWindowsCliPath(name: string): string | null;
|
|
25
|
+
/** Parse MCP transport from env. Returns null if port is not set or invalid. */
|
|
26
|
+
export declare function parseSensoriumTransport(): SensoriumTransport | null;
|
|
27
|
+
export declare const normalizeWorkingDirectory: (workingDirectory?: string) => string | undefined;
|
|
28
|
+
export declare const isStartupCleanupInProgress: () => boolean;
|
|
29
|
+
export declare const setStartupCleanupInProgress: (v: boolean) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Global concurrent-spawn guard shared by every agent module. Returns an error
|
|
32
|
+
* result when the dashboard's max-concurrent-threads limit is already reached,
|
|
33
|
+
* or null when there's room. Kept here so the limit applies uniformly to
|
|
34
|
+
* Claude, Copilot and Codex spawns rather than Claude alone.
|
|
35
|
+
*/
|
|
36
|
+
export declare function concurrencyLimitError(): {
|
|
37
|
+
error: string;
|
|
38
|
+
} | null;
|
|
39
|
+
export interface RegisterSpawnOpts {
|
|
40
|
+
child: ChildProcess;
|
|
41
|
+
threadId: number;
|
|
42
|
+
name: string;
|
|
43
|
+
logFilePath: string;
|
|
44
|
+
configPath: string;
|
|
45
|
+
agentLabel: string;
|
|
46
|
+
memorySourceThreadId?: number;
|
|
47
|
+
threadType?: "worker" | "branch";
|
|
48
|
+
}
|
|
49
|
+
export declare function registerSpawnedProcess(opts: RegisterSpawnOpts, threadLifecycle: ThreadLifecycleService): {
|
|
50
|
+
pid: number;
|
|
51
|
+
logFile: string;
|
|
52
|
+
} | {
|
|
53
|
+
error: string;
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=spawn-common.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn-common.d.ts","sourceRoot":"","sources":["../../src/services/spawn-common.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAWlE,OAAO,EAAe,KAAK,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACzF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAIlE,mDAAmD;AACnD,MAAM,MAAM,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAgB/E,eAAO,MAAM,gBAAgB,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,KAAG,MAAM,CAAC,UAKpF,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,EAAE,SAAS,MAAM,KAAG,MAAM,GAAG,IASvE,CAAC;AAEF,2FAA2F;AAC3F,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWjE;AAED,gFAAgF;AAChF,wBAAgB,uBAAuB,IAAI,kBAAkB,GAAG,IAAI,CAInE;AAED,eAAO,MAAM,yBAAyB,GAAI,mBAAmB,MAAM,KAAG,MAAM,GAAG,SAK9E,CAAC;AAOF,eAAO,MAAM,0BAA0B,QAAO,OAAmC,CAAC;AAClF,eAAO,MAAM,2BAA2B,GAAI,GAAG,OAAO,KAAG,IAAyC,CAAC;AAEnG;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAIhE;AAID,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,YAAY,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAClC;AA+DD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,iBAAiB,EAAE,eAAe,EAAE,sBAAsB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAa7J"}
|