mcp-codex-worker 0.1.13 → 0.1.14

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.
@@ -12,7 +12,10 @@ import {
12
12
  type ProviderSpawnOptions,
13
13
  type AvailabilityResult,
14
14
  } from './base-adapter.js';
15
- import type { CodexRuntime } from '../services/codex-runtime.js';
15
+ import { CodexRuntime } from '../services/codex-runtime.js';
16
+ import type { AppServerClient } from '../services/app-server-client.js';
17
+ import { attachPauseFlow } from './codex-pause-flow.js';
18
+ import { REQUEST_TIMEOUT_MS } from '../config/defaults.js';
16
19
 
17
20
  // ---------------------------------------------------------------------------
18
21
  // Options
@@ -52,16 +55,103 @@ export class CodexAdapter extends BaseProviderAdapter {
52
55
  return {};
53
56
  }
54
57
 
58
+ // -------------------------------------------------------------------------
59
+ // Core session lifecycle
60
+ // -------------------------------------------------------------------------
61
+
55
62
  protected async executeSession(
56
- _handle: TaskHandle,
57
- _prompt: string,
63
+ handle: TaskHandle,
64
+ prompt: string,
58
65
  _signal: AbortSignal,
59
- _options: ProviderSpawnOptions,
66
+ options: ProviderSpawnOptions,
60
67
  ): Promise<void> {
61
- throw new Error('CodexAdapter.executeSession is not yet implemented');
68
+ const runtime = this.getRuntime();
69
+ let detachPauseFlow: (() => void) | undefined;
70
+
71
+ try {
72
+ // 1. Create a new thread
73
+ const { params: threadParams } = await runtime.buildThreadStartParams({
74
+ model: options.model,
75
+ cwd: options.cwd,
76
+ });
77
+ const threadResult = await runtime.request('thread/start', threadParams) as {
78
+ thread?: { id?: string };
79
+ };
80
+ const threadId = threadResult?.thread?.id;
81
+ if (!threadId) {
82
+ throw new Error('thread/start did not return a thread ID');
83
+ }
84
+
85
+ // 2. Mark running with the thread ID as session identifier
86
+ handle.markRunning(threadId);
87
+
88
+ // 3. Attach pause-flow: translate server-requests → PendingQuestions
89
+ // getCurrentClient() is private on CodexRuntime; access via cast.
90
+ // Safe after a successful request() call guarantees the client exists.
91
+ const client = (runtime as unknown as { getCurrentClient(): AppServerClient })
92
+ .getCurrentClient();
93
+ detachPauseFlow = attachPauseFlow(client, handle, threadId);
94
+
95
+ // 4. Build turn params and start the turn via bridged request
96
+ const { params: turnParams } = await runtime.buildTurnStartParams({
97
+ threadId,
98
+ userInput: prompt,
99
+ model: options.model,
100
+ });
101
+ const bridgeResult = await runtime.requestWithBridge(
102
+ 'turn/start',
103
+ turnParams,
104
+ { threadId },
105
+ );
106
+
107
+ // 5. Handle bridge result
108
+ if (bridgeResult.status === 'pending_request') {
109
+ // Pause flow already queued the question on the handle and
110
+ // markInputRequired was called. Nothing more to do here —
111
+ // the wait-task / answer-task handlers drive the rest.
112
+ return;
113
+ }
114
+
115
+ if (bridgeResult.status === 'completed') {
116
+ handle.markCompleted();
117
+ return;
118
+ }
119
+
120
+ // status === 'running' — the bridge timed out before completion;
121
+ // poll until the operation settles.
122
+ const timeoutMs = options.timeout > 0 ? options.timeout : REQUEST_TIMEOUT_MS;
123
+ const op = await runtime.waitForOperation(
124
+ bridgeResult.operationId,
125
+ timeoutMs,
126
+ 500,
127
+ );
128
+
129
+ if (op.status === 'completed') {
130
+ handle.markCompleted();
131
+ } else {
132
+ handle.markFailed(op.error ?? 'Turn failed');
133
+ }
134
+ } finally {
135
+ detachPauseFlow?.();
136
+ }
62
137
  }
63
138
 
64
139
  async shutdown(): Promise<void> {
65
140
  await this.runtime?.shutdown();
66
141
  }
142
+
143
+ // -------------------------------------------------------------------------
144
+ // Internal
145
+ // -------------------------------------------------------------------------
146
+
147
+ private getRuntime(): CodexRuntime {
148
+ if (!this.runtime) {
149
+ this.runtime = new CodexRuntime({
150
+ command: this.options.command,
151
+ args: this.options.args,
152
+ env: this.options.env,
153
+ });
154
+ }
155
+ return this.runtime;
156
+ }
67
157
  }
package/src/index.ts CHANGED
@@ -64,6 +64,21 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
64
64
 
65
65
  async function main(): Promise<void> {
66
66
  await app.initialize();
67
+
68
+ // Wire state-change notifications: when any task status changes,
69
+ // notify MCP clients that the scoreboard and task detail resources are updated.
70
+ const taskManager = app.getTaskManager();
71
+ taskManager.onStatusChange((task) => {
72
+ server.notification({
73
+ method: 'notifications/resources/updated',
74
+ params: { uri: 'task:///all' },
75
+ }).catch(() => {});
76
+ server.notification({
77
+ method: 'notifications/resources/updated',
78
+ params: { uri: `task:///${task.id}` },
79
+ }).catch(() => {});
80
+ });
81
+
67
82
  const transport = new StdioServerTransport();
68
83
  await server.connect(transport);
69
84
  process.stdin.resume();
@@ -164,6 +164,7 @@ export function createToolDefinitions(input: CreateToolDefinitionsInput): ToolDe
164
164
  {
165
165
  name: 'codex-thread-start',
166
166
  description: [
167
+ '⚠️ DEPRECATED — Use spawn-task/wait-task/respond-task instead. This tool will be removed in v2.0.\n',
167
168
  'Launch a new Codex agent as a background thread.',
168
169
  '',
169
170
  'PARALLEL EXECUTION: Launch multiple threads simultaneously — each thread is an independent agent workspace with its own context and conversation history.',
@@ -192,7 +193,7 @@ export function createToolDefinitions(input: CreateToolDefinitionsInput): ToolDe
192
193
  },
193
194
  {
194
195
  name: 'codex-thread-resume',
195
- description: 'Resume a previously started Codex thread. Reloads context and reconnects the agent. Use to continue work on an existing thread after a pause, or to send follow-up instructions to a completed thread.',
196
+ description: '⚠️ DEPRECATED — Use spawn-task/wait-task/respond-task instead. This tool will be removed in v2.0.\n\nResume a previously started Codex thread. Reloads context and reconnects the agent. Use to continue work on an existing thread after a pause, or to send follow-up instructions to a completed thread.',
196
197
  inputSchema: objectSchema({
197
198
  thread_id: { type: 'string', minLength: 1, description: 'ID of the thread to resume.' },
198
199
  model: {
@@ -208,6 +209,7 @@ export function createToolDefinitions(input: CreateToolDefinitionsInput): ToolDe
208
209
  {
209
210
  name: 'codex-thread-read',
210
211
  description: [
212
+ '⚠️ DEPRECATED — Use spawn-task/wait-task/respond-task instead. This tool will be removed in v2.0.\n',
211
213
  'Read thread status and conversation history. Use to check what an agent has done, inspect its output, or verify task completion. Set include_turns=true for full turn details including tool calls and file changes.',
212
214
  threadBanner,
213
215
  ].filter(Boolean).join('\n\n'),
@@ -219,7 +221,7 @@ export function createToolDefinitions(input: CreateToolDefinitionsInput): ToolDe
219
221
  },
220
222
  {
221
223
  name: 'codex-thread-list',
222
- description: 'List recent Codex threads across all sessions. Use to discover existing threads before starting new ones, or to find a thread ID you need to resume.',
224
+ description: '⚠️ DEPRECATED — Use spawn-task/wait-task/respond-task instead. This tool will be removed in v2.0.\n\nList recent Codex threads across all sessions. Use to discover existing threads before starting new ones, or to find a thread ID you need to resume.',
223
225
  inputSchema: objectSchema({
224
226
  limit: { type: 'integer', minimum: 1, maximum: 100, description: 'Max threads to return. Default 50.' },
225
227
  cursor: { type: 'string', description: 'Pagination cursor from a previous response.' },
@@ -230,6 +232,7 @@ export function createToolDefinitions(input: CreateToolDefinitionsInput): ToolDe
230
232
  name: 'codex-turn-start',
231
233
  description: [
232
234
  [
235
+ '⚠️ DEPRECATED — Use spawn-task/wait-task/respond-task instead. This tool will be removed in v2.0.\n',
233
236
  'Send a task to an active Codex thread, starting an autonomous agent turn.',
234
237
  '',
235
238
  'The agent executes independently — it reads files, writes code, runs commands, and commits changes.',
@@ -255,7 +258,7 @@ export function createToolDefinitions(input: CreateToolDefinitionsInput): ToolDe
255
258
  {
256
259
  name: 'codex-turn-steer',
257
260
  description: [
258
- 'Redirect an in-progress turn with new instructions. The agent adjusts course without losing prior context. Use when you see the agent heading in the wrong direction via codex-thread-read or codex-request-list.',
261
+ '⚠️ DEPRECATED — Use spawn-task/wait-task/respond-task instead. This tool will be removed in v2.0.\n\nRedirect an in-progress turn with new instructions. The agent adjusts course without losing prior context. Use when you see the agent heading in the wrong direction via codex-thread-read or codex-request-list.',
259
262
  threadBanner,
260
263
  ].filter(Boolean).join('\n\n'),
261
264
  inputSchema: objectSchema({
@@ -267,7 +270,7 @@ export function createToolDefinitions(input: CreateToolDefinitionsInput): ToolDe
267
270
  },
268
271
  {
269
272
  name: 'codex-turn-interrupt',
270
- description: 'Stop an active turn immediately. Use when the agent is heading in the wrong direction and steering is not enough, or when you need to cancel work in progress.',
273
+ description: '⚠️ DEPRECATED — Use spawn-task/wait-task/respond-task instead. This tool will be removed in v2.0.\n\nStop an active turn immediately. Use when the agent is heading in the wrong direction and steering is not enough, or when you need to cancel work in progress.',
271
274
  inputSchema: objectSchema({
272
275
  thread_id: { type: 'string', minLength: 1, description: 'Thread containing the turn.' },
273
276
  turn_id: { type: 'string', minLength: 1, description: 'Turn ID to interrupt.' },
@@ -278,6 +281,7 @@ export function createToolDefinitions(input: CreateToolDefinitionsInput): ToolDe
278
281
  name: 'codex-request-list',
279
282
  description: [
280
283
  [
284
+ '⚠️ DEPRECATED — Use spawn-task/wait-task/respond-task instead. This tool will be removed in v2.0.\n',
281
285
  'List pending approval requests from Codex agents (command execution, file changes, permissions).',
282
286
  '',
283
287
  'CRITICAL: Check this after every codex-turn-start — agents frequently pause and wait for approval before executing shell commands or writing files.',
@@ -295,6 +299,7 @@ export function createToolDefinitions(input: CreateToolDefinitionsInput): ToolDe
295
299
  name: 'codex-request-respond',
296
300
  description: [
297
301
  [
302
+ '⚠️ DEPRECATED — Use spawn-task/wait-task/respond-task instead. This tool will be removed in v2.0.\n',
298
303
  'Approve or decline a pending Codex agent request (command execution, file changes, permissions, user input).',
299
304
  '',
300
305
  'Common patterns:',
@@ -323,6 +328,7 @@ export function createToolDefinitions(input: CreateToolDefinitionsInput): ToolDe
323
328
  {
324
329
  name: 'codex-wait',
325
330
  description: [
331
+ '⚠️ DEPRECATED — Use spawn-task/wait-task/respond-task instead. This tool will be removed in v2.0.\n',
326
332
  'Block until a Codex turn completes or a pending approval request appears.',
327
333
  '',
328
334
  'Use after codex-turn-start to wait for the agent to finish or ask for permission.',