@bbigbang/agent-node 0.1.0
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/agentHost.js +483 -0
- package/dist/appVersion.js +14 -0
- package/dist/assetCachePaths.js +35 -0
- package/dist/attachmentInput.js +588 -0
- package/dist/attachmentMaterializer.js +230 -0
- package/dist/bigbangCli.js +17 -0
- package/dist/bigbangMessageSendDetection.js +284 -0
- package/dist/builtinSkillRoots.js +54 -0
- package/dist/claudeConfig.js +32 -0
- package/dist/claudeDirectRuntime.js +1960 -0
- package/dist/claudeSessionControls.js +78 -0
- package/dist/claudeTranscriptFs.js +147 -0
- package/dist/codexAppServerClient.js +188 -0
- package/dist/codexAppServerEnv.js +14 -0
- package/dist/codexAppServerRpc.js +273 -0
- package/dist/codexAppServerRuntime.js +3495 -0
- package/dist/codexBuiltinPrompt.js +117 -0
- package/dist/codexConversationSummarizer.js +76 -0
- package/dist/codexTranscriptFs.js +145 -0
- package/dist/config.js +129 -0
- package/dist/connection.js +151 -0
- package/dist/dispatchQueueStore.js +39 -0
- package/dist/dreamEnv.js +1 -0
- package/dist/dreamMemoryFallback.js +118 -0
- package/dist/dreamToolPolicy.js +293 -0
- package/dist/droidMissionRunner.js +808 -0
- package/dist/executor.js +1078 -0
- package/dist/hostRuntime.js +1 -0
- package/dist/libraryAuthorityFs.js +74 -0
- package/dist/libraryMirror.js +183 -0
- package/dist/main.js +1659 -0
- package/dist/native-worker/native-worker.mjs +475 -0
- package/dist/nativeMissionAgentDispatch.js +463 -0
- package/dist/nativeMissionRunner.js +461 -0
- package/dist/nativeSkillMounts.js +204 -0
- package/dist/nativeWorkerHost.js +142 -0
- package/dist/nodeSink.js +142 -0
- package/dist/panelHttpFetch.js +334 -0
- package/dist/runtimeDrivers.js +62 -0
- package/dist/skillFs.js +229 -0
- package/dist/soloHost.js +165 -0
- package/dist/soloNodeSink.js +138 -0
- package/dist/terminalManager.js +254 -0
- package/dist/workspaceFs.js +1020 -0
- package/dist/workspaceGit.js +694 -0
- package/dist/workspaceInspect.js +22 -0
- package/package.json +49 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { CLAUDE_SESSION_MODEL_OPTIONS } from '@bbigbang/protocol';
|
|
2
|
+
const CLAUDE_SESSION_MODES = [
|
|
3
|
+
{
|
|
4
|
+
id: 'default',
|
|
5
|
+
label: 'Always Ask',
|
|
6
|
+
description: 'Prompts for permission the first time a tool is used',
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
id: 'acceptEdits',
|
|
10
|
+
label: 'Accept File Edits',
|
|
11
|
+
description: 'Automatically approves edit-focused tools without prompting',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
id: 'plan',
|
|
15
|
+
label: 'Plan Mode',
|
|
16
|
+
description: 'Analyze the codebase without executing tools or edits',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: 'bypassPermissions',
|
|
20
|
+
label: 'Bypass',
|
|
21
|
+
description: 'Skip all permission prompts (use with caution)',
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
const CLAUDE_SESSION_MODE_IDS = new Set(CLAUDE_SESSION_MODES.map((mode) => mode.id));
|
|
25
|
+
const CLAUDE_SESSION_MODELS = CLAUDE_SESSION_MODEL_OPTIONS.map((model) => ({ ...model }));
|
|
26
|
+
const CLAUDE_SESSION_MODEL_IDS = new Set(CLAUDE_SESSION_MODELS.map((model) => model.id));
|
|
27
|
+
const CLAUDE_SESSION_COMMANDS = [
|
|
28
|
+
{
|
|
29
|
+
name: 'rewind',
|
|
30
|
+
description: 'Rewind tracked files to a previous Claude user message',
|
|
31
|
+
argumentHint: '[user_message_uuid]',
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
const CLAUDE_SESSION_COMMAND_NAMES = new Set(CLAUDE_SESSION_COMMANDS.map((command) => command.name));
|
|
35
|
+
export function listClaudeSessionModes() {
|
|
36
|
+
return CLAUDE_SESSION_MODES.map((mode) => ({ ...mode }));
|
|
37
|
+
}
|
|
38
|
+
export function listClaudeSessionModels() {
|
|
39
|
+
return CLAUDE_SESSION_MODELS.map((model) => ({ ...model }));
|
|
40
|
+
}
|
|
41
|
+
export function listClaudeSessionCommands() {
|
|
42
|
+
return CLAUDE_SESSION_COMMANDS.map((command) => ({ ...command }));
|
|
43
|
+
}
|
|
44
|
+
export function normalizeClaudeSessionModeId(value) {
|
|
45
|
+
const trimmed = value?.trim() ?? '';
|
|
46
|
+
if (trimmed && CLAUDE_SESSION_MODE_IDS.has(trimmed)) {
|
|
47
|
+
return trimmed;
|
|
48
|
+
}
|
|
49
|
+
return 'default';
|
|
50
|
+
}
|
|
51
|
+
export function isClaudeSessionModeId(value) {
|
|
52
|
+
return Boolean(value && CLAUDE_SESSION_MODE_IDS.has(value));
|
|
53
|
+
}
|
|
54
|
+
export function isClaudeSessionModelId(value) {
|
|
55
|
+
return Boolean(value && CLAUDE_SESSION_MODEL_IDS.has(value));
|
|
56
|
+
}
|
|
57
|
+
export function getDefaultClaudeSessionModelId() {
|
|
58
|
+
return CLAUDE_SESSION_MODELS.find((model) => model.isDefault)?.id ?? CLAUDE_SESSION_MODELS[0].id;
|
|
59
|
+
}
|
|
60
|
+
export function isClaudeSessionCommandName(value) {
|
|
61
|
+
return Boolean(value && CLAUDE_SESSION_COMMAND_NAMES.has(value));
|
|
62
|
+
}
|
|
63
|
+
export function buildClaudeSessionControlState(params) {
|
|
64
|
+
const normalizedModeId = normalizeClaudeSessionModeId(params.modeId);
|
|
65
|
+
const normalizedModelId = isClaudeSessionModelId(params.modelId) ? params.modelId : null;
|
|
66
|
+
const defaultModelId = getDefaultClaudeSessionModelId();
|
|
67
|
+
const effectiveModelId = params.effectiveModelId?.trim() || normalizedModelId || defaultModelId;
|
|
68
|
+
return {
|
|
69
|
+
sessionId: params.sessionId,
|
|
70
|
+
modeId: normalizedModeId,
|
|
71
|
+
modelId: normalizedModelId,
|
|
72
|
+
effectiveModelId,
|
|
73
|
+
checkpointingEnabled: true,
|
|
74
|
+
availableModes: listClaudeSessionModes(),
|
|
75
|
+
availableModels: listClaudeSessionModels(),
|
|
76
|
+
availableCommands: listClaudeSessionCommands(),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const CLAUDE_RUNTIME_DIRNAME = '.claude-runtime';
|
|
4
|
+
const CLAUDE_PROJECTS_DIRNAME = 'projects';
|
|
5
|
+
const MAX_TRANSCRIPT_BYTES = 2 * 1024 * 1024;
|
|
6
|
+
const TRANSCRIPT_HEADER_READ_BYTES = 16 * 1024;
|
|
7
|
+
export class ClaudeTranscriptFsError extends Error {
|
|
8
|
+
code;
|
|
9
|
+
constructor(code, message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.code = code;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function listClaudeTranscriptFiles(workspaceRoot, maxFiles = 1000) {
|
|
15
|
+
const rootPath = getClaudeProjectsRoot(workspaceRoot);
|
|
16
|
+
const files = [];
|
|
17
|
+
const normalizedMax = Math.max(1, Math.min(maxFiles, 5000));
|
|
18
|
+
const rootStat = fs.statSync(rootPath, { throwIfNoEntry: false });
|
|
19
|
+
if (!rootStat) {
|
|
20
|
+
return { rootPath, files: [], truncated: false };
|
|
21
|
+
}
|
|
22
|
+
if (!rootStat.isDirectory()) {
|
|
23
|
+
throw new ClaudeTranscriptFsError('not_directory', 'Claude transcript root is not a directory.');
|
|
24
|
+
}
|
|
25
|
+
const stack = [rootPath];
|
|
26
|
+
while (stack.length > 0) {
|
|
27
|
+
const current = stack.pop();
|
|
28
|
+
const entries = fs.readdirSync(current, { withFileTypes: true });
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
const absolutePath = path.join(current, entry.name);
|
|
31
|
+
if (entry.isDirectory()) {
|
|
32
|
+
stack.push(absolutePath);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (!entry.isFile() || !entry.name.endsWith('.jsonl')) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const stat = fs.statSync(absolutePath, { throwIfNoEntry: false });
|
|
39
|
+
if (!stat?.isFile())
|
|
40
|
+
continue;
|
|
41
|
+
const header = readClaudeTranscriptHeader(absolutePath, stat.size);
|
|
42
|
+
files.push({
|
|
43
|
+
path: toRelativeTranscriptPath(rootPath, absolutePath),
|
|
44
|
+
size: stat.size,
|
|
45
|
+
modifiedAt: Math.floor(stat.mtimeMs),
|
|
46
|
+
sessionId: header.sessionId,
|
|
47
|
+
cwd: header.cwd,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
files.sort((a, b) => {
|
|
52
|
+
if (a.modifiedAt !== b.modifiedAt)
|
|
53
|
+
return b.modifiedAt - a.modifiedAt;
|
|
54
|
+
return a.path.localeCompare(b.path);
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
rootPath,
|
|
58
|
+
files: files.slice(0, normalizedMax),
|
|
59
|
+
truncated: files.length > normalizedMax,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function readClaudeTranscriptFile(workspaceRoot, relativePath) {
|
|
63
|
+
const rootPath = getClaudeProjectsRoot(workspaceRoot);
|
|
64
|
+
const absolutePath = resolveTranscriptPath(rootPath, relativePath);
|
|
65
|
+
const stat = fs.statSync(absolutePath, { throwIfNoEntry: false });
|
|
66
|
+
if (!stat)
|
|
67
|
+
throw new ClaudeTranscriptFsError('not_found', 'Claude transcript not found.');
|
|
68
|
+
if (!stat.isFile())
|
|
69
|
+
throw new ClaudeTranscriptFsError('not_file', 'Claude transcript path is not a file.');
|
|
70
|
+
if (stat.size > MAX_TRANSCRIPT_BYTES) {
|
|
71
|
+
throw new ClaudeTranscriptFsError('file_too_large', `Claude transcript exceeds ${MAX_TRANSCRIPT_BYTES} bytes.`);
|
|
72
|
+
}
|
|
73
|
+
const contentBuffer = fs.readFileSync(absolutePath);
|
|
74
|
+
if (looksBinary(contentBuffer)) {
|
|
75
|
+
throw new ClaudeTranscriptFsError('binary_file', 'Claude transcript is not a text file.');
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
rootPath,
|
|
79
|
+
path: normalizeRelativePath(relativePath),
|
|
80
|
+
content: contentBuffer.toString('utf8'),
|
|
81
|
+
size: stat.size,
|
|
82
|
+
modifiedAt: Math.floor(stat.mtimeMs),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function getClaudeProjectsRoot(workspaceRoot) {
|
|
86
|
+
return path.join(path.resolve(workspaceRoot), CLAUDE_RUNTIME_DIRNAME, CLAUDE_PROJECTS_DIRNAME);
|
|
87
|
+
}
|
|
88
|
+
function resolveTranscriptPath(rootPath, relativePath) {
|
|
89
|
+
const normalized = normalizeRelativePath(relativePath);
|
|
90
|
+
const absolutePath = path.resolve(rootPath, normalized);
|
|
91
|
+
const resolvedRoot = path.resolve(rootPath);
|
|
92
|
+
if (absolutePath !== resolvedRoot && !absolutePath.startsWith(`${resolvedRoot}${path.sep}`)) {
|
|
93
|
+
throw new ClaudeTranscriptFsError('path_outside_workspace', 'Transcript path escapes Claude transcript root.');
|
|
94
|
+
}
|
|
95
|
+
return absolutePath;
|
|
96
|
+
}
|
|
97
|
+
function toRelativeTranscriptPath(rootPath, absolutePath) {
|
|
98
|
+
const relative = path.relative(path.resolve(rootPath), path.resolve(absolutePath));
|
|
99
|
+
return normalizeRelativePath(relative);
|
|
100
|
+
}
|
|
101
|
+
function normalizeRelativePath(relativePath) {
|
|
102
|
+
return relativePath.replace(/^\/+/, '').split(path.sep).join('/').trim();
|
|
103
|
+
}
|
|
104
|
+
function looksBinary(content) {
|
|
105
|
+
const limit = Math.min(content.length, 8000);
|
|
106
|
+
for (let index = 0; index < limit; index += 1) {
|
|
107
|
+
if (content[index] === 0)
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
function readClaudeTranscriptHeader(absolutePath, fileSize) {
|
|
113
|
+
const bytesToRead = Math.max(1, Math.min(fileSize, TRANSCRIPT_HEADER_READ_BYTES));
|
|
114
|
+
const fd = fs.openSync(absolutePath, 'r');
|
|
115
|
+
try {
|
|
116
|
+
const buffer = Buffer.allocUnsafe(bytesToRead);
|
|
117
|
+
const bytesRead = fs.readSync(fd, buffer, 0, bytesToRead, 0);
|
|
118
|
+
if (bytesRead <= 0)
|
|
119
|
+
return {};
|
|
120
|
+
const text = buffer.toString('utf8', 0, bytesRead);
|
|
121
|
+
let sessionId;
|
|
122
|
+
let cwd;
|
|
123
|
+
for (const line of text.split(/\r?\n/)) {
|
|
124
|
+
const trimmed = line.trim();
|
|
125
|
+
if (!trimmed)
|
|
126
|
+
continue;
|
|
127
|
+
try {
|
|
128
|
+
const parsed = JSON.parse(trimmed);
|
|
129
|
+
sessionId = typeof parsed.sessionId === 'string' && parsed.sessionId.trim()
|
|
130
|
+
? parsed.sessionId.trim()
|
|
131
|
+
: sessionId;
|
|
132
|
+
cwd = typeof parsed.cwd === 'string' && parsed.cwd.trim()
|
|
133
|
+
? parsed.cwd.trim()
|
|
134
|
+
: cwd;
|
|
135
|
+
if (sessionId && cwd)
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { sessionId, cwd };
|
|
143
|
+
}
|
|
144
|
+
finally {
|
|
145
|
+
fs.closeSync(fd);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import readline from 'node:readline';
|
|
2
|
+
import { log } from '@bbigbang/runtime-acp';
|
|
3
|
+
export const DEFAULT_CODEX_APP_SERVER_REQUEST_TIMEOUT_MS = 300_000;
|
|
4
|
+
const STDERR_BUFFER_MAX_CHARS = 8192;
|
|
5
|
+
export class CodexAppServerClient {
|
|
6
|
+
child;
|
|
7
|
+
rl;
|
|
8
|
+
pending = new Map();
|
|
9
|
+
requestHandlers = new Map();
|
|
10
|
+
defaultRequestTimeoutMs;
|
|
11
|
+
exitPromise;
|
|
12
|
+
nextId = 1;
|
|
13
|
+
disposed = false;
|
|
14
|
+
stderrBuffer = '';
|
|
15
|
+
notificationHandler = null;
|
|
16
|
+
exitHandler = null;
|
|
17
|
+
resolveExitPromise = null;
|
|
18
|
+
constructor(params) {
|
|
19
|
+
this.child = params.child;
|
|
20
|
+
this.defaultRequestTimeoutMs = params.requestTimeoutMs ?? DEFAULT_CODEX_APP_SERVER_REQUEST_TIMEOUT_MS;
|
|
21
|
+
this.rl = readline.createInterface({ input: this.child.stdout });
|
|
22
|
+
this.exitPromise = new Promise((resolve) => {
|
|
23
|
+
this.resolveExitPromise = resolve;
|
|
24
|
+
});
|
|
25
|
+
this.rl.on('line', (line) => {
|
|
26
|
+
void this.handleLine(line);
|
|
27
|
+
});
|
|
28
|
+
this.child.stderr.on('data', (chunk) => {
|
|
29
|
+
this.stderrBuffer += chunk.toString();
|
|
30
|
+
if (this.stderrBuffer.length > STDERR_BUFFER_MAX_CHARS) {
|
|
31
|
+
this.stderrBuffer = this.stderrBuffer.slice(-STDERR_BUFFER_MAX_CHARS);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
this.child.on('error', (error) => {
|
|
35
|
+
this.handleChildExit(error instanceof Error ? error : new Error(String(error)));
|
|
36
|
+
});
|
|
37
|
+
this.child.on('exit', (code, signal) => {
|
|
38
|
+
const message = code === 0 && !signal
|
|
39
|
+
? 'Codex app-server exited.'
|
|
40
|
+
: `Codex app-server exited with code ${code ?? 'null'} and signal ${signal ?? 'null'}.`;
|
|
41
|
+
this.handleChildExit(new Error([message, this.stderrBuffer.trim()].filter(Boolean).join('\n')));
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
setNotificationHandler(handler) {
|
|
45
|
+
this.notificationHandler = handler;
|
|
46
|
+
}
|
|
47
|
+
setExitHandler(handler) {
|
|
48
|
+
this.exitHandler = handler;
|
|
49
|
+
}
|
|
50
|
+
setRequestHandler(method, handler) {
|
|
51
|
+
this.requestHandlers.set(method, handler);
|
|
52
|
+
}
|
|
53
|
+
request(method, params, timeoutMs = this.defaultRequestTimeoutMs) {
|
|
54
|
+
if (this.disposed) {
|
|
55
|
+
return Promise.reject(new Error('Codex app-server client is closed.'));
|
|
56
|
+
}
|
|
57
|
+
const id = this.nextId++;
|
|
58
|
+
const payload = { id, method, params };
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
const timer = setTimeout(() => {
|
|
61
|
+
this.pending.delete(id);
|
|
62
|
+
reject(new Error(`Codex app-server request timed out for ${method}.`));
|
|
63
|
+
}, timeoutMs);
|
|
64
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
65
|
+
this.writeLine(JSON.stringify(payload));
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
notify(method, params) {
|
|
69
|
+
if (this.disposed)
|
|
70
|
+
return;
|
|
71
|
+
const payload = { method, params };
|
|
72
|
+
this.writeLine(JSON.stringify(payload));
|
|
73
|
+
}
|
|
74
|
+
async dispose() {
|
|
75
|
+
if (this.disposed) {
|
|
76
|
+
await this.exitPromise;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
this.disposed = true;
|
|
80
|
+
this.rl.close();
|
|
81
|
+
try {
|
|
82
|
+
this.child.stdin.end();
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Ignore stream shutdown errors during disposal.
|
|
86
|
+
}
|
|
87
|
+
terminateChildProcessTree(this.child);
|
|
88
|
+
await this.exitPromise;
|
|
89
|
+
}
|
|
90
|
+
writeLine(line) {
|
|
91
|
+
const stdin = this.child.stdin;
|
|
92
|
+
if (this.disposed || stdin.destroyed || !stdin.writable)
|
|
93
|
+
return;
|
|
94
|
+
stdin.write(`${line}\n`);
|
|
95
|
+
}
|
|
96
|
+
handleChildExit(error) {
|
|
97
|
+
for (const pending of this.pending.values()) {
|
|
98
|
+
clearTimeout(pending.timer);
|
|
99
|
+
pending.reject(error);
|
|
100
|
+
}
|
|
101
|
+
this.pending.clear();
|
|
102
|
+
this.disposed = true;
|
|
103
|
+
this.exitHandler?.(error);
|
|
104
|
+
this.resolveExitPromise?.();
|
|
105
|
+
this.resolveExitPromise = null;
|
|
106
|
+
}
|
|
107
|
+
async handleLine(line) {
|
|
108
|
+
if (!line.trim())
|
|
109
|
+
return;
|
|
110
|
+
let message;
|
|
111
|
+
try {
|
|
112
|
+
message = JSON.parse(line);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
log.warn('[codex-app-server] failed to parse JSON-RPC line', {
|
|
116
|
+
error: String(error?.message ?? error),
|
|
117
|
+
line,
|
|
118
|
+
});
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (typeof message.id === 'number') {
|
|
122
|
+
const id = message.id;
|
|
123
|
+
if ('result' in message || 'error' in message) {
|
|
124
|
+
const pending = this.pending.get(id);
|
|
125
|
+
if (!pending)
|
|
126
|
+
return;
|
|
127
|
+
clearTimeout(pending.timer);
|
|
128
|
+
this.pending.delete(id);
|
|
129
|
+
if (message.error) {
|
|
130
|
+
pending.reject(new Error(message.error?.message ?? 'Codex app-server request failed.'));
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
pending.resolve(message.result);
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (typeof message.method === 'string') {
|
|
138
|
+
const request = message;
|
|
139
|
+
const handler = this.requestHandlers.get(request.method);
|
|
140
|
+
try {
|
|
141
|
+
const result = handler ? await handler(request.params) : {};
|
|
142
|
+
this.writeLine(JSON.stringify({ id: request.id, result }));
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
this.writeLine(JSON.stringify({
|
|
146
|
+
id: request.id,
|
|
147
|
+
error: { message: String(error?.message ?? error) },
|
|
148
|
+
}));
|
|
149
|
+
}
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (typeof message.method === 'string') {
|
|
154
|
+
this.notificationHandler?.(message.method, message.params);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
export function buildCodexAppServerInitializeParams() {
|
|
159
|
+
return {
|
|
160
|
+
clientInfo: {
|
|
161
|
+
name: 'bigbang',
|
|
162
|
+
title: 'Bigbang',
|
|
163
|
+
version: '0.1.0',
|
|
164
|
+
},
|
|
165
|
+
capabilities: {
|
|
166
|
+
experimentalApi: true,
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
export function terminateChildProcessTree(child) {
|
|
171
|
+
if (!child || child.killed)
|
|
172
|
+
return;
|
|
173
|
+
if (process.platform !== 'win32' && typeof child.pid === 'number' && child.pid > 0) {
|
|
174
|
+
try {
|
|
175
|
+
process.kill(-child.pid, 'SIGTERM');
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
// Fall back to killing the direct child.
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
child.kill('SIGTERM');
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
// Ignore best-effort shutdown failures.
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const CODEX_CHILD_ENV_DENYLIST = [
|
|
2
|
+
'CODEX_SANDBOX_NETWORK_DISABLED',
|
|
3
|
+
'CODEX_THREAD_ID',
|
|
4
|
+
];
|
|
5
|
+
export function buildCodexAppServerChildEnv(baseEnv, runtimeEnv = {}) {
|
|
6
|
+
const env = {
|
|
7
|
+
...baseEnv,
|
|
8
|
+
...runtimeEnv,
|
|
9
|
+
};
|
|
10
|
+
for (const key of CODEX_CHILD_ENV_DENYLIST) {
|
|
11
|
+
delete env[key];
|
|
12
|
+
}
|
|
13
|
+
return env;
|
|
14
|
+
}
|