thinkpool-pair 0.7.273 → 0.7.274
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/codex-app-server.mjs +53 -0
- package/codex-session.mjs +8 -2
- package/package.json +1 -1
- package/thinkpool-capabilities.json +8 -4
package/codex-app-server.mjs
CHANGED
|
@@ -99,6 +99,8 @@ export class CodexAppServerClient {
|
|
|
99
99
|
this.pending = new Map()
|
|
100
100
|
this.turnWaiters = new Map()
|
|
101
101
|
this.completedTurns = new Map()
|
|
102
|
+
this.mcpStartup = new Map()
|
|
103
|
+
this.mcpWaiters = new Map()
|
|
102
104
|
this.closedError = null
|
|
103
105
|
this.stderrTail = ''
|
|
104
106
|
}
|
|
@@ -196,6 +198,25 @@ export class CodexAppServerClient {
|
|
|
196
198
|
}
|
|
197
199
|
}
|
|
198
200
|
}
|
|
201
|
+
if (message.method === 'mcpServer/startupStatus/updated') {
|
|
202
|
+
const params = message.params || {}
|
|
203
|
+
const threadId = String(params.threadId || '')
|
|
204
|
+
const name = String(params.name || '')
|
|
205
|
+
if (threadId && name) {
|
|
206
|
+
const key = `${threadId}\0${name}`
|
|
207
|
+
this.mcpStartup.set(key, params)
|
|
208
|
+
const waiter = this.mcpWaiters.get(key)
|
|
209
|
+
if (waiter && params.status === 'ready') {
|
|
210
|
+
this.mcpWaiters.delete(key)
|
|
211
|
+
if (waiter.timer) clearTimeout(waiter.timer)
|
|
212
|
+
waiter.resolve(params)
|
|
213
|
+
} else if (waiter && (params.status === 'failed' || params.error || params.failureReason)) {
|
|
214
|
+
this.mcpWaiters.delete(key)
|
|
215
|
+
if (waiter.timer) clearTimeout(waiter.timer)
|
|
216
|
+
waiter.reject(new Error(`Codex MCP server ${name} failed to start: ${params.error || params.failureReason || params.status}`))
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
199
220
|
try { this.onNotification?.(message.method, message.params || {}) } catch { /* consumer isolation */ }
|
|
200
221
|
}
|
|
201
222
|
|
|
@@ -208,6 +229,12 @@ export class CodexAppServerClient {
|
|
|
208
229
|
for (const { reject } of this.turnWaiters.values()) reject(this.closedError)
|
|
209
230
|
this.turnWaiters.clear()
|
|
210
231
|
this.completedTurns.clear()
|
|
232
|
+
for (const { reject, timer } of this.mcpWaiters.values()) {
|
|
233
|
+
if (timer) clearTimeout(timer)
|
|
234
|
+
reject(this.closedError)
|
|
235
|
+
}
|
|
236
|
+
this.mcpWaiters.clear()
|
|
237
|
+
this.mcpStartup.clear()
|
|
211
238
|
try { this.onClose?.(this.closedError) } catch { /* consumer isolation */ }
|
|
212
239
|
}
|
|
213
240
|
|
|
@@ -221,6 +248,32 @@ export class CodexAppServerClient {
|
|
|
221
248
|
return id
|
|
222
249
|
}
|
|
223
250
|
|
|
251
|
+
waitForMcpServer({ threadId, name, timeoutMs = this.threadTimeoutMs } = {}) {
|
|
252
|
+
const safeThreadId = String(threadId || '')
|
|
253
|
+
const safeName = String(name || '')
|
|
254
|
+
if (!safeThreadId || !safeName) return Promise.reject(new Error('Codex MCP readiness needs a thread id and server name'))
|
|
255
|
+
const key = `${safeThreadId}\0${safeName}`
|
|
256
|
+
const current = this.mcpStartup.get(key)
|
|
257
|
+
if (current?.status === 'ready') return Promise.resolve(current)
|
|
258
|
+
if (current && (current.status === 'failed' || current.error || current.failureReason)) {
|
|
259
|
+
return Promise.reject(new Error(`Codex MCP server ${safeName} failed to start: ${current.error || current.failureReason || current.status}`))
|
|
260
|
+
}
|
|
261
|
+
if (this.mcpWaiters.has(key)) return this.mcpWaiters.get(key).promise
|
|
262
|
+
let timer = null
|
|
263
|
+
let resolveWaiter
|
|
264
|
+
let rejectWaiter
|
|
265
|
+
const promise = new Promise((resolve, reject) => {
|
|
266
|
+
resolveWaiter = resolve
|
|
267
|
+
rejectWaiter = reject
|
|
268
|
+
if (timeoutMs > 0) timer = setTimeout(() => {
|
|
269
|
+
this.mcpWaiters.delete(key)
|
|
270
|
+
reject(new Error(`Codex MCP server ${safeName} did not become ready within ${timeoutMs}ms`))
|
|
271
|
+
}, timeoutMs)
|
|
272
|
+
})
|
|
273
|
+
this.mcpWaiters.set(key, { promise, resolve: resolveWaiter, reject: rejectWaiter, timer })
|
|
274
|
+
return promise
|
|
275
|
+
}
|
|
276
|
+
|
|
224
277
|
async startTurn({ threadId, input, images, model, effort, approvalPolicy, collaborationMode } = {}) {
|
|
225
278
|
const result = await this.request('turn/start', {
|
|
226
279
|
threadId,
|
package/codex-session.mjs
CHANGED
|
@@ -352,7 +352,7 @@ function appServerItemForMapper(item) {
|
|
|
352
352
|
* @param {string} [o.providerConfig] optional -c overrides / provider block (M2: from the provider registry)
|
|
353
353
|
* @returns {{ sendTurn(text, options?), abort(), end(), readonly sessionId }}
|
|
354
354
|
*/
|
|
355
|
-
export function startCodexSession({ cwd, model, effort: initialEffort = 'high', resume, env, sandbox, mode = 'default', onEvent, providerConfig, terminalRolePrompt, rolePrompt, roomContext, mcpServers, prepareCwd = null, requestPermission, appServerGate = codexAppServerGate, appServerFactory = createCodexAppServer, spawnImpl = spawn }) {
|
|
355
|
+
export function startCodexSession({ cwd, model, effort: initialEffort = 'high', resume, env, sandbox, mode = 'default', onEvent, providerConfig, terminalRolePrompt, rolePrompt, roomContext, mcpServers, prepareCwd = null, requestPermission, appServerGate = codexAppServerGate, appServerFactory = createCodexAppServer, mcpHttpFactory = startCodexMcpHttp, spawnImpl = spawn }) {
|
|
356
356
|
let activeMode = CODEX_MODE_CONFIG[mode] ? mode : 'default'
|
|
357
357
|
let modeConfig = codexConfigForMode(activeMode)
|
|
358
358
|
sandbox = normalizeCodexSandbox(sandbox || modeConfig.sandbox)
|
|
@@ -424,7 +424,7 @@ export function startCodexSession({ cwd, model, effort: initialEffort = 'high',
|
|
|
424
424
|
async function ensureMcpHttp() {
|
|
425
425
|
const thinkpool = mcpServers?.thinkpool
|
|
426
426
|
if (!thinkpool) return null
|
|
427
|
-
if (!mcpHttpPromise) mcpHttpPromise =
|
|
427
|
+
if (!mcpHttpPromise) mcpHttpPromise = mcpHttpFactory({ sdkServer: thinkpool })
|
|
428
428
|
return mcpHttpPromise
|
|
429
429
|
}
|
|
430
430
|
|
|
@@ -526,6 +526,12 @@ export function startCodexSession({ cwd, model, effort: initialEffort = 'high',
|
|
|
526
526
|
// independent ThinkPool sandbox / approval posture above.
|
|
527
527
|
config: { 'features.default_mode_request_user_input': true },
|
|
528
528
|
})
|
|
529
|
+
// App Server reports thread/start before its per-thread MCP clients finish
|
|
530
|
+
// initializing. Starting the first turn in that gap snapshots a toolset
|
|
531
|
+
// without ThinkPool even though the server becomes ready milliseconds later.
|
|
532
|
+
// Hold the turn boundary until the room MCP is actually ready; a timeout or
|
|
533
|
+
// startup failure drops into the required-MCP codex exec fallback below.
|
|
534
|
+
if (peer?.url) await appServer.waitForMcpServer({ threadId: sessionId, name: 'thinkpool' })
|
|
529
535
|
appServerThreadReady = true
|
|
530
536
|
pushMappedEvent({ type: 'thread.started', thread_id: sessionId })
|
|
531
537
|
return true
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"bundleVersion":
|
|
3
|
+
"bundleVersion": 5,
|
|
4
4
|
"contracts": [
|
|
5
5
|
{
|
|
6
6
|
"id": "room-coordination",
|
|
7
|
-
"version":
|
|
7
|
+
"version": 2,
|
|
8
8
|
"routes": [
|
|
9
9
|
{
|
|
10
10
|
"id": "room-awareness",
|
|
@@ -27,12 +27,16 @@
|
|
|
27
27
|
],
|
|
28
28
|
"impact": [
|
|
29
29
|
{"path": "bridge/cross-terminal.mjs"},
|
|
30
|
-
{"path": "bridge/bridge.mjs", "diffPattern": "read_terminal|list_sessions|read_session|post_to_terminal|post_to_session"}
|
|
30
|
+
{"path": "bridge/bridge.mjs", "diffPattern": "read_terminal|list_sessions|read_session|post_to_terminal|post_to_session"},
|
|
31
|
+
{"path": "bridge/codex-session.mjs", "diffPattern": "MCP|Mcp|mcp|read_terminal|list_sessions|read_session|post_to_terminal|post_to_session"},
|
|
32
|
+
{"path": "bridge/codex-app-server.mjs", "diffPattern": "MCP|Mcp|mcp"}
|
|
31
33
|
],
|
|
32
34
|
"evidence": [
|
|
33
35
|
{"path": "bridge/cross-terminal.mjs", "pattern": "read_terminal"},
|
|
34
36
|
{"path": "bridge/cross-terminal.mjs", "pattern": "post_to_session"},
|
|
35
|
-
{"path": "bridge/bridge.mjs", "pattern": "'list_sessions'"}
|
|
37
|
+
{"path": "bridge/bridge.mjs", "pattern": "'list_sessions'"},
|
|
38
|
+
{"path": "bridge/codex-session.mjs", "pattern": "waitForMcpServer"},
|
|
39
|
+
{"path": "bridge/codex-app-server.mjs", "pattern": "mcpServer/startupStatus/updated"}
|
|
36
40
|
]
|
|
37
41
|
},
|
|
38
42
|
{
|