@jungjaehoon/mama-os 0.23.0 → 0.24.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/agent/agent-loop.d.ts +3 -6
- package/dist/agent/agent-loop.d.ts.map +1 -1
- package/dist/agent/agent-loop.js +390 -202
- package/dist/agent/agent-loop.js.map +1 -1
- package/dist/agent/code-act/constants.d.ts +2 -2
- package/dist/agent/code-act/constants.d.ts.map +1 -1
- package/dist/agent/code-act/constants.js +16 -9
- package/dist/agent/code-act/constants.js.map +1 -1
- package/dist/agent/code-act/host-bridge.d.ts +12 -11
- package/dist/agent/code-act/host-bridge.d.ts.map +1 -1
- package/dist/agent/code-act/host-bridge.js +92 -15
- package/dist/agent/code-act/host-bridge.js.map +1 -1
- package/dist/agent/code-act/index.d.ts +2 -0
- package/dist/agent/code-act/index.d.ts.map +1 -1
- package/dist/agent/code-act/index.js +5 -1
- package/dist/agent/code-act/index.js.map +1 -1
- package/dist/agent/code-act/tool-policy.d.ts +42 -0
- package/dist/agent/code-act/tool-policy.d.ts.map +1 -0
- package/dist/agent/code-act/tool-policy.js +122 -0
- package/dist/agent/code-act/tool-policy.js.map +1 -0
- package/dist/agent/code-act/type-definition-generator.d.ts +4 -3
- package/dist/agent/code-act/type-definition-generator.d.ts.map +1 -1
- package/dist/agent/code-act/type-definition-generator.js +26 -48
- package/dist/agent/code-act/type-definition-generator.js.map +1 -1
- package/dist/agent/codex-app-server-process.d.ts +116 -0
- package/dist/agent/codex-app-server-process.d.ts.map +1 -0
- package/dist/agent/codex-app-server-process.js +1382 -0
- package/dist/agent/codex-app-server-process.js.map +1 -0
- package/dist/agent/codex-home.d.ts +9 -0
- package/dist/agent/codex-home.d.ts.map +1 -1
- package/dist/agent/codex-home.js +626 -4
- package/dist/agent/codex-home.js.map +1 -1
- package/dist/agent/codex-thread-registry.d.ts +63 -0
- package/dist/agent/codex-thread-registry.d.ts.map +1 -0
- package/dist/agent/codex-thread-registry.js +433 -0
- package/dist/agent/codex-thread-registry.js.map +1 -0
- package/dist/agent/gateway-tool-executor.d.ts +2 -7
- package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
- package/dist/agent/gateway-tool-executor.js +69 -84
- package/dist/agent/gateway-tool-executor.js.map +1 -1
- package/dist/agent/managed-agent-runtime-sync.d.ts.map +1 -1
- package/dist/agent/managed-agent-runtime-sync.js +0 -3
- package/dist/agent/managed-agent-runtime-sync.js.map +1 -1
- package/dist/agent/managed-agent-validation.js +1 -1
- package/dist/agent/managed-agent-validation.js.map +1 -1
- package/dist/agent/model-runner.d.ts +51 -3
- package/dist/agent/model-runner.d.ts.map +1 -1
- package/dist/agent/model-runner.js +1 -1
- package/dist/agent/model-runner.js.map +1 -1
- package/dist/agent/persistent-cli-adapter.d.ts +1 -0
- package/dist/agent/persistent-cli-adapter.d.ts.map +1 -1
- package/dist/agent/persistent-cli-adapter.js +3 -0
- package/dist/agent/persistent-cli-adapter.js.map +1 -1
- package/dist/agent/session-pool.d.ts +2 -2
- package/dist/agent/session-pool.d.ts.map +1 -1
- package/dist/agent/session-pool.js +6 -6
- package/dist/agent/session-pool.js.map +1 -1
- package/dist/agent/tool-registry.d.ts +14 -0
- package/dist/agent/tool-registry.d.ts.map +1 -1
- package/dist/agent/tool-registry.js +46 -7
- package/dist/agent/tool-registry.js.map +1 -1
- package/dist/agent/types.d.ts +40 -6
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/api/graph-api.d.ts.map +1 -1
- package/dist/api/graph-api.js +19 -7
- package/dist/api/graph-api.js.map +1 -1
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +22 -14
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +7 -4
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/start.d.ts +2 -0
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +77 -24
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/status.js +2 -2
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/config/config-manager.d.ts.map +1 -1
- package/dist/cli/config/config-manager.js +21 -4
- package/dist/cli/config/config-manager.js.map +1 -1
- package/dist/cli/config/types.d.ts +4 -4
- package/dist/cli/config/types.d.ts.map +1 -1
- package/dist/cli/config/types.js +1 -0
- package/dist/cli/config/types.js.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/runtime/agent-loop-init.d.ts +1 -1
- package/dist/cli/runtime/agent-loop-init.d.ts.map +1 -1
- package/dist/cli/runtime/agent-loop-init.js +12 -11
- package/dist/cli/runtime/agent-loop-init.js.map +1 -1
- package/dist/cli/runtime/connector-init.d.ts.map +1 -1
- package/dist/cli/runtime/connector-init.js +13 -17
- package/dist/cli/runtime/connector-init.js.map +1 -1
- package/dist/cli/runtime/envelope-bootstrap.d.ts.map +1 -1
- package/dist/cli/runtime/envelope-bootstrap.js +13 -1
- package/dist/cli/runtime/envelope-bootstrap.js.map +1 -1
- package/dist/cli/runtime/gateway-init.d.ts +1 -1
- package/dist/cli/runtime/gateway-init.d.ts.map +1 -1
- package/dist/cli/runtime/gateway-init.js.map +1 -1
- package/dist/cli/runtime/mama-core-init.d.ts +2 -2
- package/dist/cli/runtime/mama-core-init.d.ts.map +1 -1
- package/dist/cli/runtime/mama-core-init.js +17 -0
- package/dist/cli/runtime/mama-core-init.js.map +1 -1
- package/dist/cli/runtime/memory-agent-init.d.ts +1 -1
- package/dist/cli/runtime/memory-agent-init.d.ts.map +1 -1
- package/dist/cli/runtime/memory-agent-init.js +16 -6
- package/dist/cli/runtime/memory-agent-init.js.map +1 -1
- package/dist/cli/runtime/types.d.ts +4 -26
- package/dist/cli/runtime/types.d.ts.map +1 -1
- package/dist/cli/runtime/utilities.js +2 -2
- package/dist/cli/runtime/utilities.js.map +1 -1
- package/dist/connectors/config-loader.d.ts +24 -0
- package/dist/connectors/config-loader.d.ts.map +1 -0
- package/dist/connectors/config-loader.js +205 -0
- package/dist/connectors/config-loader.js.map +1 -0
- package/dist/connectors/framework/types.d.ts +2 -0
- package/dist/connectors/framework/types.d.ts.map +1 -1
- package/dist/connectors/kagemusha/query-tools.js +2 -2
- package/dist/connectors/kagemusha/query-tools.js.map +1 -1
- package/dist/envelope/reactive-config.d.ts +2 -2
- package/dist/envelope/reactive-config.d.ts.map +1 -1
- package/dist/envelope/reactive-config.js +13 -6
- package/dist/envelope/reactive-config.js.map +1 -1
- package/dist/gateways/context-injector.d.ts +2 -1
- package/dist/gateways/context-injector.d.ts.map +1 -1
- package/dist/gateways/context-injector.js.map +1 -1
- package/dist/gateways/message-router.d.ts +1 -0
- package/dist/gateways/message-router.d.ts.map +1 -1
- package/dist/gateways/message-router.js +25 -3
- package/dist/gateways/message-router.js.map +1 -1
- package/dist/gateways/types.d.ts +1 -1
- package/dist/gateways/types.d.ts.map +1 -1
- package/dist/multi-agent/agent-process-manager.d.ts +9 -1
- package/dist/multi-agent/agent-process-manager.d.ts.map +1 -1
- package/dist/multi-agent/agent-process-manager.js +197 -49
- package/dist/multi-agent/agent-process-manager.js.map +1 -1
- package/dist/multi-agent/multi-agent-base.d.ts.map +1 -1
- package/dist/multi-agent/multi-agent-base.js +2 -1
- package/dist/multi-agent/multi-agent-base.js.map +1 -1
- package/dist/multi-agent/runtime-process.d.ts +18 -15
- package/dist/multi-agent/runtime-process.d.ts.map +1 -1
- package/dist/multi-agent/runtime-process.js +63 -59
- package/dist/multi-agent/runtime-process.js.map +1 -1
- package/dist/multi-agent/types.d.ts +13 -7
- package/dist/multi-agent/types.d.ts.map +1 -1
- package/dist/multi-agent/types.js.map +1 -1
- package/dist/multi-agent/workflow-engine.js +3 -3
- package/dist/multi-agent/workflow-engine.js.map +1 -1
- package/dist/multi-agent/workflow-types.d.ts +2 -2
- package/dist/multi-agent/workflow-types.d.ts.map +1 -1
- package/dist/operator/operator-trigger-loop.d.ts +3 -0
- package/dist/operator/operator-trigger-loop.d.ts.map +1 -1
- package/dist/operator/operator-trigger-loop.js +1 -0
- package/dist/operator/operator-trigger-loop.js.map +1 -1
- package/dist/operator/report-run.d.ts +4 -4
- package/dist/operator/situation-report.d.ts +3 -0
- package/dist/operator/situation-report.d.ts.map +1 -1
- package/dist/operator/situation-report.js +43 -26
- package/dist/operator/situation-report.js.map +1 -1
- package/dist/operator/trigger-author.d.ts +35 -1
- package/dist/operator/trigger-author.d.ts.map +1 -1
- package/dist/operator/trigger-author.js +73 -10
- package/dist/operator/trigger-author.js.map +1 -1
- package/dist/operator/worker-run.d.ts +30 -0
- package/dist/operator/worker-run.d.ts.map +1 -1
- package/dist/operator/worker-run.js +64 -1
- package/dist/operator/worker-run.js.map +1 -1
- package/dist/operator/workorder-consumer.d.ts +7 -4
- package/dist/operator/workorder-consumer.d.ts.map +1 -1
- package/dist/operator/workorder-consumer.js +8 -3
- package/dist/operator/workorder-consumer.js.map +1 -1
- package/dist/setup/setup-prompt.d.ts +1 -1
- package/dist/setup/setup-prompt.d.ts.map +1 -1
- package/dist/setup/setup-prompt.js +4 -5
- package/dist/setup/setup-prompt.js.map +1 -1
- package/package.json +1 -1
- package/public/viewer/js/modules/agents.js +13 -9
- package/public/viewer/js/modules/settings.js +15 -10
- package/public/viewer/src/modules/agents.ts +12 -10
- package/public/viewer/src/modules/settings.ts +17 -12
- package/public/viewer/src/utils/api.ts +2 -2
- package/templates/AGENTS.codex.md +2 -23
- package/templates/personas/conductor.md +1 -1
- package/dist/agent/codex-mcp-process.d.ts +0 -105
- package/dist/agent/codex-mcp-process.d.ts.map +0 -1
- package/dist/agent/codex-mcp-process.js +0 -748
- package/dist/agent/codex-mcp-process.js.map +0 -1
|
@@ -1,748 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Codex MCP Process - Codex via MCP protocol
|
|
4
|
-
*
|
|
5
|
-
* Architecture:
|
|
6
|
-
* Chat → MCP Client → codex mcp-server → MCP → Chat
|
|
7
|
-
*
|
|
8
|
-
* Uses standard MCP protocol instead of app-server's JSON-RPC.
|
|
9
|
-
* Benefits:
|
|
10
|
-
* - Standard MCP protocol
|
|
11
|
-
* - compact-prompt parameter for compaction control
|
|
12
|
-
* - threadId-based session management
|
|
13
|
-
*/
|
|
14
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
15
|
-
if (k2 === undefined) k2 = k;
|
|
16
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
17
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
18
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
19
|
-
}
|
|
20
|
-
Object.defineProperty(o, k2, desc);
|
|
21
|
-
}) : (function(o, m, k, k2) {
|
|
22
|
-
if (k2 === undefined) k2 = k;
|
|
23
|
-
o[k2] = m[k];
|
|
24
|
-
}));
|
|
25
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
26
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
27
|
-
}) : function(o, v) {
|
|
28
|
-
o["default"] = v;
|
|
29
|
-
});
|
|
30
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
31
|
-
var ownKeys = function(o) {
|
|
32
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
33
|
-
var ar = [];
|
|
34
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
35
|
-
return ar;
|
|
36
|
-
};
|
|
37
|
-
return ownKeys(o);
|
|
38
|
-
};
|
|
39
|
-
return function (mod) {
|
|
40
|
-
if (mod && mod.__esModule) return mod;
|
|
41
|
-
var result = {};
|
|
42
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
43
|
-
__setModuleDefault(result, mod);
|
|
44
|
-
return result;
|
|
45
|
-
};
|
|
46
|
-
})();
|
|
47
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
-
exports.CodexMCPProcess = void 0;
|
|
49
|
-
const child_process_1 = require("child_process");
|
|
50
|
-
const events_1 = require("events");
|
|
51
|
-
const readline = __importStar(require("readline"));
|
|
52
|
-
const fs_1 = require("fs");
|
|
53
|
-
const os_1 = require("os");
|
|
54
|
-
const path_1 = require("path");
|
|
55
|
-
const debugLogger = __importStar(require("@jungjaehoon/mama-core/debug-logger"));
|
|
56
|
-
const config_manager_js_1 = require("../cli/config/config-manager.js");
|
|
57
|
-
const process_tree_js_1 = require("./process-tree.js");
|
|
58
|
-
const codex_auth_js_1 = require("./codex-auth.js");
|
|
59
|
-
const codex_home_js_1 = require("./codex-home.js");
|
|
60
|
-
const { DebugLogger } = debugLogger;
|
|
61
|
-
const logger = new DebugLogger('CodexMCP');
|
|
62
|
-
const DEFAULT_REQUEST_TIMEOUT_MS = () => (0, config_manager_js_1.getConfig)().timeouts?.codex_request_ms ?? 180_000;
|
|
63
|
-
const DEFAULT_INITIALIZE_TIMEOUT_MS = () => (0, config_manager_js_1.getConfig)().timeouts?.initialize_ms ?? 60_000;
|
|
64
|
-
class CodexMCPProcess extends events_1.EventEmitter {
|
|
65
|
-
process = null;
|
|
66
|
-
currentCallbacks = null;
|
|
67
|
-
options;
|
|
68
|
-
state = 'dead';
|
|
69
|
-
threadId = null;
|
|
70
|
-
requestId = 0;
|
|
71
|
-
pendingRequests = new Map();
|
|
72
|
-
rl = null;
|
|
73
|
-
lastAuthFailure = null;
|
|
74
|
-
constructor(options = {}) {
|
|
75
|
-
super();
|
|
76
|
-
this.options = options;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Start the Codex MCP server process
|
|
80
|
-
*/
|
|
81
|
-
async start() {
|
|
82
|
-
if (this.state !== 'dead') {
|
|
83
|
-
logger.info(`Process already in state: ${this.state}`);
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
this.state = 'starting';
|
|
87
|
-
this.lastAuthFailure = null;
|
|
88
|
-
let command;
|
|
89
|
-
try {
|
|
90
|
-
command = this.resolveCodexCommand();
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
93
|
-
this.state = 'dead';
|
|
94
|
-
throw error;
|
|
95
|
-
}
|
|
96
|
-
logger.info(`Starting Codex MCP server with command: ${command}`);
|
|
97
|
-
// Use a MAMA-specific CODEX_HOME so we control MCP server wiring, while
|
|
98
|
-
// syncing auth from the user's global Codex home on every start.
|
|
99
|
-
const codexHome = this.options.codexHome || (0, path_1.join)((0, os_1.homedir)(), '.mama', '.codex');
|
|
100
|
-
try {
|
|
101
|
-
this.ensureCodexHome(codexHome);
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
104
|
-
const bootstrapError = error instanceof Error ? error : new Error(String(error));
|
|
105
|
-
this.state = 'dead';
|
|
106
|
-
logger.error('Failed to prepare CODEX_HOME:', bootstrapError);
|
|
107
|
-
throw bootstrapError;
|
|
108
|
-
}
|
|
109
|
-
const spawnEnv = { ...process.env, CODEX_HOME: codexHome };
|
|
110
|
-
try {
|
|
111
|
-
this.process = (0, child_process_1.spawn)(command, ['mcp-server'], {
|
|
112
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
113
|
-
cwd: this.options.cwd,
|
|
114
|
-
env: spawnEnv,
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
catch (error) {
|
|
118
|
-
const startError = error instanceof Error ? error : new Error(String(error));
|
|
119
|
-
logger.error('Failed to start Codex MCP process:', startError);
|
|
120
|
-
this.state = 'dead';
|
|
121
|
-
this.process = null;
|
|
122
|
-
throw startError;
|
|
123
|
-
}
|
|
124
|
-
if (!this.process) {
|
|
125
|
-
const startError = new Error(`Failed to create Codex MCP process with command: ${command}`);
|
|
126
|
-
this.state = 'dead';
|
|
127
|
-
throw startError;
|
|
128
|
-
}
|
|
129
|
-
// Set up readline for JSON parsing
|
|
130
|
-
this.rl = readline.createInterface({
|
|
131
|
-
input: this.process.stdout,
|
|
132
|
-
crlfDelay: Infinity,
|
|
133
|
-
});
|
|
134
|
-
this.rl.on('line', (line) => this.handleLine(line));
|
|
135
|
-
this.process.stderr?.on('data', (chunk) => {
|
|
136
|
-
const text = chunk.toString().trim();
|
|
137
|
-
if (text) {
|
|
138
|
-
const authFailure = (0, codex_auth_js_1.extractCodexAuthFailure)(text);
|
|
139
|
-
if (authFailure) {
|
|
140
|
-
const error = new Error(authFailure);
|
|
141
|
-
this.lastAuthFailure = error;
|
|
142
|
-
logger.error('Codex auth failure detected:', authFailure);
|
|
143
|
-
this.shutdown(error, true);
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
logger.warn('stderr:', text);
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
this.process.on('close', (code) => {
|
|
150
|
-
logger.info(`Process closed with code ${code}`);
|
|
151
|
-
this.shutdown(new Error(`Process closed with code ${code ?? 'unknown'}`), false);
|
|
152
|
-
});
|
|
153
|
-
// Wait for process to either start successfully or fail with spawn error
|
|
154
|
-
await new Promise((resolve, reject) => {
|
|
155
|
-
const onSpawnError = (error) => {
|
|
156
|
-
logger.error('Process spawn error:', error);
|
|
157
|
-
this.state = 'dead';
|
|
158
|
-
reject(error);
|
|
159
|
-
};
|
|
160
|
-
this.process.on('error', onSpawnError);
|
|
161
|
-
// Give process a moment to start; if no error fires, it spawned OK
|
|
162
|
-
setTimeout(() => {
|
|
163
|
-
this.process?.removeListener('error', onSpawnError);
|
|
164
|
-
this.process?.on('error', (error) => {
|
|
165
|
-
logger.error('Process error:', error);
|
|
166
|
-
if (this.listenerCount('error') > 0) {
|
|
167
|
-
this.emit('error', error);
|
|
168
|
-
}
|
|
169
|
-
this.shutdown(error instanceof Error ? error : new Error(String(error)), true);
|
|
170
|
-
});
|
|
171
|
-
resolve();
|
|
172
|
-
}, 200);
|
|
173
|
-
});
|
|
174
|
-
try {
|
|
175
|
-
// MCP Initialize (bounded timeout to avoid dead startup)
|
|
176
|
-
await Promise.race([
|
|
177
|
-
this.sendRequest('initialize', {
|
|
178
|
-
protocolVersion: '2024-11-05',
|
|
179
|
-
capabilities: {},
|
|
180
|
-
clientInfo: { name: 'MAMA', version: '1.0.0' },
|
|
181
|
-
}),
|
|
182
|
-
new Promise((_, reject) => {
|
|
183
|
-
setTimeout(() => {
|
|
184
|
-
reject(new Error(`MCP initialize timeout after ${DEFAULT_INITIALIZE_TIMEOUT_MS()}ms`));
|
|
185
|
-
}, DEFAULT_INITIALIZE_TIMEOUT_MS());
|
|
186
|
-
}),
|
|
187
|
-
]);
|
|
188
|
-
this.state = 'ready';
|
|
189
|
-
logger.info('Codex MCP server ready');
|
|
190
|
-
}
|
|
191
|
-
catch (error) {
|
|
192
|
-
logger.error('MCP initialization failed:', error);
|
|
193
|
-
this.cleanup('MCP initialization failed');
|
|
194
|
-
throw error;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Send a prompt and get response
|
|
199
|
-
*/
|
|
200
|
-
async prompt(content, callbacks, options) {
|
|
201
|
-
// Ensure process is running (retry once on failure)
|
|
202
|
-
if (this.state === 'dead') {
|
|
203
|
-
try {
|
|
204
|
-
await this.start();
|
|
205
|
-
}
|
|
206
|
-
catch (err) {
|
|
207
|
-
logger.warn('First start attempt failed, retrying in 1s:', err);
|
|
208
|
-
this.cleanup('Process restart after failed start');
|
|
209
|
-
await new Promise((r) => setTimeout(r, 1000));
|
|
210
|
-
await this.start();
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
// Handle resumeSession option
|
|
214
|
-
if (options?.resumeSession === false) {
|
|
215
|
-
this.threadId = null;
|
|
216
|
-
}
|
|
217
|
-
// Override model if provided
|
|
218
|
-
const effectiveModel = options?.model || this.options.model;
|
|
219
|
-
// Wait if not ready (with timeout)
|
|
220
|
-
const maxWaitMs = this.options.timeoutMs ?? 120000;
|
|
221
|
-
const waitStart = Date.now();
|
|
222
|
-
while (this.state !== 'ready') {
|
|
223
|
-
if (this.state === 'dead') {
|
|
224
|
-
throw new Error('Process is not running');
|
|
225
|
-
}
|
|
226
|
-
if (Date.now() - waitStart > maxWaitMs) {
|
|
227
|
-
throw new Error('Timed out waiting for process to be ready');
|
|
228
|
-
}
|
|
229
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
230
|
-
}
|
|
231
|
-
this.state = 'busy';
|
|
232
|
-
this.currentCallbacks = callbacks || null;
|
|
233
|
-
try {
|
|
234
|
-
let result;
|
|
235
|
-
if (!this.threadId) {
|
|
236
|
-
// First message: use "codex" tool
|
|
237
|
-
const args = {
|
|
238
|
-
prompt: content,
|
|
239
|
-
};
|
|
240
|
-
if (effectiveModel) {
|
|
241
|
-
args.model = effectiveModel;
|
|
242
|
-
}
|
|
243
|
-
if (this.options.cwd) {
|
|
244
|
-
args.cwd = this.options.cwd;
|
|
245
|
-
}
|
|
246
|
-
if (this.options.sandbox) {
|
|
247
|
-
args.sandbox = this.options.sandbox;
|
|
248
|
-
}
|
|
249
|
-
const effectiveSystemPrompt = options?.systemPrompt ?? this.options.systemPrompt;
|
|
250
|
-
if (effectiveSystemPrompt) {
|
|
251
|
-
args['developer-instructions'] = effectiveSystemPrompt;
|
|
252
|
-
}
|
|
253
|
-
if (this.options.compactPrompt) {
|
|
254
|
-
args['compact-prompt'] = this.options.compactPrompt;
|
|
255
|
-
}
|
|
256
|
-
result = await this.callToolWithRetry('codex', args);
|
|
257
|
-
this.threadId = result.threadId;
|
|
258
|
-
logger.info(`Thread started: ${this.threadId}`);
|
|
259
|
-
}
|
|
260
|
-
else {
|
|
261
|
-
// Subsequent messages: use "codex-reply" tool
|
|
262
|
-
result = await this.callToolWithRetry('codex-reply', {
|
|
263
|
-
threadId: this.threadId,
|
|
264
|
-
prompt: content,
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
const response = result.content || '';
|
|
268
|
-
this.currentCallbacks = null;
|
|
269
|
-
callbacks?.onFinal?.({ content: response, toolUseBlocks: [] });
|
|
270
|
-
return {
|
|
271
|
-
response,
|
|
272
|
-
usage: {
|
|
273
|
-
input_tokens: result.usage?.inputTokens ?? 0,
|
|
274
|
-
output_tokens: result.usage?.outputTokens ?? 0,
|
|
275
|
-
cached_input_tokens: result.usage?.cachedTokens ?? 0,
|
|
276
|
-
},
|
|
277
|
-
session_id: this.threadId || '',
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
finally {
|
|
281
|
-
// Only reset to ready if process is still alive (not crashed)
|
|
282
|
-
// Note: close handler may have set state to 'dead' asynchronously
|
|
283
|
-
if (this.process !== null && this.state !== 'dead') {
|
|
284
|
-
this.state = 'ready';
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Reset the session
|
|
290
|
-
*/
|
|
291
|
-
async resetSession() {
|
|
292
|
-
this.threadId = null;
|
|
293
|
-
logger.info('Session reset');
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Get current session ID
|
|
297
|
-
*/
|
|
298
|
-
getSessionId() {
|
|
299
|
-
return this.threadId ?? '';
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* Set session ID (for compatibility)
|
|
303
|
-
* Note: CodexMCPProcess manages its own threadId from Codex responses.
|
|
304
|
-
* External session IDs are ignored to prevent conflicts.
|
|
305
|
-
*/
|
|
306
|
-
setSessionId(_sessionId) {
|
|
307
|
-
// Ignore external session IDs - Codex MCP manages threadId internally
|
|
308
|
-
// The threadId is set only from Codex 'codex' tool response
|
|
309
|
-
logger.debug(`setSessionId called but ignored (MCP manages threadId internally)`);
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Set system prompt
|
|
313
|
-
*/
|
|
314
|
-
setSystemPrompt(prompt) {
|
|
315
|
-
this.options.systemPrompt = prompt;
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* Stop the process
|
|
319
|
-
*/
|
|
320
|
-
stop() {
|
|
321
|
-
this.cleanup('Process stopped');
|
|
322
|
-
logger.info('Process stopped');
|
|
323
|
-
}
|
|
324
|
-
cleanup(reason = 'Process terminated') {
|
|
325
|
-
this.shutdown(new Error(reason), true);
|
|
326
|
-
}
|
|
327
|
-
// ============================================================================
|
|
328
|
-
// Internal methods
|
|
329
|
-
// ============================================================================
|
|
330
|
-
async callTool(name, args) {
|
|
331
|
-
logger.info(`[CALL_START] ${name} thread=${this.threadId || 'none'} args=${Object.keys(args).join(',')}`);
|
|
332
|
-
const response = (await this.sendRequest('tools/call', {
|
|
333
|
-
name,
|
|
334
|
-
arguments: args,
|
|
335
|
-
}));
|
|
336
|
-
const keys = Object.keys(response);
|
|
337
|
-
logger.debug(`[RESPONSE_KEYS] ${keys.join(', ')}`);
|
|
338
|
-
// Extract token usage if available
|
|
339
|
-
const usage = response._meta?.usage;
|
|
340
|
-
if (usage) {
|
|
341
|
-
logger.debug(`[TOKENS] input: ${usage.inputTokens}, cached: ${usage.cachedTokens || 0}, output: ${usage.outputTokens}`);
|
|
342
|
-
}
|
|
343
|
-
// Check structuredContent first (preferred - has threadId)
|
|
344
|
-
if (response.structuredContent?.threadId) {
|
|
345
|
-
logger.info(`[CALL_DONE] ${name} thread=${response.structuredContent.threadId} content_len=${response.structuredContent.content?.length || 0}`);
|
|
346
|
-
return {
|
|
347
|
-
threadId: response.structuredContent.threadId,
|
|
348
|
-
content: response.structuredContent.content || '',
|
|
349
|
-
usage,
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
// Fallback: Extract from content array
|
|
353
|
-
if (response.content && Array.isArray(response.content)) {
|
|
354
|
-
const textContent = response.content.find((c) => c.type === 'text');
|
|
355
|
-
if (textContent?.text) {
|
|
356
|
-
try {
|
|
357
|
-
const parsed = JSON.parse(textContent.text);
|
|
358
|
-
logger.info(`[CALL_DONE] ${name} thread=${parsed.threadId || this.threadId || 'none'} content_len=${parsed.content?.length || textContent.text.length}`);
|
|
359
|
-
return {
|
|
360
|
-
threadId: parsed.threadId || this.threadId || '',
|
|
361
|
-
content: parsed.content || textContent.text,
|
|
362
|
-
usage,
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
catch {
|
|
366
|
-
logger.info(`[CALL_DONE] ${name} thread=${this.threadId || 'none'} content_len=${textContent.text.length}`);
|
|
367
|
-
return { content: textContent.text, threadId: this.threadId || '', usage };
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
// Defensive fallback for unexpected response format
|
|
372
|
-
logger.warn(`Unexpected callTool response format: ${JSON.stringify(response)}`);
|
|
373
|
-
return { threadId: this.threadId || '', content: '', usage };
|
|
374
|
-
}
|
|
375
|
-
async callToolWithRetry(name, args) {
|
|
376
|
-
let attempt = 0;
|
|
377
|
-
while (attempt < 2) {
|
|
378
|
-
attempt += 1;
|
|
379
|
-
try {
|
|
380
|
-
logger.debug(`[CALL] ${name} (attempt=${attempt})`);
|
|
381
|
-
return await this.callTool(name, args);
|
|
382
|
-
}
|
|
383
|
-
catch (error) {
|
|
384
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
385
|
-
if (this.lastAuthFailure) {
|
|
386
|
-
throw this.lastAuthFailure;
|
|
387
|
-
}
|
|
388
|
-
if (attempt >= 2 || !this.isRetryableToolError(err)) {
|
|
389
|
-
logger.error(`Call failed: ${name} (attempt=${attempt})`, err);
|
|
390
|
-
throw err;
|
|
391
|
-
}
|
|
392
|
-
logger.warn(`Retrying ${name} after recoverable tool error: ${err.message}`);
|
|
393
|
-
this.threadId = null;
|
|
394
|
-
this.cleanup();
|
|
395
|
-
await this.start();
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
throw new Error(`Tool call failed after ${attempt} attempts: ${name}`);
|
|
399
|
-
}
|
|
400
|
-
async sendRequest(method, params) {
|
|
401
|
-
if (!this.process?.stdin) {
|
|
402
|
-
throw new Error('Process not running');
|
|
403
|
-
}
|
|
404
|
-
const id = ++this.requestId;
|
|
405
|
-
const request = {
|
|
406
|
-
jsonrpc: '2.0',
|
|
407
|
-
id,
|
|
408
|
-
method,
|
|
409
|
-
params,
|
|
410
|
-
};
|
|
411
|
-
return new Promise((resolve, reject) => {
|
|
412
|
-
const timeoutMs = this.options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS();
|
|
413
|
-
// 0 = unlimited (no timeout)
|
|
414
|
-
const timeout = timeoutMs > 0
|
|
415
|
-
? setTimeout(() => {
|
|
416
|
-
const timeoutError = new Error(`Request timeout: ${method} (id=${id}, timeoutMs=${timeoutMs})`);
|
|
417
|
-
this.failPendingRequest(id, timeoutError);
|
|
418
|
-
this.shutdown(timeoutError, true);
|
|
419
|
-
}, timeoutMs)
|
|
420
|
-
: null;
|
|
421
|
-
this.pendingRequests.set(id, { resolve, reject, method, timeout });
|
|
422
|
-
const line = JSON.stringify(request) + '\n';
|
|
423
|
-
try {
|
|
424
|
-
this.process.stdin.write(line);
|
|
425
|
-
logger.debug(`Sent: ${method} (id=${id})`);
|
|
426
|
-
}
|
|
427
|
-
catch (error) {
|
|
428
|
-
const requestError = error instanceof Error ? error : new Error(String(error));
|
|
429
|
-
logger.error('Failed to write MCP request:', requestError);
|
|
430
|
-
this.failPendingRequest(id, requestError);
|
|
431
|
-
this.shutdown(requestError, true);
|
|
432
|
-
reject(requestError);
|
|
433
|
-
}
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
handleLine(line) {
|
|
437
|
-
if (!line.trim())
|
|
438
|
-
return;
|
|
439
|
-
try {
|
|
440
|
-
const msg = JSON.parse(line);
|
|
441
|
-
if ('id' in msg && msg.id !== undefined) {
|
|
442
|
-
const pending = this.pendingRequests.get(msg.id);
|
|
443
|
-
if (pending) {
|
|
444
|
-
if (pending.timeout)
|
|
445
|
-
clearTimeout(pending.timeout);
|
|
446
|
-
this.pendingRequests.delete(msg.id);
|
|
447
|
-
if (msg.error) {
|
|
448
|
-
pending.reject(new Error(msg.error.message));
|
|
449
|
-
}
|
|
450
|
-
else {
|
|
451
|
-
pending.resolve(msg.result);
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
else if ('method' in msg) {
|
|
456
|
-
// Notification (no id) - parse Codex events for tool usage + streaming
|
|
457
|
-
const notification = msg;
|
|
458
|
-
this.handleNotification(notification);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
catch {
|
|
462
|
-
logger.warn('Failed to parse line:', line.substring(0, 100));
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
/**
|
|
466
|
-
* Handle Codex MCP notifications (codex/event)
|
|
467
|
-
* Events: mcp_tool_call_begin, mcp_tool_call_end, agent_message_delta
|
|
468
|
-
*/
|
|
469
|
-
handleNotification(notification) {
|
|
470
|
-
if (notification.method !== 'codex/event')
|
|
471
|
-
return;
|
|
472
|
-
const params = notification.params;
|
|
473
|
-
const msg = params?.msg;
|
|
474
|
-
if (!msg)
|
|
475
|
-
return;
|
|
476
|
-
const cb = this.currentCallbacks;
|
|
477
|
-
switch (msg.type) {
|
|
478
|
-
case 'mcp_tool_call_begin':
|
|
479
|
-
logger.info(`[EVENT] mcp_tool_call_begin thread=${params?._meta?.threadId || this.threadId || 'none'} server=${msg.invocation?.server || 'unknown'} tool=${msg.invocation?.tool || 'unknown'}`);
|
|
480
|
-
if (cb?.onToolUse && msg.invocation) {
|
|
481
|
-
const toolName = msg.invocation.server
|
|
482
|
-
? `${msg.invocation.server}:${msg.invocation.tool}`
|
|
483
|
-
: msg.invocation.tool || 'unknown';
|
|
484
|
-
cb.onToolUse(toolName, msg.invocation.arguments || {});
|
|
485
|
-
logger.info(`[TOOL_BEGIN] ${toolName}`);
|
|
486
|
-
}
|
|
487
|
-
break;
|
|
488
|
-
case 'mcp_tool_call_end':
|
|
489
|
-
logger.info(`[EVENT] mcp_tool_call_end thread=${params?._meta?.threadId || this.threadId || 'none'} server=${msg.invocation?.server || 'unknown'} tool=${msg.invocation?.tool || 'unknown'}`);
|
|
490
|
-
if (cb?.onToolComplete && msg.call_id) {
|
|
491
|
-
const toolName = msg.invocation?.tool || 'unknown';
|
|
492
|
-
const isError = false; // Codex doesn't indicate error in this event
|
|
493
|
-
cb.onToolComplete(toolName, msg.call_id, isError);
|
|
494
|
-
logger.info(`[TOOL_END] ${toolName}`);
|
|
495
|
-
}
|
|
496
|
-
break;
|
|
497
|
-
case 'agent_message_delta':
|
|
498
|
-
logger.debug(`[EVENT] agent_message_delta len=${typeof msg.delta === 'string' ? msg.delta.length : 0}`);
|
|
499
|
-
if (cb?.onDelta && typeof msg.delta === 'string') {
|
|
500
|
-
cb.onDelta(msg.delta);
|
|
501
|
-
}
|
|
502
|
-
break;
|
|
503
|
-
// Codex built-in tools (Bash, Write, Read etc.) — not MCP tools
|
|
504
|
-
case 'function_call':
|
|
505
|
-
if (cb?.onToolUse) {
|
|
506
|
-
const fnName = msg.name || 'unknown';
|
|
507
|
-
let fnArgs = {};
|
|
508
|
-
try {
|
|
509
|
-
const raw = msg.arguments;
|
|
510
|
-
if (raw)
|
|
511
|
-
fnArgs = JSON.parse(raw);
|
|
512
|
-
}
|
|
513
|
-
catch {
|
|
514
|
-
// arguments may not be valid JSON
|
|
515
|
-
}
|
|
516
|
-
cb.onToolUse(fnName, fnArgs);
|
|
517
|
-
logger.info(`[TOOL_BEGIN] ${fnName} (builtin)`);
|
|
518
|
-
}
|
|
519
|
-
break;
|
|
520
|
-
case 'function_call_output':
|
|
521
|
-
if (cb?.onToolComplete) {
|
|
522
|
-
const callId = msg.call_id || msg.id || 'unknown';
|
|
523
|
-
cb.onToolComplete('builtin', callId, false);
|
|
524
|
-
logger.info(`[TOOL_END] builtin (call_id=${callId})`);
|
|
525
|
-
}
|
|
526
|
-
break;
|
|
527
|
-
// raw_response_item wraps function_call for streaming
|
|
528
|
-
case 'raw_response_item': {
|
|
529
|
-
const item = msg.item;
|
|
530
|
-
if (!item)
|
|
531
|
-
break;
|
|
532
|
-
if (item.type === 'function_call' && cb?.onToolUse) {
|
|
533
|
-
const fnName = item.name || 'unknown';
|
|
534
|
-
let fnArgs = {};
|
|
535
|
-
try {
|
|
536
|
-
if (item.arguments)
|
|
537
|
-
fnArgs = JSON.parse(item.arguments);
|
|
538
|
-
}
|
|
539
|
-
catch {
|
|
540
|
-
/* */
|
|
541
|
-
}
|
|
542
|
-
cb.onToolUse(fnName, fnArgs);
|
|
543
|
-
logger.info(`[TOOL_BEGIN] ${fnName} (raw_response_item)`);
|
|
544
|
-
}
|
|
545
|
-
else if (item.type === 'function_call_output' && cb?.onToolComplete) {
|
|
546
|
-
const callId = item.call_id || 'unknown';
|
|
547
|
-
cb.onToolComplete('builtin', callId, false);
|
|
548
|
-
logger.info(`[TOOL_END] builtin (raw_response_item, call_id=${callId})`);
|
|
549
|
-
}
|
|
550
|
-
break;
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
resolveCodexCommand() {
|
|
555
|
-
const configured = [
|
|
556
|
-
this.options.command,
|
|
557
|
-
process.env.MAMA_CODEX_COMMAND,
|
|
558
|
-
process.env.CODEX_COMMAND,
|
|
559
|
-
];
|
|
560
|
-
for (const candidate of configured) {
|
|
561
|
-
if (!candidate) {
|
|
562
|
-
continue;
|
|
563
|
-
}
|
|
564
|
-
const trimmed = candidate.trim();
|
|
565
|
-
if (!trimmed) {
|
|
566
|
-
continue;
|
|
567
|
-
}
|
|
568
|
-
if (this.isExecutable(trimmed)) {
|
|
569
|
-
return trimmed;
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
const fromPath = this.findExecutableInPath('codex');
|
|
573
|
-
if (fromPath) {
|
|
574
|
-
return fromPath;
|
|
575
|
-
}
|
|
576
|
-
const home = (0, os_1.homedir)();
|
|
577
|
-
const fallbackCandidates = [
|
|
578
|
-
(0, path_1.join)(home, '.local', 'bin', 'codex'),
|
|
579
|
-
(0, path_1.join)(home, 'bin', 'codex'),
|
|
580
|
-
'/usr/local/bin/codex',
|
|
581
|
-
'/usr/bin/codex',
|
|
582
|
-
'/opt/homebrew/bin/codex',
|
|
583
|
-
'/bin/codex',
|
|
584
|
-
];
|
|
585
|
-
for (const candidate of fallbackCandidates) {
|
|
586
|
-
if (this.isExecutable(candidate)) {
|
|
587
|
-
return candidate;
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
throw new Error('Codex command not found. Set MAMA_CODEX_COMMAND or CODEX_COMMAND to an executable path, or install codex in PATH.');
|
|
591
|
-
}
|
|
592
|
-
isExecutable(target) {
|
|
593
|
-
try {
|
|
594
|
-
(0, fs_1.accessSync)(target, fs_1.constants.X_OK);
|
|
595
|
-
return true;
|
|
596
|
-
}
|
|
597
|
-
catch {
|
|
598
|
-
return false;
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
ensureCodexHome(codexHome) {
|
|
602
|
-
if (!(0, fs_1.existsSync)(codexHome)) {
|
|
603
|
-
(0, fs_1.mkdirSync)(codexHome, { recursive: true, mode: 0o700 });
|
|
604
|
-
}
|
|
605
|
-
(0, fs_1.chmodSync)(codexHome, 0o700);
|
|
606
|
-
const configPath = (0, path_1.join)(codexHome, 'config.toml');
|
|
607
|
-
const configToml = (0, codex_home_js_1.buildMAMACodexConfig)(this.options.mcpConfigPath);
|
|
608
|
-
(0, fs_1.writeFileSync)(configPath, configToml, 'utf-8');
|
|
609
|
-
(0, fs_1.chmodSync)(configPath, 0o600);
|
|
610
|
-
const internalAuthPath = (0, path_1.join)(codexHome, 'auth.json');
|
|
611
|
-
const externalAuthPath = (0, path_1.join)((0, os_1.homedir)(), '.codex', 'auth.json');
|
|
612
|
-
if ((0, fs_1.existsSync)(externalAuthPath)) {
|
|
613
|
-
try {
|
|
614
|
-
(0, fs_1.copyFileSync)(externalAuthPath, internalAuthPath);
|
|
615
|
-
(0, fs_1.chmodSync)(internalAuthPath, 0o600);
|
|
616
|
-
logger.info(`Synced Codex auth into ${internalAuthPath}`);
|
|
617
|
-
}
|
|
618
|
-
catch (error) {
|
|
619
|
-
logger.warn(`Failed to sync Codex auth: ${error instanceof Error ? error.message : String(error)}`);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
else if ((0, fs_1.existsSync)(internalAuthPath)) {
|
|
623
|
-
try {
|
|
624
|
-
(0, fs_1.unlinkSync)(internalAuthPath);
|
|
625
|
-
logger.info('Removed stale internal Codex auth file (external auth deleted)');
|
|
626
|
-
}
|
|
627
|
-
catch (unlinkErr) {
|
|
628
|
-
logger.warn(`Failed to remove stale Codex auth: ${unlinkErr instanceof Error ? unlinkErr.message : String(unlinkErr)}`);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
findExecutableInPath(commandName) {
|
|
633
|
-
const pathValue = process.env.PATH || '';
|
|
634
|
-
if (!pathValue) {
|
|
635
|
-
return null;
|
|
636
|
-
}
|
|
637
|
-
const pathEntries = pathValue
|
|
638
|
-
.split(path_1.delimiter)
|
|
639
|
-
.map((value) => value.trim())
|
|
640
|
-
.filter(Boolean);
|
|
641
|
-
for (const dir of pathEntries) {
|
|
642
|
-
const candidate = (0, path_1.join)(dir, commandName);
|
|
643
|
-
if (this.isExecutable(candidate)) {
|
|
644
|
-
return candidate;
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
return null;
|
|
648
|
-
}
|
|
649
|
-
failPendingRequest(id, error) {
|
|
650
|
-
const pending = this.pendingRequests.get(id);
|
|
651
|
-
if (!pending) {
|
|
652
|
-
return;
|
|
653
|
-
}
|
|
654
|
-
if (pending.timeout)
|
|
655
|
-
clearTimeout(pending.timeout);
|
|
656
|
-
this.pendingRequests.delete(id);
|
|
657
|
-
pending.reject(error);
|
|
658
|
-
}
|
|
659
|
-
clearPendingRequests(error) {
|
|
660
|
-
for (const [, pending] of this.pendingRequests) {
|
|
661
|
-
if (pending.timeout)
|
|
662
|
-
clearTimeout(pending.timeout);
|
|
663
|
-
pending.reject(new Error(`${error.message} (${pending.method})`));
|
|
664
|
-
}
|
|
665
|
-
this.pendingRequests.clear();
|
|
666
|
-
}
|
|
667
|
-
isRetryableToolError(error) {
|
|
668
|
-
const message = error.message.toLowerCase();
|
|
669
|
-
if ((0, codex_auth_js_1.extractCodexAuthFailure)(error.message)) {
|
|
670
|
-
return false;
|
|
671
|
-
}
|
|
672
|
-
return (!message.includes('request timeout') &&
|
|
673
|
-
(message.includes('process is not running') ||
|
|
674
|
-
message.includes('process closed with code') ||
|
|
675
|
-
message.includes('mcp initialize timeout') ||
|
|
676
|
-
message.includes('connection closed') ||
|
|
677
|
-
message.includes('econnreset')));
|
|
678
|
-
}
|
|
679
|
-
shutdown(error, shouldKillProcess) {
|
|
680
|
-
if (this.state === 'dead' && this.pendingRequests.size === 0 && !shouldKillProcess) {
|
|
681
|
-
return;
|
|
682
|
-
}
|
|
683
|
-
this.state = 'dead';
|
|
684
|
-
this.clearPendingRequests(error);
|
|
685
|
-
if (shouldKillProcess && this.process) {
|
|
686
|
-
const processToKill = this.process;
|
|
687
|
-
const rootPid = processToKill.pid;
|
|
688
|
-
if (!rootPid) {
|
|
689
|
-
this.rl?.close();
|
|
690
|
-
this.rl = null;
|
|
691
|
-
this.process = null;
|
|
692
|
-
this.threadId = null;
|
|
693
|
-
return;
|
|
694
|
-
}
|
|
695
|
-
const forceKillTimer = setTimeout(() => {
|
|
696
|
-
this.killProcessTree(rootPid, 'SIGKILL');
|
|
697
|
-
}, 1000);
|
|
698
|
-
forceKillTimer.unref();
|
|
699
|
-
processToKill.once('close', () => {
|
|
700
|
-
clearTimeout(forceKillTimer);
|
|
701
|
-
});
|
|
702
|
-
try {
|
|
703
|
-
this.killProcessTree(rootPid, 'SIGTERM');
|
|
704
|
-
}
|
|
705
|
-
catch {
|
|
706
|
-
clearTimeout(forceKillTimer);
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
if (this.rl) {
|
|
710
|
-
this.rl.close();
|
|
711
|
-
this.rl = null;
|
|
712
|
-
}
|
|
713
|
-
this.process = null;
|
|
714
|
-
this.threadId = null;
|
|
715
|
-
}
|
|
716
|
-
killProcessTree(rootPid, signal) {
|
|
717
|
-
const descendants = this.listDescendantPids(rootPid);
|
|
718
|
-
for (const pid of [...descendants.reverse(), rootPid]) {
|
|
719
|
-
try {
|
|
720
|
-
process.kill(pid, signal);
|
|
721
|
-
}
|
|
722
|
-
catch {
|
|
723
|
-
// Process may already be gone.
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
listDescendantPids(rootPid) {
|
|
728
|
-
try {
|
|
729
|
-
const output = (0, child_process_1.execFileSync)('ps', ['-Ao', 'pid=,ppid='], { encoding: 'utf8' });
|
|
730
|
-
const rows = output
|
|
731
|
-
.split('\n')
|
|
732
|
-
.map((line) => line.trim())
|
|
733
|
-
.filter(Boolean)
|
|
734
|
-
.map((line) => {
|
|
735
|
-
const [pid, ppid] = line.split(/\s+/);
|
|
736
|
-
return { pid: Number(pid), ppid: Number(ppid) };
|
|
737
|
-
})
|
|
738
|
-
.filter((row) => Number.isFinite(row.pid) && Number.isFinite(row.ppid));
|
|
739
|
-
return (0, process_tree_js_1.collectDescendantPids)(rootPid, rows);
|
|
740
|
-
}
|
|
741
|
-
catch (error) {
|
|
742
|
-
logger.warn(`Failed to inspect codex process descendants: ${error instanceof Error ? error.message : String(error)}`);
|
|
743
|
-
return [];
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
exports.CodexMCPProcess = CodexMCPProcess;
|
|
748
|
-
//# sourceMappingURL=codex-mcp-process.js.map
|