@ai.weget.jp/bot 0.1.13 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -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 o from"node:path";import{spawn as a,spawnSync as n}from"node:child_process";const i="gpt-5.4",c=r(import.meta.url);let d=null,l=null,g=null,u=null;const m=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")},w=t=>String(t||"").replace(/\u001b\[[0-9;?]*[ -/]*[@-~]/g,""),p=t=>{let e="";return{push:r=>{if(!t)return;e+=w(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=""}}},f=t=>{const e=w(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=w(String(t||"")).replace(/\s+/g," ").trim();return r?r.length>180?`${r.slice(0,177)}...`:r:e},h=e=>{const r=(new Date).toISOString(),s=`exec-${Date.now()}`;let a="",n="",i=!1,c=Promise.resolve();const d=[],l=async()=>{if(i)return n;const r=o.join(e,"codex-sessions");await t.mkdir(r,{recursive:!0});const c=String(a||s||"").trim().replace(/[^a-zA-Z0-9._-]+/g,"_");return n=o.join(r,`${c}.log`),i=!0,d.length>0&&(await t.appendFile(n,d.join(""),"utf8"),d.length=0),n},g=(e,r={})=>{(e=>{c=c.then(async()=>{if(!i&&!a)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},setSessionId:t=>{const e=String(t||"").trim();e&&a!==e&&(a=e,g("session_identified",{sessionId:e}))},write:g,flush:async()=>(i||await l(),await c,n)}},y=()=>{if(l)return l;const t=[o.join(String(process.env.ProgramFiles||"C:\\Program Files"),"nodejs","npx.cmd"),o.join(String(process.env["ProgramFiles(x86)"]||"C:\\Program Files (x86)"),"nodejs","npx.cmd"),o.join(String(process.env.APPDATA||""),"npm","npx.cmd")].filter(Boolean);for(const r of t)if(e(r))return l=r,r;const r=n("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"},S=()=>{if(g)return g;const t=[o.join(String(process.env.ProgramFiles||"C:\\Program Files"),"nodejs","node.exe"),o.join(String(process.env["ProgramFiles(x86)"]||"C:\\Program Files (x86)"),"nodejs","node.exe")];for(const r of t)if(e(r))return g=r,r;return g="node",g},C=()=>{if(u)return u;try{const t=c.resolve("@ai.weget.jp/weget-gateway-mcp/dist/index.js");return u=t,t}catch{}const t=[o.join(String(process.env.APPDATA||""),"npm","node_modules","@ai.weget.jp","weget-gateway-mcp","dist","index.js"),o.join(String(process.env.ProgramFiles||"C:\\Program Files"),"nodejs","node_modules","@ai.weget.jp","weget-gateway-mcp","dist","index.js"),o.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 u=r,r;return u=o.join(String(process.env.APPDATA||""),"npm","node_modules","@ai.weget.jp","weget-gateway-mcp","dist","index.js"),u},_=t=>{const e=o.join(t,"weget-gateway-context.json");return"win32"===process.platform?{command:S(),args:[C(),"--context-file",e]}:{command:"npx",args:["-y","@ai.weget.jp/weget-gateway-mcp@latest","--context-file",e]}},v=t=>String(t||"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),P=(t,e)=>{const r=String(t||""),s=_(e);if("win32"===process.platform){const t=new RegExp(`command:\\s+${v(s.command)}`,"i"),e=new RegExp(v(String(s.args[0]||"")),"i"),o=new RegExp(v(String(s.args[2]||"")),"i");return t.test(r)&&e.test(r)&&o.test(r)}return new RegExp(`command:\\s+${v(s.command)}`,"i").test(r)&&r.includes(String(s.args[0]||""))},k=async({args:t,stdinText:r,cwd:s,extraEnv:i,onStdoutLine:c,onStderrLine:l})=>new Promise((g,u)=>{const w=(()=>{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=o.join(r,"nodejs","node.exe"),s=o.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=n("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})(),f={...process.env,...i||{},NO_COLOR:"1",FORCE_COLOR:"0",CLICOLOR:"0"},x=a(w.command,[...w.baseArgs,...t],{cwd:s,stdio:["pipe","pipe","pipe"],windowsHide:!0,env:f});let h=!1;const y=t=>{h||(h=!0,t())},S=m(x.stdout),C=m(x.stderr),_=p(c),v=p(l);x.stdout?.on("data",t=>_.push(t)),x.stderr?.on("data",t=>v.push(t)),x.on("error",t=>{y(()=>u(t))}),x.on("close",async t=>{_.flush(),v.flush();const[e,r]=await Promise.all([S,C]);y(()=>g({stdout:e,stderr:r,exitCode:Number.isFinite(t)?Number(t):1}))}),"string"==typeof r&&x.stdin.write(r),x.stdin.end()}),$=async({command:t,args:e,cwd:r})=>new Promise((s,o)=>{const n=a(t,e,{cwd:r,stdio:["pipe","pipe","pipe"],windowsHide:!0,env:{...process.env,NO_COLOR:"1",FORCE_COLOR:"0",CLICOLOR:"0"}});let i=!1;const c=t=>{i||(i=!0,t())},d=m(n.stdout),l=m(n.stderr);n.on("error",t=>c(()=>o(t))),n.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}))})});export const createCodexService=({getModel:e,getWorkingDir:r,getLogDir:n,emitLog:c,getGatewayContext:d})=>{const l=()=>{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(),o=String(t.accessToken||"").trim(),a=String(t.fileBridgeDir||"").trim(),n=String(t.fileBridgeToken||"").trim();return r&&(e.WEGET_BOT_ID=r),s&&(e.WEGET_PLATFORM_API_BASE_URL=s),o&&(e.WEGET_PLATFORM_API_ACCESS_TOKEN=o),a&&(e.WEGET_FILE_BRIDGE_DIR=a),n&&(e.WEGET_FILE_BRIDGE_TOKEN=n),e},g=()=>o.join(r(),"weget-gateway-context.json"),u=async()=>{const e=d?.()||{};await t.mkdir(r(),{recursive:!0}),await t.writeFile(g(),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:n(),updatedAt:(new Date).toISOString()},null,2),"utf8")},m=async({target:e,payload:r})=>{const s=o.join(n(),"gateway-tests");await t.mkdir(s,{recursive:!0});const a=o.join(s,`${e}-${Date.now()}.log`);return await t.writeFile(a,`${JSON.stringify(r,null,2)}\n`,"utf8"),a},w=async({userPrompt:t,contextLabel:r})=>{const s=d?.()||{},o=Array.isArray(s.activeSkills)?s.activeSkills:[],a=s.hostMetadata&&"object"==typeof s.hostMetadata?s.hostMetadata:{},[n,c]=await Promise.all([p("weget-gateway"),S()]);return["You are running inside WeGet Bot Host.","","Active skills:",...o.length?o.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"],"","Runtime status:",...[`- weget-gateway MCP: ${n.status}`,`- browser runtime: ${c.status}`,`- context: ${String(r||"").trim()||"general"}`,`- default model: ${String(a.aiModel||e()||i).trim()||i}`],"","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.","- Keep the final answer plain text only.",...(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."]:[],"","User request:",String(t||"").trim(),"","Respond as plain text only."].join("\n")},p=async t=>{const e=String(t||"").trim();if(!e)return{status:"unknown",detail:"MCP server name is required"};try{"weget-gateway"===e&&await u().catch(()=>{});const t=await k({cwd:r(),args:["mcp","get",e],extraEnv:l()}),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||P(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)}}},S=async()=>{try{const t="win32"===process.platform?"powershell.exe":"npx",e="win32"===process.platform?["-NoProfile","-Command",`& '${y().replace(/'/g,"''")}' playwright install --list`]:["playwright","install","--list"],s=await $({command:t,args:e,cwd:r()}),o=String(s.stdout||s.stderr||"").trim();return 0!==s.exitCode?{status:"unknown",detail:o||"playwright install --list failed"}:/chromium-\d+/i.test(o)||/\\ms-playwright\\chromium-/i.test(o)?{status:"installed",detail:o}:{status:"missing",detail:o||"Chromium is not installed for Playwright."}}catch(t){return{status:"unknown",detail:t instanceof Error?t.message:String(t)}}};return{runPrompt:async({prompt:a,model:d,contextLabel:m,onStatus:p})=>{const x=String(d||e()||i).trim()||i,y=r();await u().catch(()=>{});const S=h(n()),C=await t.mkdtemp(o.join(s.tmpdir(),"weget-codex-")),_=o.join(C,"last-message.txt"),v=await w({userPrompt:String(a||"").trim(),contextLabel:m});S.write("exec_start",{model:x,cwd:y,context:String(m||"").trim(),prompt:String(a||"").trim(),instruction:v,outputPath:_,tempDir:C,gatewayContextFile:g(),traceStartedAt:S.startedAt}),p?.("Preparing request"),c("[codex] exec start",{model:x,cwd:y,context:String(m||"").trim()});try{const e=await k({cwd:y,extraEnv:l(),args:["exec","--enable","rmcp_client","--dangerously-bypass-approvals-and-sandbox","-C",y,"--skip-git-repo-check","-m",x,"-o",_,"-"],stdinText:v,onStdoutLine:t=>{S.write("stdout_line",{line:t});const e=f(t);if(e)return/^re-connecting/i.test(e)||/checking tools|tool use|using tool|calling tool/i.test(e)?(S.write("status",{source:"stdout",status:e}),void p?.(e)):void(/reading data|fetching|loading|snapshot|calendar|news/i.test(e)&&(S.write("status",{source:"stdout",status:e}),p?.(e)))},onStderrLine:t=>{S.write("stderr_line",{line:t});const e=String(t||"").match(/session id:\s*([a-zA-Z0-9-]+)/i);e?.[1]&&S.setSessionId(e[1]);const r=f(t);if(r&&!/^--------$/.test(r)&&!/^user$/i.test(r))return/^OpenAI Codex/i.test(r)?(S.write("status",{source:"stderr",status:"Starting Codex"}),void p?.("Starting Codex")):void(/workdir:|model:|provider:|approval:|sandbox:|reasoning effort:|reasoning summaries:|session id:/i.test(r)||(S.write("status",{source:"stderr",status:r}),p?.(r)))}});S.write("status",{source:"host",status:"Finalizing reply"}),p?.("Finalizing reply");const r=await t.readFile(_,"utf8").catch(()=>"");if(0!==e.exitCode)throw S.write("exec_error",{exitCode:e.exitCode,stdout:e.stdout,stderr:e.stderr,lastMessage:r}),new Error((e.stderr||e.stdout||`codex exec failed with code ${e.exitCode}`).trim());const s=String(r||e.stdout||"").trim();if(!s)throw S.write("exec_error",{exitCode:e.exitCode,stdout:e.stdout,stderr:e.stderr,lastMessage:r,error:"codex returned empty output"}),new Error("codex returned empty output");return S.write("exec_completed",{exitCode:e.exitCode,stdout:e.stdout,stderr:e.stderr,lastMessage:r,finalAnswer:s}),c("[codex] exec completed",{model:x,context:String(m||"").trim()}),s}catch(t){throw S.write("exec_exception",{error:t instanceof Error?t.message:String(t)}),t}finally{const e=await S.flush().catch(()=>"");e&&c("[codex] session trace written",{context:String(m||"").trim(),tracePath:e}),await t.rm(C,{recursive:!0,force:!0}).catch(()=>{})}},getAuthStatus:async()=>{try{const t=await k({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,"''"),n=o.join(s.tmpdir(),`weget-codex-login-${Date.now()}.ps1`),i=["$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(n,i,"utf8");const c=["$script = @()",'$script += "-NoExit"','$script += "-ExecutionPolicy"','$script += "Bypass"','$script += "-File"',`$script += '${n.replace(/'/g,"''")}'`,`Start-Process -FilePath 'powershell.exe' -WorkingDirectory '${r}' -ArgumentList $script`].join("; ");return a("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 a("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`,n=[["x-terminal-emulator",["-e","bash","-lc",r]],["gnome-terminal",["--","bash","-lc",r]],["konsole",["-e","bash","-lc",r]]];for(const[t,r]of n)try{return a(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:p,installWegetGatewayMcp:async()=>{try{await u();const t=await p("weget-gateway");if("configured"===t.status&&P(t.detail,r()))return{ok:!0,detail:t.detail||"WeGet Gateway MCP is already configured."};const e=await k({cwd:r(),args:["mcp","remove","weget-gateway"],extraEnv:l()});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=_(r()),o=await k({cwd:r(),args:["mcp","add","weget-gateway",s.command,...s.args],extraEnv:l()}),a=String(o.stdout||o.stderr||"").trim();if(0!==o.exitCode)return{ok:!1,detail:a||"Failed to add WeGet Gateway MCP to Codex."};const n=await p("weget-gateway");return"configured"===n.status?{ok:!0,detail:n.detail||"WeGet Gateway MCP configured."}:{ok:!0,detail:a||"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:S,getGatewayContextFilePath:g,runGatewaySelfTest:async e=>{if("codex_macro"===e){const a=(new Date).toISOString().slice(0,10);await u().catch(()=>{});const c=h(n()),d=await t.mkdtemp(o.join(s.tmpdir(),"weget-codex-test-")),w=o.join(d,"last-message.txt"),p=["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=${a}, and weget_macro_list_news with dateKey=${a}.`,"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:i,cwd:r(),context:"gateway_self_test:codex_macro",prompt:"codex macro chain self-test",instruction:p,outputPath:w,tempDir:d,gatewayContextFile:g(),traceStartedAt:c.startedAt});try{const s=await k({cwd:r(),extraEnv:l(),args:["exec","--enable","rmcp_client","--dangerously-bypass-approvals-and-sandbox","-C",r(),"--skip-git-repo-check","-m",i,"-o",w,"-"],stdinText:p,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(w,"utf8").catch(()=>""),n=String(o||s.stdout||"").trim(),u=String(s.stderr||""),f=String(s.stdout||""),h=/tool weget-gateway\.weget_macro_get_snapshot\(\{\}\)/i.test(u),y=new RegExp(`tool weget-gateway\\.weget_macro_list_calendar\\(\\{"dateKey":"${v(a)}"\\}\\)`,"i").test(u),S=new RegExp(`tool weget-gateway\\.weget_macro_list_news\\(\\{"dateKey":"${v(a)}"\\}\\)`,"i").test(u),C=/weget-gateway\.weget_macro_get_snapshot\(\{\}\) success/i.test(u),_=/weget-gateway\.weget_macro_list_calendar\(\{\"dateKey\":\"\d{4}-\d{2}-\d{2}\"\}\) success/i.test(u),P=/weget-gateway\.weget_macro_list_news\(\{\"dateKey\":\"\d{4}-\d{2}-\d{2}\"\}\) success/i.test(u),$=0===s.exitCode&&/^OK macro chain$/i.test(n)&&h&&y&&S&&C&&_&&P;c.write($?"exec_completed":"exec_error",{exitCode:s.exitCode,stdout:f,stderr:u,lastMessage:o,finalAnswer:n,invokedSnapshot:h,invokedCalendar:y,invokedNews:S,succeededSnapshot:C,succeededCalendar:_,succeededNews:P});const O=await c.flush().catch(()=>""),E={target:e,ok:$,summary:$?"Codex gateway macro chain OK":"Codex gateway macro chain failed",contextFilePath:g(),tracePath:O,codex:{exitCode:s.exitCode,stdout:f,stderr:u,finalAnswer:n},assertions:{invokedSnapshot:h,invokedCalendar:y,invokedNews:S,succeededSnapshot:C,succeededCalendar:_,succeededNews:P},ts:(new Date).toISOString()},j=await m({target:e,payload:E});return await t.rm(d,{recursive:!0,force:!0}).catch(()=>{}),{ok:$,summary:$?"Codex gateway macro chain OK":x(n||u,"Codex gateway macro chain failed"),detail:n||u||f,logPath:j,result:E}}catch(r){c.write("exec_exception",{error:r instanceof Error?r.message:String(r)});const s=await c.flush().catch(()=>""),o=r instanceof Error?r.message:String(r),a=await m({target:e,payload:{target:e,ok:!1,summary:"Codex gateway macro chain failed",contextFilePath:g(),tracePath:s,error:o,ts:(new Date).toISOString()}});return await t.rm(d,{recursive:!0,force:!0}).catch(()=>{}),{ok:!1,summary:x(o,"Codex gateway macro chain failed"),detail:o,logPath:a}}}await u();const c=_(r());let d,w=null;try{d=await $({command:c.command,args:[...c.args,"--self-test","--test-target",e],cwd:r()}),"gateway"===e&&(w=await(async({command:t,args:e,cwd:r,timeoutMs:s=2500})=>new Promise((o,n)=>{const i=a(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 g=t=>{l||(l=!0,o(t))};i.stdout.on("data",t=>c.push(Buffer.from(t))),i.stderr.on("data",t=>d.push(Buffer.from(t))),i.on("error",t=>{l||(l=!0,n(t))}),i.on("close",t=>{g({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=i.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);i.kill(),g({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 m({target:e,payload:{target:e,launch:c,contextFilePath:g(),failure:"spawn_exception",error:r,ts:(new Date).toISOString()}});return{ok:!1,summary:x(r,`${e} test failed`),detail:r,logPath:s}}const p=String(d.stdout||d.stderr||"").trim();let f;if(p)try{f=JSON.parse(p)}catch{}let y=0===d.exitCode&&Boolean(!f||!1!==f.ok),S=x(p,`${e} self-test completed`);"gateway"===e&&w&&!w.ok?(y=!1,S=x(w.stderr||w.stdout,"Gateway handshake probe failed.")):"gateway"===e&&w?.ok&&(S="Gateway MCP handshake OK");const C={target:e,ok:y,summary:S,launch:c,contextFilePath:g(),selfTest:{exitCode:d.exitCode,stdout:d.stdout,stderr:d.stderr,result:f??null},handshakeProbe:w?{ok:w.ok,exitCode:w.exitCode,stdout:w.stdout,stderr:w.stderr,responseText:w.responseText}:null,ts:(new Date).toISOString()};return{ok:y,summary:S,detail:p||S,logPath:await m({target:e,payload:C}),result:f}}}};
|
|
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 o from"node:path";import{spawn as a,spawnSync as n}from"node:child_process";const i="gpt-5.4",c=r(import.meta.url);let d=null,l=null,g=null,u=null,m=null,w=null;const p=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,""),h=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=""}}},x=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:""},y=(t,e)=>{const r=f(String(t||"")).replace(/\s+/g," ").trim();return r?r.length>180?`${r.slice(0,177)}...`:r:e},S=e=>{const r=(new Date).toISOString(),s=`exec-${Date.now()}`;let a="",n="",i=!1,c=Promise.resolve();const d=[],l=async()=>{if(i)return n;const r=o.join(e,"codex-sessions");await t.mkdir(r,{recursive:!0});const c=String(a||s||"").trim().replace(/[^a-zA-Z0-9._-]+/g,"_");return n=o.join(r,`${c}.log`),i=!0,d.length>0&&(await t.appendFile(n,d.join(""),"utf8"),d.length=0),n},g=(e,r={})=>{(e=>{c=c.then(async()=>{if(!i&&!a)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},setSessionId:t=>{const e=String(t||"").trim();e&&a!==e&&(a=e,g("session_identified",{sessionId:e}))},write:g,flush:async()=>(i||await l(),await c,n)}},C=()=>{if(l)return l;const t=[o.join(String(process.env.ProgramFiles||"C:\\Program Files"),"nodejs","npx.cmd"),o.join(String(process.env["ProgramFiles(x86)"]||"C:\\Program Files (x86)"),"nodejs","npx.cmd"),o.join(String(process.env.APPDATA||""),"npm","npx.cmd")].filter(Boolean);for(const r of t)if(e(r))return l=r,r;const r=n("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"},_=()=>{if(g)return g;const t=[o.join(String(process.env.ProgramFiles||"C:\\Program Files"),"nodejs","node.exe"),o.join(String(process.env["ProgramFiles(x86)"]||"C:\\Program Files (x86)"),"nodejs","node.exe")];for(const r of t)if(e(r))return g=r,r;return g="node",g},P=()=>{if(u)return u;try{const t=c.resolve("@ai.weget.jp/weget-gateway-mcp/dist/index.js");return u=t,t}catch{}const t=[o.join(String(process.env.APPDATA||""),"npm","node_modules","@ai.weget.jp","weget-gateway-mcp","dist","index.js"),o.join(String(process.env.ProgramFiles||"C:\\Program Files"),"nodejs","node_modules","@ai.weget.jp","weget-gateway-mcp","dist","index.js"),o.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 u=r,r;return u=o.join(String(process.env.APPDATA||""),"npm","node_modules","@ai.weget.jp","weget-gateway-mcp","dist","index.js"),u},v=t=>{const e=o.join(t,"weget-gateway-context.json");return"win32"===process.platform?{command:_(),args:[P(),"--context-file",e]}:{command:"npx",args:["-y","@ai.weget.jp/weget-gateway-mcp@latest","--context-file",e]}},k=t=>String(t||"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),$=(t,e)=>{const r=String(t||""),s=v(e);if("win32"===process.platform){const t=new RegExp(`command:\\s+${k(s.command)}`,"i"),e=new RegExp(k(String(s.args[0]||"")),"i"),o=new RegExp(k(String(s.args[2]||"")),"i");return t.test(r)&&e.test(r)&&o.test(r)}return new RegExp(`command:\\s+${k(s.command)}`,"i").test(r)&&r.includes(String(s.args[0]||""))},O=async({args:t,stdinText:r,cwd:s,extraEnv:i,onStdoutLine:c,onStderrLine:l})=>new Promise((g,u)=>{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=o.join(r,"nodejs","node.exe"),s=o.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=n("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})(),w={...process.env,...i||{},NO_COLOR:"1",FORCE_COLOR:"0",CLICOLOR:"0"},f=a(m.command,[...m.baseArgs,...t],{cwd:s,stdio:["pipe","pipe","pipe"],windowsHide:!0,env:w});let x=!1;const y=t=>{x||(x=!0,t())},S=p(f.stdout),C=p(f.stderr),_=h(c),P=h(l);f.stdout?.on("data",t=>_.push(t)),f.stderr?.on("data",t=>P.push(t)),f.on("error",t=>{y(()=>u(t))}),f.on("close",async t=>{_.flush(),P.flush();const[e,r]=await Promise.all([S,C]);y(()=>g({stdout:e,stderr:r,exitCode:Number.isFinite(t)?Number(t):1}))}),"string"==typeof r&&f.stdin.write(r),f.stdin.end()}),E=async({command:t,args:e,cwd:r})=>new Promise((s,o)=>{const n=a(t,e,{cwd:r,stdio:["pipe","pipe","pipe"],windowsHide:!0,env:{...process.env,NO_COLOR:"1",FORCE_COLOR:"0",CLICOLOR:"0"}});let i=!1;const c=t=>{i||(i=!0,t())},d=p(n.stdout),l=p(n.stderr);n.on("error",t=>c(()=>o(t))),n.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}))})}),j=async t=>null!==m?m:(w||(w=(async(t,e)=>{const r=String(t||"").trim();if(!r)return!1;try{const t=await O({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(()=>{w=null})),w),A=async({cwd:t,model:e,outputPath:r})=>{const s=["exec"];return await j(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:n,emitLog:c,getGatewayContext:d})=>{const l=()=>{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(),o=String(t.accessToken||"").trim(),a=String(t.fileBridgeDir||"").trim(),n=String(t.fileBridgeToken||"").trim();return r&&(e.WEGET_BOT_ID=r),s&&(e.WEGET_PLATFORM_API_BASE_URL=s),o&&(e.WEGET_PLATFORM_API_ACCESS_TOKEN=o),a&&(e.WEGET_FILE_BRIDGE_DIR=a),n&&(e.WEGET_FILE_BRIDGE_TOKEN=n),e},g=()=>o.join(r(),"weget-gateway-context.json"),u=async()=>{const e=d?.()||{};await t.mkdir(r(),{recursive:!0}),await t.writeFile(g(),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:n(),updatedAt:(new Date).toISOString()},null,2),"utf8")},m=async({target:e,payload:r})=>{const s=o.join(n(),"gateway-tests");await t.mkdir(s,{recursive:!0});const a=o.join(s,`${e}-${Date.now()}.log`);return await t.writeFile(a,`${JSON.stringify(r,null,2)}\n`,"utf8"),a},w=async({userPrompt:t,contextLabel:r})=>{const s=d?.()||{},o=Array.isArray(s.activeSkills)?s.activeSkills:[],a=s.hostMetadata&&"object"==typeof s.hostMetadata?s.hostMetadata:{},[n,c]=await Promise.all([p("weget-gateway"),f()]);return["You are running inside WeGet Bot Host.","","Active skills:",...o.length?o.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"],"","Runtime status:",...[`- weget-gateway MCP: ${n.status}`,`- browser runtime: ${c.status}`,`- context: ${String(r||"").trim()||"general"}`,`- default model: ${String(a.aiModel||e()||i).trim()||i}`],"","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.","- Keep the final answer plain text only.",...(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."]:[],"","User request:",String(t||"").trim(),"","Respond as plain text only."].join("\n")},p=async t=>{const e=String(t||"").trim();if(!e)return{status:"unknown",detail:"MCP server name is required"};try{"weget-gateway"===e&&await u().catch(()=>{});const t=await O({cwd:r(),args:["mcp","get",e],extraEnv:l()}),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||$(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)}}},f=async()=>{try{const t="win32"===process.platform?"powershell.exe":"npx",e="win32"===process.platform?["-NoProfile","-Command",`& '${C().replace(/'/g,"''")}' playwright install --list`]:["playwright","install","--list"],s=await E({command:t,args:e,cwd:r()}),o=String(s.stdout||s.stderr||"").trim();return 0!==s.exitCode?{status:"unknown",detail:o||"playwright install --list failed"}:/chromium-\d+/i.test(o)||/\\ms-playwright\\chromium-/i.test(o)?{status:"installed",detail:o}:{status:"missing",detail:o||"Chromium is not installed for Playwright."}}catch(t){return{status:"unknown",detail:t instanceof Error?t.message:String(t)}}};return{runPrompt:async({prompt:a,model:d,contextLabel:m,onStatus:p})=>{const f=String(d||e()||i).trim()||i,h=r();await u().catch(()=>{});const y=S(n()),C=await t.mkdtemp(o.join(s.tmpdir(),"weget-codex-")),_=o.join(C,"last-message.txt"),P=await w({userPrompt:String(a||"").trim(),contextLabel:m});y.write("exec_start",{model:f,cwd:h,context:String(m||"").trim(),prompt:String(a||"").trim(),instruction:P,outputPath:_,tempDir:C,gatewayContextFile:g(),traceStartedAt:y.startedAt}),p?.("Preparing request"),c("[codex] exec start",{model:f,cwd:h,context:String(m||"").trim()});try{const e=await A({cwd:h,model:f,outputPath:_}),r=await O({cwd:h,extraEnv:l(),args:e,stdinText:P,onStdoutLine:t=>{y.write("stdout_line",{line:t});const e=x(t);if(e)return/^re-connecting/i.test(e)||/checking tools|tool use|using tool|calling tool/i.test(e)?(y.write("status",{source:"stdout",status:e}),void p?.(e)):void(/reading data|fetching|loading|snapshot|calendar|news/i.test(e)&&(y.write("status",{source:"stdout",status:e}),p?.(e)))},onStderrLine:t=>{y.write("stderr_line",{line:t});const e=String(t||"").match(/session id:\s*([a-zA-Z0-9-]+)/i);e?.[1]&&y.setSessionId(e[1]);const r=x(t);if(r&&!/^--------$/.test(r)&&!/^user$/i.test(r))return/^OpenAI Codex/i.test(r)?(y.write("status",{source:"stderr",status:"Starting Codex"}),void p?.("Starting Codex")):void(/workdir:|model:|provider:|approval:|sandbox:|reasoning effort:|reasoning summaries:|session id:/i.test(r)||(y.write("status",{source:"stderr",status:r}),p?.(r)))}});y.write("status",{source:"host",status:"Finalizing reply"}),p?.("Finalizing reply");const s=await t.readFile(_,"utf8").catch(()=>"");if(0!==r.exitCode)throw y.write("exec_error",{exitCode:r.exitCode,stdout:r.stdout,stderr:r.stderr,lastMessage:s}),new Error((r.stderr||r.stdout||`codex exec failed with code ${r.exitCode}`).trim());const o=String(s||r.stdout||"").trim();if(!o)throw y.write("exec_error",{exitCode:r.exitCode,stdout:r.stdout,stderr:r.stderr,lastMessage:s,error:"codex returned empty output"}),new Error("codex returned empty output");return y.write("exec_completed",{exitCode:r.exitCode,stdout:r.stdout,stderr:r.stderr,lastMessage:s,finalAnswer:o}),c("[codex] exec completed",{model:f,context:String(m||"").trim()}),o}catch(t){throw y.write("exec_exception",{error:t instanceof Error?t.message:String(t)}),t}finally{const e=await y.flush().catch(()=>"");e&&c("[codex] session trace written",{context:String(m||"").trim(),tracePath:e}),await t.rm(C,{recursive:!0,force:!0}).catch(()=>{})}},getAuthStatus:async()=>{try{const t=await O({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,"''"),n=o.join(s.tmpdir(),`weget-codex-login-${Date.now()}.ps1`),i=["$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(n,i,"utf8");const c=["$script = @()",'$script += "-NoExit"','$script += "-ExecutionPolicy"','$script += "Bypass"','$script += "-File"',`$script += '${n.replace(/'/g,"''")}'`,`Start-Process -FilePath 'powershell.exe' -WorkingDirectory '${r}' -ArgumentList $script`].join("; ");return a("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 a("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`,n=[["x-terminal-emulator",["-e","bash","-lc",r]],["gnome-terminal",["--","bash","-lc",r]],["konsole",["-e","bash","-lc",r]]];for(const[t,r]of n)try{return a(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:p,installWegetGatewayMcp:async()=>{try{await u();const t=await p("weget-gateway");if("configured"===t.status&&$(t.detail,r()))return{ok:!0,detail:t.detail||"WeGet Gateway MCP is already configured."};const e=await O({cwd:r(),args:["mcp","remove","weget-gateway"],extraEnv:l()});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=v(r()),o=await O({cwd:r(),args:["mcp","add","weget-gateway",s.command,...s.args],extraEnv:l()}),a=String(o.stdout||o.stderr||"").trim();if(0!==o.exitCode)return{ok:!1,detail:a||"Failed to add WeGet Gateway MCP to Codex."};const n=await p("weget-gateway");return"configured"===n.status?{ok:!0,detail:n.detail||"WeGet Gateway MCP configured."}:{ok:!0,detail:a||"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:f,getGatewayContextFilePath:g,runGatewaySelfTest:async e=>{if("codex_macro"===e){const a=(new Date).toISOString().slice(0,10);await u().catch(()=>{});const c=S(n()),d=await t.mkdtemp(o.join(s.tmpdir(),"weget-codex-test-")),w=o.join(d,"last-message.txt"),p=["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=${a}, and weget_macro_list_news with dateKey=${a}.`,"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:i,cwd:r(),context:"gateway_self_test:codex_macro",prompt:"codex macro chain self-test",instruction:p,outputPath:w,tempDir:d,gatewayContextFile:g(),traceStartedAt:c.startedAt});try{const s=await A({cwd:r(),model:i,outputPath:w}),o=await O({cwd:r(),extraEnv:l(),args:s,stdinText:p,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])}}),n=await t.readFile(w,"utf8").catch(()=>""),u=String(n||o.stdout||"").trim(),f=String(o.stderr||""),h=String(o.stdout||""),x=/tool weget-gateway\.weget_macro_get_snapshot\(\{\}\)/i.test(f),S=new RegExp(`tool weget-gateway\\.weget_macro_list_calendar\\(\\{"dateKey":"${k(a)}"\\}\\)`,"i").test(f),C=new RegExp(`tool weget-gateway\\.weget_macro_list_news\\(\\{"dateKey":"${k(a)}"\\}\\)`,"i").test(f),_=/weget-gateway\.weget_macro_get_snapshot\(\{\}\) success/i.test(f),P=/weget-gateway\.weget_macro_list_calendar\(\{\"dateKey\":\"\d{4}-\d{2}-\d{2}\"\}\) success/i.test(f),v=/weget-gateway\.weget_macro_list_news\(\{\"dateKey\":\"\d{4}-\d{2}-\d{2}\"\}\) success/i.test(f),$=0===o.exitCode&&/^OK macro chain$/i.test(u)&&x&&S&&C&&_&&P&&v;c.write($?"exec_completed":"exec_error",{exitCode:o.exitCode,stdout:h,stderr:f,lastMessage:n,finalAnswer:u,invokedSnapshot:x,invokedCalendar:S,invokedNews:C,succeededSnapshot:_,succeededCalendar:P,succeededNews:v});const E=await c.flush().catch(()=>""),j={target:e,ok:$,summary:$?"Codex gateway macro chain OK":"Codex gateway macro chain failed",contextFilePath:g(),tracePath:E,codex:{exitCode:o.exitCode,stdout:h,stderr:f,finalAnswer:u},assertions:{invokedSnapshot:x,invokedCalendar:S,invokedNews:C,succeededSnapshot:_,succeededCalendar:P,succeededNews:v},ts:(new Date).toISOString()},F=await m({target:e,payload:j});return await t.rm(d,{recursive:!0,force:!0}).catch(()=>{}),{ok:$,summary:$?"Codex gateway macro chain OK":y(u||f,"Codex gateway macro chain failed"),detail:u||f||h,logPath:F,result:j}}catch(r){c.write("exec_exception",{error:r instanceof Error?r.message:String(r)});const s=await c.flush().catch(()=>""),o=r instanceof Error?r.message:String(r),a=await m({target:e,payload:{target:e,ok:!1,summary:"Codex gateway macro chain failed",contextFilePath:g(),tracePath:s,error:o,ts:(new Date).toISOString()}});return await t.rm(d,{recursive:!0,force:!0}).catch(()=>{}),{ok:!1,summary:y(o,"Codex gateway macro chain failed"),detail:o,logPath:a}}}await u();const c=v(r());let d,w=null;try{d=await E({command:c.command,args:[...c.args,"--self-test","--test-target",e],cwd:r()}),"gateway"===e&&(w=await(async({command:t,args:e,cwd:r,timeoutMs:s=2500})=>new Promise((o,n)=>{const i=a(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 g=t=>{l||(l=!0,o(t))};i.stdout.on("data",t=>c.push(Buffer.from(t))),i.stderr.on("data",t=>d.push(Buffer.from(t))),i.on("error",t=>{l||(l=!0,n(t))}),i.on("close",t=>{g({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=i.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);i.kill(),g({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 m({target:e,payload:{target:e,launch:c,contextFilePath:g(),failure:"spawn_exception",error:r,ts:(new Date).toISOString()}});return{ok:!1,summary:y(r,`${e} test failed`),detail:r,logPath:s}}const p=String(d.stdout||d.stderr||"").trim();let f;if(p)try{f=JSON.parse(p)}catch{}let h=0===d.exitCode&&Boolean(!f||!1!==f.ok),x=y(p,`${e} self-test completed`);"gateway"===e&&w&&!w.ok?(h=!1,x=y(w.stderr||w.stdout,"Gateway handshake probe failed.")):"gateway"===e&&w?.ok&&(x="Gateway MCP handshake OK");const C={target:e,ok:h,summary:x,launch:c,contextFilePath:g(),selfTest:{exitCode:d.exitCode,stdout:d.stdout,stderr:d.stderr,result:f??null},handshakeProbe:w?{ok:w.ok,exitCode:w.exitCode,stdout:w.stdout,stderr:w.stderr,responseText:w.responseText}:null,ts:(new Date).toISOString()};return{ok:h,summary:x,detail:p||x,logPath:await m({target:e,payload:C}),result:f}}}};
|