@ai.weget.jp/bot 0.1.24 → 0.1.25
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 +1 -1
- package/package.json +1 -1
package/dist/src/main.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import t from"node:path";import e from"node:fs/promises";import{existsSync as a}from"node:fs";import{fileURLToPath as i}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 c}from"./services/codexService.js";import{createGatewayFileBridgeService as d}from"./services/gatewayFileBridgeService.js";import{createPlatformApiClient as g}from"./platformApi.js";import{createSkillRuntimeManager as m}from"./skillRuntimeManager.js";import{parseTaskDirective as u,stripWegetControlBlocks as p}from"./services/taskDirective.js";import{createWindowManager as k}from"./services/windowManagerService.js";import{createSkillHostState as y}from"./skillHostState.js";const S=r(import.meta.url),{app:f,BrowserWindow:_,ipcMain:w,nativeImage:b}=S("electron"),v=i(import.meta.url),h=t.dirname(v),I=["trade","ai"],x=()=>t.join(f.getPath("userData"),"login-profile.json"),A=()=>t.join(f.getPath("userData"),"host-config.json"),C=()=>t.join(f.getPath("userData"),"skill-states.json");let O=null,E=null,P={aiModel:"gpt-5.4",logOutputDir:""};const M=new Map;let j=()=>t.join(f.getPath("documents"),"weget-bot-logs");const T=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"},D=async({level:a,source:i,message:r,details:s,ts:n})=>{const o=j();await e.mkdir(o,{recursive:!0});const l=new Date,c=l.getFullYear(),d=String(l.getMonth()+1).padStart(2,"0"),g=String(l.getDate()).padStart(2,"0"),m=t.join(o,`${a}-${c}${d}${g}.log`),u=JSON.stringify({ts:n||l.toISOString(),level:a,source:i,message:r,details:s??null},null,0);await e.appendFile(m,`${u}\n`,"utf8")},B=k({BrowserWindow:_,preloadPath:t.join(h,"preload.cjs"),rendererDir:t.join(h,"renderer"),windowIconPath:t.join(h,"renderer","logo.png")}),q=(t,e)=>{const a=(new Date).toISOString();B.emitBotLog({message:t,data:e||null,ts:a}),D({level:T(t),source:"runtime",message:t,details:e,ts:a}).catch(()=>{})},L=t=>{B.emitChatEvent(t)},U=t=>({taskId:t.taskId,title:t.title,prompt:t.prompt,status:t.status,source:t.source,channel:t.channel,lineUserId:t.lineUserId,conversationId:t.conversationId,startedAt:t.startedAt,lastProgressAt:t.lastProgressAt,canCancel:!t.cancelled}),R=()=>{B.emitTaskRuntime({type:"snapshot",tasks:Array.from(M.values()).map(U)})},N=(t,e)=>{const a=M.get(t);if(!a)return;const i={...a,...e,taskId:t,abortController:e.abortController||a.abortController,lastProgressAt:e.lastProgressAt||(new Date).toISOString()};M.set(t,i),B.emitTaskRuntime({type:"upsert",task:U(i)})},F=t=>{M.has(t)&&(M.delete(t),B.emitTaskRuntime({type:"remove",taskId:t}))},G=(t,e)=>({summary:t?.cancelReason||e,data_json:{reason:t?.cancelReason||e,requested_by_task_id:t?.cancelRequestedByTaskId||null,requested_by_action:t?.cancelRequestedByAction||null,ts:(new Date).toISOString()}}),K=async({taskId:t,directive:e,promptBundle:a})=>{const i=$(a.arbitration_context),r=$(i.active_task),s=String(e.targetTaskId||r.task_id||"").trim();if("cancel_running_task"===e.action){const a=await(async({taskId:t,reason:e,requestedByTaskId:a,requestedByAction:i})=>{const r=String(t||"").trim();if(!r)return{ok:!1,mode:"invalid",error:"task_id is required"};const s=M.get(r);if(s)return s.cancelled=!0,s.cancelReason=e,s.cancelRequestedByTaskId=a,s.cancelRequestedByAction=i,s.abortController.abort(),N(r,{status:"Cancelling..."}),q("[task] cancellation requested",{task_id:r,mode:"local",reason:e,requested_by_task_id:a||"",requested_by_action:i||""}),{ok:!0,mode:"local"};try{return await z.request({method:"POST",path:"/bot/tasks/cancel",body:{task_id:r}}),q("[task] cancellation requested",{task_id:r,mode:"platform",reason:e,requested_by_task_id:a||"",requested_by_action:i||""}),{ok:!0,mode:"platform"}}catch(t){return{ok:!1,mode:"platform",error:t instanceof Error?t.message:String(t)}}})({taskId:s,reason:e.reason||"arbitration_cancelled",requestedByTaskId:t,requestedByAction:e.action});return E?.sendTaskEvent(t,"task_control_action",{action:e.action,target_task_id:s||null,ok:a.ok,mode:a.mode,error:"error"in a?a.error:null,ts:(new Date).toISOString()}),a}return E?.sendTaskEvent(t,"task_control_action",{action:e.action,target_task_id:s||null,ok:!0,mode:"advisory",ts:(new Date).toISOString()}),{ok:!0,mode:"advisory"}},$=t=>t&&"object"==typeof t?t:{},W=y({log:q}),J=l({getEnv:()=>({loginApiUrl:s.loginApiUrl,botUploadApiUrl:s.botUploadApiUrl}),emitLog:q,getCurrentSession:()=>O}),z=g({getBaseUrl:()=>String(s.loginApiUrl||"").trim().replace(/\/login\/?$/i,""),getSession:()=>O,log:q}),H=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 J.callBotApi(e,t)},Q=m({installRoot:t.join(f.getPath("userData"),"skills"),botId:()=>String(O?.botId||"").trim()||void 0,log:q,api:z,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 a=`trade-${Date.now()}`;E?.sendTaskEvent(a,"trade_history",{package_name:t,...e.payload&&"object"==typeof e.payload?e.payload:{}}),q("[trade] history event sent (execution)",{package_name:t,payload:e.payload})}}else B.emitTradeExecution(e.payload)}}),X=()=>{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},Y=()=>{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},V=()=>Q.getLoadedSkill("@ai.weget.jp/skill-gmo-fx")?.runtime,Z=()=>Q.getLoadedSkill("@ai.weget.jp/skill-gmo-coin")?.runtime,tt=()=>{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},et=()=>Q.getLoadedSkill("@ai.weget.jp/skill-macro-economy")?.runtime,at=({isLineTask:t,status:e})=>{const a=String(e||"").trim();return a?t?`LINE task: ${a}`:a:""},it=(t,e)=>{const a=t.gateway[e];if("function"!=typeof a)throw new Error(`skill runtime does not implement gateway.${e}`);return a},rt=t=>{const e=$(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"}},st=t=>{const e=$(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"}};j=()=>String(P.logOutputDir||"").trim()||t.join(f.getPath("documents"),"weget-bot-logs");const nt=c({getModel:()=>{const t=V(),e=Z();return P.aiModel||t?.getConfig?.().aiModel||e?.getConfig?.().aiModel||"gpt-5.4"},getWorkingDir:()=>f.getPath("userData"),getLogDir:()=>j(),emitLog:q,getGatewayContext:()=>({activeSkills:W.getManagedSkills().filter(t=>t.enabled).map(t=>({name:t.name,displayName:t.displayName,version:t.version,tools:t.tools})),hostMetadata:{aiModel:P.aiModel||"gpt-5.4",capabilities:I,userDataPath:f.getPath("userData"),platform:process.platform,gmoCoinPublicBaseUrl:s.gmoCryptoPublicApiBaseUrl,gmoFxPublicBaseUrl:s.gmoFxPublicApiBaseUrl},botId:String(O?.botId||"").trim(),platformApiBaseUrl:String(s.loginApiUrl||"").trim().replace(/\/login\/?$/i,""),accessToken:String(O?.accessToken||"").trim(),fileBridgeDir:String(kt.getContext()?.dir||"").trim(),fileBridgeToken:String(kt.getContext()?.token||"").trim()})}),ot=async t=>{const a=$(t);return P={aiModel:String(a.aiModel||P.aiModel||"gpt-5.4").trim()||"gpt-5.4",logOutputDir:String(a.logOutputDir||"").trim()},await e.writeFile(A(),JSON.stringify({...P,updatedAt:(new Date).toISOString()},null,2),"utf8"),P};const lt=async()=>{const t=await Q.refreshLoadedSkills();return W.setAvailableSkills(t.map(t=>t.manifest)),t},ct=async t=>{const e=await lt();q("[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}))})},dt=()=>{const t=W.isSkillEnabled("@ai.weget.jp/skill-gmo-fx"),e=W.isSkillEnabled("@ai.weget.jp/skill-gmo-coin"),a=V(),i=Z();a&&("connected"===E?.getStatus()&&t?a.startExecutionStreams():a.stopExecutionStreams()),i&&("connected"===E?.getStatus()&&e?i.startExecutionStreams():i.stopExecutionStreams()),q("[skills] applied managed states",{active_skills:W.getActiveSkills().map(t=>t.name)})},gt=async()=>{const t=J.getBotRuntimeConfigApiUrl(),e=String(O?.botId||"").trim();if(!t||!e)return;const a=await J.callBotApi(t,{bot_id:e}),i=String(a.chat_model||"").trim(),r={...i?{aiModel:i}:{}};if(0===Object.keys(r).length)return;await ot({...P,...r});const s=V(),n=Z();s&&await s.saveConfig({...s.getConfig(),...r}),n&&await n.saveConfig({...n.getConfig(),...r}),q("[config] runtime config synced",{chat_model:i||""})},mt=async()=>{const t=J.getBotSkillsListApiUrl(),a=String(O?.botId||"").trim();if(!t||!a)return;const i=await J.callBotApi(t,{bot_id:a}),r=Array.isArray(i.states)?i.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:$(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})):[];W.applySnapshots(r),await(async t=>{await e.writeFile(C(),JSON.stringify({updatedAt:(new Date).toISOString(),items:t},null,2),"utf8")})(r),await ct(r),dt(),q("[config] skill states synced",{count:r.length,bot_id:a,enabled:r.filter(t=>t.enabled).length})},ut=t=>{if("fx"===t&&!W.isSkillEnabled("@ai.weget.jp/skill-gmo-fx"))throw new Error("GMO FX skill is disabled");if("coin"===t&&!W.isSkillEnabled("@ai.weget.jp/skill-gmo-coin"))throw new Error("GMO Coin skill is disabled")},pt=()=>{if(!W.isSkillEnabled("@ai.weget.jp/skill-macro-economy"))throw new Error("Macro Economy skill is disabled")},kt=d({getMacroSnapshot:async({force:t}={})=>(pt(),tt().getSnapshot({force:t})),getMacroCalendar:async({dateKey:t})=>(pt(),tt().listCalendar({dateKey:t})),getMacroNews:async({dateKey:t})=>(pt(),tt().listNews({dateKey:t})),emitLog:q,getWorkingDir:()=>f.getPath("userData")}),yt={"@ai.weget.jp/skill-gmo-fx":{getConfig:()=>rt(X().getConfig()),saveConfig:async t=>{const e=X(),a=await e.saveConfig({...e.getConfig(),...rt(t)});return"connected"===E?.getStatus()&&dt(),rt(a)}},"@ai.weget.jp/skill-gmo-coin":{getConfig:()=>st(Y().getConfig()),saveConfig:async t=>{const e=Y(),a=await e.saveConfig({...e.getConfig(),...st(t)});return"connected"===E?.getStatus()&&dt(),st(a)}}},St=t=>{const e=String(t||"").trim(),a=yt[e];if(!a)throw new Error(`skill config is not managed by bot host: ${t}`);return a},ft=async()=>{await Q.ensureInstallRoot(),await lt();const t=await async function(){try{const t=await e.readFile(C(),"utf8"),a=JSON.parse(t);return(Array.isArray(a?.items)?a.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:$(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&&(W.applySnapshots(t),q("[skills] restored local snapshot",{count:t.length}),await ct(t)),dt()};E=new n({wsUrl:"wss://ws.weget.jp",taskEventApiUrl:String(s.loginApiUrl||"").trim().replace(/\/login\/?$/i,"/bot/runtime/task-event"),version:"0.2.0",capabilities:I,heartbeatSec:30,reconnectMs:3e3,reconnectMaxAttempts:10,wsPingIntervalSec:25,wsPongTimeoutSec:12},{onLog:(t,e)=>q(t,e),onStatus:t=>{B.emitBotStatus({status:t}),dt()},onLineMessage:async t=>{const e=String(t.line_user_id||""),a=String(t.text||"").trim();if(L({type:"line_user",lineUserId:e,text:a}),!a)return{answer:""};try{const t=await nt.runPrompt({prompt:a,contextLabel:"line_message"});return L({type:"line_assistant",lineUserId:e,text:t}),{answer:t}}catch(t){const a=t instanceof Error?t.message:String(t);q("[ai] line reply failed",{error:a});const i=`AI error: ${a}`;return L({type:"line_assistant",lineUserId:e,text:i}),{answer:i}}},onRunTask:async t=>{const e=String(t.task_id||"").trim(),a=String(t.prompt||"").trim(),i=$(t.metadata_json),r=$(t.prompt_bundle),s=$(t.runtime_config),n=String(i.source||r.source||"").trim(),o=String(i.channel||r.channel||"").trim(),l=String(t.skill_id||i.skill_id||r.skill_id||"").trim(),c=String(t.bot_id||O?.botId||"").trim(),d=String(i.line_user_id||"").trim(),g=String(i.line_reply_token||"").trim(),m="line"===n||"line"===o||Boolean(d&&g),k="bot_host"===n,y=String(t.model||s.chat_model||"").trim(),S=String(s.system_prompt||r.system_prompt||"").trim();if(!e)return void q("[task] run_task missing task_id");const f=(new Date).toISOString();if(M.set(e,{cancelled:!1,abortController:new AbortController,taskId:e,title:String(t.title||a.slice(0,120)||e).trim(),prompt:a,status:"Task received",source:n||"unknown",channel:o||"",lineUserId:d||void 0,conversationId:String(t.conversation_id||"").trim()||void 0,startedAt:f,lastProgressAt:f}),R(),m&&d&&a&&L({type:"line_user",lineUserId:d,text:a}),E?.sendTaskEvent(e,"task_received",{prompt:a,conversation_id:String(t.conversation_id||""),continue_from_task_id:String(t.continue_from_task_id||""),ts:(new Date).toISOString()}),!a)return E?.sendTaskResult(e,"failed",{error:"prompt is required",data_json:{ts:(new Date).toISOString()}}),void M.delete(e);try{if(k||m){const t=at({isLineTask:m,status:"Task received"});L({type:"assistant_status",status:t}),N(e,{status:t})}l&&E?.sendSkillStatus(e,{skill_id:l,status:"running",summary:"task execution started",data_json:{ts:(new Date).toISOString()}}),E?.sendTaskEvent(e,"step_started",{step:"codex_chat",ts:(new Date).toISOString()});const f=await nt.runPrompt({prompt:a,model:y||void 0,systemPrompt:S||void 0,contextLabel:`task:${e}`,promptBundle:r,metadata:i,onStatus:k||m?t=>{const a=at({isLineTask:m,status:t});L({type:"assistant_status",status:a}),N(e,{status:a})}:void 0,abortSignal:M.get(e)?.abortController.signal}),_=u(f),w=_.pendingRequest,b=_.arbitrationAction,v=_.visibleText||p(f),h=M.get(e);if(h?.cancelled)return E?.sendTaskResult(e,"cancelled",G(h,"server_cancelled")),void F(e);let I=null;if(b){if(I=await K({taskId:e,directive:b,promptBundle:r}),!I.ok&&"cancel_running_task"===b.action)throw new Error("error"in I&&I.error||"failed to cancel running task");if("start_new_task"===b.action){const t=await(async({taskId:t,prompt:e,visibleAnswer:a,source:i,channel:r,botId:s,skillId:n,runtimeConfig:o,promptBundle:l,metadata:c})=>{const d=String(l.conversation_id||"").trim();if(!d)return{ok:!1,error:"conversation_id is required for start_new_task"};const g={...c,arbitration_parent_task_id:t,arbitration_decision:"start_new_task",arbitration_visible_answer:a},m=await z.request({method:"POST",path:"/bot/tasks",body:{source:i||null,channel:r||null,bot_id:s,skill_id:n||void 0,prompt:e,title:e.slice(0,80),conversation_id:d,continue_from_task_id:t,model:String(o.chat_model||"").trim()||void 0,sandbox_mode:String(o.sandbox_mode||"").trim()||void 0,approval_policy:String(o.approval_policy||"").trim()||void 0,metadata_json:g}});return{ok:!0,taskId:String($(m.task).task_id||"").trim()||null,dispatch:$(m.dispatch_result)}})({taskId:e,prompt:a,visibleAnswer:v,source:n,channel:o,botId:c,skillId:l||void 0,runtimeConfig:s,promptBundle:r,metadata:i});if(!t.ok)throw new Error(t.error||"failed to queue arbitrated new task");I={ok:!0,mode:"local"===I.mode||"platform"===I.mode||"advisory"===I.mode?I.mode:"advisory",queuedTaskId:t.taskId,dispatch:t.dispatch}}}if(E?.sendTaskEvent(e,"ai_output",{summary:v,action:b?.action||null,ts:(new Date).toISOString()}),k&&L({type:"assistant",text:v}),m&&d&&g){L({type:"line_assistant",lineUserId:d,text:v});const a={bot_id:String(t.bot_id||O?.botId||""),line_user_id:d,line_reply_token:g,text:v};try{await H(a)}catch(t){q("[line] callback line reply failed",{error:t instanceof Error?t.message:String(t)})}E?.sendTaskEvent(e,"line_message_ai_output",{line_user_id:d,answer:v,ts:(new Date).toISOString()})}if(E?.sendTaskEvent(e,"step_finished",{step:"codex_chat",action:b?.action||null,ts:(new Date).toISOString()}),w)return"approval"===w.requestType?E?.requestTaskApproval(e,{prompt:w.prompt,approval_type:w.subtype||"generic",data_json:{prompt:w.prompt,approval_type:w.subtype||"generic",ts:(new Date).toISOString()}}):E?.requestTaskInput(e,{prompt:w.prompt,input_type:w.subtype||"text",data_json:{prompt:w.prompt,input_type:w.subtype||"text",ts:(new Date).toISOString()}}),l&&E?.sendSkillStatus(e,{skill_id:l,status:"approval"===w.requestType?"waiting_approval":"waiting_input",summary:w.prompt.slice(0,200),data_json:{ts:(new Date).toISOString(),request_type:w.requestType}}),void F(e);E?.sendTaskResult(e,"succeeded",{summary:v.slice(0,500),data_json:{ts:(new Date).toISOString(),action:b?.action||null,target_task_id:b?.targetTaskId||null,action_reason:b?.reason||null,action_mode:I?.mode||null,queued_task_id:I?.queuedTaskId||null}}),l&&E?.sendSkillStatus(e,{skill_id:l,status:"succeeded",summary:v.slice(0,200),data_json:{ts:(new Date).toISOString()}})}catch(a){if(k){const t=`Error: ${a instanceof Error?a.message:String(a)}`;L({type:"assistant",text:t})}const i=M.get(e);if(i?.cancelled)return E?.sendTaskResult(e,"cancelled",G(i,"server_cancelled")),void F(e);if(m&&d&&g){const e=`AI error: ${a instanceof Error?a.message:String(a)}`;L({type:"line_assistant",lineUserId:d,text:e});const i={bot_id:String(t.bot_id||O?.botId||""),line_user_id:d,line_reply_token:g,text:e};try{await H(i)}catch(t){q("[line] callback line reply failed",{error:t instanceof Error?t.message:String(t)})}}E?.sendTaskResult(e,"failed",{error:a instanceof Error?a.message:String(a),data_json:{ts:(new Date).toISOString()}}),l&&E?.sendSkillStatus(e,{skill_id:l,status:"failed",summary:a instanceof Error?a.message:String(a),data_json:{ts:(new Date).toISOString()}})}finally{F(e)}},onTaskControl:async t=>{const e=String(t.task_id||"").trim(),a=String(t.action||"").trim();if(e&&a&&"cancel_task"===a){const a=M.get(e);if(a){a.cancelled=!0,a.cancelReason="server_cancelled",a.cancelRequestedByAction="cancel_task",a.abortController.abort();const i=String(t.skill_id||"").trim();return i&&E?.sendSkillStatus(e,{skill_id:i,status:"cancelled",summary:"server_cancelled",data_json:{ts:(new Date).toISOString()}}),void q("[task] cancel requested",{task_id:e})}E?.sendTaskResult(e,"cancelled",G(void 0,"server_cancelled"))}},onServerConfigUpdate:async t=>{const e=Array.isArray(t.scopes)?t.scopes.map(t=>String(t||"").trim()):[],a=e.length>0?e:["runtime","skills"];a.includes("runtime")&&await gt(),a.includes("skills")&&await mt()}}),o({ipcMain:w,env:{capabilities:I,loginApiUrl:s.loginApiUrl},signInWithLoginApi:J.signInWithLoginApi,saveLoginProfile:async({botId:t,email:a,password:i,remember:r})=>{if(r)await e.writeFile(x(),JSON.stringify({botId:t,email:a,password:i,remember:!0,updatedAt:(new Date).toISOString()},null,2),"utf8");else try{await e.unlink(x())}catch(t){if("ENOENT"!==t?.code)throw t}},readSavedLoginProfile:async()=>{try{const t=await e.readFile(x(),"utf8"),a=JSON.parse(t);return{botId:String(a?.botId||""),email:String(a?.email||""),password:String(a?.password||""),remember:Boolean(a?.remember)}}catch(t){if("ENOENT"===t?.code)return{botId:"",email:"",password:"",remember:!1};throw t}},getSkillConfig:t=>({config:St(t).getConfig()}),saveSkillConfig:async(t,e)=>({config:await St(t).saveConfig(e)}),getAiConfig:()=>({aiModel:String(P.aiModel||"gpt-5.4"),logOutputDir:String(P.logOutputDir||"")}),saveAiConfig:async t=>{const e=t&&"object"==typeof t?t:{},a=await ot({...P,...e}),i=V(),r=Z(),s=i?await i.saveConfig({...i.getConfig(),...e}):null;return r&&await r.saveConfig({...r.getConfig(),...e}),{aiModel:String(a.aiModel||s?.aiModel||e.aiModel||"gpt-5.4"),logOutputDir:String(a.logOutputDir||"")}},setCurrentSession:t=>{O=t||null;const e=O?"connected":"disconnected";B.emitBotStatus({status:e})},getCurrentSession:()=>O,getActiveSkills:()=>W.getActiveSkills().map(t=>({name:t.name,displayName:t.displayName,version:t.version})),getCodexAuthStatus:()=>nt.getAuthStatus(),getCodexMcpStatus:t=>nt.getMcpServerStatus(t),getPlaywrightBrowserStatus:()=>nt.getPlaywrightBrowserStatus(),startCodexLogin:()=>nt.startLogin(),installPlaywrightMcp:()=>nt.installWegetGatewayMcp(),getGatewayContextFilePath:()=>nt.getGatewayContextFilePath(),runGatewaySelfTest:t=>nt.runGatewaySelfTest(t),getManagedSkills:()=>W.getManagedSkills().map(t=>({...t,ui:Q.getLoadedSkill(t.name)?.ui||void 0})),getMacroSnapshot:async({force:t}={})=>(pt(),tt().getSnapshot({force:t})),getMacroCalendar:async({dateKey:t})=>(pt(),tt().listCalendar({dateKey:t})),getMacroNews:async({dateKey:t})=>(pt(),tt().listNews({dateKey:t})),emitLog:q,openGmoKlineWindow:async({symbol:t,interval:e,market:a})=>(()=>{const i="fx"===a?"fx":"coin";return ut(i),("fx"===i?X().marketData:Y().marketData).fetchKline({symbol:t,interval:e,market:i})})(),getGmoMarketQuotes:async({market:t,symbols:e})=>(()=>{const a="fx"===t?"fx":"coin";return ut(a),("fx"===a?X().marketData:Y().marketData).fetchQuotes({market:a,symbols:e})})(),getGmoSymbolRules:async({market:t})=>(()=>{const e="fx"===t?"fx":"coin";return ut(e),("fx"===e?X().marketData:Y().marketData).fetchSymbolRules({market:e})})(),getGmoBuyingPower:async({market:t})=>({market:t,availableJpy:await(ut(t),("fx"===t?X().gateway:Y().gateway).getBuyingPower(t))}),getGmoAccountMetrics:async({market:t})=>(ut(t),("fx"===t?X().gateway:Y().gateway).getAccountMetrics(t)),getGmoPositionSummary:async({market:t,symbol:e})=>({market:t,symbol:e,items:await(ut(t),("fx"===t?X().gateway:Y().gateway).getPositionSummary({market:t,symbol:e}))}),getGmoOpenPositions:async({market:t,symbol:e,page:a,prevId:i,count:r})=>({market:t,symbol:e||"",items:await(ut(t),("fx"===t?X().gateway:Y().gateway).getOpenPositions({market:"fx"===t?"fx":"crypto",symbol:e||void 0,page:a,prevId:i,count:r}))}),placeGmoFxOrder:async({symbol:t,side:e,size:a})=>{ut("fx");return await it(X(),"placeFxOrder")({symbol:t,side:e,size:a,executionType:"MARKET"})},placeGmoCoinOrder:async({symbol:t,side:e,size:a})=>{ut("coin");return await it(Y(),"placeCoinOrder")({symbol:t,side:e,size:a,executionType:"MARKET"})},placeGmoFxCloseOrder:async({symbol:t,side:e,positionId:a,size:i})=>{ut("fx");return await it(X(),"placeFxCloseOrder")({symbol:t,side:e,positionId:a,size:i,executionType:"MARKET"})},placeGmoCoinCloseOrder:async({symbol:t,side:e,positionId:a,size:i})=>{ut("coin");return await it(Y(),"placeCoinCloseOrder")({symbol:t,side:e,positionId:a,size:i,executionType:"MARKET"})},getGmoApiState:t=>{const e="fx"===t?V():Z();return e?.status.getApiState()||"unknown"},testGmoApi:t=>(ut(t),"fx"===t?X().status.testApi():Y().status.testApi()),buildTradeStatusSnapshot:t=>(ut(t),"fx"===t?X().status.buildSnapshot():Y().status.buildSnapshot()),closeTradeWindows:()=>{},startWsClient:t=>{E?.start(t),gt().catch(t=>{q("[config] runtime sync failed after login",{error:t instanceof Error?t.message:String(t)})}),mt().catch(t=>{q("[config] skill sync failed after login",{error:t instanceof Error?t.message:String(t)})}),dt()},stopWsClient:()=>{V()?.stopExecutionStreams(),Z()?.stopExecutionStreams(),et()?.stop?.(),E?.stop(),R()},handleBotChatMessage:async({text:t})=>{const e=String(t||"").trim(),a=String(O?.botId||"").trim();if(!e)throw new Error("message is required");if(!a)throw new Error("bot session is not ready");L({type:"assistant_status",status:"Submitting task"});const i=await z.request({method:"POST",path:"/bot/tasks",body:{source:"bot_host",bot_id:a,prompt:e,title:e.slice(0,80),channel:"desktop",metadata_json:{source:"bot_host",channel:"desktop"}}}),r=$(i.dispatch_result);if(!1===r.delivered)throw new Error(`task queued but bot is offline (${String(r.status||"offline")})`);return{answer:"",taskId:String($(i.task).task_id||"")}},getActiveTaskRuntimes:()=>Array.from(M.values()).map(U),cancelActiveTaskRuntime:async t=>{const e=M.get(String(t||"").trim());return e?(e.cancelled=!0,e.cancelReason="local_cancelled",e.cancelRequestedByAction="cancel_task",e.abortController.abort(),N(e.taskId,{status:"Cancelling..."}),q("[task] local cancel requested",{task_id:e.taskId}),{ok:!0}):{ok:!1,error:"task not found"}},writeErrorLog:async({source:t,message:e,details:a})=>{await(async({source:t,message:e,details:a})=>{await D({level:"error",source:t,message:e,details:a})})({source:t,message:e,details:a})},writeRuntimeLog:async({level:t,source:e,message:a,details:i})=>{await D({level:t,source:e,message:a,details:i})}});const _t=t.join(h,"renderer","logo.png");f.whenReady().then(async()=>{(()=>{if("darwin"!==process.platform)return;if(!a(_t))return;const t=b.createFromPath(_t);t.isEmpty()||f.dock.setIcon(t)})(),await(async()=>{try{const t=await e.readFile(A(),"utf8"),a=JSON.parse(t);P={aiModel:String(a?.aiModel||"gpt-5.4").trim()||"gpt-5.4",logOutputDir:String(a?.logOutputDir||"").trim()}}catch(t){if("ENOENT"!==t?.code)throw t;P={aiModel:"gpt-5.4",logOutputDir:""}}return P})();try{await kt.ensureStarted()}catch(t){q("[gateway-file-bridge] startup failed",{error:t instanceof Error?t.message:String(t)})}try{await ft()}catch(t){q("[skills] local initialization failed",{error:t instanceof Error?t.message:String(t)})}B.createMainWindow(),R(),f.on("activate",()=>{0===_.getAllWindows().length&&(B.createMainWindow(),R())})}),f.on("window-all-closed",()=>{V()?.stopExecutionStreams(),Z()?.stopExecutionStreams(),et()?.stop?.(),kt.stop().catch(()=>{}),E?.stop(),"darwin"!==process.platform&&f.quit()});
|
|
1
|
+
import t from"node:path";import e from"node:fs/promises";import{existsSync as a}from"node:fs";import{fileURLToPath as i}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 c}from"./services/codexService.js";import{createGatewayFileBridgeService as d}from"./services/gatewayFileBridgeService.js";import{createPlatformApiClient as g}from"./platformApi.js";import{createSkillRuntimeManager as m}from"./skillRuntimeManager.js";import{parseTaskDirective as u,stripWegetControlBlocks as p}from"./services/taskDirective.js";import{createWindowManager as k}from"./services/windowManagerService.js";import{createSkillHostState as y}from"./skillHostState.js";const S=r(import.meta.url),{app:f,BrowserWindow:_,ipcMain:w,nativeImage:b}=S("electron"),v=i(import.meta.url),h=t.dirname(v),I=["trade","ai"],x=()=>t.join(f.getPath("userData"),"login-profile.json"),A=()=>t.join(f.getPath("userData"),"host-config.json"),C=()=>t.join(f.getPath("userData"),"skill-states.json");let E=null,O=null,P={aiModel:"gpt-5.4",logOutputDir:""};const j=new Map;let M=()=>t.join(f.getPath("documents"),"weget-bot-logs");const T=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"},D=async({level:a,source:i,message:r,details:s,ts:n})=>{const o=M();await e.mkdir(o,{recursive:!0});const l=new Date,c=l.getFullYear(),d=String(l.getMonth()+1).padStart(2,"0"),g=String(l.getDate()).padStart(2,"0"),m=t.join(o,`${a}-${c}${d}${g}.log`),u=JSON.stringify({ts:n||l.toISOString(),level:a,source:i,message:r,details:s??null},null,0);await e.appendFile(m,`${u}\n`,"utf8")},B=k({BrowserWindow:_,preloadPath:t.join(h,"preload.cjs"),rendererDir:t.join(h,"renderer"),windowIconPath:t.join(h,"renderer","logo.png")}),q=(t,e)=>{const a=(new Date).toISOString();B.emitBotLog({message:t,data:e||null,ts:a}),D({level:T(t),source:"runtime",message:t,details:e,ts:a}).catch(()=>{})},L=t=>{B.emitChatEvent(t)},U=t=>({taskId:t.taskId,title:t.title,prompt:t.prompt,status:t.status,source:t.source,channel:t.channel,lineUserId:t.lineUserId,conversationId:t.conversationId,startedAt:t.startedAt,lastProgressAt:t.lastProgressAt,canCancel:!t.cancelled}),R=()=>{B.emitTaskRuntime({type:"snapshot",tasks:Array.from(j.values()).map(U)})},N=(t,e)=>{const a=j.get(t);if(!a)return;const i={...a,...e,taskId:t,abortController:e.abortController||a.abortController,lastProgressAt:e.lastProgressAt||(new Date).toISOString()};j.set(t,i),B.emitTaskRuntime({type:"upsert",task:U(i)})},F=t=>{j.has(t)&&(j.delete(t),B.emitTaskRuntime({type:"remove",taskId:t}))},G=(t,e)=>({summary:t?.cancelReason||e,data_json:{reason:t?.cancelReason||e,requested_by_task_id:t?.cancelRequestedByTaskId||null,requested_by_action:t?.cancelRequestedByAction||null,ts:(new Date).toISOString()}}),K=async({taskId:t,directive:e,promptBundle:a})=>{const i=$(a.arbitration_context),r=$(i.active_task),s=String(e.targetTaskId||r.task_id||"").trim();if("cancel_running_task"===e.action){const a=await(async({taskId:t,reason:e,requestedByTaskId:a,requestedByAction:i})=>{const r=String(t||"").trim();if(!r)return{ok:!1,mode:"invalid",error:"task_id is required"};const s=j.get(r);if(s)return s.cancelled=!0,s.cancelReason=e,s.cancelRequestedByTaskId=a,s.cancelRequestedByAction=i,s.abortController.abort(),N(r,{status:"Cancelling..."}),q("[task] cancellation requested",{task_id:r,mode:"local",reason:e,requested_by_task_id:a||"",requested_by_action:i||""}),{ok:!0,mode:"local"};try{return await z.request({method:"POST",path:"/bot/tasks/cancel",body:{task_id:r}}),q("[task] cancellation requested",{task_id:r,mode:"platform",reason:e,requested_by_task_id:a||"",requested_by_action:i||""}),{ok:!0,mode:"platform"}}catch(t){return{ok:!1,mode:"platform",error:t instanceof Error?t.message:String(t)}}})({taskId:s,reason:e.reason||"arbitration_cancelled",requestedByTaskId:t,requestedByAction:e.action});return O?.sendTaskEvent(t,"task_control_action",{action:e.action,target_task_id:s||null,ok:a.ok,mode:a.mode,error:"error"in a?a.error:null,ts:(new Date).toISOString()}),a}return O?.sendTaskEvent(t,"task_control_action",{action:e.action,target_task_id:s||null,ok:!0,mode:"advisory",ts:(new Date).toISOString()}),{ok:!0,mode:"advisory"}},$=t=>t&&"object"==typeof t?t:{},W=y({log:q}),J=l({getEnv:()=>({loginApiUrl:s.loginApiUrl,botUploadApiUrl:s.botUploadApiUrl}),emitLog:q,getCurrentSession:()=>E}),z=g({getBaseUrl:()=>String(s.loginApiUrl||"").trim().replace(/\/login\/?$/i,""),getSession:()=>E,log:q}),H=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 J.callBotApi(e,t)},Q=m({installRoot:t.join(f.getPath("userData"),"skills"),botId:()=>String(E?.botId||"").trim()||void 0,log:q,api:z,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 a=`trade-${Date.now()}`;O?.sendTaskEvent(a,"trade_history",{package_name:t,...e.payload&&"object"==typeof e.payload?e.payload:{}}),q("[trade] history event sent (execution)",{package_name:t,payload:e.payload})}}else B.emitTradeExecution(e.payload)}}),X=()=>{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},Y=()=>{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},V=()=>Q.getLoadedSkill("@ai.weget.jp/skill-gmo-fx")?.runtime,Z=()=>Q.getLoadedSkill("@ai.weget.jp/skill-gmo-coin")?.runtime,tt=()=>{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},et=()=>Q.getLoadedSkill("@ai.weget.jp/skill-macro-economy")?.runtime,at=({isLineTask:t,status:e})=>{const a=String(e||"").trim();return a?t?`LINE task: ${a}`:a:""},it=(t,e)=>{const a=t.gateway[e];if("function"!=typeof a)throw new Error(`skill runtime does not implement gateway.${e}`);return a},rt=t=>{const e=$(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"}},st=t=>{const e=$(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"}};M=()=>String(P.logOutputDir||"").trim()||t.join(f.getPath("documents"),"weget-bot-logs");const nt=c({getModel:()=>{const t=V(),e=Z();return P.aiModel||t?.getConfig?.().aiModel||e?.getConfig?.().aiModel||"gpt-5.4"},getWorkingDir:()=>f.getPath("userData"),getLogDir:()=>M(),emitLog:q,getGatewayContext:()=>({activeSkills:W.getManagedSkills().filter(t=>t.enabled).map(t=>({name:t.name,displayName:t.displayName,version:t.version,tools:t.tools})),hostMetadata:{aiModel:P.aiModel||"gpt-5.4",capabilities:I,userDataPath:f.getPath("userData"),platform:process.platform,gmoCoinPublicBaseUrl:s.gmoCryptoPublicApiBaseUrl,gmoFxPublicBaseUrl:s.gmoFxPublicApiBaseUrl},botId:String(E?.botId||"").trim(),platformApiBaseUrl:String(s.loginApiUrl||"").trim().replace(/\/login\/?$/i,""),accessToken:String(E?.accessToken||"").trim(),fileBridgeDir:String(kt.getContext()?.dir||"").trim(),fileBridgeToken:String(kt.getContext()?.token||"").trim()})}),ot=async t=>{const a=$(t);return P={aiModel:String(a.aiModel||P.aiModel||"gpt-5.4").trim()||"gpt-5.4",logOutputDir:String(a.logOutputDir||"").trim()},await e.writeFile(A(),JSON.stringify({...P,updatedAt:(new Date).toISOString()},null,2),"utf8"),P};const lt=async()=>{const t=await Q.refreshLoadedSkills();return W.setAvailableSkills(t.map(t=>t.manifest)),t},ct=async t=>{const e=await lt();q("[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}))})},dt=()=>{const t=W.isSkillEnabled("@ai.weget.jp/skill-gmo-fx"),e=W.isSkillEnabled("@ai.weget.jp/skill-gmo-coin"),a=V(),i=Z();a&&("connected"===O?.getStatus()&&t?a.startExecutionStreams():a.stopExecutionStreams()),i&&("connected"===O?.getStatus()&&e?i.startExecutionStreams():i.stopExecutionStreams()),q("[skills] applied managed states",{active_skills:W.getActiveSkills().map(t=>t.name)})},gt=async()=>{const t=J.getBotRuntimeConfigApiUrl(),e=String(E?.botId||"").trim();if(!t||!e)return;const a=await J.callBotApi(t,{bot_id:e}),i=String(a.chat_model||"").trim(),r={...i?{aiModel:i}:{}};if(0===Object.keys(r).length)return;await ot({...P,...r});const s=V(),n=Z();s&&await s.saveConfig({...s.getConfig(),...r}),n&&await n.saveConfig({...n.getConfig(),...r}),q("[config] runtime config synced",{chat_model:i||""})},mt=async()=>{const t=J.getBotSkillsListApiUrl(),a=String(E?.botId||"").trim();if(!t||!a)return;const i=await J.callBotApi(t,{bot_id:a}),r=Array.isArray(i.states)?i.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:$(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})):[];W.applySnapshots(r),await(async t=>{await e.writeFile(C(),JSON.stringify({updatedAt:(new Date).toISOString(),items:t},null,2),"utf8")})(r),await ct(r),dt(),q("[config] skill states synced",{count:r.length,bot_id:a,enabled:r.filter(t=>t.enabled).length})},ut=t=>{if("fx"===t&&!W.isSkillEnabled("@ai.weget.jp/skill-gmo-fx"))throw new Error("GMO FX skill is disabled");if("coin"===t&&!W.isSkillEnabled("@ai.weget.jp/skill-gmo-coin"))throw new Error("GMO Coin skill is disabled")},pt=()=>{if(!W.isSkillEnabled("@ai.weget.jp/skill-macro-economy"))throw new Error("Macro Economy skill is disabled")},kt=d({getMacroSnapshot:async({force:t}={})=>(pt(),tt().getSnapshot({force:t})),getMacroCalendar:async({dateKey:t})=>(pt(),tt().listCalendar({dateKey:t})),getMacroNews:async({dateKey:t})=>(pt(),tt().listNews({dateKey:t})),emitLog:q,getWorkingDir:()=>f.getPath("userData")}),yt={"@ai.weget.jp/skill-gmo-fx":{getConfig:()=>rt(X().getConfig()),saveConfig:async t=>{const e=X(),a=await e.saveConfig({...e.getConfig(),...rt(t)});return"connected"===O?.getStatus()&&dt(),rt(a)}},"@ai.weget.jp/skill-gmo-coin":{getConfig:()=>st(Y().getConfig()),saveConfig:async t=>{const e=Y(),a=await e.saveConfig({...e.getConfig(),...st(t)});return"connected"===O?.getStatus()&&dt(),st(a)}}},St=t=>{const e=String(t||"").trim(),a=yt[e];if(!a)throw new Error(`skill config is not managed by bot host: ${t}`);return a},ft=async()=>{await Q.ensureInstallRoot(),await lt(),await(async()=>{const t=[{packageName:"@ai.weget.jp/skill-gmo-fx",runtime:V()},{packageName:"@ai.weget.jp/skill-gmo-coin",runtime:Z()}];for(const e of t)if(e.runtime)try{await e.runtime.loadConfig()}catch(t){q("[config] local skill config load failed",{package_name:e.packageName,error:t instanceof Error?t.message:String(t)})}})();const t=await async function(){try{const t=await e.readFile(C(),"utf8"),a=JSON.parse(t);return(Array.isArray(a?.items)?a.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:$(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&&(W.applySnapshots(t),q("[skills] restored local snapshot",{count:t.length}),await ct(t)),dt()};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:I,heartbeatSec:30,reconnectMs:3e3,reconnectMaxAttempts:10,wsPingIntervalSec:25,wsPongTimeoutSec:12},{onLog:(t,e)=>q(t,e),onStatus:t=>{B.emitBotStatus({status:t}),dt()},onLineMessage:async t=>{const e=String(t.line_user_id||""),a=String(t.text||"").trim();if(L({type:"line_user",lineUserId:e,text:a}),!a)return{answer:""};try{const t=await nt.runPrompt({prompt:a,contextLabel:"line_message"});return L({type:"line_assistant",lineUserId:e,text:t}),{answer:t}}catch(t){const a=t instanceof Error?t.message:String(t);q("[ai] line reply failed",{error:a});const i=`AI error: ${a}`;return L({type:"line_assistant",lineUserId:e,text:i}),{answer:i}}},onRunTask:async t=>{const e=String(t.task_id||"").trim(),a=String(t.prompt||"").trim(),i=$(t.metadata_json),r=$(t.prompt_bundle),s=$(t.runtime_config),n=String(i.source||r.source||"").trim(),o=String(i.channel||r.channel||"").trim(),l=String(t.skill_id||i.skill_id||r.skill_id||"").trim(),c=String(t.bot_id||E?.botId||"").trim(),d=String(i.line_user_id||"").trim(),g=String(i.line_reply_token||"").trim(),m="line"===n||"line"===o||Boolean(d&&g),k="bot_host"===n,y=String(t.model||s.chat_model||"").trim(),S=String(s.system_prompt||r.system_prompt||"").trim();if(!e)return void q("[task] run_task missing task_id");const f=(new Date).toISOString();if(j.set(e,{cancelled:!1,abortController:new AbortController,taskId:e,title:String(t.title||a.slice(0,120)||e).trim(),prompt:a,status:"Task received",source:n||"unknown",channel:o||"",lineUserId:d||void 0,conversationId:String(t.conversation_id||"").trim()||void 0,startedAt:f,lastProgressAt:f}),R(),m&&d&&a&&L({type:"line_user",lineUserId:d,text:a}),O?.sendTaskEvent(e,"task_received",{prompt:a,conversation_id:String(t.conversation_id||""),continue_from_task_id:String(t.continue_from_task_id||""),ts:(new Date).toISOString()}),!a)return O?.sendTaskResult(e,"failed",{error:"prompt is required",data_json:{ts:(new Date).toISOString()}}),void j.delete(e);try{if(k||m){const t=at({isLineTask:m,status:"Task received"});L({type:"assistant_status",status:t}),N(e,{status:t})}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 f=await nt.runPrompt({prompt:a,model:y||void 0,systemPrompt:S||void 0,contextLabel:`task:${e}`,promptBundle:r,metadata:i,onStatus:k||m?t=>{const a=at({isLineTask:m,status:t});L({type:"assistant_status",status:a}),N(e,{status:a})}:void 0,abortSignal:j.get(e)?.abortController.signal}),_=u(f),w=_.pendingRequest,b=_.arbitrationAction,v=_.visibleText||p(f),h=j.get(e);if(h?.cancelled)return O?.sendTaskResult(e,"cancelled",G(h,"server_cancelled")),void F(e);let I=null;if(b){if(I=await K({taskId:e,directive:b,promptBundle:r}),!I.ok&&"cancel_running_task"===b.action)throw new Error("error"in I&&I.error||"failed to cancel running task");if("start_new_task"===b.action){const t=await(async({taskId:t,prompt:e,visibleAnswer:a,source:i,channel:r,botId:s,skillId:n,runtimeConfig:o,promptBundle:l,metadata:c})=>{const d=String(l.conversation_id||"").trim();if(!d)return{ok:!1,error:"conversation_id is required for start_new_task"};const g={...c,arbitration_parent_task_id:t,arbitration_decision:"start_new_task",arbitration_visible_answer:a},m=await z.request({method:"POST",path:"/bot/tasks",body:{source:i||null,channel:r||null,bot_id:s,skill_id:n||void 0,prompt:e,title:e.slice(0,80),conversation_id:d,continue_from_task_id:t,model:String(o.chat_model||"").trim()||void 0,sandbox_mode:String(o.sandbox_mode||"").trim()||void 0,approval_policy:String(o.approval_policy||"").trim()||void 0,metadata_json:g}});return{ok:!0,taskId:String($(m.task).task_id||"").trim()||null,dispatch:$(m.dispatch_result)}})({taskId:e,prompt:a,visibleAnswer:v,source:n,channel:o,botId:c,skillId:l||void 0,runtimeConfig:s,promptBundle:r,metadata:i});if(!t.ok)throw new Error(t.error||"failed to queue arbitrated new task");I={ok:!0,mode:"local"===I.mode||"platform"===I.mode||"advisory"===I.mode?I.mode:"advisory",queuedTaskId:t.taskId,dispatch:t.dispatch}}}if(O?.sendTaskEvent(e,"ai_output",{summary:v,action:b?.action||null,ts:(new Date).toISOString()}),k&&L({type:"assistant",text:v}),m&&d&&g){L({type:"line_assistant",lineUserId:d,text:v});const a={bot_id:String(t.bot_id||E?.botId||""),line_user_id:d,line_reply_token:g,text:v};try{await H(a)}catch(t){q("[line] callback line reply failed",{error:t instanceof Error?t.message:String(t)})}O?.sendTaskEvent(e,"line_message_ai_output",{line_user_id:d,answer:v,ts:(new Date).toISOString()})}if(O?.sendTaskEvent(e,"step_finished",{step:"codex_chat",action:b?.action||null,ts:(new Date).toISOString()}),w)return"approval"===w.requestType?O?.requestTaskApproval(e,{prompt:w.prompt,approval_type:w.subtype||"generic",data_json:{prompt:w.prompt,approval_type:w.subtype||"generic",ts:(new Date).toISOString()}}):O?.requestTaskInput(e,{prompt:w.prompt,input_type:w.subtype||"text",data_json:{prompt:w.prompt,input_type:w.subtype||"text",ts:(new Date).toISOString()}}),l&&O?.sendSkillStatus(e,{skill_id:l,status:"approval"===w.requestType?"waiting_approval":"waiting_input",summary:w.prompt.slice(0,200),data_json:{ts:(new Date).toISOString(),request_type:w.requestType}}),void F(e);O?.sendTaskResult(e,"succeeded",{summary:v.slice(0,500),data_json:{ts:(new Date).toISOString(),action:b?.action||null,target_task_id:b?.targetTaskId||null,action_reason:b?.reason||null,action_mode:I?.mode||null,queued_task_id:I?.queuedTaskId||null}}),l&&O?.sendSkillStatus(e,{skill_id:l,status:"succeeded",summary:v.slice(0,200),data_json:{ts:(new Date).toISOString()}})}catch(a){if(k){const t=`Error: ${a instanceof Error?a.message:String(a)}`;L({type:"assistant",text:t})}const i=j.get(e);if(i?.cancelled)return O?.sendTaskResult(e,"cancelled",G(i,"server_cancelled")),void F(e);if(m&&d&&g){const e=`AI error: ${a instanceof Error?a.message:String(a)}`;L({type:"line_assistant",lineUserId:d,text:e});const i={bot_id:String(t.bot_id||E?.botId||""),line_user_id:d,line_reply_token:g,text:e};try{await H(i)}catch(t){q("[line] callback line reply failed",{error:t instanceof Error?t.message:String(t)})}}O?.sendTaskResult(e,"failed",{error:a instanceof Error?a.message:String(a),data_json:{ts:(new Date).toISOString()}}),l&&O?.sendSkillStatus(e,{skill_id:l,status:"failed",summary:a instanceof Error?a.message:String(a),data_json:{ts:(new Date).toISOString()}})}finally{F(e)}},onTaskControl:async t=>{const e=String(t.task_id||"").trim(),a=String(t.action||"").trim();if(e&&a&&"cancel_task"===a){const a=j.get(e);if(a){a.cancelled=!0,a.cancelReason="server_cancelled",a.cancelRequestedByAction="cancel_task",a.abortController.abort();const i=String(t.skill_id||"").trim();return i&&O?.sendSkillStatus(e,{skill_id:i,status:"cancelled",summary:"server_cancelled",data_json:{ts:(new Date).toISOString()}}),void q("[task] cancel requested",{task_id:e})}O?.sendTaskResult(e,"cancelled",G(void 0,"server_cancelled"))}},onServerConfigUpdate:async t=>{const e=Array.isArray(t.scopes)?t.scopes.map(t=>String(t||"").trim()):[],a=e.length>0?e:["runtime","skills"];a.includes("runtime")&&await gt(),a.includes("skills")&&await mt()}}),o({ipcMain:w,env:{capabilities:I,loginApiUrl:s.loginApiUrl},signInWithLoginApi:J.signInWithLoginApi,saveLoginProfile:async({botId:t,email:a,password:i,remember:r})=>{if(r)await e.writeFile(x(),JSON.stringify({botId:t,email:a,password:i,remember:!0,updatedAt:(new Date).toISOString()},null,2),"utf8");else try{await e.unlink(x())}catch(t){if("ENOENT"!==t?.code)throw t}},readSavedLoginProfile:async()=>{try{const t=await e.readFile(x(),"utf8"),a=JSON.parse(t);return{botId:String(a?.botId||""),email:String(a?.email||""),password:String(a?.password||""),remember:Boolean(a?.remember)}}catch(t){if("ENOENT"===t?.code)return{botId:"",email:"",password:"",remember:!1};throw t}},getSkillConfig:t=>({config:St(t).getConfig()}),saveSkillConfig:async(t,e)=>({config:await St(t).saveConfig(e)}),getAiConfig:()=>({aiModel:String(P.aiModel||"gpt-5.4"),logOutputDir:String(P.logOutputDir||"")}),saveAiConfig:async t=>{const e=t&&"object"==typeof t?t:{},a=await ot({...P,...e}),i=V(),r=Z(),s=i?await i.saveConfig({...i.getConfig(),...e}):null;return r&&await r.saveConfig({...r.getConfig(),...e}),{aiModel:String(a.aiModel||s?.aiModel||e.aiModel||"gpt-5.4"),logOutputDir:String(a.logOutputDir||"")}},setCurrentSession:t=>{E=t||null;const e=E?"connected":"disconnected";B.emitBotStatus({status:e})},getCurrentSession:()=>E,getActiveSkills:()=>W.getActiveSkills().map(t=>({name:t.name,displayName:t.displayName,version:t.version})),getCodexAuthStatus:()=>nt.getAuthStatus(),getCodexMcpStatus:t=>nt.getMcpServerStatus(t),getPlaywrightBrowserStatus:()=>nt.getPlaywrightBrowserStatus(),startCodexLogin:()=>nt.startLogin(),installPlaywrightMcp:()=>nt.installWegetGatewayMcp(),getGatewayContextFilePath:()=>nt.getGatewayContextFilePath(),runGatewaySelfTest:t=>nt.runGatewaySelfTest(t),getManagedSkills:()=>W.getManagedSkills().map(t=>({...t,ui:Q.getLoadedSkill(t.name)?.ui||void 0})),getMacroSnapshot:async({force:t}={})=>(pt(),tt().getSnapshot({force:t})),getMacroCalendar:async({dateKey:t})=>(pt(),tt().listCalendar({dateKey:t})),getMacroNews:async({dateKey:t})=>(pt(),tt().listNews({dateKey:t})),emitLog:q,openGmoKlineWindow:async({symbol:t,interval:e,market:a})=>(()=>{const i="fx"===a?"fx":"coin";return ut(i),("fx"===i?X().marketData:Y().marketData).fetchKline({symbol:t,interval:e,market:i})})(),getGmoMarketQuotes:async({market:t,symbols:e})=>(()=>{const a="fx"===t?"fx":"coin";return ut(a),("fx"===a?X().marketData:Y().marketData).fetchQuotes({market:a,symbols:e})})(),getGmoSymbolRules:async({market:t})=>(()=>{const e="fx"===t?"fx":"coin";return ut(e),("fx"===e?X().marketData:Y().marketData).fetchSymbolRules({market:e})})(),getGmoBuyingPower:async({market:t})=>({market:t,availableJpy:await(ut(t),("fx"===t?X().gateway:Y().gateway).getBuyingPower(t))}),getGmoAccountMetrics:async({market:t})=>(ut(t),("fx"===t?X().gateway:Y().gateway).getAccountMetrics(t)),getGmoPositionSummary:async({market:t,symbol:e})=>({market:t,symbol:e,items:await(ut(t),("fx"===t?X().gateway:Y().gateway).getPositionSummary({market:t,symbol:e}))}),getGmoOpenPositions:async({market:t,symbol:e,page:a,prevId:i,count:r})=>({market:t,symbol:e||"",items:await(ut(t),("fx"===t?X().gateway:Y().gateway).getOpenPositions({market:"fx"===t?"fx":"crypto",symbol:e||void 0,page:a,prevId:i,count:r}))}),placeGmoFxOrder:async({symbol:t,side:e,size:a})=>{ut("fx");return await it(X(),"placeFxOrder")({symbol:t,side:e,size:a,executionType:"MARKET"})},placeGmoCoinOrder:async({symbol:t,side:e,size:a})=>{ut("coin");return await it(Y(),"placeCoinOrder")({symbol:t,side:e,size:a,executionType:"MARKET"})},placeGmoFxCloseOrder:async({symbol:t,side:e,positionId:a,size:i})=>{ut("fx");return await it(X(),"placeFxCloseOrder")({symbol:t,side:e,positionId:a,size:i,executionType:"MARKET"})},placeGmoCoinCloseOrder:async({symbol:t,side:e,positionId:a,size:i})=>{ut("coin");return await it(Y(),"placeCoinCloseOrder")({symbol:t,side:e,positionId:a,size:i,executionType:"MARKET"})},getGmoApiState:t=>{const e="fx"===t?V():Z();return e?.status.getApiState()||"unknown"},testGmoApi:t=>(ut(t),"fx"===t?X().status.testApi():Y().status.testApi()),buildTradeStatusSnapshot:t=>(ut(t),"fx"===t?X().status.buildSnapshot():Y().status.buildSnapshot()),closeTradeWindows:()=>{},startWsClient:t=>{O?.start(t),gt().catch(t=>{q("[config] runtime sync failed after login",{error:t instanceof Error?t.message:String(t)})}),mt().catch(t=>{q("[config] skill sync failed after login",{error:t instanceof Error?t.message:String(t)})}),dt()},stopWsClient:()=>{V()?.stopExecutionStreams(),Z()?.stopExecutionStreams(),et()?.stop?.(),O?.stop(),R()},handleBotChatMessage:async({text:t})=>{const e=String(t||"").trim(),a=String(E?.botId||"").trim();if(!e)throw new Error("message is required");if(!a)throw new Error("bot session is not ready");L({type:"assistant_status",status:"Submitting task"});const i=await z.request({method:"POST",path:"/bot/tasks",body:{source:"bot_host",bot_id:a,prompt:e,title:e.slice(0,80),channel:"desktop",metadata_json:{source:"bot_host",channel:"desktop"}}}),r=$(i.dispatch_result);if(!1===r.delivered)throw new Error(`task queued but bot is offline (${String(r.status||"offline")})`);return{answer:"",taskId:String($(i.task).task_id||"")}},getActiveTaskRuntimes:()=>Array.from(j.values()).map(U),cancelActiveTaskRuntime:async t=>{const e=j.get(String(t||"").trim());return e?(e.cancelled=!0,e.cancelReason="local_cancelled",e.cancelRequestedByAction="cancel_task",e.abortController.abort(),N(e.taskId,{status:"Cancelling..."}),q("[task] local cancel requested",{task_id:e.taskId}),{ok:!0}):{ok:!1,error:"task not found"}},writeErrorLog:async({source:t,message:e,details:a})=>{await(async({source:t,message:e,details:a})=>{await D({level:"error",source:t,message:e,details:a})})({source:t,message:e,details:a})},writeRuntimeLog:async({level:t,source:e,message:a,details:i})=>{await D({level:t,source:e,message:a,details:i})}});const _t=t.join(h,"renderer","logo.png");f.whenReady().then(async()=>{(()=>{if("darwin"!==process.platform)return;if(!a(_t))return;const t=b.createFromPath(_t);t.isEmpty()||f.dock.setIcon(t)})(),await(async()=>{try{const t=await e.readFile(A(),"utf8"),a=JSON.parse(t);P={aiModel:String(a?.aiModel||"gpt-5.4").trim()||"gpt-5.4",logOutputDir:String(a?.logOutputDir||"").trim()}}catch(t){if("ENOENT"!==t?.code)throw t;P={aiModel:"gpt-5.4",logOutputDir:""}}return P})();try{await kt.ensureStarted()}catch(t){q("[gateway-file-bridge] startup failed",{error:t instanceof Error?t.message:String(t)})}try{await ft()}catch(t){q("[skills] local initialization failed",{error:t instanceof Error?t.message:String(t)})}B.createMainWindow(),R(),f.on("activate",()=>{0===_.getAllWindows().length&&(B.createMainWindow(),R())})}),f.on("window-all-closed",()=>{V()?.stopExecutionStreams(),Z()?.stopExecutionStreams(),et()?.stop?.(),kt.stop().catch(()=>{}),O?.stop(),"darwin"!==process.platform&&f.quit()});
|