@midscene/mcp 1.5.5 → 1.5.6

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/index.js CHANGED
@@ -21852,6 +21852,566 @@ var __webpack_modules__ = {
21852
21852
  }
21853
21853
  return debugInstances.get(cacheKey);
21854
21854
  }
21855
+ function _define_property(obj, key, value) {
21856
+ if (key in obj) Object.defineProperty(obj, key, {
21857
+ value: value,
21858
+ enumerable: true,
21859
+ configurable: true,
21860
+ writable: true
21861
+ });
21862
+ else obj[key] = value;
21863
+ return obj;
21864
+ }
21865
+ const CODEX_DEFAULT_TIMEOUT_MS = 600000;
21866
+ const CODEX_DEFAULT_PROCESS_START_TIMEOUT_MS = 15000;
21867
+ const CODEX_DEFAULT_CLEANUP_TIMEOUT_MS = 8000;
21868
+ const CODEX_TEXT_INPUT_MAX_LENGTH = 262144;
21869
+ const debugCodex = logger_getDebug('ai:call:codex');
21870
+ const warnCodex = logger_getDebug('ai:call:codex', {
21871
+ console: true
21872
+ });
21873
+ class SerializedRunner {
21874
+ async run(work) {
21875
+ const previous = this.tail;
21876
+ let release;
21877
+ this.tail = new Promise((resolve)=>{
21878
+ release = resolve;
21879
+ });
21880
+ await previous;
21881
+ try {
21882
+ return await work();
21883
+ } finally{
21884
+ release();
21885
+ }
21886
+ }
21887
+ constructor(){
21888
+ _define_property(this, "tail", Promise.resolve());
21889
+ }
21890
+ }
21891
+ const codex_app_server_isAbortError = (error)=>{
21892
+ if (!error) return false;
21893
+ if (error instanceof Error && 'AbortError' === error.name) return true;
21894
+ const message = error instanceof Error ? error.message : String(error ?? 'unknown error');
21895
+ return /aborted|abort/i.test(message);
21896
+ };
21897
+ const toNonEmptyString = (value)=>{
21898
+ if ('string' != typeof value) return;
21899
+ const trimmed = value.trim();
21900
+ return trimmed || void 0;
21901
+ };
21902
+ const normalizeCodexLocalImagePath = (imageUrl, platform = process.platform)=>{
21903
+ if (!imageUrl.startsWith('file://')) return imageUrl;
21904
+ try {
21905
+ const parsed = new URL(imageUrl);
21906
+ const pathname = decodeURIComponent(parsed.pathname);
21907
+ const host = parsed.hostname.toLowerCase();
21908
+ if ('win32' === platform) {
21909
+ const windowsPath = pathname.replace(/\//g, '\\').replace(/^\\([A-Za-z]:)/, '$1');
21910
+ if (host && 'localhost' !== host) return `\\\\${parsed.hostname}${windowsPath}`;
21911
+ return windowsPath;
21912
+ }
21913
+ if (host && 'localhost' !== host) return `//${parsed.hostname}${pathname}`;
21914
+ return pathname;
21915
+ } catch {
21916
+ return decodeURIComponent(imageUrl.slice(7));
21917
+ }
21918
+ };
21919
+ const extractTextFromMessage = (message)=>{
21920
+ const content = message.content;
21921
+ if ('string' == typeof content) return content;
21922
+ if (Array.isArray(content)) return content.map((part)=>{
21923
+ if (!part || 'object' != typeof part) return '';
21924
+ if ('text' === part.type && 'string' == typeof part.text) return part.text;
21925
+ if ('input_text' === part.type && 'string' == typeof part.text) return part.text;
21926
+ return '';
21927
+ }).filter(Boolean).join('\n');
21928
+ return '';
21929
+ };
21930
+ const extractImageInputs = (message, imageDetailOverride)=>{
21931
+ const content = message.content;
21932
+ if (!Array.isArray(content)) return [];
21933
+ const inputs = [];
21934
+ for (const part of content){
21935
+ if (!part || 'object' != typeof part) continue;
21936
+ const partType = String(part.type || '');
21937
+ const imageUrl = 'image_url' === partType ? toNonEmptyString(part.image_url?.url) : 'input_image' === partType ? toNonEmptyString(part.image_url || part.url) : void 0;
21938
+ if (!imageUrl) continue;
21939
+ const detail = imageDetailOverride || toNonEmptyString(part.image_url?.detail) || toNonEmptyString(part.detail);
21940
+ if (imageUrl.startsWith('/') || imageUrl.startsWith('./') || imageUrl.startsWith('../') || imageUrl.startsWith('file://')) {
21941
+ const path = imageUrl.startsWith('file://') ? normalizeCodexLocalImagePath(imageUrl) : imageUrl;
21942
+ inputs.push({
21943
+ type: 'localImage',
21944
+ path,
21945
+ ...detail ? {
21946
+ detail
21947
+ } : {}
21948
+ });
21949
+ continue;
21950
+ }
21951
+ inputs.push({
21952
+ type: 'image',
21953
+ url: imageUrl,
21954
+ ...detail ? {
21955
+ detail
21956
+ } : {}
21957
+ });
21958
+ }
21959
+ return inputs;
21960
+ };
21961
+ const resolveCodexReasoningEffort = ({ deepThink, modelConfig })=>{
21962
+ if (true === deepThink) return 'high';
21963
+ if (false === deepThink) return 'low';
21964
+ const normalized = modelConfig.reasoningEffort?.trim().toLowerCase();
21965
+ if ('low' === normalized || 'medium' === normalized || 'high' === normalized || 'xhigh' === normalized) return normalized;
21966
+ if (true === modelConfig.reasoningEnabled) return 'high';
21967
+ if (false === modelConfig.reasoningEnabled) return 'low';
21968
+ };
21969
+ const buildCodexTurnPayloadFromMessages = (messages, options)=>{
21970
+ const developerInstructionParts = [];
21971
+ const transcriptParts = [];
21972
+ const imageInputs = [];
21973
+ for (const message of messages){
21974
+ const role = String(message.role || 'user');
21975
+ const text = extractTextFromMessage(message);
21976
+ if ('system' === role) {
21977
+ if (text.trim()) developerInstructionParts.push(text.trim());
21978
+ continue;
21979
+ }
21980
+ const roleTag = role.toUpperCase();
21981
+ if (text.trim()) transcriptParts.push(`[${roleTag}]\n${text.trim()}`);
21982
+ else transcriptParts.push(`[${roleTag}]\n(no text content)`);
21983
+ if ('user' === role) imageInputs.push(...extractImageInputs(message, options?.imageDetailOverride));
21984
+ }
21985
+ const fullTranscript = transcriptParts.join('\n\n');
21986
+ const transcriptText = (fullTranscript.length > CODEX_TEXT_INPUT_MAX_LENGTH ? fullTranscript.slice(-CODEX_TEXT_INPUT_MAX_LENGTH) : fullTranscript) || 'Please answer the latest user request.';
21987
+ const input = [
21988
+ {
21989
+ type: 'text',
21990
+ text: transcriptText,
21991
+ text_elements: []
21992
+ },
21993
+ ...imageInputs
21994
+ ];
21995
+ const developerInstructions = developerInstructionParts.length ? developerInstructionParts.join('\n\n') : void 0;
21996
+ return {
21997
+ developerInstructions,
21998
+ input
21999
+ };
22000
+ };
22001
+ class CodexAppServerConnection {
22002
+ static async create() {
22003
+ if (utils.ht) throw new Error('codex app-server provider is not supported in browser runtime');
22004
+ const childProcessModuleName = 'node:child_process';
22005
+ const readlineModuleName = 'node:readline';
22006
+ const { spawn } = await import(childProcessModuleName);
22007
+ const readline = await import(readlineModuleName);
22008
+ const child = spawn('codex', [
22009
+ 'app-server'
22010
+ ], {
22011
+ stdio: [
22012
+ 'pipe',
22013
+ 'pipe',
22014
+ 'pipe'
22015
+ ]
22016
+ });
22017
+ if (!child.stdin || !child.stdout || !child.stderr) throw new Error('failed to start codex app-server: stdio unavailable');
22018
+ const lineReader = readline.createInterface({
22019
+ input: child.stdout,
22020
+ crlfDelay: 1 / 0
22021
+ });
22022
+ const connection = new CodexAppServerConnection(child, lineReader);
22023
+ connection.detachFromEventLoop();
22024
+ connection.attachProcessListeners();
22025
+ await connection.initializeHandshake();
22026
+ return connection;
22027
+ }
22028
+ isClosed() {
22029
+ return this.closed;
22030
+ }
22031
+ async runTurn({ messages, modelConfig, stream, onChunk, deepThink, abortSignal }) {
22032
+ const startTime = Date.now();
22033
+ const timeoutMs = modelConfig.timeout || CODEX_DEFAULT_TIMEOUT_MS;
22034
+ const deadlineAt = Date.now() + timeoutMs;
22035
+ const isStreaming = !!(stream && onChunk);
22036
+ const imageDetailOverride = 'gpt-5' === modelConfig.modelFamily ? 'original' : void 0;
22037
+ const { developerInstructions, input } = buildCodexTurnPayloadFromMessages(messages, {
22038
+ imageDetailOverride
22039
+ });
22040
+ const effort = resolveCodexReasoningEffort({
22041
+ deepThink,
22042
+ modelConfig
22043
+ });
22044
+ let threadId;
22045
+ let turnId;
22046
+ let latestErrorMessage;
22047
+ let accumulatedText = '';
22048
+ let accumulatedReasoning = '';
22049
+ let latestUsage;
22050
+ const emitChunk = ({ content, reasoning, isComplete, usage })=>{
22051
+ if (!isStreaming || !onChunk) return;
22052
+ const chunk = {
22053
+ content,
22054
+ reasoning_content: reasoning,
22055
+ accumulated: accumulatedText,
22056
+ isComplete,
22057
+ usage
22058
+ };
22059
+ onChunk(chunk);
22060
+ };
22061
+ try {
22062
+ const threadStartResponse = await this.request({
22063
+ method: 'thread/start',
22064
+ params: {
22065
+ model: modelConfig.modelName,
22066
+ cwd: process.cwd(),
22067
+ approvalPolicy: 'never',
22068
+ sandbox: 'read-only',
22069
+ ephemeral: true,
22070
+ experimentalRawEvents: false,
22071
+ persistExtendedHistory: false,
22072
+ developerInstructions: developerInstructions || null
22073
+ },
22074
+ deadlineAt,
22075
+ abortSignal
22076
+ });
22077
+ threadId = threadStartResponse?.thread?.id;
22078
+ if (!threadId) throw new Error('thread/start did not return a thread id');
22079
+ const turnStartResponse = await this.request({
22080
+ method: 'turn/start',
22081
+ params: {
22082
+ threadId,
22083
+ input,
22084
+ effort
22085
+ },
22086
+ deadlineAt,
22087
+ abortSignal
22088
+ });
22089
+ turnId = turnStartResponse?.turn?.id;
22090
+ if (!turnId) throw new Error('turn/start did not return a turn id');
22091
+ let turnStatus;
22092
+ while(!turnStatus){
22093
+ const message = await this.nextMessage({
22094
+ deadlineAt,
22095
+ abortSignal
22096
+ });
22097
+ if (this.isResponseMessage(message)) continue;
22098
+ if (this.isRequestMessage(message)) {
22099
+ await this.respondToServerRequest(message);
22100
+ continue;
22101
+ }
22102
+ const notification = message;
22103
+ const method = notification.method;
22104
+ const params = notification.params || {};
22105
+ if ('error' === method) {
22106
+ const messageText = params.error?.message || params.message || 'codex app-server reported turn error';
22107
+ latestErrorMessage = String(messageText);
22108
+ continue;
22109
+ }
22110
+ if ('item/agentMessage/delta' === method && params.threadId === threadId && params.turnId === turnId) {
22111
+ const delta = String(params.delta || '');
22112
+ if (delta) {
22113
+ accumulatedText += delta;
22114
+ emitChunk({
22115
+ content: delta,
22116
+ reasoning: '',
22117
+ isComplete: false
22118
+ });
22119
+ }
22120
+ continue;
22121
+ }
22122
+ if (('item/reasoning/summaryTextDelta' === method || 'item/reasoning/textDelta' === method) && params.threadId === threadId && params.turnId === turnId) {
22123
+ const delta = String(params.delta || '');
22124
+ if (delta) {
22125
+ accumulatedReasoning += delta;
22126
+ emitChunk({
22127
+ content: '',
22128
+ reasoning: delta,
22129
+ isComplete: false
22130
+ });
22131
+ }
22132
+ continue;
22133
+ }
22134
+ if ('item/completed' === method && params.threadId === threadId && params.turnId === turnId && params.item?.type === 'agentMessage' && 'string' == typeof params.item?.text && !accumulatedText) {
22135
+ accumulatedText = params.item.text;
22136
+ continue;
22137
+ }
22138
+ if ('thread/tokenUsage/updated' === method && params.threadId === threadId && params.turnId === turnId) {
22139
+ latestUsage = this.mapUsage({
22140
+ usage: params,
22141
+ modelConfig,
22142
+ turnId,
22143
+ startTime
22144
+ });
22145
+ continue;
22146
+ }
22147
+ if ('turn/completed' === method && params.threadId === threadId && params.turn?.id === turnId) {
22148
+ turnStatus = String(params.turn.status || '');
22149
+ latestErrorMessage = params.turn?.error?.message || latestErrorMessage || void 0;
22150
+ break;
22151
+ }
22152
+ }
22153
+ if ('completed' !== turnStatus) throw new Error(latestErrorMessage || `codex turn finished with status "${turnStatus || 'unknown'}"`);
22154
+ if (isStreaming) emitChunk({
22155
+ content: '',
22156
+ reasoning: '',
22157
+ isComplete: true,
22158
+ usage: latestUsage
22159
+ });
22160
+ return {
22161
+ content: accumulatedText,
22162
+ reasoning_content: accumulatedReasoning || void 0,
22163
+ usage: latestUsage,
22164
+ isStreamed: isStreaming
22165
+ };
22166
+ } catch (error) {
22167
+ if (codex_app_server_isAbortError(error) && threadId && turnId) await this.request({
22168
+ method: 'turn/interrupt',
22169
+ params: {
22170
+ threadId,
22171
+ turnId
22172
+ },
22173
+ deadlineAt: Date.now() + 5000
22174
+ }).catch(()=>{});
22175
+ throw error;
22176
+ } finally{
22177
+ if (threadId) await this.request({
22178
+ method: 'thread/unsubscribe',
22179
+ params: {
22180
+ threadId
22181
+ },
22182
+ deadlineAt: Date.now() + CODEX_DEFAULT_CLEANUP_TIMEOUT_MS
22183
+ }).catch((error)=>{
22184
+ warnCodex(`failed to unsubscribe codex thread ${threadId}: ${String(error)}`);
22185
+ });
22186
+ }
22187
+ }
22188
+ async dispose() {
22189
+ if (this.closed) return;
22190
+ this.closed = true;
22191
+ try {
22192
+ this.lineReader?.close?.();
22193
+ } catch {}
22194
+ try {
22195
+ this.child?.stdin?.end?.();
22196
+ } catch {}
22197
+ try {
22198
+ this.child?.kill?.();
22199
+ } catch {}
22200
+ }
22201
+ attachProcessListeners() {
22202
+ this.lineReader.on('line', (line)=>{
22203
+ this.lineBuffer.push(line);
22204
+ });
22205
+ this.child.stderr.on('data', (chunk)=>{
22206
+ const text = Buffer.isBuffer(chunk) ? chunk.toString('utf8') : String(chunk);
22207
+ this.stderrBuffer += text;
22208
+ if (this.stderrBuffer.length > 8192) this.stderrBuffer = this.stderrBuffer.slice(-8192);
22209
+ });
22210
+ this.child.on('exit', (code)=>{
22211
+ this.closed = true;
22212
+ this.lastExitCode = code;
22213
+ });
22214
+ this.child.on('error', (error)=>{
22215
+ this.closed = true;
22216
+ this.processErrorMessage = error.message;
22217
+ });
22218
+ }
22219
+ detachFromEventLoop() {
22220
+ this.child.unref?.();
22221
+ this.child.stdin?.unref?.();
22222
+ this.child.stdout?.unref?.();
22223
+ this.child.stderr?.unref?.();
22224
+ }
22225
+ async initializeHandshake() {
22226
+ const deadlineAt = Date.now() + CODEX_DEFAULT_PROCESS_START_TIMEOUT_MS;
22227
+ await this.request({
22228
+ method: 'initialize',
22229
+ params: {
22230
+ clientInfo: {
22231
+ name: 'midscene_codex_provider',
22232
+ title: 'Midscene Codex Provider',
22233
+ version: '1.0.0'
22234
+ },
22235
+ capabilities: {
22236
+ experimentalApi: false
22237
+ }
22238
+ },
22239
+ deadlineAt
22240
+ });
22241
+ await this.sendMessage({
22242
+ method: 'initialized'
22243
+ });
22244
+ }
22245
+ mapUsage({ usage, modelConfig, turnId, startTime }) {
22246
+ const tokenUsage = usage.tokenUsage;
22247
+ const picked = tokenUsage?.last || tokenUsage?.total;
22248
+ if (!picked) return;
22249
+ return {
22250
+ prompt_tokens: picked.inputTokens ?? 0,
22251
+ completion_tokens: picked.outputTokens ?? 0,
22252
+ total_tokens: picked.totalTokens ?? 0,
22253
+ cached_input: picked.cachedInputTokens ?? 0,
22254
+ time_cost: Date.now() - startTime,
22255
+ model_name: modelConfig.modelName,
22256
+ model_description: modelConfig.modelDescription,
22257
+ intent: modelConfig.intent,
22258
+ request_id: turnId
22259
+ };
22260
+ }
22261
+ isRequestMessage(message) {
22262
+ return 'string' == typeof message?.method && message?.id !== void 0;
22263
+ }
22264
+ isResponseMessage(message) {
22265
+ return message?.id !== void 0 && (message?.result !== void 0 || message?.error !== void 0) && 'string' != typeof message?.method;
22266
+ }
22267
+ async request({ method, params, deadlineAt, abortSignal }) {
22268
+ const requestId = this.nextRequestId++;
22269
+ await this.sendMessage({
22270
+ id: requestId,
22271
+ method,
22272
+ params
22273
+ });
22274
+ while(true){
22275
+ const message = await this.nextMessage({
22276
+ deadlineAt,
22277
+ abortSignal,
22278
+ includePending: false
22279
+ });
22280
+ if (this.isResponseMessage(message) && message.id === requestId) {
22281
+ if (message.error) throw new Error(`codex app-server ${method} failed: ${message.error.message || 'unknown error'}`);
22282
+ return message.result || {};
22283
+ }
22284
+ if (this.isRequestMessage(message)) {
22285
+ await this.respondToServerRequest(message);
22286
+ continue;
22287
+ }
22288
+ this.pendingMessages.push(message);
22289
+ }
22290
+ }
22291
+ async respondToServerRequest(request) {
22292
+ const requestId = request.id;
22293
+ const method = request.method;
22294
+ let result = {};
22295
+ if ('item/commandExecution/requestApproval' === method) result = {
22296
+ decision: 'decline'
22297
+ };
22298
+ else if ('item/fileChange/requestApproval' === method) result = {
22299
+ decision: 'decline'
22300
+ };
22301
+ else if ('mcpServer/elicitation/request' === method) result = {
22302
+ action: 'cancel',
22303
+ content: null
22304
+ };
22305
+ else {
22306
+ if ('item/tool/requestUserInput' !== method) return void await this.sendMessage({
22307
+ id: requestId,
22308
+ error: {
22309
+ code: -32601,
22310
+ message: `unsupported server request: ${method}`
22311
+ }
22312
+ });
22313
+ result = {
22314
+ answers: []
22315
+ };
22316
+ }
22317
+ await this.sendMessage({
22318
+ id: requestId,
22319
+ result
22320
+ });
22321
+ }
22322
+ async nextMessage({ deadlineAt, abortSignal, includePending = true }) {
22323
+ if (includePending && this.pendingMessages.length) return this.pendingMessages.shift();
22324
+ while(true){
22325
+ if (abortSignal?.aborted) throw new Error('codex app-server request aborted');
22326
+ if (deadlineAt && Date.now() > deadlineAt) throw new Error('codex app-server request timed out');
22327
+ if (this.lineBuffer.length) {
22328
+ const line = this.lineBuffer.shift();
22329
+ const trimmed = line.trim();
22330
+ if (!trimmed) continue;
22331
+ let parsed;
22332
+ try {
22333
+ parsed = JSON.parse(trimmed);
22334
+ } catch (error) {
22335
+ warnCodex(`ignored non-JSON message from codex app-server: ${trimmed}`);
22336
+ continue;
22337
+ }
22338
+ return parsed;
22339
+ }
22340
+ if (this.closed) throw this.createClosedConnectionError();
22341
+ await new Promise((resolve)=>setTimeout(resolve, 20));
22342
+ }
22343
+ }
22344
+ async sendMessage(payload) {
22345
+ if (this.closed) throw this.createClosedConnectionError();
22346
+ const line = JSON.stringify(payload);
22347
+ await new Promise((resolve, reject)=>{
22348
+ this.child.stdin.write(`${line}\n`, (error)=>{
22349
+ if (error) return void reject(new Error(`failed writing to codex app-server stdin: ${error.message}`));
22350
+ resolve();
22351
+ });
22352
+ });
22353
+ }
22354
+ createClosedConnectionError() {
22355
+ const stderr = this.stderrBuffer.trim();
22356
+ if (this.processErrorMessage) return new Error(stderr ? `codex app-server process error: ${this.processErrorMessage}. stderr=${stderr}` : `codex app-server process error: ${this.processErrorMessage}`);
22357
+ return new Error(stderr ? `codex app-server connection closed (exitCode=${this.lastExitCode}). stderr=${stderr}` : `codex app-server connection closed (exitCode=${this.lastExitCode})`);
22358
+ }
22359
+ constructor(child, lineReader){
22360
+ _define_property(this, "child", void 0);
22361
+ _define_property(this, "lineReader", void 0);
22362
+ _define_property(this, "pendingMessages", []);
22363
+ _define_property(this, "lineBuffer", []);
22364
+ _define_property(this, "nextRequestId", 1);
22365
+ _define_property(this, "closed", false);
22366
+ _define_property(this, "lastExitCode", null);
22367
+ _define_property(this, "processErrorMessage", null);
22368
+ _define_property(this, "stderrBuffer", '');
22369
+ this.child = child;
22370
+ this.lineReader = lineReader;
22371
+ }
22372
+ }
22373
+ class CodexAppServerConnectionManager {
22374
+ async runTurn({ messages, modelConfig, stream, onChunk, deepThink, abortSignal }) {
22375
+ return this.runner.run(async ()=>{
22376
+ const connection = await this.getConnection();
22377
+ try {
22378
+ return await connection.runTurn({
22379
+ messages,
22380
+ modelConfig,
22381
+ stream,
22382
+ onChunk,
22383
+ deepThink,
22384
+ abortSignal
22385
+ });
22386
+ } catch (error) {
22387
+ if (connection.isClosed() || !codex_app_server_isAbortError(error)) await this.resetConnection();
22388
+ throw error;
22389
+ }
22390
+ });
22391
+ }
22392
+ async shutdownForTests() {
22393
+ await this.resetConnection();
22394
+ }
22395
+ async getConnection() {
22396
+ if (!this.connection || this.connection.isClosed()) {
22397
+ this.connection = await CodexAppServerConnection.create();
22398
+ debugCodex('started long-lived codex app-server connection');
22399
+ }
22400
+ return this.connection;
22401
+ }
22402
+ async resetConnection() {
22403
+ if (!this.connection) return;
22404
+ const staleConnection = this.connection;
22405
+ this.connection = null;
22406
+ await staleConnection.dispose();
22407
+ debugCodex('reset codex app-server connection');
22408
+ }
22409
+ constructor(){
22410
+ _define_property(this, "connection", null);
22411
+ _define_property(this, "runner", new SerializedRunner());
22412
+ }
22413
+ }
22414
+ new CodexAppServerConnectionManager();
21855
22415
  logger_getDebug('ai:common');
21856
22416
  const PointSchema = lib.z.object({
21857
22417
  left: lib.z.number(),
@@ -24715,7 +25275,7 @@ For more information, visit: https://midscenejs.com/mcp-migration
24715
25275
  constructor(){
24716
25276
  super({
24717
25277
  name: '@midscene/mcp',
24718
- version: '1.5.5',
25278
+ version: '1.5.6',
24719
25279
  description: 'Deprecated - Use @midscene/web-bridge-mcp, @midscene/android-mcp, or @midscene/ios-mcp'
24720
25280
  });
24721
25281
  }
@@ -31814,9 +32374,11 @@ For more information, visit: https://midscenejs.com/mcp-migration
31814
32374
  "use strict";
31815
32375
  __webpack_require__.d(__webpack_exports__, {
31816
32376
  $9: ()=>ifInNode,
31817
- H1: ()=>setIsMcp
32377
+ H1: ()=>setIsMcp,
32378
+ ht: ()=>ifInBrowser
31818
32379
  });
31819
32380
  __webpack_require__("../../node_modules/.pnpm/js-sha256@0.11.0/node_modules/js-sha256/src/sha256.js");
32381
+ const ifInBrowser = 'undefined' != typeof window;
31820
32382
  const ifInNode = 'undefined' != typeof process && process.versions?.node;
31821
32383
  function setIsMcp(value) {}
31822
32384
  },
package/dist/server.js CHANGED
@@ -23241,9 +23241,11 @@ var __webpack_modules__ = {
23241
23241
  "use strict";
23242
23242
  __webpack_require__.d(__webpack_exports__, {
23243
23243
  $9: ()=>ifInNode,
23244
- H1: ()=>setIsMcp
23244
+ H1: ()=>setIsMcp,
23245
+ ht: ()=>ifInBrowser
23245
23246
  });
23246
23247
  __webpack_require__("../../node_modules/.pnpm/js-sha256@0.11.0/node_modules/js-sha256/src/sha256.js");
23248
+ const ifInBrowser = 'undefined' != typeof window;
23247
23249
  const ifInNode = 'undefined' != typeof process && process.versions?.node;
23248
23250
  function setIsMcp(value) {}
23249
23251
  },
@@ -29082,6 +29084,566 @@ var __webpack_exports__ = {};
29082
29084
  }
29083
29085
  return debugInstances.get(cacheKey);
29084
29086
  }
29087
+ function _define_property(obj, key, value) {
29088
+ if (key in obj) Object.defineProperty(obj, key, {
29089
+ value: value,
29090
+ enumerable: true,
29091
+ configurable: true,
29092
+ writable: true
29093
+ });
29094
+ else obj[key] = value;
29095
+ return obj;
29096
+ }
29097
+ const CODEX_DEFAULT_TIMEOUT_MS = 600000;
29098
+ const CODEX_DEFAULT_PROCESS_START_TIMEOUT_MS = 15000;
29099
+ const CODEX_DEFAULT_CLEANUP_TIMEOUT_MS = 8000;
29100
+ const CODEX_TEXT_INPUT_MAX_LENGTH = 262144;
29101
+ const debugCodex = logger_getDebug('ai:call:codex');
29102
+ const warnCodex = logger_getDebug('ai:call:codex', {
29103
+ console: true
29104
+ });
29105
+ class SerializedRunner {
29106
+ async run(work) {
29107
+ const previous = this.tail;
29108
+ let release;
29109
+ this.tail = new Promise((resolve)=>{
29110
+ release = resolve;
29111
+ });
29112
+ await previous;
29113
+ try {
29114
+ return await work();
29115
+ } finally{
29116
+ release();
29117
+ }
29118
+ }
29119
+ constructor(){
29120
+ _define_property(this, "tail", Promise.resolve());
29121
+ }
29122
+ }
29123
+ const codex_app_server_isAbortError = (error)=>{
29124
+ if (!error) return false;
29125
+ if (error instanceof Error && 'AbortError' === error.name) return true;
29126
+ const message = error instanceof Error ? error.message : String(error ?? 'unknown error');
29127
+ return /aborted|abort/i.test(message);
29128
+ };
29129
+ const toNonEmptyString = (value)=>{
29130
+ if ('string' != typeof value) return;
29131
+ const trimmed = value.trim();
29132
+ return trimmed || void 0;
29133
+ };
29134
+ const normalizeCodexLocalImagePath = (imageUrl, platform = process.platform)=>{
29135
+ if (!imageUrl.startsWith('file://')) return imageUrl;
29136
+ try {
29137
+ const parsed = new URL(imageUrl);
29138
+ const pathname = decodeURIComponent(parsed.pathname);
29139
+ const host = parsed.hostname.toLowerCase();
29140
+ if ('win32' === platform) {
29141
+ const windowsPath = pathname.replace(/\//g, '\\').replace(/^\\([A-Za-z]:)/, '$1');
29142
+ if (host && 'localhost' !== host) return `\\\\${parsed.hostname}${windowsPath}`;
29143
+ return windowsPath;
29144
+ }
29145
+ if (host && 'localhost' !== host) return `//${parsed.hostname}${pathname}`;
29146
+ return pathname;
29147
+ } catch {
29148
+ return decodeURIComponent(imageUrl.slice(7));
29149
+ }
29150
+ };
29151
+ const extractTextFromMessage = (message)=>{
29152
+ const content = message.content;
29153
+ if ('string' == typeof content) return content;
29154
+ if (Array.isArray(content)) return content.map((part)=>{
29155
+ if (!part || 'object' != typeof part) return '';
29156
+ if ('text' === part.type && 'string' == typeof part.text) return part.text;
29157
+ if ('input_text' === part.type && 'string' == typeof part.text) return part.text;
29158
+ return '';
29159
+ }).filter(Boolean).join('\n');
29160
+ return '';
29161
+ };
29162
+ const extractImageInputs = (message, imageDetailOverride)=>{
29163
+ const content = message.content;
29164
+ if (!Array.isArray(content)) return [];
29165
+ const inputs = [];
29166
+ for (const part of content){
29167
+ if (!part || 'object' != typeof part) continue;
29168
+ const partType = String(part.type || '');
29169
+ const imageUrl = 'image_url' === partType ? toNonEmptyString(part.image_url?.url) : 'input_image' === partType ? toNonEmptyString(part.image_url || part.url) : void 0;
29170
+ if (!imageUrl) continue;
29171
+ const detail = imageDetailOverride || toNonEmptyString(part.image_url?.detail) || toNonEmptyString(part.detail);
29172
+ if (imageUrl.startsWith('/') || imageUrl.startsWith('./') || imageUrl.startsWith('../') || imageUrl.startsWith('file://')) {
29173
+ const path = imageUrl.startsWith('file://') ? normalizeCodexLocalImagePath(imageUrl) : imageUrl;
29174
+ inputs.push({
29175
+ type: 'localImage',
29176
+ path,
29177
+ ...detail ? {
29178
+ detail
29179
+ } : {}
29180
+ });
29181
+ continue;
29182
+ }
29183
+ inputs.push({
29184
+ type: 'image',
29185
+ url: imageUrl,
29186
+ ...detail ? {
29187
+ detail
29188
+ } : {}
29189
+ });
29190
+ }
29191
+ return inputs;
29192
+ };
29193
+ const resolveCodexReasoningEffort = ({ deepThink, modelConfig })=>{
29194
+ if (true === deepThink) return 'high';
29195
+ if (false === deepThink) return 'low';
29196
+ const normalized = modelConfig.reasoningEffort?.trim().toLowerCase();
29197
+ if ('low' === normalized || 'medium' === normalized || 'high' === normalized || 'xhigh' === normalized) return normalized;
29198
+ if (true === modelConfig.reasoningEnabled) return 'high';
29199
+ if (false === modelConfig.reasoningEnabled) return 'low';
29200
+ };
29201
+ const buildCodexTurnPayloadFromMessages = (messages, options)=>{
29202
+ const developerInstructionParts = [];
29203
+ const transcriptParts = [];
29204
+ const imageInputs = [];
29205
+ for (const message of messages){
29206
+ const role = String(message.role || 'user');
29207
+ const text = extractTextFromMessage(message);
29208
+ if ('system' === role) {
29209
+ if (text.trim()) developerInstructionParts.push(text.trim());
29210
+ continue;
29211
+ }
29212
+ const roleTag = role.toUpperCase();
29213
+ if (text.trim()) transcriptParts.push(`[${roleTag}]\n${text.trim()}`);
29214
+ else transcriptParts.push(`[${roleTag}]\n(no text content)`);
29215
+ if ('user' === role) imageInputs.push(...extractImageInputs(message, options?.imageDetailOverride));
29216
+ }
29217
+ const fullTranscript = transcriptParts.join('\n\n');
29218
+ const transcriptText = (fullTranscript.length > CODEX_TEXT_INPUT_MAX_LENGTH ? fullTranscript.slice(-CODEX_TEXT_INPUT_MAX_LENGTH) : fullTranscript) || 'Please answer the latest user request.';
29219
+ const input = [
29220
+ {
29221
+ type: 'text',
29222
+ text: transcriptText,
29223
+ text_elements: []
29224
+ },
29225
+ ...imageInputs
29226
+ ];
29227
+ const developerInstructions = developerInstructionParts.length ? developerInstructionParts.join('\n\n') : void 0;
29228
+ return {
29229
+ developerInstructions,
29230
+ input
29231
+ };
29232
+ };
29233
+ class CodexAppServerConnection {
29234
+ static async create() {
29235
+ if (utils.ht) throw new Error('codex app-server provider is not supported in browser runtime');
29236
+ const childProcessModuleName = 'node:child_process';
29237
+ const readlineModuleName = 'node:readline';
29238
+ const { spawn } = await import(childProcessModuleName);
29239
+ const readline = await import(readlineModuleName);
29240
+ const child = spawn('codex', [
29241
+ 'app-server'
29242
+ ], {
29243
+ stdio: [
29244
+ 'pipe',
29245
+ 'pipe',
29246
+ 'pipe'
29247
+ ]
29248
+ });
29249
+ if (!child.stdin || !child.stdout || !child.stderr) throw new Error('failed to start codex app-server: stdio unavailable');
29250
+ const lineReader = readline.createInterface({
29251
+ input: child.stdout,
29252
+ crlfDelay: 1 / 0
29253
+ });
29254
+ const connection = new CodexAppServerConnection(child, lineReader);
29255
+ connection.detachFromEventLoop();
29256
+ connection.attachProcessListeners();
29257
+ await connection.initializeHandshake();
29258
+ return connection;
29259
+ }
29260
+ isClosed() {
29261
+ return this.closed;
29262
+ }
29263
+ async runTurn({ messages, modelConfig, stream, onChunk, deepThink, abortSignal }) {
29264
+ const startTime = Date.now();
29265
+ const timeoutMs = modelConfig.timeout || CODEX_DEFAULT_TIMEOUT_MS;
29266
+ const deadlineAt = Date.now() + timeoutMs;
29267
+ const isStreaming = !!(stream && onChunk);
29268
+ const imageDetailOverride = 'gpt-5' === modelConfig.modelFamily ? 'original' : void 0;
29269
+ const { developerInstructions, input } = buildCodexTurnPayloadFromMessages(messages, {
29270
+ imageDetailOverride
29271
+ });
29272
+ const effort = resolveCodexReasoningEffort({
29273
+ deepThink,
29274
+ modelConfig
29275
+ });
29276
+ let threadId;
29277
+ let turnId;
29278
+ let latestErrorMessage;
29279
+ let accumulatedText = '';
29280
+ let accumulatedReasoning = '';
29281
+ let latestUsage;
29282
+ const emitChunk = ({ content, reasoning, isComplete, usage })=>{
29283
+ if (!isStreaming || !onChunk) return;
29284
+ const chunk = {
29285
+ content,
29286
+ reasoning_content: reasoning,
29287
+ accumulated: accumulatedText,
29288
+ isComplete,
29289
+ usage
29290
+ };
29291
+ onChunk(chunk);
29292
+ };
29293
+ try {
29294
+ const threadStartResponse = await this.request({
29295
+ method: 'thread/start',
29296
+ params: {
29297
+ model: modelConfig.modelName,
29298
+ cwd: process.cwd(),
29299
+ approvalPolicy: 'never',
29300
+ sandbox: 'read-only',
29301
+ ephemeral: true,
29302
+ experimentalRawEvents: false,
29303
+ persistExtendedHistory: false,
29304
+ developerInstructions: developerInstructions || null
29305
+ },
29306
+ deadlineAt,
29307
+ abortSignal
29308
+ });
29309
+ threadId = threadStartResponse?.thread?.id;
29310
+ if (!threadId) throw new Error('thread/start did not return a thread id');
29311
+ const turnStartResponse = await this.request({
29312
+ method: 'turn/start',
29313
+ params: {
29314
+ threadId,
29315
+ input,
29316
+ effort
29317
+ },
29318
+ deadlineAt,
29319
+ abortSignal
29320
+ });
29321
+ turnId = turnStartResponse?.turn?.id;
29322
+ if (!turnId) throw new Error('turn/start did not return a turn id');
29323
+ let turnStatus;
29324
+ while(!turnStatus){
29325
+ const message = await this.nextMessage({
29326
+ deadlineAt,
29327
+ abortSignal
29328
+ });
29329
+ if (this.isResponseMessage(message)) continue;
29330
+ if (this.isRequestMessage(message)) {
29331
+ await this.respondToServerRequest(message);
29332
+ continue;
29333
+ }
29334
+ const notification = message;
29335
+ const method = notification.method;
29336
+ const params = notification.params || {};
29337
+ if ('error' === method) {
29338
+ const messageText = params.error?.message || params.message || 'codex app-server reported turn error';
29339
+ latestErrorMessage = String(messageText);
29340
+ continue;
29341
+ }
29342
+ if ('item/agentMessage/delta' === method && params.threadId === threadId && params.turnId === turnId) {
29343
+ const delta = String(params.delta || '');
29344
+ if (delta) {
29345
+ accumulatedText += delta;
29346
+ emitChunk({
29347
+ content: delta,
29348
+ reasoning: '',
29349
+ isComplete: false
29350
+ });
29351
+ }
29352
+ continue;
29353
+ }
29354
+ if (('item/reasoning/summaryTextDelta' === method || 'item/reasoning/textDelta' === method) && params.threadId === threadId && params.turnId === turnId) {
29355
+ const delta = String(params.delta || '');
29356
+ if (delta) {
29357
+ accumulatedReasoning += delta;
29358
+ emitChunk({
29359
+ content: '',
29360
+ reasoning: delta,
29361
+ isComplete: false
29362
+ });
29363
+ }
29364
+ continue;
29365
+ }
29366
+ if ('item/completed' === method && params.threadId === threadId && params.turnId === turnId && params.item?.type === 'agentMessage' && 'string' == typeof params.item?.text && !accumulatedText) {
29367
+ accumulatedText = params.item.text;
29368
+ continue;
29369
+ }
29370
+ if ('thread/tokenUsage/updated' === method && params.threadId === threadId && params.turnId === turnId) {
29371
+ latestUsage = this.mapUsage({
29372
+ usage: params,
29373
+ modelConfig,
29374
+ turnId,
29375
+ startTime
29376
+ });
29377
+ continue;
29378
+ }
29379
+ if ('turn/completed' === method && params.threadId === threadId && params.turn?.id === turnId) {
29380
+ turnStatus = String(params.turn.status || '');
29381
+ latestErrorMessage = params.turn?.error?.message || latestErrorMessage || void 0;
29382
+ break;
29383
+ }
29384
+ }
29385
+ if ('completed' !== turnStatus) throw new Error(latestErrorMessage || `codex turn finished with status "${turnStatus || 'unknown'}"`);
29386
+ if (isStreaming) emitChunk({
29387
+ content: '',
29388
+ reasoning: '',
29389
+ isComplete: true,
29390
+ usage: latestUsage
29391
+ });
29392
+ return {
29393
+ content: accumulatedText,
29394
+ reasoning_content: accumulatedReasoning || void 0,
29395
+ usage: latestUsage,
29396
+ isStreamed: isStreaming
29397
+ };
29398
+ } catch (error) {
29399
+ if (codex_app_server_isAbortError(error) && threadId && turnId) await this.request({
29400
+ method: 'turn/interrupt',
29401
+ params: {
29402
+ threadId,
29403
+ turnId
29404
+ },
29405
+ deadlineAt: Date.now() + 5000
29406
+ }).catch(()=>{});
29407
+ throw error;
29408
+ } finally{
29409
+ if (threadId) await this.request({
29410
+ method: 'thread/unsubscribe',
29411
+ params: {
29412
+ threadId
29413
+ },
29414
+ deadlineAt: Date.now() + CODEX_DEFAULT_CLEANUP_TIMEOUT_MS
29415
+ }).catch((error)=>{
29416
+ warnCodex(`failed to unsubscribe codex thread ${threadId}: ${String(error)}`);
29417
+ });
29418
+ }
29419
+ }
29420
+ async dispose() {
29421
+ if (this.closed) return;
29422
+ this.closed = true;
29423
+ try {
29424
+ this.lineReader?.close?.();
29425
+ } catch {}
29426
+ try {
29427
+ this.child?.stdin?.end?.();
29428
+ } catch {}
29429
+ try {
29430
+ this.child?.kill?.();
29431
+ } catch {}
29432
+ }
29433
+ attachProcessListeners() {
29434
+ this.lineReader.on('line', (line)=>{
29435
+ this.lineBuffer.push(line);
29436
+ });
29437
+ this.child.stderr.on('data', (chunk)=>{
29438
+ const text = Buffer.isBuffer(chunk) ? chunk.toString('utf8') : String(chunk);
29439
+ this.stderrBuffer += text;
29440
+ if (this.stderrBuffer.length > 8192) this.stderrBuffer = this.stderrBuffer.slice(-8192);
29441
+ });
29442
+ this.child.on('exit', (code)=>{
29443
+ this.closed = true;
29444
+ this.lastExitCode = code;
29445
+ });
29446
+ this.child.on('error', (error)=>{
29447
+ this.closed = true;
29448
+ this.processErrorMessage = error.message;
29449
+ });
29450
+ }
29451
+ detachFromEventLoop() {
29452
+ this.child.unref?.();
29453
+ this.child.stdin?.unref?.();
29454
+ this.child.stdout?.unref?.();
29455
+ this.child.stderr?.unref?.();
29456
+ }
29457
+ async initializeHandshake() {
29458
+ const deadlineAt = Date.now() + CODEX_DEFAULT_PROCESS_START_TIMEOUT_MS;
29459
+ await this.request({
29460
+ method: 'initialize',
29461
+ params: {
29462
+ clientInfo: {
29463
+ name: 'midscene_codex_provider',
29464
+ title: 'Midscene Codex Provider',
29465
+ version: '1.0.0'
29466
+ },
29467
+ capabilities: {
29468
+ experimentalApi: false
29469
+ }
29470
+ },
29471
+ deadlineAt
29472
+ });
29473
+ await this.sendMessage({
29474
+ method: 'initialized'
29475
+ });
29476
+ }
29477
+ mapUsage({ usage, modelConfig, turnId, startTime }) {
29478
+ const tokenUsage = usage.tokenUsage;
29479
+ const picked = tokenUsage?.last || tokenUsage?.total;
29480
+ if (!picked) return;
29481
+ return {
29482
+ prompt_tokens: picked.inputTokens ?? 0,
29483
+ completion_tokens: picked.outputTokens ?? 0,
29484
+ total_tokens: picked.totalTokens ?? 0,
29485
+ cached_input: picked.cachedInputTokens ?? 0,
29486
+ time_cost: Date.now() - startTime,
29487
+ model_name: modelConfig.modelName,
29488
+ model_description: modelConfig.modelDescription,
29489
+ intent: modelConfig.intent,
29490
+ request_id: turnId
29491
+ };
29492
+ }
29493
+ isRequestMessage(message) {
29494
+ return 'string' == typeof message?.method && message?.id !== void 0;
29495
+ }
29496
+ isResponseMessage(message) {
29497
+ return message?.id !== void 0 && (message?.result !== void 0 || message?.error !== void 0) && 'string' != typeof message?.method;
29498
+ }
29499
+ async request({ method, params, deadlineAt, abortSignal }) {
29500
+ const requestId = this.nextRequestId++;
29501
+ await this.sendMessage({
29502
+ id: requestId,
29503
+ method,
29504
+ params
29505
+ });
29506
+ while(true){
29507
+ const message = await this.nextMessage({
29508
+ deadlineAt,
29509
+ abortSignal,
29510
+ includePending: false
29511
+ });
29512
+ if (this.isResponseMessage(message) && message.id === requestId) {
29513
+ if (message.error) throw new Error(`codex app-server ${method} failed: ${message.error.message || 'unknown error'}`);
29514
+ return message.result || {};
29515
+ }
29516
+ if (this.isRequestMessage(message)) {
29517
+ await this.respondToServerRequest(message);
29518
+ continue;
29519
+ }
29520
+ this.pendingMessages.push(message);
29521
+ }
29522
+ }
29523
+ async respondToServerRequest(request) {
29524
+ const requestId = request.id;
29525
+ const method = request.method;
29526
+ let result = {};
29527
+ if ('item/commandExecution/requestApproval' === method) result = {
29528
+ decision: 'decline'
29529
+ };
29530
+ else if ('item/fileChange/requestApproval' === method) result = {
29531
+ decision: 'decline'
29532
+ };
29533
+ else if ('mcpServer/elicitation/request' === method) result = {
29534
+ action: 'cancel',
29535
+ content: null
29536
+ };
29537
+ else {
29538
+ if ('item/tool/requestUserInput' !== method) return void await this.sendMessage({
29539
+ id: requestId,
29540
+ error: {
29541
+ code: -32601,
29542
+ message: `unsupported server request: ${method}`
29543
+ }
29544
+ });
29545
+ result = {
29546
+ answers: []
29547
+ };
29548
+ }
29549
+ await this.sendMessage({
29550
+ id: requestId,
29551
+ result
29552
+ });
29553
+ }
29554
+ async nextMessage({ deadlineAt, abortSignal, includePending = true }) {
29555
+ if (includePending && this.pendingMessages.length) return this.pendingMessages.shift();
29556
+ while(true){
29557
+ if (abortSignal?.aborted) throw new Error('codex app-server request aborted');
29558
+ if (deadlineAt && Date.now() > deadlineAt) throw new Error('codex app-server request timed out');
29559
+ if (this.lineBuffer.length) {
29560
+ const line = this.lineBuffer.shift();
29561
+ const trimmed = line.trim();
29562
+ if (!trimmed) continue;
29563
+ let parsed;
29564
+ try {
29565
+ parsed = JSON.parse(trimmed);
29566
+ } catch (error) {
29567
+ warnCodex(`ignored non-JSON message from codex app-server: ${trimmed}`);
29568
+ continue;
29569
+ }
29570
+ return parsed;
29571
+ }
29572
+ if (this.closed) throw this.createClosedConnectionError();
29573
+ await new Promise((resolve)=>setTimeout(resolve, 20));
29574
+ }
29575
+ }
29576
+ async sendMessage(payload) {
29577
+ if (this.closed) throw this.createClosedConnectionError();
29578
+ const line = JSON.stringify(payload);
29579
+ await new Promise((resolve, reject)=>{
29580
+ this.child.stdin.write(`${line}\n`, (error)=>{
29581
+ if (error) return void reject(new Error(`failed writing to codex app-server stdin: ${error.message}`));
29582
+ resolve();
29583
+ });
29584
+ });
29585
+ }
29586
+ createClosedConnectionError() {
29587
+ const stderr = this.stderrBuffer.trim();
29588
+ if (this.processErrorMessage) return new Error(stderr ? `codex app-server process error: ${this.processErrorMessage}. stderr=${stderr}` : `codex app-server process error: ${this.processErrorMessage}`);
29589
+ return new Error(stderr ? `codex app-server connection closed (exitCode=${this.lastExitCode}). stderr=${stderr}` : `codex app-server connection closed (exitCode=${this.lastExitCode})`);
29590
+ }
29591
+ constructor(child, lineReader){
29592
+ _define_property(this, "child", void 0);
29593
+ _define_property(this, "lineReader", void 0);
29594
+ _define_property(this, "pendingMessages", []);
29595
+ _define_property(this, "lineBuffer", []);
29596
+ _define_property(this, "nextRequestId", 1);
29597
+ _define_property(this, "closed", false);
29598
+ _define_property(this, "lastExitCode", null);
29599
+ _define_property(this, "processErrorMessage", null);
29600
+ _define_property(this, "stderrBuffer", '');
29601
+ this.child = child;
29602
+ this.lineReader = lineReader;
29603
+ }
29604
+ }
29605
+ class CodexAppServerConnectionManager {
29606
+ async runTurn({ messages, modelConfig, stream, onChunk, deepThink, abortSignal }) {
29607
+ return this.runner.run(async ()=>{
29608
+ const connection = await this.getConnection();
29609
+ try {
29610
+ return await connection.runTurn({
29611
+ messages,
29612
+ modelConfig,
29613
+ stream,
29614
+ onChunk,
29615
+ deepThink,
29616
+ abortSignal
29617
+ });
29618
+ } catch (error) {
29619
+ if (connection.isClosed() || !codex_app_server_isAbortError(error)) await this.resetConnection();
29620
+ throw error;
29621
+ }
29622
+ });
29623
+ }
29624
+ async shutdownForTests() {
29625
+ await this.resetConnection();
29626
+ }
29627
+ async getConnection() {
29628
+ if (!this.connection || this.connection.isClosed()) {
29629
+ this.connection = await CodexAppServerConnection.create();
29630
+ debugCodex('started long-lived codex app-server connection');
29631
+ }
29632
+ return this.connection;
29633
+ }
29634
+ async resetConnection() {
29635
+ if (!this.connection) return;
29636
+ const staleConnection = this.connection;
29637
+ this.connection = null;
29638
+ await staleConnection.dispose();
29639
+ debugCodex('reset codex app-server connection');
29640
+ }
29641
+ constructor(){
29642
+ _define_property(this, "connection", null);
29643
+ _define_property(this, "runner", new SerializedRunner());
29644
+ }
29645
+ }
29646
+ new CodexAppServerConnectionManager();
29085
29647
  logger_getDebug('ai:common');
29086
29648
  const PointSchema = lib.z.object({
29087
29649
  left: lib.z.number(),
@@ -31945,7 +32507,7 @@ For more information, visit: https://midscenejs.com/mcp-migration
31945
32507
  constructor(){
31946
32508
  super({
31947
32509
  name: '@midscene/mcp',
31948
- version: '1.5.5',
32510
+ version: '1.5.6',
31949
32511
  description: 'Deprecated - Use @midscene/web-bridge-mcp, @midscene/android-mcp, or @midscene/ios-mcp'
31950
32512
  });
31951
32513
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midscene/mcp",
3
- "version": "1.5.5",
3
+ "version": "1.5.6",
4
4
  "description": "Deprecated - Use @midscene/web-bridge-mcp, @midscene/android-mcp, or @midscene/ios-mcp",
5
5
  "bin": "dist/index.js",
6
6
  "files": [
@@ -13,11 +13,11 @@
13
13
  "@rslib/core": "^0.18.3",
14
14
  "@types/node": "^18.0.0",
15
15
  "typescript": "^5.8.3",
16
- "@midscene/android": "1.5.5",
16
+ "@midscene/android": "1.5.6",
17
17
  "@midscene/report": "1.0.0",
18
- "@midscene/core": "1.5.5",
19
- "@midscene/shared": "1.5.5",
20
- "@midscene/web": "1.5.5"
18
+ "@midscene/core": "1.5.6",
19
+ "@midscene/shared": "1.5.6",
20
+ "@midscene/web": "1.5.6"
21
21
  },
22
22
  "license": "MIT",
23
23
  "scripts": {