@ai.weget.jp/bot 0.1.17 → 0.1.18

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/src/main.js CHANGED
@@ -1 +1 @@
1
- import t from"node:path";import e from"node:fs/promises";import{existsSync as i}from"node:fs";import{fileURLToPath as a}from"node:url";import{createRequire as r}from"node:module";import{SYSTEM_CONFIG as s}from"./config/systemConfig.js";import{BotWsClient as n}from"./wsClient.js";import{registerIpcHandlers as o}from"./ipc/registerHandlers.js";import{createAuthApiService as l}from"./services/authApiService.js";import{createCodexService as g}from"./services/codexService.js";import{createGatewayFileBridgeService as c}from"./services/gatewayFileBridgeService.js";import{createPlatformApiClient as d}from"./platformApi.js";import{createSkillRuntimeManager as p}from"./skillRuntimeManager.js";import{createWindowManager as m}from"./services/windowManagerService.js";import{createSkillHostState as u}from"./skillHostState.js";const S=r(import.meta.url),{app:y,BrowserWindow:f,ipcMain:w,nativeImage:k}=S("electron"),_=a(import.meta.url),b=t.dirname(_),h=["trade","ai"],v=()=>t.join(y.getPath("userData"),"login-profile.json"),x=()=>t.join(y.getPath("userData"),"host-config.json"),C=()=>t.join(y.getPath("userData"),"skill-states.json");let A=null,O=null,M={aiModel:"gpt-5.4",logOutputDir:""};const j=new Map;let E=()=>t.join(y.getPath("documents"),"weget-bot-logs");const P=t=>{const e=String(t||"").toLowerCase();return e.includes("debug")||e.includes("[debug]")?"debug":e.includes("error")||e.includes("failed")||e.includes("exception")?"error":"info"},I=async({level:i,source:a,message:r,details:s,ts:n})=>{const o=E();await e.mkdir(o,{recursive:!0});const l=new Date,g=l.getFullYear(),c=String(l.getMonth()+1).padStart(2,"0"),d=String(l.getDate()).padStart(2,"0"),p=t.join(o,`${i}-${g}${c}${d}.log`),m=JSON.stringify({ts:n||l.toISOString(),level:i,source:a,message:r,details:s??null},null,0);await e.appendFile(p,`${m}\n`,"utf8")},D=m({BrowserWindow:f,preloadPath:t.join(b,"preload.cjs"),rendererDir:t.join(b,"renderer"),windowIconPath:t.join(b,"renderer","logo.png")}),T=(t,e)=>{const i=(new Date).toISOString();D.emitBotLog({message:t,data:e||null,ts:i}),I({level:P(t),source:"runtime",message:t,details:e,ts:i}).catch(()=>{})},B=t=>{D.emitChatEvent(t)},L=t=>t&&"object"==typeof t?t:{},U=u({log:T}),N=l({getEnv:()=>({loginApiUrl:s.loginApiUrl,botUploadApiUrl:s.botUploadApiUrl}),emitLog:T,getCurrentSession:()=>A}),F=d({getBaseUrl:()=>String(s.loginApiUrl||"").trim().replace(/\/login\/?$/i,""),getSession:()=>A,log:T}),G=async t=>{const e=(()=>{const t=String(s.loginApiUrl||"").trim();return t?t.replace(/\/login\/?$/i,"/bot/runtime/line-reply"):""})();if(!e)throw new Error("runtime line reply api url is missing");return N.callBotApi(e,t)},q=p({installRoot:t.join(y.getPath("userData"),"skills"),botId:()=>String(A?.botId||"").trim()||void 0,log:T,api:F,getRuntimeConfig:()=>({cryptoApiBaseUrl:s.gmoCryptoPrivateApiBaseUrl,fxApiBaseUrl:s.gmoFxPrivateApiBaseUrl,coinPublicBaseUrl:s.gmoCryptoPublicApiBaseUrl,fxPublicBaseUrl:s.gmoFxPublicApiBaseUrl,assetsPath:s.gmoAssetsPath,fxAssetsPath:s.gmoFxAssetsPath,coinMarginPath:s.gmoCoinMarginPath,positionsPath:s.gmoPositionsPath,positionSummaryPath:s.gmoPositionSummaryPath,fxOrderPath:s.gmoFxOrderPath,coinCloseOrderPath:s.gmoCoinCloseOrderPath,fxCloseOrderPath:s.gmoFxCloseOrderPath}),emitSkillEvent:(t,e)=>{if("trade_execution"!==e.type){if("trade_history"===e.type){const i=`trade-${Date.now()}`;O?.sendTaskEvent(i,"trade_history",{package_name:t,...e.payload&&"object"==typeof e.payload?e.payload:{}}),T("[trade] history event sent (execution)",{package_name:t,payload:e.payload})}}else D.emitTradeExecution(e.payload)}}),R=()=>{const t=q.getLoadedSkill("@ai.weget.jp/skill-gmo-fx")?.runtime;if(!t)throw new Error("GMO FX skill runtime is not installed");return t},K=()=>{const t=q.getLoadedSkill("@ai.weget.jp/skill-gmo-coin")?.runtime;if(!t)throw new Error("GMO Coin skill runtime is not installed");return t},$=()=>q.getLoadedSkill("@ai.weget.jp/skill-gmo-fx")?.runtime,J=()=>q.getLoadedSkill("@ai.weget.jp/skill-gmo-coin")?.runtime,W=()=>{const t=q.getLoadedSkill("@ai.weget.jp/skill-macro-economy")?.runtime;if(!t)throw new Error("Macro Economy skill runtime is not installed");return t},z=()=>q.getLoadedSkill("@ai.weget.jp/skill-macro-economy")?.runtime,H=(t,e)=>{const i=t.gateway[e];if("function"!=typeof i)throw new Error(`skill runtime does not implement gateway.${e}`);return i},Q=t=>{const e=L(t);return{riskDailyLossLimitJpy:Number(e.riskDailyLossLimitJpy||0),fxApiKey:String(e.fxApiKey||"").trim(),fxApiSecret:String(e.fxApiSecret||"").trim(),aiModel:String(e.aiModel||"").trim()||"gpt-5.4"}},X=t=>{const e=L(t);return{riskDailyLossLimitJpy:Number(e.riskDailyLossLimitJpy||0),cryptoApiKey:String(e.cryptoApiKey||"").trim(),cryptoApiSecret:String(e.cryptoApiSecret||"").trim(),aiModel:String(e.aiModel||"").trim()||"gpt-5.4"}};E=()=>String(M.logOutputDir||"").trim()||t.join(y.getPath("documents"),"weget-bot-logs");const Y=g({getModel:()=>{const t=$(),e=J();return M.aiModel||t?.getConfig?.().aiModel||e?.getConfig?.().aiModel||"gpt-5.4"},getWorkingDir:()=>y.getPath("userData"),getLogDir:()=>E(),emitLog:T,getGatewayContext:()=>({activeSkills:U.getManagedSkills().filter(t=>t.enabled).map(t=>({name:t.name,displayName:t.displayName,version:t.version,tools:t.tools})),hostMetadata:{aiModel:M.aiModel||"gpt-5.4",capabilities:h,userDataPath:y.getPath("userData"),platform:process.platform,gmoCoinPublicBaseUrl:s.gmoCryptoPublicApiBaseUrl,gmoFxPublicBaseUrl:s.gmoFxPublicApiBaseUrl},botId:String(A?.botId||"").trim(),platformApiBaseUrl:String(s.loginApiUrl||"").trim().replace(/\/login\/?$/i,""),accessToken:String(A?.accessToken||"").trim(),fileBridgeDir:String(nt.getContext()?.dir||"").trim(),fileBridgeToken:String(nt.getContext()?.token||"").trim()})}),V=async t=>{const i=L(t);return M={aiModel:String(i.aiModel||M.aiModel||"gpt-5.4").trim()||"gpt-5.4",logOutputDir:String(i.logOutputDir||"").trim()},await e.writeFile(x(),JSON.stringify({...M,updatedAt:(new Date).toISOString()},null,2),"utf8"),M};const Z=async()=>{const t=await q.refreshLoadedSkills();return U.setAvailableSkills(t.map(t=>t.manifest)),t},tt=async t=>{const e=await Z();T("[skills] reconciled bundled skills",{desired:t.map(t=>({package_name:t.package_name,install_status:t.install_status,enabled:t.enabled,version:t.version})),bundled:e.map(t=>({package_name:t.packageName,version:t.version}))})},et=()=>{const t=U.isSkillEnabled("@ai.weget.jp/skill-gmo-fx"),e=U.isSkillEnabled("@ai.weget.jp/skill-gmo-coin"),i=$(),a=J();i&&("connected"===O?.getStatus()&&t?i.startExecutionStreams():i.stopExecutionStreams()),a&&("connected"===O?.getStatus()&&e?a.startExecutionStreams():a.stopExecutionStreams()),T("[skills] applied managed states",{active_skills:U.getActiveSkills().map(t=>t.name)})},it=async()=>{const t=N.getBotRuntimeConfigApiUrl(),e=String(A?.botId||"").trim();if(!t||!e)return;const i=await N.callBotApi(t,{bot_id:e}),a=String(i.chat_model||"").trim(),r={...a?{aiModel:a}:{}};if(0===Object.keys(r).length)return;await V({...M,...r});const s=$(),n=J();s&&await s.saveConfig({...s.getConfig(),...r}),n&&await n.saveConfig({...n.getConfig(),...r}),T("[config] runtime config synced",{chat_model:a||""})},at=async()=>{const t=N.getBotSkillsListApiUrl(),i=String(A?.botId||"").trim();if(!t||!i)return;const a=await N.callBotApi(t,{bot_id:i}),r=Array.isArray(a.states)?a.states.filter(t=>Boolean(t&&"object"==typeof t)).map(t=>({user_id:String(t.user_id||""),bot_id:String(t.bot_id||""),skill_id:String(t.skill_id||""),package_name:String(t.package_name||""),enabled:Boolean(t.enabled),install_status:String(t.install_status||""),version:t.version?String(t.version):null,config_json:L(t.config_json),created_at:t.created_at?String(t.created_at):void 0,updated_at:t.updated_at?String(t.updated_at):void 0})):[];U.applySnapshots(r),await(async t=>{await e.writeFile(C(),JSON.stringify({updatedAt:(new Date).toISOString(),items:t},null,2),"utf8")})(r),await tt(r),et(),T("[config] skill states synced",{count:r.length,bot_id:i,enabled:r.filter(t=>t.enabled).length})},rt=t=>{if("fx"===t&&!U.isSkillEnabled("@ai.weget.jp/skill-gmo-fx"))throw new Error("GMO FX skill is disabled");if("coin"===t&&!U.isSkillEnabled("@ai.weget.jp/skill-gmo-coin"))throw new Error("GMO Coin skill is disabled")},st=()=>{if(!U.isSkillEnabled("@ai.weget.jp/skill-macro-economy"))throw new Error("Macro Economy skill is disabled")},nt=c({getMacroSnapshot:async({force:t}={})=>(st(),W().getSnapshot({force:t})),getMacroCalendar:async({dateKey:t})=>(st(),W().listCalendar({dateKey:t})),getMacroNews:async({dateKey:t})=>(st(),W().listNews({dateKey:t})),emitLog:T,getWorkingDir:()=>y.getPath("userData")}),ot={"@ai.weget.jp/skill-gmo-fx":{getConfig:()=>Q(R().getConfig()),saveConfig:async t=>{const e=R(),i=await e.saveConfig({...e.getConfig(),...Q(t)});return"connected"===O?.getStatus()&&et(),Q(i)}},"@ai.weget.jp/skill-gmo-coin":{getConfig:()=>X(K().getConfig()),saveConfig:async t=>{const e=K(),i=await e.saveConfig({...e.getConfig(),...X(t)});return"connected"===O?.getStatus()&&et(),X(i)}}},lt=t=>{const e=String(t||"").trim(),i=ot[e];if(!i)throw new Error(`skill config is not managed by bot host: ${t}`);return i},gt=async()=>{await q.ensureInstallRoot(),await Z();const t=await async function(){try{const t=await e.readFile(C(),"utf8"),i=JSON.parse(t);return(Array.isArray(i?.items)?i.items:[]).filter(t=>Boolean(t&&"object"==typeof t)).map(t=>({user_id:String(t.user_id||""),bot_id:String(t.bot_id||""),skill_id:String(t.skill_id||""),package_name:String(t.package_name||""),enabled:Boolean(t.enabled),install_status:String(t.install_status||""),version:t.version?String(t.version):null,config_json:L(t.config_json),created_at:t.created_at?String(t.created_at):void 0,updated_at:t.updated_at?String(t.updated_at):void 0}))}catch(t){if("ENOENT"===t?.code)return[];throw t}}();t.length>0&&(U.applySnapshots(t),T("[skills] restored local snapshot",{count:t.length}),await tt(t)),et()};O=new n({wsUrl:"wss://ws.weget.jp",taskEventApiUrl:String(s.loginApiUrl||"").trim().replace(/\/login\/?$/i,"/bot/runtime/task-event"),version:"0.2.0",capabilities:h,heartbeatSec:30,reconnectMs:3e3,reconnectMaxAttempts:10,wsPingIntervalSec:25,wsPongTimeoutSec:12},{onLog:(t,e)=>T(t,e),onStatus:t=>{D.emitBotStatus({status:t}),et()},onLineMessage:async t=>{const e=String(t.line_user_id||""),i=String(t.text||"").trim();if(B({type:"line_user",lineUserId:e,text:i}),!i)return{answer:""};try{const t=await Y.runPrompt({prompt:i,contextLabel:"line_message"});return B({type:"line_assistant",lineUserId:e,text:t}),{answer:t}}catch(t){const i=t instanceof Error?t.message:String(t);T("[ai] line reply failed",{error:i});const a=`AI error: ${i}`;return B({type:"line_assistant",lineUserId:e,text:a}),{answer:a}}},onRunTask:async t=>{const e=String(t.task_id||"").trim(),i=String(t.prompt||"").trim(),a=L(t.metadata_json),r=L(t.prompt_bundle),s=L(t.runtime_config),n=String(a.source||r.source||"").trim(),o=String(a.channel||r.channel||"").trim(),l=String(t.skill_id||a.skill_id||r.skill_id||"").trim(),g=String(a.line_user_id||"").trim(),c=String(a.line_reply_token||"").trim(),d="line"===n||"line"===o||Boolean(g&&c),p="bot_host"===n,m=String(t.model||s.chat_model||"").trim(),u=String(s.system_prompt||r.system_prompt||"").trim();if(e){if(j.set(e,{cancelled:!1}),d&&g&&i&&B({type:"line_user",lineUserId:g,text:i}),O?.sendTaskEvent(e,"task_received",{prompt:i,conversation_id:String(t.conversation_id||""),continue_from_task_id:String(t.continue_from_task_id||""),ts:(new Date).toISOString()}),!i)return O?.sendTaskResult(e,"failed",{error:"prompt is required",data_json:{ts:(new Date).toISOString()}}),void j.delete(e);try{p&&B({type:"assistant_status",status:"Task received"}),l&&O?.sendSkillStatus(e,{skill_id:l,status:"running",summary:"task execution started",data_json:{ts:(new Date).toISOString()}}),O?.sendTaskEvent(e,"step_started",{step:"codex_chat",ts:(new Date).toISOString()});const s=await Y.runPrompt({prompt:i,model:m||void 0,systemPrompt:u||void 0,contextLabel:`task:${e}`,promptBundle:r,metadata:a,onStatus:p?t=>B({type:"assistant_status",status:t}):void 0}),n=(t=>{const e=String(t||""),i=e.match(/```weget_result\s*([\s\S]*?)```/i);if(i?.[1])try{const t=JSON.parse(i[1].trim()),a=String(t.status||"").trim().toLowerCase(),r=t.pending_request&&"object"==typeof t.pending_request?t.pending_request:{};if("pending_request"!==a)return null;const s=String(r.type||"").trim().toLowerCase(),n=String(r.prompt||"").trim(),o=String(r.subtype||"").trim();return"input"!==s&&"approval"!==s||!n?null:{visibleText:e.replace(i[0],"").trim(),requestType:s,prompt:n,subtype:o||void 0}}catch{return null}const a=e.match(/```weget_pending_request\s*([\s\S]*?)```/i);if(!a?.[1])return null;try{const t=JSON.parse(a[1].trim()),i=String(t.type||"").trim().toLowerCase(),r=String(t.prompt||"").trim(),s=String(t.subtype||"").trim();return"input"!==i&&"approval"!==i||!r?null:{visibleText:e.replace(a[0],"").trim(),requestType:i,prompt:r,subtype:s||void 0}}catch{return null}})(s),o=n?.visibleText||s,S=j.get(e);if(S?.cancelled)return O?.sendTaskResult(e,"cancelled",{summary:"server_cancelled",data_json:{reason:"server_cancelled",ts:(new Date).toISOString()}}),void j.delete(e);if(O?.sendTaskEvent(e,"ai_output",{summary:o,ts:(new Date).toISOString()}),p&&B({type:"assistant",text:o}),d&&g&&c){B({type:"line_assistant",lineUserId:g,text:o});const i={bot_id:String(t.bot_id||A?.botId||""),line_user_id:g,line_reply_token:c,text:o};try{await G(i)}catch(t){T("[line] callback line reply failed",{error:t instanceof Error?t.message:String(t)})}O?.sendTaskEvent(e,"line_message_ai_output",{line_user_id:g,answer:s,ts:(new Date).toISOString()})}if(O?.sendTaskEvent(e,"step_finished",{step:"codex_chat",ts:(new Date).toISOString()}),n)return"approval"===n.requestType?O?.requestTaskApproval(e,{prompt:n.prompt,approval_type:n.subtype||"generic",data_json:{prompt:n.prompt,approval_type:n.subtype||"generic",ts:(new Date).toISOString()}}):O?.requestTaskInput(e,{prompt:n.prompt,input_type:n.subtype||"text",data_json:{prompt:n.prompt,input_type:n.subtype||"text",ts:(new Date).toISOString()}}),l&&O?.sendSkillStatus(e,{skill_id:l,status:"approval"===n.requestType?"waiting_approval":"waiting_input",summary:n.prompt.slice(0,200),data_json:{ts:(new Date).toISOString(),request_type:n.requestType}}),void j.delete(e);O?.sendTaskResult(e,"succeeded",{summary:o.slice(0,500),data_json:{ts:(new Date).toISOString()}}),l&&O?.sendSkillStatus(e,{skill_id:l,status:"succeeded",summary:o.slice(0,200),data_json:{ts:(new Date).toISOString()}})}catch(i){if(p){const t=`Error: ${i instanceof Error?i.message:String(i)}`;B({type:"assistant",text:t})}if(d&&g&&c){const e=`AI error: ${i instanceof Error?i.message:String(i)}`;B({type:"line_assistant",lineUserId:g,text:e});const a={bot_id:String(t.bot_id||A?.botId||""),line_user_id:g,line_reply_token:c,text:e};try{await G(a)}catch(t){T("[line] callback line reply failed",{error:t instanceof Error?t.message:String(t)})}}O?.sendTaskResult(e,"failed",{error:i instanceof Error?i.message:String(i),data_json:{ts:(new Date).toISOString()}}),l&&O?.sendSkillStatus(e,{skill_id:l,status:"failed",summary:i instanceof Error?i.message:String(i),data_json:{ts:(new Date).toISOString()}})}finally{j.delete(e)}}else T("[task] run_task missing task_id")},onTaskControl:async t=>{const e=String(t.task_id||"").trim(),i=String(t.action||"").trim();if(e&&i&&"cancel_task"===i){const i=j.get(e);if(i){i.cancelled=!0;const a=String(t.skill_id||"").trim();return a&&O?.sendSkillStatus(e,{skill_id:a,status:"cancelled",summary:"server_cancelled",data_json:{ts:(new Date).toISOString()}}),void T("[task] cancel requested",{task_id:e})}O?.sendTaskResult(e,"cancelled",{summary:"server_cancelled",data_json:{reason:"server_cancelled",ts:(new Date).toISOString()}})}},onServerConfigUpdate:async t=>{const e=Array.isArray(t.scopes)?t.scopes.map(t=>String(t||"").trim()):[],i=e.length>0?e:["runtime","skills"];i.includes("runtime")&&await it(),i.includes("skills")&&await at()}}),o({ipcMain:w,env:{capabilities:h,loginApiUrl:s.loginApiUrl},signInWithLoginApi:N.signInWithLoginApi,saveLoginProfile:async({botId:t,email:i,password:a,remember:r})=>{if(r)await e.writeFile(v(),JSON.stringify({botId:t,email:i,password:a,remember:!0,updatedAt:(new Date).toISOString()},null,2),"utf8");else try{await e.unlink(v())}catch(t){if("ENOENT"!==t?.code)throw t}},readSavedLoginProfile:async()=>{try{const t=await e.readFile(v(),"utf8"),i=JSON.parse(t);return{botId:String(i?.botId||""),email:String(i?.email||""),password:String(i?.password||""),remember:Boolean(i?.remember)}}catch(t){if("ENOENT"===t?.code)return{botId:"",email:"",password:"",remember:!1};throw t}},getSkillConfig:t=>({config:lt(t).getConfig()}),saveSkillConfig:async(t,e)=>({config:await lt(t).saveConfig(e)}),getAiConfig:()=>({aiModel:String(M.aiModel||"gpt-5.4"),logOutputDir:String(M.logOutputDir||"")}),saveAiConfig:async t=>{const e=t&&"object"==typeof t?t:{},i=await V({...M,...e}),a=$(),r=J(),s=a?await a.saveConfig({...a.getConfig(),...e}):null;return r&&await r.saveConfig({...r.getConfig(),...e}),{aiModel:String(i.aiModel||s?.aiModel||e.aiModel||"gpt-5.4"),logOutputDir:String(i.logOutputDir||"")}},setCurrentSession:t=>{A=t||null;const e=A?"connected":"disconnected";D.emitBotStatus({status:e})},getCurrentSession:()=>A,getActiveSkills:()=>U.getActiveSkills().map(t=>({name:t.name,displayName:t.displayName,version:t.version})),getCodexAuthStatus:()=>Y.getAuthStatus(),getCodexMcpStatus:t=>Y.getMcpServerStatus(t),getPlaywrightBrowserStatus:()=>Y.getPlaywrightBrowserStatus(),startCodexLogin:()=>Y.startLogin(),installPlaywrightMcp:()=>Y.installWegetGatewayMcp(),getGatewayContextFilePath:()=>Y.getGatewayContextFilePath(),runGatewaySelfTest:t=>Y.runGatewaySelfTest(t),getManagedSkills:()=>U.getManagedSkills().map(t=>({...t,ui:q.getLoadedSkill(t.name)?.ui||void 0})),getMacroSnapshot:async({force:t}={})=>(st(),W().getSnapshot({force:t})),getMacroCalendar:async({dateKey:t})=>(st(),W().listCalendar({dateKey:t})),getMacroNews:async({dateKey:t})=>(st(),W().listNews({dateKey:t})),emitLog:T,openGmoKlineWindow:async({symbol:t,interval:e,market:i})=>(()=>{const a="fx"===i?"fx":"coin";return rt(a),("fx"===a?R().marketData:K().marketData).fetchKline({symbol:t,interval:e,market:a})})(),getGmoMarketQuotes:async({market:t,symbols:e})=>(()=>{const i="fx"===t?"fx":"coin";return rt(i),("fx"===i?R().marketData:K().marketData).fetchQuotes({market:i,symbols:e})})(),getGmoSymbolRules:async({market:t})=>(()=>{const e="fx"===t?"fx":"coin";return rt(e),("fx"===e?R().marketData:K().marketData).fetchSymbolRules({market:e})})(),getGmoBuyingPower:async({market:t})=>({market:t,availableJpy:await(rt(t),("fx"===t?R().gateway:K().gateway).getBuyingPower(t))}),getGmoAccountMetrics:async({market:t})=>(rt(t),("fx"===t?R().gateway:K().gateway).getAccountMetrics(t)),getGmoPositionSummary:async({market:t,symbol:e})=>({market:t,symbol:e,items:await(rt(t),("fx"===t?R().gateway:K().gateway).getPositionSummary({market:t,symbol:e}))}),getGmoOpenPositions:async({market:t,symbol:e,page:i,prevId:a,count:r})=>({market:t,symbol:e||"",items:await(rt(t),("fx"===t?R().gateway:K().gateway).getOpenPositions({market:"fx"===t?"fx":"crypto",symbol:e||void 0,page:i,prevId:a,count:r}))}),placeGmoFxOrder:async({symbol:t,side:e,size:i})=>{rt("fx");return await H(R(),"placeFxOrder")({symbol:t,side:e,size:i,executionType:"MARKET"})},placeGmoCoinOrder:async({symbol:t,side:e,size:i})=>{rt("coin");return await H(K(),"placeCoinOrder")({symbol:t,side:e,size:i,executionType:"MARKET"})},placeGmoFxCloseOrder:async({symbol:t,side:e,positionId:i,size:a})=>{rt("fx");return await H(R(),"placeFxCloseOrder")({symbol:t,side:e,positionId:i,size:a,executionType:"MARKET"})},placeGmoCoinCloseOrder:async({symbol:t,side:e,positionId:i,size:a})=>{rt("coin");return await H(K(),"placeCoinCloseOrder")({symbol:t,side:e,positionId:i,size:a,executionType:"MARKET"})},getGmoApiState:t=>{const e="fx"===t?$():J();return e?.status.getApiState()||"unknown"},testGmoApi:t=>(rt(t),"fx"===t?R().status.testApi():K().status.testApi()),buildTradeStatusSnapshot:t=>(rt(t),"fx"===t?R().status.buildSnapshot():K().status.buildSnapshot()),closeTradeWindows:()=>{},startWsClient:t=>{O?.start(t),it().catch(t=>{T("[config] runtime sync failed after login",{error:t instanceof Error?t.message:String(t)})}),at().catch(t=>{T("[config] skill sync failed after login",{error:t instanceof Error?t.message:String(t)})}),et()},stopWsClient:()=>{$()?.stopExecutionStreams(),J()?.stopExecutionStreams(),z()?.stop?.(),O?.stop()},handleBotChatMessage:async({text:t})=>{const e=String(t||"").trim(),i=String(A?.botId||"").trim();if(!e)throw new Error("message is required");if(!i)throw new Error("bot session is not ready");B({type:"assistant_status",status:"Submitting task"});const a=await F.request({method:"POST",path:"/bot/tasks",body:{source:"bot_host",bot_id:i,prompt:e,title:e.slice(0,80),channel:"desktop",metadata_json:{source:"bot_host",channel:"desktop"}}}),r=L(a.dispatch_result);if(!1===r.delivered)throw new Error(`task queued but bot is offline (${String(r.status||"offline")})`);return{answer:"",taskId:String(L(a.task).task_id||"")}},writeErrorLog:async({source:t,message:e,details:i})=>{await(async({source:t,message:e,details:i})=>{await I({level:"error",source:t,message:e,details:i})})({source:t,message:e,details:i})},writeRuntimeLog:async({level:t,source:e,message:i,details:a})=>{await I({level:t,source:e,message:i,details:a})}});const ct=t.join(b,"renderer","logo.png");y.whenReady().then(async()=>{(()=>{if("darwin"!==process.platform)return;if(!i(ct))return;const t=k.createFromPath(ct);t.isEmpty()||y.dock.setIcon(t)})(),await(async()=>{try{const t=await e.readFile(x(),"utf8"),i=JSON.parse(t);M={aiModel:String(i?.aiModel||"gpt-5.4").trim()||"gpt-5.4",logOutputDir:String(i?.logOutputDir||"").trim()}}catch(t){if("ENOENT"!==t?.code)throw t;M={aiModel:"gpt-5.4",logOutputDir:""}}return M})();try{await nt.ensureStarted()}catch(t){T("[gateway-file-bridge] startup failed",{error:t instanceof Error?t.message:String(t)})}try{await gt()}catch(t){T("[skills] local initialization failed",{error:t instanceof Error?t.message:String(t)})}D.createMainWindow(),y.on("activate",()=>{0===f.getAllWindows().length&&D.createMainWindow()})}),y.on("window-all-closed",()=>{$()?.stopExecutionStreams(),J()?.stopExecutionStreams(),z()?.stop?.(),nt.stop().catch(()=>{}),O?.stop(),"darwin"!==process.platform&&y.quit()});
1
+ import t from"node:path";import e from"node:fs/promises";import{existsSync as i}from"node:fs";import{fileURLToPath as a}from"node:url";import{createRequire as r}from"node:module";import{SYSTEM_CONFIG as s}from"./config/systemConfig.js";import{BotWsClient as n}from"./wsClient.js";import{registerIpcHandlers as o}from"./ipc/registerHandlers.js";import{createAuthApiService as l}from"./services/authApiService.js";import{createCodexService as g}from"./services/codexService.js";import{createGatewayFileBridgeService as c}from"./services/gatewayFileBridgeService.js";import{createPlatformApiClient as d}from"./platformApi.js";import{createSkillRuntimeManager as p}from"./skillRuntimeManager.js";import{createWindowManager as m}from"./services/windowManagerService.js";import{createSkillHostState as u}from"./skillHostState.js";const S=r(import.meta.url),{app:y,BrowserWindow:f,ipcMain:w,nativeImage:k}=S("electron"),_=a(import.meta.url),b=t.dirname(_),h=["trade","ai"],v=()=>t.join(y.getPath("userData"),"login-profile.json"),x=()=>t.join(y.getPath("userData"),"host-config.json"),C=()=>t.join(y.getPath("userData"),"skill-states.json");let A=null,O=null,M={aiModel:"gpt-5.4",logOutputDir:""};const j=new Map;let E=()=>t.join(y.getPath("documents"),"weget-bot-logs");const P=t=>{const e=String(t||"").toLowerCase();return e.includes("debug")||e.includes("[debug]")?"debug":e.includes("error")||e.includes("failed")||e.includes("exception")?"error":"info"},I=async({level:i,source:a,message:r,details:s,ts:n})=>{const o=E();await e.mkdir(o,{recursive:!0});const l=new Date,g=l.getFullYear(),c=String(l.getMonth()+1).padStart(2,"0"),d=String(l.getDate()).padStart(2,"0"),p=t.join(o,`${i}-${g}${c}${d}.log`),m=JSON.stringify({ts:n||l.toISOString(),level:i,source:a,message:r,details:s??null},null,0);await e.appendFile(p,`${m}\n`,"utf8")},D=m({BrowserWindow:f,preloadPath:t.join(b,"preload.cjs"),rendererDir:t.join(b,"renderer"),windowIconPath:t.join(b,"renderer","logo.png")}),T=(t,e)=>{const i=(new Date).toISOString();D.emitBotLog({message:t,data:e||null,ts:i}),I({level:P(t),source:"runtime",message:t,details:e,ts:i}).catch(()=>{})},B=t=>{D.emitChatEvent(t)},L=t=>t&&"object"==typeof t?t:{},U=u({log:T}),N=l({getEnv:()=>({loginApiUrl:s.loginApiUrl,botUploadApiUrl:s.botUploadApiUrl}),emitLog:T,getCurrentSession:()=>A}),F=d({getBaseUrl:()=>String(s.loginApiUrl||"").trim().replace(/\/login\/?$/i,""),getSession:()=>A,log:T}),G=async t=>{const e=(()=>{const t=String(s.loginApiUrl||"").trim();return t?t.replace(/\/login\/?$/i,"/bot/runtime/line-reply"):""})();if(!e)throw new Error("runtime line reply api url is missing");return N.callBotApi(e,t)},q=p({installRoot:t.join(y.getPath("userData"),"skills"),botId:()=>String(A?.botId||"").trim()||void 0,log:T,api:F,getRuntimeConfig:()=>({cryptoApiBaseUrl:s.gmoCryptoPrivateApiBaseUrl,fxApiBaseUrl:s.gmoFxPrivateApiBaseUrl,coinPublicBaseUrl:s.gmoCryptoPublicApiBaseUrl,fxPublicBaseUrl:s.gmoFxPublicApiBaseUrl,assetsPath:s.gmoAssetsPath,fxAssetsPath:s.gmoFxAssetsPath,coinMarginPath:s.gmoCoinMarginPath,positionsPath:s.gmoPositionsPath,positionSummaryPath:s.gmoPositionSummaryPath,fxOrderPath:s.gmoFxOrderPath,coinCloseOrderPath:s.gmoCoinCloseOrderPath,fxCloseOrderPath:s.gmoFxCloseOrderPath}),emitSkillEvent:(t,e)=>{if("trade_execution"!==e.type){if("trade_history"===e.type){const i=`trade-${Date.now()}`;O?.sendTaskEvent(i,"trade_history",{package_name:t,...e.payload&&"object"==typeof e.payload?e.payload:{}}),T("[trade] history event sent (execution)",{package_name:t,payload:e.payload})}}else D.emitTradeExecution(e.payload)}}),R=()=>{const t=q.getLoadedSkill("@ai.weget.jp/skill-gmo-fx")?.runtime;if(!t)throw new Error("GMO FX skill runtime is not installed");return t},K=()=>{const t=q.getLoadedSkill("@ai.weget.jp/skill-gmo-coin")?.runtime;if(!t)throw new Error("GMO Coin skill runtime is not installed");return t},$=()=>q.getLoadedSkill("@ai.weget.jp/skill-gmo-fx")?.runtime,J=()=>q.getLoadedSkill("@ai.weget.jp/skill-gmo-coin")?.runtime,W=()=>{const t=q.getLoadedSkill("@ai.weget.jp/skill-macro-economy")?.runtime;if(!t)throw new Error("Macro Economy skill runtime is not installed");return t},z=()=>q.getLoadedSkill("@ai.weget.jp/skill-macro-economy")?.runtime,H=t=>String(t||"").replace(/```weget_result\s*[\s\S]*?```/gi,"").replace(/```weget_pending_request\s*[\s\S]*?```/gi,"").trim(),Q=(t,e)=>{const i=t.gateway[e];if("function"!=typeof i)throw new Error(`skill runtime does not implement gateway.${e}`);return i},X=t=>{const e=L(t);return{riskDailyLossLimitJpy:Number(e.riskDailyLossLimitJpy||0),fxApiKey:String(e.fxApiKey||"").trim(),fxApiSecret:String(e.fxApiSecret||"").trim(),aiModel:String(e.aiModel||"").trim()||"gpt-5.4"}},Y=t=>{const e=L(t);return{riskDailyLossLimitJpy:Number(e.riskDailyLossLimitJpy||0),cryptoApiKey:String(e.cryptoApiKey||"").trim(),cryptoApiSecret:String(e.cryptoApiSecret||"").trim(),aiModel:String(e.aiModel||"").trim()||"gpt-5.4"}};E=()=>String(M.logOutputDir||"").trim()||t.join(y.getPath("documents"),"weget-bot-logs");const V=g({getModel:()=>{const t=$(),e=J();return M.aiModel||t?.getConfig?.().aiModel||e?.getConfig?.().aiModel||"gpt-5.4"},getWorkingDir:()=>y.getPath("userData"),getLogDir:()=>E(),emitLog:T,getGatewayContext:()=>({activeSkills:U.getManagedSkills().filter(t=>t.enabled).map(t=>({name:t.name,displayName:t.displayName,version:t.version,tools:t.tools})),hostMetadata:{aiModel:M.aiModel||"gpt-5.4",capabilities:h,userDataPath:y.getPath("userData"),platform:process.platform,gmoCoinPublicBaseUrl:s.gmoCryptoPublicApiBaseUrl,gmoFxPublicBaseUrl:s.gmoFxPublicApiBaseUrl},botId:String(A?.botId||"").trim(),platformApiBaseUrl:String(s.loginApiUrl||"").trim().replace(/\/login\/?$/i,""),accessToken:String(A?.accessToken||"").trim(),fileBridgeDir:String(ot.getContext()?.dir||"").trim(),fileBridgeToken:String(ot.getContext()?.token||"").trim()})}),Z=async t=>{const i=L(t);return M={aiModel:String(i.aiModel||M.aiModel||"gpt-5.4").trim()||"gpt-5.4",logOutputDir:String(i.logOutputDir||"").trim()},await e.writeFile(x(),JSON.stringify({...M,updatedAt:(new Date).toISOString()},null,2),"utf8"),M};const tt=async()=>{const t=await q.refreshLoadedSkills();return U.setAvailableSkills(t.map(t=>t.manifest)),t},et=async t=>{const e=await tt();T("[skills] reconciled bundled skills",{desired:t.map(t=>({package_name:t.package_name,install_status:t.install_status,enabled:t.enabled,version:t.version})),bundled:e.map(t=>({package_name:t.packageName,version:t.version}))})},it=()=>{const t=U.isSkillEnabled("@ai.weget.jp/skill-gmo-fx"),e=U.isSkillEnabled("@ai.weget.jp/skill-gmo-coin"),i=$(),a=J();i&&("connected"===O?.getStatus()&&t?i.startExecutionStreams():i.stopExecutionStreams()),a&&("connected"===O?.getStatus()&&e?a.startExecutionStreams():a.stopExecutionStreams()),T("[skills] applied managed states",{active_skills:U.getActiveSkills().map(t=>t.name)})},at=async()=>{const t=N.getBotRuntimeConfigApiUrl(),e=String(A?.botId||"").trim();if(!t||!e)return;const i=await N.callBotApi(t,{bot_id:e}),a=String(i.chat_model||"").trim(),r={...a?{aiModel:a}:{}};if(0===Object.keys(r).length)return;await Z({...M,...r});const s=$(),n=J();s&&await s.saveConfig({...s.getConfig(),...r}),n&&await n.saveConfig({...n.getConfig(),...r}),T("[config] runtime config synced",{chat_model:a||""})},rt=async()=>{const t=N.getBotSkillsListApiUrl(),i=String(A?.botId||"").trim();if(!t||!i)return;const a=await N.callBotApi(t,{bot_id:i}),r=Array.isArray(a.states)?a.states.filter(t=>Boolean(t&&"object"==typeof t)).map(t=>({user_id:String(t.user_id||""),bot_id:String(t.bot_id||""),skill_id:String(t.skill_id||""),package_name:String(t.package_name||""),enabled:Boolean(t.enabled),install_status:String(t.install_status||""),version:t.version?String(t.version):null,config_json:L(t.config_json),created_at:t.created_at?String(t.created_at):void 0,updated_at:t.updated_at?String(t.updated_at):void 0})):[];U.applySnapshots(r),await(async t=>{await e.writeFile(C(),JSON.stringify({updatedAt:(new Date).toISOString(),items:t},null,2),"utf8")})(r),await et(r),it(),T("[config] skill states synced",{count:r.length,bot_id:i,enabled:r.filter(t=>t.enabled).length})},st=t=>{if("fx"===t&&!U.isSkillEnabled("@ai.weget.jp/skill-gmo-fx"))throw new Error("GMO FX skill is disabled");if("coin"===t&&!U.isSkillEnabled("@ai.weget.jp/skill-gmo-coin"))throw new Error("GMO Coin skill is disabled")},nt=()=>{if(!U.isSkillEnabled("@ai.weget.jp/skill-macro-economy"))throw new Error("Macro Economy skill is disabled")},ot=c({getMacroSnapshot:async({force:t}={})=>(nt(),W().getSnapshot({force:t})),getMacroCalendar:async({dateKey:t})=>(nt(),W().listCalendar({dateKey:t})),getMacroNews:async({dateKey:t})=>(nt(),W().listNews({dateKey:t})),emitLog:T,getWorkingDir:()=>y.getPath("userData")}),lt={"@ai.weget.jp/skill-gmo-fx":{getConfig:()=>X(R().getConfig()),saveConfig:async t=>{const e=R(),i=await e.saveConfig({...e.getConfig(),...X(t)});return"connected"===O?.getStatus()&&it(),X(i)}},"@ai.weget.jp/skill-gmo-coin":{getConfig:()=>Y(K().getConfig()),saveConfig:async t=>{const e=K(),i=await e.saveConfig({...e.getConfig(),...Y(t)});return"connected"===O?.getStatus()&&it(),Y(i)}}},gt=t=>{const e=String(t||"").trim(),i=lt[e];if(!i)throw new Error(`skill config is not managed by bot host: ${t}`);return i},ct=async()=>{await q.ensureInstallRoot(),await tt();const t=await async function(){try{const t=await e.readFile(C(),"utf8"),i=JSON.parse(t);return(Array.isArray(i?.items)?i.items:[]).filter(t=>Boolean(t&&"object"==typeof t)).map(t=>({user_id:String(t.user_id||""),bot_id:String(t.bot_id||""),skill_id:String(t.skill_id||""),package_name:String(t.package_name||""),enabled:Boolean(t.enabled),install_status:String(t.install_status||""),version:t.version?String(t.version):null,config_json:L(t.config_json),created_at:t.created_at?String(t.created_at):void 0,updated_at:t.updated_at?String(t.updated_at):void 0}))}catch(t){if("ENOENT"===t?.code)return[];throw t}}();t.length>0&&(U.applySnapshots(t),T("[skills] restored local snapshot",{count:t.length}),await et(t)),it()};O=new n({wsUrl:"wss://ws.weget.jp",taskEventApiUrl:String(s.loginApiUrl||"").trim().replace(/\/login\/?$/i,"/bot/runtime/task-event"),version:"0.2.0",capabilities:h,heartbeatSec:30,reconnectMs:3e3,reconnectMaxAttempts:10,wsPingIntervalSec:25,wsPongTimeoutSec:12},{onLog:(t,e)=>T(t,e),onStatus:t=>{D.emitBotStatus({status:t}),it()},onLineMessage:async t=>{const e=String(t.line_user_id||""),i=String(t.text||"").trim();if(B({type:"line_user",lineUserId:e,text:i}),!i)return{answer:""};try{const t=await V.runPrompt({prompt:i,contextLabel:"line_message"});return B({type:"line_assistant",lineUserId:e,text:t}),{answer:t}}catch(t){const i=t instanceof Error?t.message:String(t);T("[ai] line reply failed",{error:i});const a=`AI error: ${i}`;return B({type:"line_assistant",lineUserId:e,text:a}),{answer:a}}},onRunTask:async t=>{const e=String(t.task_id||"").trim(),i=String(t.prompt||"").trim(),a=L(t.metadata_json),r=L(t.prompt_bundle),s=L(t.runtime_config),n=String(a.source||r.source||"").trim(),o=String(a.channel||r.channel||"").trim(),l=String(t.skill_id||a.skill_id||r.skill_id||"").trim(),g=String(a.line_user_id||"").trim(),c=String(a.line_reply_token||"").trim(),d="line"===n||"line"===o||Boolean(g&&c),p="bot_host"===n,m=String(t.model||s.chat_model||"").trim(),u=String(s.system_prompt||r.system_prompt||"").trim();if(e){if(j.set(e,{cancelled:!1}),d&&g&&i&&B({type:"line_user",lineUserId:g,text:i}),O?.sendTaskEvent(e,"task_received",{prompt:i,conversation_id:String(t.conversation_id||""),continue_from_task_id:String(t.continue_from_task_id||""),ts:(new Date).toISOString()}),!i)return O?.sendTaskResult(e,"failed",{error:"prompt is required",data_json:{ts:(new Date).toISOString()}}),void j.delete(e);try{p&&B({type:"assistant_status",status:"Task received"}),l&&O?.sendSkillStatus(e,{skill_id:l,status:"running",summary:"task execution started",data_json:{ts:(new Date).toISOString()}}),O?.sendTaskEvent(e,"step_started",{step:"codex_chat",ts:(new Date).toISOString()});const s=await V.runPrompt({prompt:i,model:m||void 0,systemPrompt:u||void 0,contextLabel:`task:${e}`,promptBundle:r,metadata:a,onStatus:p?t=>B({type:"assistant_status",status:t}):void 0}),n=(t=>{const e=String(t||""),i=e.match(/```weget_result\s*([\s\S]*?)```/i);if(i?.[1])try{const t=JSON.parse(i[1].trim()),a=String(t.status||"").trim().toLowerCase(),r=t.pending_request&&"object"==typeof t.pending_request?t.pending_request:{};if("pending_request"!==a)return null;const s=String(r.type||"").trim().toLowerCase(),n=String(r.prompt||"").trim(),o=String(r.subtype||"").trim();return"input"!==s&&"approval"!==s||!n?null:{visibleText:H(e),requestType:s,prompt:n,subtype:o||void 0}}catch{return null}const a=e.match(/```weget_pending_request\s*([\s\S]*?)```/i);if(!a?.[1])return null;try{const t=JSON.parse(a[1].trim()),i=String(t.type||"").trim().toLowerCase(),r=String(t.prompt||"").trim(),s=String(t.subtype||"").trim();return"input"!==i&&"approval"!==i||!r?null:{visibleText:H(e),requestType:i,prompt:r,subtype:s||void 0}}catch{return null}})(s),o=n?.visibleText||H(s),S=j.get(e);if(S?.cancelled)return O?.sendTaskResult(e,"cancelled",{summary:"server_cancelled",data_json:{reason:"server_cancelled",ts:(new Date).toISOString()}}),void j.delete(e);if(O?.sendTaskEvent(e,"ai_output",{summary:o,ts:(new Date).toISOString()}),p&&B({type:"assistant",text:o}),d&&g&&c){B({type:"line_assistant",lineUserId:g,text:o});const i={bot_id:String(t.bot_id||A?.botId||""),line_user_id:g,line_reply_token:c,text:o};try{await G(i)}catch(t){T("[line] callback line reply failed",{error:t instanceof Error?t.message:String(t)})}O?.sendTaskEvent(e,"line_message_ai_output",{line_user_id:g,answer:o,ts:(new Date).toISOString()})}if(O?.sendTaskEvent(e,"step_finished",{step:"codex_chat",ts:(new Date).toISOString()}),n)return"approval"===n.requestType?O?.requestTaskApproval(e,{prompt:n.prompt,approval_type:n.subtype||"generic",data_json:{prompt:n.prompt,approval_type:n.subtype||"generic",ts:(new Date).toISOString()}}):O?.requestTaskInput(e,{prompt:n.prompt,input_type:n.subtype||"text",data_json:{prompt:n.prompt,input_type:n.subtype||"text",ts:(new Date).toISOString()}}),l&&O?.sendSkillStatus(e,{skill_id:l,status:"approval"===n.requestType?"waiting_approval":"waiting_input",summary:n.prompt.slice(0,200),data_json:{ts:(new Date).toISOString(),request_type:n.requestType}}),void j.delete(e);O?.sendTaskResult(e,"succeeded",{summary:o.slice(0,500),data_json:{ts:(new Date).toISOString()}}),l&&O?.sendSkillStatus(e,{skill_id:l,status:"succeeded",summary:o.slice(0,200),data_json:{ts:(new Date).toISOString()}})}catch(i){if(p){const t=`Error: ${i instanceof Error?i.message:String(i)}`;B({type:"assistant",text:t})}if(d&&g&&c){const e=`AI error: ${i instanceof Error?i.message:String(i)}`;B({type:"line_assistant",lineUserId:g,text:e});const a={bot_id:String(t.bot_id||A?.botId||""),line_user_id:g,line_reply_token:c,text:e};try{await G(a)}catch(t){T("[line] callback line reply failed",{error:t instanceof Error?t.message:String(t)})}}O?.sendTaskResult(e,"failed",{error:i instanceof Error?i.message:String(i),data_json:{ts:(new Date).toISOString()}}),l&&O?.sendSkillStatus(e,{skill_id:l,status:"failed",summary:i instanceof Error?i.message:String(i),data_json:{ts:(new Date).toISOString()}})}finally{j.delete(e)}}else T("[task] run_task missing task_id")},onTaskControl:async t=>{const e=String(t.task_id||"").trim(),i=String(t.action||"").trim();if(e&&i&&"cancel_task"===i){const i=j.get(e);if(i){i.cancelled=!0;const a=String(t.skill_id||"").trim();return a&&O?.sendSkillStatus(e,{skill_id:a,status:"cancelled",summary:"server_cancelled",data_json:{ts:(new Date).toISOString()}}),void T("[task] cancel requested",{task_id:e})}O?.sendTaskResult(e,"cancelled",{summary:"server_cancelled",data_json:{reason:"server_cancelled",ts:(new Date).toISOString()}})}},onServerConfigUpdate:async t=>{const e=Array.isArray(t.scopes)?t.scopes.map(t=>String(t||"").trim()):[],i=e.length>0?e:["runtime","skills"];i.includes("runtime")&&await at(),i.includes("skills")&&await rt()}}),o({ipcMain:w,env:{capabilities:h,loginApiUrl:s.loginApiUrl},signInWithLoginApi:N.signInWithLoginApi,saveLoginProfile:async({botId:t,email:i,password:a,remember:r})=>{if(r)await e.writeFile(v(),JSON.stringify({botId:t,email:i,password:a,remember:!0,updatedAt:(new Date).toISOString()},null,2),"utf8");else try{await e.unlink(v())}catch(t){if("ENOENT"!==t?.code)throw t}},readSavedLoginProfile:async()=>{try{const t=await e.readFile(v(),"utf8"),i=JSON.parse(t);return{botId:String(i?.botId||""),email:String(i?.email||""),password:String(i?.password||""),remember:Boolean(i?.remember)}}catch(t){if("ENOENT"===t?.code)return{botId:"",email:"",password:"",remember:!1};throw t}},getSkillConfig:t=>({config:gt(t).getConfig()}),saveSkillConfig:async(t,e)=>({config:await gt(t).saveConfig(e)}),getAiConfig:()=>({aiModel:String(M.aiModel||"gpt-5.4"),logOutputDir:String(M.logOutputDir||"")}),saveAiConfig:async t=>{const e=t&&"object"==typeof t?t:{},i=await Z({...M,...e}),a=$(),r=J(),s=a?await a.saveConfig({...a.getConfig(),...e}):null;return r&&await r.saveConfig({...r.getConfig(),...e}),{aiModel:String(i.aiModel||s?.aiModel||e.aiModel||"gpt-5.4"),logOutputDir:String(i.logOutputDir||"")}},setCurrentSession:t=>{A=t||null;const e=A?"connected":"disconnected";D.emitBotStatus({status:e})},getCurrentSession:()=>A,getActiveSkills:()=>U.getActiveSkills().map(t=>({name:t.name,displayName:t.displayName,version:t.version})),getCodexAuthStatus:()=>V.getAuthStatus(),getCodexMcpStatus:t=>V.getMcpServerStatus(t),getPlaywrightBrowserStatus:()=>V.getPlaywrightBrowserStatus(),startCodexLogin:()=>V.startLogin(),installPlaywrightMcp:()=>V.installWegetGatewayMcp(),getGatewayContextFilePath:()=>V.getGatewayContextFilePath(),runGatewaySelfTest:t=>V.runGatewaySelfTest(t),getManagedSkills:()=>U.getManagedSkills().map(t=>({...t,ui:q.getLoadedSkill(t.name)?.ui||void 0})),getMacroSnapshot:async({force:t}={})=>(nt(),W().getSnapshot({force:t})),getMacroCalendar:async({dateKey:t})=>(nt(),W().listCalendar({dateKey:t})),getMacroNews:async({dateKey:t})=>(nt(),W().listNews({dateKey:t})),emitLog:T,openGmoKlineWindow:async({symbol:t,interval:e,market:i})=>(()=>{const a="fx"===i?"fx":"coin";return st(a),("fx"===a?R().marketData:K().marketData).fetchKline({symbol:t,interval:e,market:a})})(),getGmoMarketQuotes:async({market:t,symbols:e})=>(()=>{const i="fx"===t?"fx":"coin";return st(i),("fx"===i?R().marketData:K().marketData).fetchQuotes({market:i,symbols:e})})(),getGmoSymbolRules:async({market:t})=>(()=>{const e="fx"===t?"fx":"coin";return st(e),("fx"===e?R().marketData:K().marketData).fetchSymbolRules({market:e})})(),getGmoBuyingPower:async({market:t})=>({market:t,availableJpy:await(st(t),("fx"===t?R().gateway:K().gateway).getBuyingPower(t))}),getGmoAccountMetrics:async({market:t})=>(st(t),("fx"===t?R().gateway:K().gateway).getAccountMetrics(t)),getGmoPositionSummary:async({market:t,symbol:e})=>({market:t,symbol:e,items:await(st(t),("fx"===t?R().gateway:K().gateway).getPositionSummary({market:t,symbol:e}))}),getGmoOpenPositions:async({market:t,symbol:e,page:i,prevId:a,count:r})=>({market:t,symbol:e||"",items:await(st(t),("fx"===t?R().gateway:K().gateway).getOpenPositions({market:"fx"===t?"fx":"crypto",symbol:e||void 0,page:i,prevId:a,count:r}))}),placeGmoFxOrder:async({symbol:t,side:e,size:i})=>{st("fx");return await Q(R(),"placeFxOrder")({symbol:t,side:e,size:i,executionType:"MARKET"})},placeGmoCoinOrder:async({symbol:t,side:e,size:i})=>{st("coin");return await Q(K(),"placeCoinOrder")({symbol:t,side:e,size:i,executionType:"MARKET"})},placeGmoFxCloseOrder:async({symbol:t,side:e,positionId:i,size:a})=>{st("fx");return await Q(R(),"placeFxCloseOrder")({symbol:t,side:e,positionId:i,size:a,executionType:"MARKET"})},placeGmoCoinCloseOrder:async({symbol:t,side:e,positionId:i,size:a})=>{st("coin");return await Q(K(),"placeCoinCloseOrder")({symbol:t,side:e,positionId:i,size:a,executionType:"MARKET"})},getGmoApiState:t=>{const e="fx"===t?$():J();return e?.status.getApiState()||"unknown"},testGmoApi:t=>(st(t),"fx"===t?R().status.testApi():K().status.testApi()),buildTradeStatusSnapshot:t=>(st(t),"fx"===t?R().status.buildSnapshot():K().status.buildSnapshot()),closeTradeWindows:()=>{},startWsClient:t=>{O?.start(t),at().catch(t=>{T("[config] runtime sync failed after login",{error:t instanceof Error?t.message:String(t)})}),rt().catch(t=>{T("[config] skill sync failed after login",{error:t instanceof Error?t.message:String(t)})}),it()},stopWsClient:()=>{$()?.stopExecutionStreams(),J()?.stopExecutionStreams(),z()?.stop?.(),O?.stop()},handleBotChatMessage:async({text:t})=>{const e=String(t||"").trim(),i=String(A?.botId||"").trim();if(!e)throw new Error("message is required");if(!i)throw new Error("bot session is not ready");B({type:"assistant_status",status:"Submitting task"});const a=await F.request({method:"POST",path:"/bot/tasks",body:{source:"bot_host",bot_id:i,prompt:e,title:e.slice(0,80),channel:"desktop",metadata_json:{source:"bot_host",channel:"desktop"}}}),r=L(a.dispatch_result);if(!1===r.delivered)throw new Error(`task queued but bot is offline (${String(r.status||"offline")})`);return{answer:"",taskId:String(L(a.task).task_id||"")}},writeErrorLog:async({source:t,message:e,details:i})=>{await(async({source:t,message:e,details:i})=>{await I({level:"error",source:t,message:e,details:i})})({source:t,message:e,details:i})},writeRuntimeLog:async({level:t,source:e,message:i,details:a})=>{await I({level:t,source:e,message:i,details:a})}});const dt=t.join(b,"renderer","logo.png");y.whenReady().then(async()=>{(()=>{if("darwin"!==process.platform)return;if(!i(dt))return;const t=k.createFromPath(dt);t.isEmpty()||y.dock.setIcon(t)})(),await(async()=>{try{const t=await e.readFile(x(),"utf8"),i=JSON.parse(t);M={aiModel:String(i?.aiModel||"gpt-5.4").trim()||"gpt-5.4",logOutputDir:String(i?.logOutputDir||"").trim()}}catch(t){if("ENOENT"!==t?.code)throw t;M={aiModel:"gpt-5.4",logOutputDir:""}}return M})();try{await ot.ensureStarted()}catch(t){T("[gateway-file-bridge] startup failed",{error:t instanceof Error?t.message:String(t)})}try{await ct()}catch(t){T("[skills] local initialization failed",{error:t instanceof Error?t.message:String(t)})}D.createMainWindow(),y.on("activate",()=>{0===f.getAllWindows().length&&D.createMainWindow()})}),y.on("window-all-closed",()=>{$()?.stopExecutionStreams(),J()?.stopExecutionStreams(),z()?.stop?.(),ot.stop().catch(()=>{}),O?.stop(),"darwin"!==process.platform&&y.quit()});
@@ -1 +1 @@
1
- import t from"node:fs/promises";import{existsSync as e}from"node:fs";import{createRequire as r}from"node:module";import s from"node:os";import n from"node:path";import{spawn as i,spawnSync as o}from"node:child_process";const a="gpt-5.4",c=r(import.meta.url);let d=null,l=null,u=null,g=null,m=null,p=null;const w=async t=>{if(!t)return"";const e=[];for await(const r of t)e.push(Buffer.isBuffer(r)?r:Buffer.from(String(r)));return Buffer.concat(e).toString("utf8")},f=t=>String(t||"").replace(/\u001b\[[0-9;?]*[ -/]*[@-~]/g,""),y=t=>{let e="";return{push:r=>{if(!t)return;e+=f(Buffer.isBuffer(r)?r.toString("utf8"):String(r));const s=e.split(/\r?\n/);e=s.pop()||"";for(const e of s){const r=String(e||"").trim();r&&t(r)}},flush:()=>{if(!t)return;const r=String(e||"").trim();r&&t(r),e=""}}},h=t=>{const e=f(String(t||"")).trim();return e?/^[{}[\],:]+$/.test(e)||/^["']?[a-zA-Z0-9_-]+["']?\s*:\s*$/.test(e)||/^`{3,}|^#{1,6}\s*$/.test(e)||/^Assistant:?\s*$/i.test(e)||/^Warning: no last agent message/i.test(e)?"":/^ERROR:\s*unexpected status\s+\d+/i.test(e)?"Tool call failed":e:""},x=(t,e)=>{const r=f(String(t||"")).replace(/\s+/g," ").trim();return r?r.length>180?`${r.slice(0,177)}...`:r:e},S=t=>t&&"object"==typeof t?t:{},_=t=>String(t||"").trim(),v=t=>{const e=S(t);if(0===Object.keys(e).length)return"";const r=S(e.waiting),s=[`- source task: ${_(e.task_id)||"-"}`,`- status: ${_(e.status)||"-"}`,`- title: ${_(e.title)||"-"}`,`- user prompt: ${_(e.user_prompt)||"-"}`,`- summary: ${_(e.summary)||"-"}`,`- latest output: ${_(e.latest_output)||"-"}`,`- last event: ${_(e.last_event_type)||"-"}`];return Object.keys(r).length>0&&(s.push(`- waiting type: ${_(r.type)||"-"}`),s.push(`- waiting subtype: ${_(r.subtype)||"-"}`),s.push(`- waiting prompt: ${_(r.prompt)||"-"}`)),s.join("\n")},C=e=>{const r=(new Date).toISOString(),s=`exec-${Date.now()}`;let i="",o="",a=!1,c=Promise.resolve();const d=[],l=async()=>{if(a)return o;const r=n.join(e,"codex-sessions");await t.mkdir(r,{recursive:!0});const c=String(i||s||"").trim().replace(/[^a-zA-Z0-9._-]+/g,"_");return o=n.join(r,`${c}.log`),a=!0,d.length>0&&(await t.appendFile(o,d.join(""),"utf8"),d.length=0),o},u=(e,r={})=>{(e=>{c=c.then(async()=>{if(!a&&!i)return void d.push(e);const r=await l();await t.appendFile(r,e,"utf8")}).catch(()=>{})})(`${JSON.stringify({ts:(new Date).toISOString(),event:e,...r},null,0)}\n`)};return{get startedAt(){return r},get sessionId(){return i},setSessionId:t=>{const e=String(t||"").trim();e&&i!==e&&(i=e,u("session_identified",{sessionId:e}))},write:u,flush:async()=>(a||await l(),await c,o)}},$=()=>{if(l)return l;const t=[n.join(String(process.env.ProgramFiles||"C:\\Program Files"),"nodejs","npx.cmd"),n.join(String(process.env["ProgramFiles(x86)"]||"C:\\Program Files (x86)"),"nodejs","npx.cmd"),n.join(String(process.env.APPDATA||""),"npm","npx.cmd")].filter(Boolean);for(const r of t)if(e(r))return l=r,r;const r=o("where.exe",["npx.cmd"],{windowsHide:!0,encoding:"utf8"}),s=String(r.stdout||"").split(/\r?\n/).map(t=>t.trim()).find(Boolean);return s?(l=s,s):"npx.cmd"},k=()=>{if(u)return u;const t=[n.join(String(process.env.ProgramFiles||"C:\\Program Files"),"nodejs","node.exe"),n.join(String(process.env["ProgramFiles(x86)"]||"C:\\Program Files (x86)"),"nodejs","node.exe")];for(const r of t)if(e(r))return u=r,r;return u="node",u},P=()=>{if(g)return g;try{const t=c.resolve("@ai.weget.jp/weget-gateway-mcp/dist/index.js");return g=t,t}catch{}const t=[n.join(String(process.env.APPDATA||""),"npm","node_modules","@ai.weget.jp","weget-gateway-mcp","dist","index.js"),n.join(String(process.env.ProgramFiles||"C:\\Program Files"),"nodejs","node_modules","@ai.weget.jp","weget-gateway-mcp","dist","index.js"),n.join(String(process.env["ProgramFiles(x86)"]||"C:\\Program Files (x86)"),"nodejs","node_modules","@ai.weget.jp","weget-gateway-mcp","dist","index.js")].filter(Boolean);for(const r of t)if(e(r))return g=r,r;return g=n.join(String(process.env.APPDATA||""),"npm","node_modules","@ai.weget.jp","weget-gateway-mcp","dist","index.js"),g},O=t=>{const e=n.join(t,"weget-gateway-context.json");return"win32"===process.platform?{command:k(),args:[P(),"--context-file",e]}:{command:"npx",args:["-y","@ai.weget.jp/weget-gateway-mcp@latest","--context-file",e]}},j=t=>String(t||"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),E=(t,e)=>{const r=String(t||""),s=O(e);if("win32"===process.platform){const t=new RegExp(`command:\\s+${j(s.command)}`,"i"),e=new RegExp(j(String(s.args[0]||"")),"i"),n=new RegExp(j(String(s.args[2]||"")),"i");return t.test(r)&&e.test(r)&&n.test(r)}return new RegExp(`command:\\s+${j(s.command)}`,"i").test(r)&&r.includes(String(s.args[0]||""))},A=async({args:t,stdinText:r,cwd:s,extraEnv:a,onStdoutLine:c,onStderrLine:l})=>new Promise((u,g)=>{const m=(()=>{if(d)return d;if("win32"===process.platform){const t=[String(process.env.ProgramFiles||"C:\\Program Files"),String(process.env["ProgramFiles(x86)"]||"C:\\Program Files (x86)")];for(const r of t){const t=n.join(r,"nodejs","node.exe"),s=n.join(r,"nodejs","node_modules","@openai","codex","bin","codex.js");if(e(t)&&e(s))return d={command:t,baseArgs:[s]},d}const r=["codex.cmd","codex"];for(const t of r){const e=o("where.exe",[t],{windowsHide:!0,encoding:"utf8"}),r=String(e.stdout||"").split(/\r?\n/).map(t=>t.trim()).find(Boolean);if(r)return d={command:r,baseArgs:[]},d}}return d={command:"codex",baseArgs:[]},d})(),p={...process.env,...a||{},NO_COLOR:"1",FORCE_COLOR:"0",CLICOLOR:"0"},f=i(m.command,[...m.baseArgs,...t],{cwd:s,stdio:["pipe","pipe","pipe"],windowsHide:!0,env:p});let h=!1;const x=t=>{h||(h=!0,t())},S=w(f.stdout),_=w(f.stderr),v=y(c),C=y(l);f.stdout?.on("data",t=>v.push(t)),f.stderr?.on("data",t=>C.push(t)),f.on("error",t=>{x(()=>g(t))}),f.on("close",async t=>{v.flush(),C.flush();const[e,r]=await Promise.all([S,_]);x(()=>u({stdout:e,stderr:r,exitCode:Number.isFinite(t)?Number(t):1}))}),"string"==typeof r&&f.stdin.write(r),f.stdin.end()}),b=async({command:t,args:e,cwd:r})=>new Promise((s,n)=>{const o=i(t,e,{cwd:r,stdio:["pipe","pipe","pipe"],windowsHide:!0,env:{...process.env,NO_COLOR:"1",FORCE_COLOR:"0",CLICOLOR:"0"}});let a=!1;const c=t=>{a||(a=!0,t())},d=w(o.stdout),l=w(o.stderr);o.on("error",t=>c(()=>n(t))),o.on("close",async t=>{const[e,r]=await Promise.all([d,l]);c(()=>s({stdout:e,stderr:r,exitCode:Number.isFinite(t)?Number(t):1}))})}),F=async t=>null!==m?m:(p||(p=(async(t,e)=>{const r=String(t||"").trim();if(!r)return!1;try{const t=await A({cwd:e,args:["features","list"]});return 0===t.exitCode&&f(`${t.stdout||""}\n${t.stderr||""}`).split(/\r?\n/).map(t=>t.trim()).some(t=>t.startsWith(`${r} `)||t===r)}catch{return!1}})("rmcp_client",t).then(t=>(m=t,t)).finally(()=>{p=null})),p),I=async({cwd:t,model:e,outputPath:r})=>{const s=["exec"];return await F(t)&&s.push("--enable","rmcp_client"),s.push("--dangerously-bypass-approvals-and-sandbox","-C",t,"--skip-git-repo-check","-m",e,"-o",r,"-"),s};export const createCodexService=({getModel:e,getWorkingDir:r,getLogDir:o,emitLog:c,getGatewayContext:d})=>{const l=()=>n.join(o(),"codex-session-bindings.json"),u=async()=>{try{const e=await t.readFile(l(),"utf8"),r=JSON.parse(e);return Object.fromEntries(Object.entries(r||{}).map(([t,e])=>[String(t||"").trim(),String(e||"").trim()]).filter(([t,e])=>t&&e))}catch{return{}}},g=async e=>{await t.mkdir(o(),{recursive:!0}),await t.writeFile(l(),`${JSON.stringify(e,null,2)}\n`,"utf8")},m=()=>{const t=d?.()||{},e={WEGET_ACTIVE_SKILLS:JSON.stringify(Array.isArray(t.activeSkills)?t.activeSkills:[]),WEGET_HOST_METADATA:JSON.stringify(t.hostMetadata&&"object"==typeof t.hostMetadata?t.hostMetadata:{})},r=String(t.botId||"").trim(),s=String(t.platformApiBaseUrl||"").trim(),n=String(t.accessToken||"").trim(),i=String(t.fileBridgeDir||"").trim(),o=String(t.fileBridgeToken||"").trim();return r&&(e.WEGET_BOT_ID=r),s&&(e.WEGET_PLATFORM_API_BASE_URL=s),n&&(e.WEGET_PLATFORM_API_ACCESS_TOKEN=n),i&&(e.WEGET_FILE_BRIDGE_DIR=i),o&&(e.WEGET_FILE_BRIDGE_TOKEN=o),e},p=()=>n.join(r(),"weget-gateway-context.json"),w=async()=>{const e=d?.()||{};await t.mkdir(r(),{recursive:!0}),await t.writeFile(p(),JSON.stringify({activeSkills:Array.isArray(e.activeSkills)?e.activeSkills:[],hostMetadata:e.hostMetadata&&"object"==typeof e.hostMetadata?e.hostMetadata:{},botId:String(e.botId||"").trim(),platformApiBaseUrl:String(e.platformApiBaseUrl||"").trim(),accessToken:String(e.accessToken||"").trim(),fileBridgeDir:String(e.fileBridgeDir||"").trim(),fileBridgeToken:String(e.fileBridgeToken||"").trim(),logDir:o(),updatedAt:(new Date).toISOString()},null,2),"utf8")},f=async({target:e,payload:r})=>{const s=n.join(o(),"gateway-tests");await t.mkdir(s,{recursive:!0});const i=n.join(s,`${e}-${Date.now()}.log`);return await t.writeFile(i,`${JSON.stringify(r,null,2)}\n`,"utf8"),i},y=async({userPrompt:t,systemPrompt:r,contextLabel:s,promptBundle:n,metadata:i})=>{const o=d?.()||{},c=Array.isArray(o.activeSkills)?o.activeSkills:[],l=o.hostMetadata&&"object"==typeof o.hostMetadata?o.hostMetadata:{},[u,g]=await Promise.all([k("weget-gateway"),P()]),m=c.length?c.map(t=>{const e=Array.isArray(t.tools)&&t.tools.length?` tools=${t.tools.join(", ")}`:"",r=String(t.version||"").trim()?` v${String(t.version||"").trim()}`:"";return`- ${String(t.name||"").trim()}${r}${e}`}):["- none"],p=[`- weget-gateway MCP: ${u.status}`,`- browser runtime: ${g.status}`,`- context: ${String(s||"").trim()||"general"}`,`- default model: ${String(l.aiModel||e()||a).trim()||a}`],w=(t=>{const e=String(t||"").trim().toLowerCase();return!!e&&[/macro/,/economic/,/economy/,/calendar/,/news/,/usd\s*\/\s*jpy/,/usd_jpy/,/risk sentiment/,/economic situation/,/macro snapshot/,/经济/,/宏观/,/日历/,/新闻/,/形势/,/経済/,/マクロ/,/ニュース/,/カレンダー/,/相場/].some(t=>t.test(e))})(t)?["","Macro tool routing hint:","- This request matches macro intent.","- Before answering, use the WeGet macro tools to fetch snapshot, calendar, and news if available.","- Prefer gateway tool calls such as weget_macro_get_snapshot, weget_macro_list_calendar, and weget_macro_list_news.","- Base the summary on fetched tool results rather than unsupported memory."]:[],f=String(r||"").trim(),y=S(n),h=S(i),x=v(y.latest_continuation_state),C=(t=>{const e=Array.isArray(t)?t:[];return e.length?e.slice(-6).map((t,e)=>{const r=S(t),s=v(r.continuation_state);return[`History ${e+1}:`,`- task_id: ${_(r.task_id)||"-"}`,`- title: ${_(r.title)||"-"}`,`- status: ${_(r.status)||"-"}`,`- prompt: ${_(r.prompt)||"-"}`,`- summary: ${_(r.summary)||"-"}`,...s?["- continuation state:",...s.split("\n").map(t=>` ${t}`)]:[]].join("\n")}).join("\n\n"):""})(y.conversation_context);return["You are running inside WeGet Bot Host.","","Active skills:",...m,"","Runtime status:",...p,"","Tool policy:","- Prefer direct reasoning for simple text-only requests.","- When the user asks about macro conditions, economic situation, calendar, or news, prefer the WeGet macro tools before summarizing.","- Use WeGet browser tools only for website access, page extraction, navigation, or screenshots.","- If browser runtime or gateway MCP is unavailable, state that limitation explicitly instead of pretending the task was executed.","- For trading or any action with side effects, do not claim execution unless a concrete tool call actually performed it.","- After the user-visible answer, always append a fenced control block using ```weget_result with compact JSON.",'- The JSON must be {"status":"completed"} for a finished task.','- If you must pause and wait for a user reply before continuing, output {"status":"pending_request","pending_request":{"type":"input","prompt":"...","subtype":"text"}}.','- For approvals, use {"status":"pending_request","pending_request":{"type":"approval","prompt":"...","subtype":"generic"}}.',"- Only use status=pending_request when the task truly cannot continue without the user.","- Keep the final answer plain text only.",...w,...f?["","System prompt:",f]:[],"","Task context:",...[`- conversation id: ${_(y.conversation_id)||"-"}`,`- continue from task id: ${_(y.continue_from_task_id)||"-"}`,`- source: ${_(y.source)||_(h.source)||"-"}`,`- channel: ${_(y.channel)||_(h.channel)||"-"}`],...x?["","Latest continuation state:",x]:[],...C?["","Recent conversation context:",C]:[],..._(h.pending_request_id)||_(h.pending_request_type)?["","Pending request context:",`- request id: ${_(h.pending_request_id)||"-"}`,`- request type: ${_(h.pending_request_type)||"-"}`,`- response via: ${_(h.pending_response_via)||"-"}`,`- response text: ${_(h.pending_response_text)||"-"}`]:[],"","User request:",String(t||"").trim(),"","Respond as plain text only."].join("\n")},k=async t=>{const e=String(t||"").trim();if(!e)return{status:"unknown",detail:"MCP server name is required"};try{"weget-gateway"===e&&await w().catch(()=>{});const t=await A({cwd:r(),args:["mcp","get",e],extraEnv:m()}),s=String(t.stdout||t.stderr||"").trim();return 0!==t.exitCode?/No MCP server named/i.test(s)?{status:"missing",detail:s}:{status:"unknown",detail:s||"codex mcp list failed"}:"playwright"!==e||(t=>{const e=String(t||"");return"win32"===process.platform?/command:\s+.*node(?:\.exe)?/i.test(e)&&/@playwright[\\\/]mcp[\\\/]cli\.js/i.test(e)&&/args:\s+.*--headless/i.test(e):/command:\s+npx/i.test(e)&&/@playwright\/mcp@latest/i.test(e)&&/args:\s+.*--headless/i.test(e)})(s)?"weget-gateway"!==e||E(s,r())?{status:"configured",detail:s||`${e} is configured`}:{status:"missing",detail:"WeGet Gateway MCP exists but points to an outdated launch path. Reinstall it from the host UI."}:{status:"missing",detail:"Playwright MCP exists but uses an unsupported Windows wrapper. Click Install Playwright MCP to repair it."}}catch(t){return{status:"unknown",detail:t instanceof Error?t.message:String(t)}}},P=async()=>{try{const t="win32"===process.platform?"powershell.exe":"npx",e="win32"===process.platform?["-NoProfile","-Command",`& '${$().replace(/'/g,"''")}' playwright install --list`]:["playwright","install","--list"],s=await b({command:t,args:e,cwd:r()}),n=String(s.stdout||s.stderr||"").trim();return 0!==s.exitCode?{status:"unknown",detail:n||"playwright install --list failed"}:/chromium-\d+/i.test(n)||/\\ms-playwright\\chromium-/i.test(n)?{status:"installed",detail:n}:{status:"missing",detail:n||"Chromium is not installed for Playwright."}}catch(t){return{status:"unknown",detail:t instanceof Error?t.message:String(t)}}};return{runPrompt:async({prompt:i,model:d,systemPrompt:l,contextLabel:f,promptBundle:x,metadata:_,onStatus:v})=>{const $=String(d||e()||a).trim()||a,k=r(),P=String(S(x).conversation_id||"").trim();await w().catch(()=>{});const O=C(o()),j=await t.mkdtemp(n.join(s.tmpdir(),"weget-codex-")),E=n.join(j,"last-message.txt"),b=await y({userPrompt:String(i||"").trim(),systemPrompt:String(l||"").trim(),contextLabel:f,promptBundle:x,metadata:_});O.write("exec_start",{model:$,cwd:k,context:String(f||"").trim(),prompt:String(i||"").trim(),instruction:b,outputPath:E,tempDir:j,gatewayContextFile:p(),traceStartedAt:O.startedAt}),v?.("Preparing request"),c("[codex] exec start",{model:$,cwd:k,context:String(f||"").trim(),conversationId:P||void 0});try{const e=async(t,e)=>A({cwd:k,extraEnv:m(),args:t,stdinText:e,onStdoutLine:t=>{O.write("stdout_line",{line:t});const e=h(t);if(e)return/^re-connecting/i.test(e)||/checking tools|tool use|using tool|calling tool/i.test(e)?(O.write("status",{source:"stdout",status:e}),void v?.(e)):void(/reading data|fetching|loading|snapshot|calendar|news/i.test(e)&&(O.write("status",{source:"stdout",status:e}),v?.(e)))},onStderrLine:t=>{O.write("stderr_line",{line:t});const e=String(t||"").match(/session id:\s*([a-zA-Z0-9-]+)/i);e?.[1]&&O.setSessionId(e[1]);const r=h(t);if(r&&!/^--------$/.test(r)&&!/^user$/i.test(r))return/^OpenAI Codex/i.test(r)?(O.write("status",{source:"stderr",status:"Starting Codex"}),void v?.("Starting Codex")):void(/workdir:|model:|provider:|approval:|sandbox:|reasoning effort:|reasoning summaries:|session id:/i.test(r)||(O.write("status",{source:"stderr",status:r}),v?.(r)))}}),r=P?await(async t=>{const e=String(t||"").trim();if(!e)return"";const r=await u();return String(r[e]||"").trim()})(P):"";let s=!1,n=null;if(r&&(s=!0,O.write("resume_attempt",{conversationId:P,sessionId:r}),v?.("Resuming previous Codex session"),n=await e(["exec","resume",r,"-"],b),0!==n.exitCode&&(O.write("resume_failed",{conversationId:P,sessionId:r,stdout:n.stdout,stderr:n.stderr}),await(async t=>{const e=String(t||"").trim();if(!e)return;const r=await u();r[e]&&(delete r[e],await g(r))})(P).catch(()=>{}),s=!1)),!s){const t=await I({cwd:k,model:$,outputPath:E});n=await e(t,b)}if(!n)throw new Error("codex execution result is missing");O.write("status",{source:"host",status:"Finalizing reply"}),v?.("Finalizing reply");const i=await t.readFile(E,"utf8").catch(()=>"");if(0!==n.exitCode)throw O.write("exec_error",{exitCode:n.exitCode,stdout:n.stdout,stderr:n.stderr,lastMessage:i}),new Error((n.stderr||n.stdout||`codex exec failed with code ${n.exitCode}`).trim());const o=String(i||n.stdout||"").trim();if(!o)throw O.write("exec_error",{exitCode:n.exitCode,stdout:n.stdout,stderr:n.stderr,lastMessage:i,error:"codex returned empty output"}),new Error("codex returned empty output");return O.write("exec_completed",{exitCode:n.exitCode,stdout:n.stdout,stderr:n.stderr,lastMessage:i,finalAnswer:o}),c("[codex] exec completed",{model:$,context:String(f||"").trim(),resumed:s,conversationId:P||void 0}),P&&O.sessionId&&await(async({conversationId:t,sessionId:e})=>{const r=String(t||"").trim(),s=String(e||"").trim();if(!r||!s)return;const n=await u();n[r]=s,await g(n)})({conversationId:P,sessionId:O.sessionId}).catch(()=>{}),o}catch(t){throw O.write("exec_exception",{error:t instanceof Error?t.message:String(t)}),t}finally{const e=await O.flush().catch(()=>"");e&&c("[codex] session trace written",{context:String(f||"").trim(),tracePath:e}),await t.rm(j,{recursive:!0,force:!0}).catch(()=>{})}},getAuthStatus:async()=>{try{const t=await A({cwd:r(),args:["login","status"]}),e=String(t.stdout||t.stderr||"").trim();return 0!==t.exitCode?{status:"unknown",detail:e||"codex login status failed"}:/logged in/i.test(e)?{status:"logged_in",detail:e}:/not logged in|logged out/i.test(e)?{status:"logged_out",detail:e}:{status:"unknown",detail:e||"unknown codex auth state"}}catch(t){return{status:"unknown",detail:t instanceof Error?t.message:String(t)}}},startLogin:async()=>{const e=r();try{if("win32"===process.platform){const r=String(e||"").replace(/'/g,"''"),o=n.join(s.tmpdir(),`weget-codex-login-${Date.now()}.ps1`),a=["$OutputEncoding = [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)","chcp 65001 > $null",'$env:NO_COLOR = "1"','$env:FORCE_COLOR = "0"','$env:CLICOLOR = "0"','$env:LANG = "en_US.UTF-8"','$env:LC_ALL = "en_US.UTF-8"',`Set-Location -LiteralPath '${r}'`,"$stripAnsi = {"," param([string]$line)",' if ($null -eq $line) { return "" }',' return ($line -replace "`e\\[[0-9;?]*[ -/]*[@-~]", "")',"}","codex login --device-auth 2>&1 | ForEach-Object { & $stripAnsi ([string]$_) }"].join(`${s.EOL}`);await t.writeFile(o,a,"utf8");const c=["$script = @()",'$script += "-NoExit"','$script += "-ExecutionPolicy"','$script += "Bypass"','$script += "-File"',`$script += '${o.replace(/'/g,"''")}'`,`Start-Process -FilePath 'powershell.exe' -WorkingDirectory '${r}' -ArgumentList $script`].join("; ");return i("powershell.exe",["-NoProfile","-ExecutionPolicy","Bypass","-Command",c],{cwd:e,stdio:"ignore",windowsHide:!0}).unref(),{ok:!0,detail:"Started `codex login --device-auth` in a new PowerShell window with UTF-8 output."}}if("darwin"===process.platform){const t=`cd ${JSON.stringify(e)} && codex login --device-auth`;return i("open",["-a","Terminal",t],{cwd:e,detached:!0,stdio:"ignore"}).unref(),{ok:!0,detail:"Started `codex login --device-auth` in Terminal."}}const r=`cd ${JSON.stringify(e)} && codex login --device-auth; exec $SHELL`,o=[["x-terminal-emulator",["-e","bash","-lc",r]],["gnome-terminal",["--","bash","-lc",r]],["konsole",["-e","bash","-lc",r]]];for(const[t,r]of o)try{return i(t,r,{cwd:e,detached:!0,stdio:"ignore"}).unref(),{ok:!0,detail:`Started \`codex login --device-auth\` using ${t}.`}}catch{}return{ok:!1,detail:"No supported terminal launcher was found. Run `codex login --device-auth` manually."}}catch(t){const e=t instanceof Error?t.message:String(t);return c("[codex] login launch failed",{error:e}),{ok:!1,detail:e}}},getMcpServerStatus:k,installWegetGatewayMcp:async()=>{try{await w();const t=await k("weget-gateway");if("configured"===t.status&&E(t.detail,r()))return{ok:!0,detail:t.detail||"WeGet Gateway MCP is already configured."};const e=await A({cwd:r(),args:["mcp","remove","weget-gateway"],extraEnv:m()});if(0!==e.exitCode){const t=String(e.stdout||e.stderr||"").trim().toLowerCase();if(!(t.includes("no mcp server named")||t.includes("not found")||t.includes("no server named")))return{ok:!1,detail:String(e.stdout||e.stderr||"").trim()||"Failed to remove existing WeGet Gateway MCP entry."}}const s=O(r()),n=await A({cwd:r(),args:["mcp","add","weget-gateway",s.command,...s.args],extraEnv:m()}),i=String(n.stdout||n.stderr||"").trim();if(0!==n.exitCode)return{ok:!1,detail:i||"Failed to add WeGet Gateway MCP to Codex."};const o=await k("weget-gateway");return"configured"===o.status?{ok:!0,detail:o.detail||"WeGet Gateway MCP configured."}:{ok:!0,detail:i||"WeGet Gateway MCP add command completed, but verification returned no explicit entry."}}catch(t){const e=t instanceof Error?t.message:String(t);return c("[codex] weget gateway mcp install failed",{error:e}),{ok:!1,detail:e}}},getPlaywrightBrowserStatus:P,getGatewayContextFilePath:p,runGatewaySelfTest:async e=>{if("codex_macro"===e){const i=(new Date).toISOString().slice(0,10);await w().catch(()=>{});const c=C(o()),d=await t.mkdtemp(n.join(s.tmpdir(),"weget-codex-test-")),l=n.join(d,"last-message.txt"),u=["You are running a WeGet gateway chain self-test.","Use WeGet gateway MCP tools only.",`Call weget_macro_get_snapshot, weget_macro_list_calendar with dateKey=${i}, and weget_macro_list_news with dateKey=${i}.`,"If all three tool calls succeed, reply with exactly: OK macro chain","If any tool call fails, reply with exactly: NG macro chain: <short reason>","Respond as plain text only."].join("\n");c.write("exec_start",{model:a,cwd:r(),context:"gateway_self_test:codex_macro",prompt:"codex macro chain self-test",instruction:u,outputPath:l,tempDir:d,gatewayContextFile:p(),traceStartedAt:c.startedAt});try{const s=await I({cwd:r(),model:a,outputPath:l}),n=await A({cwd:r(),extraEnv:m(),args:s,stdinText:u,onStdoutLine:t=>{c.write("stdout_line",{line:t})},onStderrLine:t=>{c.write("stderr_line",{line:t});const e=String(t||"").match(/session id:\s*([a-zA-Z0-9-]+)/i);e?.[1]&&c.setSessionId(e[1])}}),o=await t.readFile(l,"utf8").catch(()=>""),g=String(o||n.stdout||"").trim(),w=String(n.stderr||""),y=String(n.stdout||""),h=/tool weget-gateway\.weget_macro_get_snapshot\(\{\}\)/i.test(w),S=new RegExp(`tool weget-gateway\\.weget_macro_list_calendar\\(\\{"dateKey":"${j(i)}"\\}\\)`,"i").test(w),_=new RegExp(`tool weget-gateway\\.weget_macro_list_news\\(\\{"dateKey":"${j(i)}"\\}\\)`,"i").test(w),v=/weget-gateway\.weget_macro_get_snapshot\(\{\}\) success/i.test(w),C=/weget-gateway\.weget_macro_list_calendar\(\{\"dateKey\":\"\d{4}-\d{2}-\d{2}\"\}\) success/i.test(w),$=/weget-gateway\.weget_macro_list_news\(\{\"dateKey\":\"\d{4}-\d{2}-\d{2}\"\}\) success/i.test(w),k=0===n.exitCode&&/^OK macro chain$/i.test(g)&&h&&S&&_&&v&&C&&$;c.write(k?"exec_completed":"exec_error",{exitCode:n.exitCode,stdout:y,stderr:w,lastMessage:o,finalAnswer:g,invokedSnapshot:h,invokedCalendar:S,invokedNews:_,succeededSnapshot:v,succeededCalendar:C,succeededNews:$});const P=await c.flush().catch(()=>""),O={target:e,ok:k,summary:k?"Codex gateway macro chain OK":"Codex gateway macro chain failed",contextFilePath:p(),tracePath:P,codex:{exitCode:n.exitCode,stdout:y,stderr:w,finalAnswer:g},assertions:{invokedSnapshot:h,invokedCalendar:S,invokedNews:_,succeededSnapshot:v,succeededCalendar:C,succeededNews:$},ts:(new Date).toISOString()},E=await f({target:e,payload:O});return await t.rm(d,{recursive:!0,force:!0}).catch(()=>{}),{ok:k,summary:k?"Codex gateway macro chain OK":x(g||w,"Codex gateway macro chain failed"),detail:g||w||y,logPath:E,result:O}}catch(r){c.write("exec_exception",{error:r instanceof Error?r.message:String(r)});const s=await c.flush().catch(()=>""),n=r instanceof Error?r.message:String(r),i=await f({target:e,payload:{target:e,ok:!1,summary:"Codex gateway macro chain failed",contextFilePath:p(),tracePath:s,error:n,ts:(new Date).toISOString()}});return await t.rm(d,{recursive:!0,force:!0}).catch(()=>{}),{ok:!1,summary:x(n,"Codex gateway macro chain failed"),detail:n,logPath:i}}}await w();const c=O(r());let d,l=null;try{d=await b({command:c.command,args:[...c.args,"--self-test","--test-target",e],cwd:r()}),"gateway"===e&&(l=await(async({command:t,args:e,cwd:r,timeoutMs:s=2500})=>new Promise((n,o)=>{const a=i(t,e,{cwd:r,stdio:["ignore","pipe","pipe"],windowsHide:!0,env:{...process.env,NO_COLOR:"1",FORCE_COLOR:"0",CLICOLOR:"0"}}),c=[],d=[];let l=!1;const u=t=>{l||(l=!0,n(t))};a.stdout.on("data",t=>c.push(Buffer.from(t))),a.stderr.on("data",t=>d.push(Buffer.from(t))),a.on("error",t=>{l||(l=!0,o(t))}),a.on("close",t=>{u({ok:!1,exitCode:Number.isFinite(t)?Number(t):1,stdout:Buffer.concat(c).toString("utf8"),stderr:Buffer.concat(d).toString("utf8"),responseText:""})}),setTimeout(()=>{const t=a.stdin;t?.write(`${JSON.stringify({jsonrpc:"2.0",id:1,method:"initialize",params:{protocolVersion:"2024-11-05",capabilities:{},clientInfo:{name:"weget-gateway-probe",version:"0.1.0"}}})}\n`)},150),setTimeout(()=>{if(l)return;const t=Buffer.concat(c).toString("utf8"),e=Buffer.concat(d).toString("utf8"),r=t.trim(),s=/"result"\s*:/.test(r)&&/"protocolVersion"\s*:/.test(r);a.kill(),u({ok:s,exitCode:null,stdout:t,stderr:e,responseText:r})},Math.max(250,s))}))({command:c.command,args:c.args,cwd:r()}))}catch(t){const r=t instanceof Error?t.message:String(t),s=await f({target:e,payload:{target:e,launch:c,contextFilePath:p(),failure:"spawn_exception",error:r,ts:(new Date).toISOString()}});return{ok:!1,summary:x(r,`${e} test failed`),detail:r,logPath:s}}const u=String(d.stdout||d.stderr||"").trim();let g;if(u)try{g=JSON.parse(u)}catch{}let y=0===d.exitCode&&Boolean(!g||!1!==g.ok),h=x(u,`${e} self-test completed`);"gateway"===e&&l&&!l.ok?(y=!1,h=x(l.stderr||l.stdout,"Gateway handshake probe failed.")):"gateway"===e&&l?.ok&&(h="Gateway MCP handshake OK");const S={target:e,ok:y,summary:h,launch:c,contextFilePath:p(),selfTest:{exitCode:d.exitCode,stdout:d.stdout,stderr:d.stderr,result:g??null},handshakeProbe:l?{ok:l.ok,exitCode:l.exitCode,stdout:l.stdout,stderr:l.stderr,responseText:l.responseText}:null,ts:(new Date).toISOString()};return{ok:y,summary:h,detail:u||h,logPath:await f({target:e,payload:S}),result:g}}}};
1
+ import t from"node:fs/promises";import{existsSync as e}from"node:fs";import{createRequire as r}from"node:module";import s from"node:os";import n from"node:path";import{spawn as i,spawnSync as o}from"node:child_process";const a="gpt-5.4",c=r(import.meta.url);let d=null,l=null,u=null,g=null,m=null,p=null;const w=async t=>{if(!t)return"";const e=[];for await(const r of t)e.push(Buffer.isBuffer(r)?r:Buffer.from(String(r)));return Buffer.concat(e).toString("utf8")},f=t=>String(t||"").replace(/\u001b\[[0-9;?]*[ -/]*[@-~]/g,""),y=t=>{let e="";return{push:r=>{if(!t)return;e+=f(Buffer.isBuffer(r)?r.toString("utf8"):String(r));const s=e.split(/\r?\n/);e=s.pop()||"";for(const e of s){const r=String(e||"").trim();r&&t(r)}},flush:()=>{if(!t)return;const r=String(e||"").trim();r&&t(r),e=""}}},h=t=>{const e=f(String(t||"")).trim();return e?/^[{}[\],:]+$/.test(e)||/^["']?[a-zA-Z0-9_-]+["']?\s*:\s*$/.test(e)||/^`{3,}|^#{1,6}\s*$/.test(e)||/^Assistant:?\s*$/i.test(e)||/^Warning: no last agent message/i.test(e)?"":/^ERROR:\s*unexpected status\s+\d+/i.test(e)?"Tool call failed":e:""},x=(t,e)=>{const r=f(String(t||"")).replace(/\s+/g," ").trim();return r?r.length>180?`${r.slice(0,177)}...`:r:e},S=t=>t&&"object"==typeof t?t:{},_=t=>String(t||"").trim(),v=t=>{const e=S(t);if(0===Object.keys(e).length)return"";const r=S(e.waiting),s=[`- source task: ${_(e.task_id)||"-"}`,`- status: ${_(e.status)||"-"}`,`- title: ${_(e.title)||"-"}`,`- user prompt: ${_(e.user_prompt)||"-"}`,`- summary: ${_(e.summary)||"-"}`,`- latest output: ${_(e.latest_output)||"-"}`,`- last event: ${_(e.last_event_type)||"-"}`];return Object.keys(r).length>0&&(s.push(`- waiting type: ${_(r.type)||"-"}`),s.push(`- waiting subtype: ${_(r.subtype)||"-"}`),s.push(`- waiting prompt: ${_(r.prompt)||"-"}`)),s.join("\n")},C=e=>{const r=(new Date).toISOString(),s=`exec-${Date.now()}`;let i="",o="",a=!1,c=Promise.resolve();const d=[],l=async()=>{if(a)return o;const r=n.join(e,"codex-sessions");await t.mkdir(r,{recursive:!0});const c=String(i||s||"").trim().replace(/[^a-zA-Z0-9._-]+/g,"_");return o=n.join(r,`${c}.log`),a=!0,d.length>0&&(await t.appendFile(o,d.join(""),"utf8"),d.length=0),o},u=(e,r={})=>{(e=>{c=c.then(async()=>{if(!a&&!i)return void d.push(e);const r=await l();await t.appendFile(r,e,"utf8")}).catch(()=>{})})(`${JSON.stringify({ts:(new Date).toISOString(),event:e,...r},null,0)}\n`)};return{get startedAt(){return r},get sessionId(){return i},setSessionId:t=>{const e=String(t||"").trim();e&&i!==e&&(i=e,u("session_identified",{sessionId:e}))},write:u,flush:async()=>(a||await l(),await c,o)}},$=()=>{if(l)return l;const t=[n.join(String(process.env.ProgramFiles||"C:\\Program Files"),"nodejs","npx.cmd"),n.join(String(process.env["ProgramFiles(x86)"]||"C:\\Program Files (x86)"),"nodejs","npx.cmd"),n.join(String(process.env.APPDATA||""),"npm","npx.cmd")].filter(Boolean);for(const r of t)if(e(r))return l=r,r;const r=o("where.exe",["npx.cmd"],{windowsHide:!0,encoding:"utf8"}),s=String(r.stdout||"").split(/\r?\n/).map(t=>t.trim()).find(Boolean);return s?(l=s,s):"npx.cmd"},k=()=>{if(u)return u;const t=[n.join(String(process.env.ProgramFiles||"C:\\Program Files"),"nodejs","node.exe"),n.join(String(process.env["ProgramFiles(x86)"]||"C:\\Program Files (x86)"),"nodejs","node.exe")];for(const r of t)if(e(r))return u=r,r;return u="node",u},P=()=>{if(g)return g;try{const t=c.resolve("@ai.weget.jp/weget-gateway-mcp/dist/index.js");return g=t,t}catch{}const t=[n.join(String(process.env.APPDATA||""),"npm","node_modules","@ai.weget.jp","weget-gateway-mcp","dist","index.js"),n.join(String(process.env.ProgramFiles||"C:\\Program Files"),"nodejs","node_modules","@ai.weget.jp","weget-gateway-mcp","dist","index.js"),n.join(String(process.env["ProgramFiles(x86)"]||"C:\\Program Files (x86)"),"nodejs","node_modules","@ai.weget.jp","weget-gateway-mcp","dist","index.js")].filter(Boolean);for(const r of t)if(e(r))return g=r,r;return g=n.join(String(process.env.APPDATA||""),"npm","node_modules","@ai.weget.jp","weget-gateway-mcp","dist","index.js"),g},O=t=>{const e=n.join(t,"weget-gateway-context.json");return"win32"===process.platform?{command:k(),args:[P(),"--context-file",e]}:{command:"npx",args:["-y","@ai.weget.jp/weget-gateway-mcp@latest","--context-file",e]}},j=t=>String(t||"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),E=(t,e)=>{const r=String(t||""),s=O(e);if("win32"===process.platform){const t=new RegExp(`command:\\s+${j(s.command)}`,"i"),e=new RegExp(j(String(s.args[0]||"")),"i"),n=new RegExp(j(String(s.args[2]||"")),"i");return t.test(r)&&e.test(r)&&n.test(r)}return new RegExp(`command:\\s+${j(s.command)}`,"i").test(r)&&r.includes(String(s.args[0]||""))},b=async({args:t,stdinText:r,cwd:s,extraEnv:a,onStdoutLine:c,onStderrLine:l})=>new Promise((u,g)=>{const m=(()=>{if(d)return d;if("win32"===process.platform){const t=[String(process.env.ProgramFiles||"C:\\Program Files"),String(process.env["ProgramFiles(x86)"]||"C:\\Program Files (x86)")];for(const r of t){const t=n.join(r,"nodejs","node.exe"),s=n.join(r,"nodejs","node_modules","@openai","codex","bin","codex.js");if(e(t)&&e(s))return d={command:t,baseArgs:[s]},d}const r=["codex.cmd","codex"];for(const t of r){const e=o("where.exe",[t],{windowsHide:!0,encoding:"utf8"}),r=String(e.stdout||"").split(/\r?\n/).map(t=>t.trim()).find(Boolean);if(r)return d={command:r,baseArgs:[]},d}}return d={command:"codex",baseArgs:[]},d})(),p={...process.env,...a||{},NO_COLOR:"1",FORCE_COLOR:"0",CLICOLOR:"0"},f=i(m.command,[...m.baseArgs,...t],{cwd:s,stdio:["pipe","pipe","pipe"],windowsHide:!0,env:p});let h=!1;const x=t=>{h||(h=!0,t())},S=w(f.stdout),_=w(f.stderr),v=y(c),C=y(l);f.stdout?.on("data",t=>v.push(t)),f.stderr?.on("data",t=>C.push(t)),f.on("error",t=>{x(()=>g(t))}),f.on("close",async t=>{v.flush(),C.flush();const[e,r]=await Promise.all([S,_]);x(()=>u({stdout:e,stderr:r,exitCode:Number.isFinite(t)?Number(t):1}))}),"string"==typeof r&&f.stdin.write(r),f.stdin.end()}),A=async({command:t,args:e,cwd:r})=>new Promise((s,n)=>{const o=i(t,e,{cwd:r,stdio:["pipe","pipe","pipe"],windowsHide:!0,env:{...process.env,NO_COLOR:"1",FORCE_COLOR:"0",CLICOLOR:"0"}});let a=!1;const c=t=>{a||(a=!0,t())},d=w(o.stdout),l=w(o.stderr);o.on("error",t=>c(()=>n(t))),o.on("close",async t=>{const[e,r]=await Promise.all([d,l]);c(()=>s({stdout:e,stderr:r,exitCode:Number.isFinite(t)?Number(t):1}))})}),F=async t=>null!==m?m:(p||(p=(async(t,e)=>{const r=String(t||"").trim();if(!r)return!1;try{const t=await b({cwd:e,args:["features","list"]});return 0===t.exitCode&&f(`${t.stdout||""}\n${t.stderr||""}`).split(/\r?\n/).map(t=>t.trim()).some(t=>t.startsWith(`${r} `)||t===r)}catch{return!1}})("rmcp_client",t).then(t=>(m=t,t)).finally(()=>{p=null})),p),I=async({cwd:t,model:e,outputPath:r})=>{const s=["exec"];return await F(t)&&s.push("--enable","rmcp_client"),s.push("--dangerously-bypass-approvals-and-sandbox","-C",t,"--skip-git-repo-check","-m",e,"-o",r,"-"),s};export const createCodexService=({getModel:e,getWorkingDir:r,getLogDir:o,emitLog:c,getGatewayContext:d})=>{const l=()=>n.join(o(),"codex-session-bindings.json"),u=async()=>{try{const e=await t.readFile(l(),"utf8"),r=JSON.parse(e);return Object.fromEntries(Object.entries(r||{}).map(([t,e])=>[String(t||"").trim(),String(e||"").trim()]).filter(([t,e])=>t&&e))}catch{return{}}},g=async e=>{await t.mkdir(o(),{recursive:!0}),await t.writeFile(l(),`${JSON.stringify(e,null,2)}\n`,"utf8")},m=()=>{const t=d?.()||{},e={WEGET_ACTIVE_SKILLS:JSON.stringify(Array.isArray(t.activeSkills)?t.activeSkills:[]),WEGET_HOST_METADATA:JSON.stringify(t.hostMetadata&&"object"==typeof t.hostMetadata?t.hostMetadata:{})},r=String(t.botId||"").trim(),s=String(t.platformApiBaseUrl||"").trim(),n=String(t.accessToken||"").trim(),i=String(t.fileBridgeDir||"").trim(),o=String(t.fileBridgeToken||"").trim();return r&&(e.WEGET_BOT_ID=r),s&&(e.WEGET_PLATFORM_API_BASE_URL=s),n&&(e.WEGET_PLATFORM_API_ACCESS_TOKEN=n),i&&(e.WEGET_FILE_BRIDGE_DIR=i),o&&(e.WEGET_FILE_BRIDGE_TOKEN=o),e},p=()=>n.join(r(),"weget-gateway-context.json"),w=async()=>{const e=d?.()||{};await t.mkdir(r(),{recursive:!0}),await t.writeFile(p(),JSON.stringify({activeSkills:Array.isArray(e.activeSkills)?e.activeSkills:[],hostMetadata:e.hostMetadata&&"object"==typeof e.hostMetadata?e.hostMetadata:{},botId:String(e.botId||"").trim(),platformApiBaseUrl:String(e.platformApiBaseUrl||"").trim(),accessToken:String(e.accessToken||"").trim(),fileBridgeDir:String(e.fileBridgeDir||"").trim(),fileBridgeToken:String(e.fileBridgeToken||"").trim(),logDir:o(),updatedAt:(new Date).toISOString()},null,2),"utf8")},f=async({target:e,payload:r})=>{const s=n.join(o(),"gateway-tests");await t.mkdir(s,{recursive:!0});const i=n.join(s,`${e}-${Date.now()}.log`);return await t.writeFile(i,`${JSON.stringify(r,null,2)}\n`,"utf8"),i},y=async({userPrompt:t,systemPrompt:r,contextLabel:s,promptBundle:n,metadata:i})=>{const o=d?.()||{},c=Array.isArray(o.activeSkills)?o.activeSkills:[],l=o.hostMetadata&&"object"==typeof o.hostMetadata?o.hostMetadata:{},[u,g]=await Promise.all([k("weget-gateway"),P()]),m=c.length?c.map(t=>{const e=Array.isArray(t.tools)&&t.tools.length?` tools=${t.tools.join(", ")}`:"",r=String(t.version||"").trim()?` v${String(t.version||"").trim()}`:"";return`- ${String(t.name||"").trim()}${r}${e}`}):["- none"],p=[`- weget-gateway MCP: ${u.status}`,`- browser runtime: ${g.status}`,`- context: ${String(s||"").trim()||"general"}`,`- default model: ${String(l.aiModel||e()||a).trim()||a}`],w=(t=>{const e=String(t||"").trim().toLowerCase();return!!e&&[/macro/,/economic/,/economy/,/calendar/,/news/,/usd\s*\/\s*jpy/,/usd_jpy/,/risk sentiment/,/economic situation/,/macro snapshot/,/经济/,/宏观/,/日历/,/新闻/,/形势/,/経済/,/マクロ/,/ニュース/,/カレンダー/,/相場/].some(t=>t.test(e))})(t)?["","Macro tool routing hint:","- This request matches macro intent.","- Before answering, use the WeGet macro tools to fetch snapshot, calendar, and news if available.","- Prefer gateway tool calls such as weget_macro_get_snapshot, weget_macro_list_calendar, and weget_macro_list_news.","- Base the summary on fetched tool results rather than unsupported memory."]:[],f=String(r||"").trim(),y=S(n),h=S(i),x=v(y.latest_continuation_state),C=(t=>{const e=Array.isArray(t)?t:[];return e.length?e.slice(-6).map((t,e)=>{const r=S(t),s=v(r.continuation_state);return[`History ${e+1}:`,`- task_id: ${_(r.task_id)||"-"}`,`- title: ${_(r.title)||"-"}`,`- status: ${_(r.status)||"-"}`,`- prompt: ${_(r.prompt)||"-"}`,`- summary: ${_(r.summary)||"-"}`,...s?["- continuation state:",...s.split("\n").map(t=>` ${t}`)]:[]].join("\n")}).join("\n\n"):""})(y.conversation_context);return["You are running inside WeGet Bot Host.","","Active skills:",...m,"","Runtime status:",...p,"","Tool policy:","- Prefer direct reasoning for simple text-only requests.","- When the user asks about macro conditions, economic situation, calendar, or news, prefer the WeGet macro tools before summarizing.","- Use WeGet browser tools only for website access, page extraction, navigation, or screenshots.","- If browser runtime or gateway MCP is unavailable, state that limitation explicitly instead of pretending the task was executed.","- For trading or any action with side effects, do not claim execution unless a concrete tool call actually performed it.","- After the user-visible answer, always append a fenced control block using ```weget_result with compact JSON.",'- The JSON must be {"status":"completed"} for a finished task.','- If you must pause and wait for a user reply before continuing, output {"status":"pending_request","pending_request":{"type":"input","prompt":"...","subtype":"text"}}.','- For approvals, use {"status":"pending_request","pending_request":{"type":"approval","prompt":"...","subtype":"generic"}}.',"- Only use status=pending_request when the task truly cannot continue without the user.","- Keep the final answer plain text only.",...w,...f?["","System prompt:",f]:[],"","Task context:",...[`- conversation id: ${_(y.conversation_id)||"-"}`,`- continue from task id: ${_(y.continue_from_task_id)||"-"}`,`- source: ${_(y.source)||_(h.source)||"-"}`,`- channel: ${_(y.channel)||_(h.channel)||"-"}`],...x?["","Latest continuation state:",x]:[],...C?["","Recent conversation context:",C]:[],..._(h.pending_request_id)||_(h.pending_request_type)?["","Pending request context:",`- request id: ${_(h.pending_request_id)||"-"}`,`- request type: ${_(h.pending_request_type)||"-"}`,`- response via: ${_(h.pending_response_via)||"-"}`,`- response text: ${_(h.pending_response_text)||"-"}`]:[],"","User request:",String(t||"").trim(),"","Respond as plain text only."].join("\n")},k=async t=>{const e=String(t||"").trim();if(!e)return{status:"unknown",detail:"MCP server name is required"};try{"weget-gateway"===e&&await w().catch(()=>{});const t=await b({cwd:r(),args:["mcp","get",e],extraEnv:m()}),s=String(t.stdout||t.stderr||"").trim();return 0!==t.exitCode?/No MCP server named/i.test(s)?{status:"missing",detail:s}:{status:"unknown",detail:s||"codex mcp list failed"}:"playwright"!==e||(t=>{const e=String(t||"");return"win32"===process.platform?/command:\s+.*node(?:\.exe)?/i.test(e)&&/@playwright[\\\/]mcp[\\\/]cli\.js/i.test(e)&&/args:\s+.*--headless/i.test(e):/command:\s+npx/i.test(e)&&/@playwright\/mcp@latest/i.test(e)&&/args:\s+.*--headless/i.test(e)})(s)?"weget-gateway"!==e||E(s,r())?{status:"configured",detail:s||`${e} is configured`}:{status:"missing",detail:"WeGet Gateway MCP exists but points to an outdated launch path. Reinstall it from the host UI."}:{status:"missing",detail:"Playwright MCP exists but uses an unsupported Windows wrapper. Click Install Playwright MCP to repair it."}}catch(t){return{status:"unknown",detail:t instanceof Error?t.message:String(t)}}},P=async()=>{try{const t="win32"===process.platform?"powershell.exe":"npx",e="win32"===process.platform?["-NoProfile","-Command",`& '${$().replace(/'/g,"''")}' playwright install --list`]:["playwright","install","--list"],s=await A({command:t,args:e,cwd:r()}),n=String(s.stdout||s.stderr||"").trim();return 0!==s.exitCode?{status:"unknown",detail:n||"playwright install --list failed"}:/chromium-\d+/i.test(n)||/\\ms-playwright\\chromium-/i.test(n)?{status:"installed",detail:n}:{status:"missing",detail:n||"Chromium is not installed for Playwright."}}catch(t){return{status:"unknown",detail:t instanceof Error?t.message:String(t)}}};return{runPrompt:async({prompt:i,model:d,systemPrompt:l,contextLabel:f,promptBundle:x,metadata:_,onStatus:v})=>{const $=String(d||e()||a).trim()||a,k=r(),P=String(S(x).conversation_id||"").trim();await w().catch(()=>{});const O=C(o()),j=await t.mkdtemp(n.join(s.tmpdir(),"weget-codex-")),E=n.join(j,"last-message.txt"),A=await y({userPrompt:String(i||"").trim(),systemPrompt:String(l||"").trim(),contextLabel:f,promptBundle:x,metadata:_});O.write("exec_start",{model:$,cwd:k,context:String(f||"").trim(),prompt:String(i||"").trim(),instruction:A,outputPath:E,tempDir:j,gatewayContextFile:p(),traceStartedAt:O.startedAt}),v?.("Preparing request"),c("[codex] exec start",{model:$,cwd:k,context:String(f||"").trim(),conversationId:P||void 0});try{const e=async(t,e)=>b({cwd:k,extraEnv:m(),args:t,stdinText:e,onStdoutLine:t=>{O.write("stdout_line",{line:t});const e=h(t);if(e)return/^re-connecting/i.test(e)||/checking tools|tool use|using tool|calling tool/i.test(e)?(O.write("status",{source:"stdout",status:e}),void v?.(e)):void(/reading data|fetching|loading|snapshot|calendar|news/i.test(e)&&(O.write("status",{source:"stdout",status:e}),v?.(e)))},onStderrLine:t=>{O.write("stderr_line",{line:t});const e=String(t||"").match(/session id:\s*([a-zA-Z0-9-]+)/i);e?.[1]&&O.setSessionId(e[1]);const r=h(t);if(r&&!/^--------$/.test(r)&&!/^user$/i.test(r))return/^OpenAI Codex/i.test(r)?(O.write("status",{source:"stderr",status:"Starting Codex"}),void v?.("Starting Codex")):void(/workdir:|model:|provider:|approval:|sandbox:|reasoning effort:|reasoning summaries:|session id:/i.test(r)||(O.write("status",{source:"stderr",status:r}),v?.(r)))}}),r=P?await(async t=>{const e=String(t||"").trim();if(!e)return"";const r=await u();return String(r[e]||"").trim()})(P):"";let s=!1,n=null;if(r&&(s=!0,O.write("resume_attempt",{conversationId:P,sessionId:r}),v?.("Resuming previous Codex session"),n=await e((({cwd:t,sessionId:e,outputPath:r})=>["exec","resume","--dangerously-bypass-approvals-and-sandbox","-C",t,"--skip-git-repo-check","-o",r,e,"-"])({cwd:k,sessionId:r,outputPath:E}),A),0!==n.exitCode&&(O.write("resume_failed",{conversationId:P,sessionId:r,stdout:n.stdout,stderr:n.stderr}),await(async t=>{const e=String(t||"").trim();if(!e)return;const r=await u();r[e]&&(delete r[e],await g(r))})(P).catch(()=>{}),s=!1)),!s){const t=await I({cwd:k,model:$,outputPath:E});n=await e(t,A)}if(!n)throw new Error("codex execution result is missing");O.write("status",{source:"host",status:"Finalizing reply"}),v?.("Finalizing reply");const i=await t.readFile(E,"utf8").catch(()=>"");if(0!==n.exitCode)throw O.write("exec_error",{exitCode:n.exitCode,stdout:n.stdout,stderr:n.stderr,lastMessage:i}),new Error((n.stderr||n.stdout||`codex exec failed with code ${n.exitCode}`).trim());const o=String(i||n.stdout||"").trim();if(!o)throw O.write("exec_error",{exitCode:n.exitCode,stdout:n.stdout,stderr:n.stderr,lastMessage:i,error:"codex returned empty output"}),new Error("codex returned empty output");return O.write("exec_completed",{exitCode:n.exitCode,stdout:n.stdout,stderr:n.stderr,lastMessage:i,finalAnswer:o}),c("[codex] exec completed",{model:$,context:String(f||"").trim(),resumed:s,conversationId:P||void 0}),P&&O.sessionId&&await(async({conversationId:t,sessionId:e})=>{const r=String(t||"").trim(),s=String(e||"").trim();if(!r||!s)return;const n=await u();n[r]=s,await g(n)})({conversationId:P,sessionId:O.sessionId}).catch(()=>{}),o}catch(t){throw O.write("exec_exception",{error:t instanceof Error?t.message:String(t)}),t}finally{const e=await O.flush().catch(()=>"");e&&c("[codex] session trace written",{context:String(f||"").trim(),tracePath:e}),await t.rm(j,{recursive:!0,force:!0}).catch(()=>{})}},getAuthStatus:async()=>{try{const t=await b({cwd:r(),args:["login","status"]}),e=String(t.stdout||t.stderr||"").trim();return 0!==t.exitCode?{status:"unknown",detail:e||"codex login status failed"}:/logged in/i.test(e)?{status:"logged_in",detail:e}:/not logged in|logged out/i.test(e)?{status:"logged_out",detail:e}:{status:"unknown",detail:e||"unknown codex auth state"}}catch(t){return{status:"unknown",detail:t instanceof Error?t.message:String(t)}}},startLogin:async()=>{const e=r();try{if("win32"===process.platform){const r=String(e||"").replace(/'/g,"''"),o=n.join(s.tmpdir(),`weget-codex-login-${Date.now()}.ps1`),a=["$OutputEncoding = [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)","chcp 65001 > $null",'$env:NO_COLOR = "1"','$env:FORCE_COLOR = "0"','$env:CLICOLOR = "0"','$env:LANG = "en_US.UTF-8"','$env:LC_ALL = "en_US.UTF-8"',`Set-Location -LiteralPath '${r}'`,"$stripAnsi = {"," param([string]$line)",' if ($null -eq $line) { return "" }',' return ($line -replace "`e\\[[0-9;?]*[ -/]*[@-~]", "")',"}","codex login --device-auth 2>&1 | ForEach-Object { & $stripAnsi ([string]$_) }"].join(`${s.EOL}`);await t.writeFile(o,a,"utf8");const c=["$script = @()",'$script += "-NoExit"','$script += "-ExecutionPolicy"','$script += "Bypass"','$script += "-File"',`$script += '${o.replace(/'/g,"''")}'`,`Start-Process -FilePath 'powershell.exe' -WorkingDirectory '${r}' -ArgumentList $script`].join("; ");return i("powershell.exe",["-NoProfile","-ExecutionPolicy","Bypass","-Command",c],{cwd:e,stdio:"ignore",windowsHide:!0}).unref(),{ok:!0,detail:"Started `codex login --device-auth` in a new PowerShell window with UTF-8 output."}}if("darwin"===process.platform){const t=`cd ${JSON.stringify(e)} && codex login --device-auth`;return i("open",["-a","Terminal",t],{cwd:e,detached:!0,stdio:"ignore"}).unref(),{ok:!0,detail:"Started `codex login --device-auth` in Terminal."}}const r=`cd ${JSON.stringify(e)} && codex login --device-auth; exec $SHELL`,o=[["x-terminal-emulator",["-e","bash","-lc",r]],["gnome-terminal",["--","bash","-lc",r]],["konsole",["-e","bash","-lc",r]]];for(const[t,r]of o)try{return i(t,r,{cwd:e,detached:!0,stdio:"ignore"}).unref(),{ok:!0,detail:`Started \`codex login --device-auth\` using ${t}.`}}catch{}return{ok:!1,detail:"No supported terminal launcher was found. Run `codex login --device-auth` manually."}}catch(t){const e=t instanceof Error?t.message:String(t);return c("[codex] login launch failed",{error:e}),{ok:!1,detail:e}}},getMcpServerStatus:k,installWegetGatewayMcp:async()=>{try{await w();const t=await k("weget-gateway");if("configured"===t.status&&E(t.detail,r()))return{ok:!0,detail:t.detail||"WeGet Gateway MCP is already configured."};const e=await b({cwd:r(),args:["mcp","remove","weget-gateway"],extraEnv:m()});if(0!==e.exitCode){const t=String(e.stdout||e.stderr||"").trim().toLowerCase();if(!(t.includes("no mcp server named")||t.includes("not found")||t.includes("no server named")))return{ok:!1,detail:String(e.stdout||e.stderr||"").trim()||"Failed to remove existing WeGet Gateway MCP entry."}}const s=O(r()),n=await b({cwd:r(),args:["mcp","add","weget-gateway",s.command,...s.args],extraEnv:m()}),i=String(n.stdout||n.stderr||"").trim();if(0!==n.exitCode)return{ok:!1,detail:i||"Failed to add WeGet Gateway MCP to Codex."};const o=await k("weget-gateway");return"configured"===o.status?{ok:!0,detail:o.detail||"WeGet Gateway MCP configured."}:{ok:!0,detail:i||"WeGet Gateway MCP add command completed, but verification returned no explicit entry."}}catch(t){const e=t instanceof Error?t.message:String(t);return c("[codex] weget gateway mcp install failed",{error:e}),{ok:!1,detail:e}}},getPlaywrightBrowserStatus:P,getGatewayContextFilePath:p,runGatewaySelfTest:async e=>{if("codex_macro"===e){const i=(new Date).toISOString().slice(0,10);await w().catch(()=>{});const c=C(o()),d=await t.mkdtemp(n.join(s.tmpdir(),"weget-codex-test-")),l=n.join(d,"last-message.txt"),u=["You are running a WeGet gateway chain self-test.","Use WeGet gateway MCP tools only.",`Call weget_macro_get_snapshot, weget_macro_list_calendar with dateKey=${i}, and weget_macro_list_news with dateKey=${i}.`,"If all three tool calls succeed, reply with exactly: OK macro chain","If any tool call fails, reply with exactly: NG macro chain: <short reason>","Respond as plain text only."].join("\n");c.write("exec_start",{model:a,cwd:r(),context:"gateway_self_test:codex_macro",prompt:"codex macro chain self-test",instruction:u,outputPath:l,tempDir:d,gatewayContextFile:p(),traceStartedAt:c.startedAt});try{const s=await I({cwd:r(),model:a,outputPath:l}),n=await b({cwd:r(),extraEnv:m(),args:s,stdinText:u,onStdoutLine:t=>{c.write("stdout_line",{line:t})},onStderrLine:t=>{c.write("stderr_line",{line:t});const e=String(t||"").match(/session id:\s*([a-zA-Z0-9-]+)/i);e?.[1]&&c.setSessionId(e[1])}}),o=await t.readFile(l,"utf8").catch(()=>""),g=String(o||n.stdout||"").trim(),w=String(n.stderr||""),y=String(n.stdout||""),h=/tool weget-gateway\.weget_macro_get_snapshot\(\{\}\)/i.test(w),S=new RegExp(`tool weget-gateway\\.weget_macro_list_calendar\\(\\{"dateKey":"${j(i)}"\\}\\)`,"i").test(w),_=new RegExp(`tool weget-gateway\\.weget_macro_list_news\\(\\{"dateKey":"${j(i)}"\\}\\)`,"i").test(w),v=/weget-gateway\.weget_macro_get_snapshot\(\{\}\) success/i.test(w),C=/weget-gateway\.weget_macro_list_calendar\(\{\"dateKey\":\"\d{4}-\d{2}-\d{2}\"\}\) success/i.test(w),$=/weget-gateway\.weget_macro_list_news\(\{\"dateKey\":\"\d{4}-\d{2}-\d{2}\"\}\) success/i.test(w),k=0===n.exitCode&&/^OK macro chain$/i.test(g)&&h&&S&&_&&v&&C&&$;c.write(k?"exec_completed":"exec_error",{exitCode:n.exitCode,stdout:y,stderr:w,lastMessage:o,finalAnswer:g,invokedSnapshot:h,invokedCalendar:S,invokedNews:_,succeededSnapshot:v,succeededCalendar:C,succeededNews:$});const P=await c.flush().catch(()=>""),O={target:e,ok:k,summary:k?"Codex gateway macro chain OK":"Codex gateway macro chain failed",contextFilePath:p(),tracePath:P,codex:{exitCode:n.exitCode,stdout:y,stderr:w,finalAnswer:g},assertions:{invokedSnapshot:h,invokedCalendar:S,invokedNews:_,succeededSnapshot:v,succeededCalendar:C,succeededNews:$},ts:(new Date).toISOString()},E=await f({target:e,payload:O});return await t.rm(d,{recursive:!0,force:!0}).catch(()=>{}),{ok:k,summary:k?"Codex gateway macro chain OK":x(g||w,"Codex gateway macro chain failed"),detail:g||w||y,logPath:E,result:O}}catch(r){c.write("exec_exception",{error:r instanceof Error?r.message:String(r)});const s=await c.flush().catch(()=>""),n=r instanceof Error?r.message:String(r),i=await f({target:e,payload:{target:e,ok:!1,summary:"Codex gateway macro chain failed",contextFilePath:p(),tracePath:s,error:n,ts:(new Date).toISOString()}});return await t.rm(d,{recursive:!0,force:!0}).catch(()=>{}),{ok:!1,summary:x(n,"Codex gateway macro chain failed"),detail:n,logPath:i}}}await w();const c=O(r());let d,l=null;try{d=await A({command:c.command,args:[...c.args,"--self-test","--test-target",e],cwd:r()}),"gateway"===e&&(l=await(async({command:t,args:e,cwd:r,timeoutMs:s=2500})=>new Promise((n,o)=>{const a=i(t,e,{cwd:r,stdio:["ignore","pipe","pipe"],windowsHide:!0,env:{...process.env,NO_COLOR:"1",FORCE_COLOR:"0",CLICOLOR:"0"}}),c=[],d=[];let l=!1;const u=t=>{l||(l=!0,n(t))};a.stdout.on("data",t=>c.push(Buffer.from(t))),a.stderr.on("data",t=>d.push(Buffer.from(t))),a.on("error",t=>{l||(l=!0,o(t))}),a.on("close",t=>{u({ok:!1,exitCode:Number.isFinite(t)?Number(t):1,stdout:Buffer.concat(c).toString("utf8"),stderr:Buffer.concat(d).toString("utf8"),responseText:""})}),setTimeout(()=>{const t=a.stdin;t?.write(`${JSON.stringify({jsonrpc:"2.0",id:1,method:"initialize",params:{protocolVersion:"2024-11-05",capabilities:{},clientInfo:{name:"weget-gateway-probe",version:"0.1.0"}}})}\n`)},150),setTimeout(()=>{if(l)return;const t=Buffer.concat(c).toString("utf8"),e=Buffer.concat(d).toString("utf8"),r=t.trim(),s=/"result"\s*:/.test(r)&&/"protocolVersion"\s*:/.test(r);a.kill(),u({ok:s,exitCode:null,stdout:t,stderr:e,responseText:r})},Math.max(250,s))}))({command:c.command,args:c.args,cwd:r()}))}catch(t){const r=t instanceof Error?t.message:String(t),s=await f({target:e,payload:{target:e,launch:c,contextFilePath:p(),failure:"spawn_exception",error:r,ts:(new Date).toISOString()}});return{ok:!1,summary:x(r,`${e} test failed`),detail:r,logPath:s}}const u=String(d.stdout||d.stderr||"").trim();let g;if(u)try{g=JSON.parse(u)}catch{}let y=0===d.exitCode&&Boolean(!g||!1!==g.ok),h=x(u,`${e} self-test completed`);"gateway"===e&&l&&!l.ok?(y=!1,h=x(l.stderr||l.stdout,"Gateway handshake probe failed.")):"gateway"===e&&l?.ok&&(h="Gateway MCP handshake OK");const S={target:e,ok:y,summary:h,launch:c,contextFilePath:p(),selfTest:{exitCode:d.exitCode,stdout:d.stdout,stderr:d.stderr,result:g??null},handshakeProbe:l?{ok:l.ok,exitCode:l.exitCode,stdout:l.stdout,stderr:l.stderr,responseText:l.responseText}:null,ts:(new Date).toISOString()};return{ok:y,summary:h,detail:u||h,logPath:await f({target:e,payload:S}),result:g}}}};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai.weget.jp/bot",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "WeGet bot host for Codex-centered skill runtime ",