@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.
Files changed (190) hide show
  1. package/dist/agent/agent-loop.d.ts +3 -6
  2. package/dist/agent/agent-loop.d.ts.map +1 -1
  3. package/dist/agent/agent-loop.js +390 -202
  4. package/dist/agent/agent-loop.js.map +1 -1
  5. package/dist/agent/code-act/constants.d.ts +2 -2
  6. package/dist/agent/code-act/constants.d.ts.map +1 -1
  7. package/dist/agent/code-act/constants.js +16 -9
  8. package/dist/agent/code-act/constants.js.map +1 -1
  9. package/dist/agent/code-act/host-bridge.d.ts +12 -11
  10. package/dist/agent/code-act/host-bridge.d.ts.map +1 -1
  11. package/dist/agent/code-act/host-bridge.js +92 -15
  12. package/dist/agent/code-act/host-bridge.js.map +1 -1
  13. package/dist/agent/code-act/index.d.ts +2 -0
  14. package/dist/agent/code-act/index.d.ts.map +1 -1
  15. package/dist/agent/code-act/index.js +5 -1
  16. package/dist/agent/code-act/index.js.map +1 -1
  17. package/dist/agent/code-act/tool-policy.d.ts +42 -0
  18. package/dist/agent/code-act/tool-policy.d.ts.map +1 -0
  19. package/dist/agent/code-act/tool-policy.js +122 -0
  20. package/dist/agent/code-act/tool-policy.js.map +1 -0
  21. package/dist/agent/code-act/type-definition-generator.d.ts +4 -3
  22. package/dist/agent/code-act/type-definition-generator.d.ts.map +1 -1
  23. package/dist/agent/code-act/type-definition-generator.js +26 -48
  24. package/dist/agent/code-act/type-definition-generator.js.map +1 -1
  25. package/dist/agent/codex-app-server-process.d.ts +116 -0
  26. package/dist/agent/codex-app-server-process.d.ts.map +1 -0
  27. package/dist/agent/codex-app-server-process.js +1382 -0
  28. package/dist/agent/codex-app-server-process.js.map +1 -0
  29. package/dist/agent/codex-home.d.ts +9 -0
  30. package/dist/agent/codex-home.d.ts.map +1 -1
  31. package/dist/agent/codex-home.js +626 -4
  32. package/dist/agent/codex-home.js.map +1 -1
  33. package/dist/agent/codex-thread-registry.d.ts +63 -0
  34. package/dist/agent/codex-thread-registry.d.ts.map +1 -0
  35. package/dist/agent/codex-thread-registry.js +433 -0
  36. package/dist/agent/codex-thread-registry.js.map +1 -0
  37. package/dist/agent/gateway-tool-executor.d.ts +2 -7
  38. package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
  39. package/dist/agent/gateway-tool-executor.js +69 -84
  40. package/dist/agent/gateway-tool-executor.js.map +1 -1
  41. package/dist/agent/managed-agent-runtime-sync.d.ts.map +1 -1
  42. package/dist/agent/managed-agent-runtime-sync.js +0 -3
  43. package/dist/agent/managed-agent-runtime-sync.js.map +1 -1
  44. package/dist/agent/managed-agent-validation.js +1 -1
  45. package/dist/agent/managed-agent-validation.js.map +1 -1
  46. package/dist/agent/model-runner.d.ts +51 -3
  47. package/dist/agent/model-runner.d.ts.map +1 -1
  48. package/dist/agent/model-runner.js +1 -1
  49. package/dist/agent/model-runner.js.map +1 -1
  50. package/dist/agent/persistent-cli-adapter.d.ts +1 -0
  51. package/dist/agent/persistent-cli-adapter.d.ts.map +1 -1
  52. package/dist/agent/persistent-cli-adapter.js +3 -0
  53. package/dist/agent/persistent-cli-adapter.js.map +1 -1
  54. package/dist/agent/session-pool.d.ts +2 -2
  55. package/dist/agent/session-pool.d.ts.map +1 -1
  56. package/dist/agent/session-pool.js +6 -6
  57. package/dist/agent/session-pool.js.map +1 -1
  58. package/dist/agent/tool-registry.d.ts +14 -0
  59. package/dist/agent/tool-registry.d.ts.map +1 -1
  60. package/dist/agent/tool-registry.js +46 -7
  61. package/dist/agent/tool-registry.js.map +1 -1
  62. package/dist/agent/types.d.ts +40 -6
  63. package/dist/agent/types.d.ts.map +1 -1
  64. package/dist/agent/types.js.map +1 -1
  65. package/dist/api/graph-api.d.ts.map +1 -1
  66. package/dist/api/graph-api.js +19 -7
  67. package/dist/api/graph-api.js.map +1 -1
  68. package/dist/cli/commands/init.d.ts +1 -1
  69. package/dist/cli/commands/init.d.ts.map +1 -1
  70. package/dist/cli/commands/init.js +22 -14
  71. package/dist/cli/commands/init.js.map +1 -1
  72. package/dist/cli/commands/run.d.ts.map +1 -1
  73. package/dist/cli/commands/run.js +7 -4
  74. package/dist/cli/commands/run.js.map +1 -1
  75. package/dist/cli/commands/start.d.ts +2 -0
  76. package/dist/cli/commands/start.d.ts.map +1 -1
  77. package/dist/cli/commands/start.js +77 -24
  78. package/dist/cli/commands/start.js.map +1 -1
  79. package/dist/cli/commands/status.js +2 -2
  80. package/dist/cli/commands/status.js.map +1 -1
  81. package/dist/cli/config/config-manager.d.ts.map +1 -1
  82. package/dist/cli/config/config-manager.js +21 -4
  83. package/dist/cli/config/config-manager.js.map +1 -1
  84. package/dist/cli/config/types.d.ts +4 -4
  85. package/dist/cli/config/types.d.ts.map +1 -1
  86. package/dist/cli/config/types.js +1 -0
  87. package/dist/cli/config/types.js.map +1 -1
  88. package/dist/cli/index.js +2 -2
  89. package/dist/cli/index.js.map +1 -1
  90. package/dist/cli/runtime/agent-loop-init.d.ts +1 -1
  91. package/dist/cli/runtime/agent-loop-init.d.ts.map +1 -1
  92. package/dist/cli/runtime/agent-loop-init.js +12 -11
  93. package/dist/cli/runtime/agent-loop-init.js.map +1 -1
  94. package/dist/cli/runtime/connector-init.d.ts.map +1 -1
  95. package/dist/cli/runtime/connector-init.js +13 -17
  96. package/dist/cli/runtime/connector-init.js.map +1 -1
  97. package/dist/cli/runtime/envelope-bootstrap.d.ts.map +1 -1
  98. package/dist/cli/runtime/envelope-bootstrap.js +13 -1
  99. package/dist/cli/runtime/envelope-bootstrap.js.map +1 -1
  100. package/dist/cli/runtime/gateway-init.d.ts +1 -1
  101. package/dist/cli/runtime/gateway-init.d.ts.map +1 -1
  102. package/dist/cli/runtime/gateway-init.js.map +1 -1
  103. package/dist/cli/runtime/mama-core-init.d.ts +2 -2
  104. package/dist/cli/runtime/mama-core-init.d.ts.map +1 -1
  105. package/dist/cli/runtime/mama-core-init.js +17 -0
  106. package/dist/cli/runtime/mama-core-init.js.map +1 -1
  107. package/dist/cli/runtime/memory-agent-init.d.ts +1 -1
  108. package/dist/cli/runtime/memory-agent-init.d.ts.map +1 -1
  109. package/dist/cli/runtime/memory-agent-init.js +16 -6
  110. package/dist/cli/runtime/memory-agent-init.js.map +1 -1
  111. package/dist/cli/runtime/types.d.ts +4 -26
  112. package/dist/cli/runtime/types.d.ts.map +1 -1
  113. package/dist/cli/runtime/utilities.js +2 -2
  114. package/dist/cli/runtime/utilities.js.map +1 -1
  115. package/dist/connectors/config-loader.d.ts +24 -0
  116. package/dist/connectors/config-loader.d.ts.map +1 -0
  117. package/dist/connectors/config-loader.js +205 -0
  118. package/dist/connectors/config-loader.js.map +1 -0
  119. package/dist/connectors/framework/types.d.ts +2 -0
  120. package/dist/connectors/framework/types.d.ts.map +1 -1
  121. package/dist/connectors/kagemusha/query-tools.js +2 -2
  122. package/dist/connectors/kagemusha/query-tools.js.map +1 -1
  123. package/dist/envelope/reactive-config.d.ts +2 -2
  124. package/dist/envelope/reactive-config.d.ts.map +1 -1
  125. package/dist/envelope/reactive-config.js +13 -6
  126. package/dist/envelope/reactive-config.js.map +1 -1
  127. package/dist/gateways/context-injector.d.ts +2 -1
  128. package/dist/gateways/context-injector.d.ts.map +1 -1
  129. package/dist/gateways/context-injector.js.map +1 -1
  130. package/dist/gateways/message-router.d.ts +1 -0
  131. package/dist/gateways/message-router.d.ts.map +1 -1
  132. package/dist/gateways/message-router.js +25 -3
  133. package/dist/gateways/message-router.js.map +1 -1
  134. package/dist/gateways/types.d.ts +1 -1
  135. package/dist/gateways/types.d.ts.map +1 -1
  136. package/dist/multi-agent/agent-process-manager.d.ts +9 -1
  137. package/dist/multi-agent/agent-process-manager.d.ts.map +1 -1
  138. package/dist/multi-agent/agent-process-manager.js +197 -49
  139. package/dist/multi-agent/agent-process-manager.js.map +1 -1
  140. package/dist/multi-agent/multi-agent-base.d.ts.map +1 -1
  141. package/dist/multi-agent/multi-agent-base.js +2 -1
  142. package/dist/multi-agent/multi-agent-base.js.map +1 -1
  143. package/dist/multi-agent/runtime-process.d.ts +18 -15
  144. package/dist/multi-agent/runtime-process.d.ts.map +1 -1
  145. package/dist/multi-agent/runtime-process.js +63 -59
  146. package/dist/multi-agent/runtime-process.js.map +1 -1
  147. package/dist/multi-agent/types.d.ts +13 -7
  148. package/dist/multi-agent/types.d.ts.map +1 -1
  149. package/dist/multi-agent/types.js.map +1 -1
  150. package/dist/multi-agent/workflow-engine.js +3 -3
  151. package/dist/multi-agent/workflow-engine.js.map +1 -1
  152. package/dist/multi-agent/workflow-types.d.ts +2 -2
  153. package/dist/multi-agent/workflow-types.d.ts.map +1 -1
  154. package/dist/operator/operator-trigger-loop.d.ts +3 -0
  155. package/dist/operator/operator-trigger-loop.d.ts.map +1 -1
  156. package/dist/operator/operator-trigger-loop.js +1 -0
  157. package/dist/operator/operator-trigger-loop.js.map +1 -1
  158. package/dist/operator/report-run.d.ts +4 -4
  159. package/dist/operator/situation-report.d.ts +3 -0
  160. package/dist/operator/situation-report.d.ts.map +1 -1
  161. package/dist/operator/situation-report.js +43 -26
  162. package/dist/operator/situation-report.js.map +1 -1
  163. package/dist/operator/trigger-author.d.ts +35 -1
  164. package/dist/operator/trigger-author.d.ts.map +1 -1
  165. package/dist/operator/trigger-author.js +73 -10
  166. package/dist/operator/trigger-author.js.map +1 -1
  167. package/dist/operator/worker-run.d.ts +30 -0
  168. package/dist/operator/worker-run.d.ts.map +1 -1
  169. package/dist/operator/worker-run.js +64 -1
  170. package/dist/operator/worker-run.js.map +1 -1
  171. package/dist/operator/workorder-consumer.d.ts +7 -4
  172. package/dist/operator/workorder-consumer.d.ts.map +1 -1
  173. package/dist/operator/workorder-consumer.js +8 -3
  174. package/dist/operator/workorder-consumer.js.map +1 -1
  175. package/dist/setup/setup-prompt.d.ts +1 -1
  176. package/dist/setup/setup-prompt.d.ts.map +1 -1
  177. package/dist/setup/setup-prompt.js +4 -5
  178. package/dist/setup/setup-prompt.js.map +1 -1
  179. package/package.json +1 -1
  180. package/public/viewer/js/modules/agents.js +13 -9
  181. package/public/viewer/js/modules/settings.js +15 -10
  182. package/public/viewer/src/modules/agents.ts +12 -10
  183. package/public/viewer/src/modules/settings.ts +17 -12
  184. package/public/viewer/src/utils/api.ts +2 -2
  185. package/templates/AGENTS.codex.md +2 -23
  186. package/templates/personas/conductor.md +1 -1
  187. package/dist/agent/codex-mcp-process.d.ts +0 -105
  188. package/dist/agent/codex-mcp-process.d.ts.map +0 -1
  189. package/dist/agent/codex-mcp-process.js +0 -748
  190. 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