@automagik/genie 4.260405.16 → 4.260406.1

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.
@@ -10,7 +10,7 @@
10
10
  "plugins": [
11
11
  {
12
12
  "name": "genie",
13
- "version": "4.260405.16",
13
+ "version": "4.260406.1",
14
14
  "source": "./plugins/genie",
15
15
  "description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, wish them into plans, make with parallel agents, ship as one team. A coding genie that grows with your project."
16
16
  }
package/dist/genie.js CHANGED
@@ -1985,16 +1985,16 @@ ${answer}
1985
1985
  AND table_type = 'BASE TABLE'
1986
1986
  AND table_name NOT LIKE '_genie_%'
1987
1987
  ORDER BY table_name
1988
- `).map((r)=>r.table_name)}async function filterAvailableTables(sql,requested){let existing=new Set(await getAvailableTables(sql)),available=[],skipped=[];for(let table of requested)if(existing.has(table))available.push(table);else skipped.push(table);return{available,skipped}}function isValid2(value){return typeof value==="string"&&VALID.has(value)}function resolveExecutorType(override){if(isValid2(override))return override;let env=process.env.GENIE_EXECUTOR;if(isValid2(env))return env;try{let persisted=loadGenieConfigSync().omni?.executor;if(isValid2(persisted))return persisted}catch{}return"tmux"}var VALID;var init_executor_config=__esm(()=>{init_genie_config2();VALID=new Set(["tmux","sdk"])});import{createHash as createHash4,randomUUID as randomUUID8}from"crypto";import{mkdirSync as mkdirSync18,writeFileSync as writeFileSync19}from"fs";import{homedir as homedir28}from"os";import{join as join48}from"path";function sanitizeWindowName2(chatId){let hash=createHash4("md5").update(chatId).digest("hex").slice(0,12);return`${chatId.replace(/[^a-zA-Z0-9]/g,"").slice(0,24)}-${hash}`||"chat"}class ClaudeCodeOmniExecutor{sessions=new Map;safePgCall=null;setSafePgCall(fn){this.safePgCall=fn}async injectNudge(session,text){let nudgeText=`[system] ${text}`;await executeTmux2(`send-keys -t '${session.paneId}' ${shellQuote(nudgeText)} Enter`)}async spawn(agentName,chatId,env){let resolved=await resolve3(agentName);if(!resolved)throw Error(`Agent "${agentName}" not found in genie directory`);let entry=resolved.entry,tmuxSession=agentName,windowName=sanitizeWindowName2(chatId),{paneId,created}=await ensureTeamWindow(tmuxSession,windowName,entry.dir);if(created){let envVars={...env,GENIE_OMNI_CHAT_ID:chatId,GENIE_OMNI_AGENT:agentName},envPrefix=Object.entries(envVars).map(([k,v])=>`${k}=${shellQuote(v)}`).join(" "),systemPromptFile=join48(entry.dir,"AGENTS.md"),promptFlag=entry.promptMode==="system"?"--system-prompt-file":"--append-system-prompt-file",modelFlag=entry.model?`--model ${shellQuote(entry.model)}`:"",sessionId=randomUUID8(),cmd=[envPrefix,"claude",promptFlag,shellQuote(systemPromptFile),modelFlag,"--session-id",shellQuote(sessionId),"--dangerously-skip-permissions"].filter(Boolean).join(" ");await executeTmux2(`send-keys -t '${paneId}' ${shellQuote(cmd)} Enter`)}let sessionKey2=`${agentName}:${chatId}`,executorId=await this.registerInWorldA(agentName,chatId,env.OMNI_INSTANCE??"",tmuxSession,windowName,paneId);if(this.sessions.set(sessionKey2,{executorId}),executorId)await this.updateState(executorId,"running",chatId);let now=Date.now();return{id:sessionKey2,agentName,chatId,tmuxSession,tmuxWindow:windowName,paneId,createdAt:now,lastActivityAt:now}}async registerInWorldA(agentName,chatId,instanceId,tmuxSession,tmuxWindow,tmuxPaneId){if(!this.safePgCall)return null;let agent=await this.safePgCall("tmux-find-or-create-agent",()=>findOrCreateAgent(agentName,"omni","omni"),null,{chatId});if(!agent)return null;return(await this.safePgCall("tmux-create-executor",()=>createAndLinkExecutor(agent.id,"claude","tmux",{tmuxSession,tmuxWindow,tmuxPaneId,tmuxWindowId:null,metadata:{source:"omni",chat_id:chatId,instance_id:instanceId}}),null,{chatId}))?.id??null}async updateState(executorId,state,chatId){if(!this.safePgCall)return;await this.safePgCall("tmux-update-executor-state",()=>updateExecutorState(executorId,state),void 0,{executorId,chatId})}async deliver(session,message){let state=this.sessions.get(session.id);if(state?.executorId)await this.updateState(state.executorId,"working",session.chatId);let inboxDir=join48(process.env.CLAUDE_CONFIG_DIR??join48(homedir28(),".claude"),"teams",session.tmuxSession,"inboxes");mkdirSync18(inboxDir,{recursive:!0});let inboxFile=join48(inboxDir,`${sanitizeWindowName2(session.chatId)}.json`),messages2=[];try{let{readFileSync:readFileSync22}=await import("fs");messages2=JSON.parse(readFileSync22(inboxFile,"utf-8"))}catch{}if(messages2.push({from:message.sender||"whatsapp-user",text:message.content,summary:message.content.slice(0,120),timestamp:message.timestamp||new Date().toISOString(),read:!1}),writeFileSync19(inboxFile,JSON.stringify(messages2,null,2)),session.lastActivityAt=Date.now(),state?.executorId)await this.updateState(state.executorId,"idle",session.chatId)}async shutdown(session){let state=this.sessions.get(session.id);try{await killWindow(session.tmuxSession,session.tmuxWindow)}finally{if(state?.executorId&&this.safePgCall)await this.safePgCall("tmux-terminate-executor",()=>terminateExecutor(state.executorId),void 0,{executorId:state.executorId,chatId:session.chatId});this.sessions.delete(session.id)}}async isAlive(session){try{if(!await isPaneAlive(session.paneId))return!1;return await isPaneProcessRunning(session.paneId,"claude")}catch{return!1}}}var init_claude_code2=__esm(()=>{init_agent_directory();init_agent_registry();init_executor_registry();init_team_lead_command();init_tmux()});async function recordAuditEvent2(safePgCall,type2,attrs){let entityType=attrs.entity_type??"executor",entityId=attrs.entity_id??attrs.executor_id??"",actor=attrs.actor??attrs.agent_id??null,{entity_type:_et,entity_id:_eid,actor:_a,...details}=attrs;await safePgCall(`audit:${type2}`,(sql)=>sql`INSERT INTO audit_events (entity_type, entity_id, event_type, actor, details)
1988
+ `).map((r)=>r.table_name)}async function filterAvailableTables(sql,requested){let existing=new Set(await getAvailableTables(sql)),available=[],skipped=[];for(let table of requested)if(existing.has(table))available.push(table);else skipped.push(table);return{available,skipped}}function isValid2(value){return typeof value==="string"&&VALID.has(value)}function resolveExecutorType(override){if(isValid2(override))return override;let env=process.env.GENIE_EXECUTOR;if(isValid2(env))return env;try{let persisted=loadGenieConfigSync().omni?.executor;if(isValid2(persisted))return persisted}catch{}return"tmux"}var VALID;var init_executor_config=__esm(()=>{init_genie_config2();VALID=new Set(["tmux","sdk"])});import{createHash as createHash4,randomUUID as randomUUID8}from"crypto";import{mkdirSync as mkdirSync18,writeFileSync as writeFileSync19}from"fs";import{homedir as homedir28}from"os";import{join as join48}from"path";function sanitizeWindowName2(chatId){let hash=createHash4("md5").update(chatId).digest("hex").slice(0,12);return`${chatId.replace(/[^a-zA-Z0-9]/g,"").slice(0,24)}-${hash}`||"chat"}class ClaudeCodeOmniExecutor{sessions=new Map;safePgCall=null;setSafePgCall(fn){this.safePgCall=fn}setNatsPublish(_fn){}async injectNudge(session,text){let nudgeText=`[system] ${text}`;await executeTmux2(`send-keys -t '${session.paneId}' ${shellQuote(nudgeText)} Enter`)}async spawn(agentName,chatId,env){let resolved=await resolve3(agentName);if(!resolved)throw Error(`Agent "${agentName}" not found in genie directory`);let entry=resolved.entry,tmuxSession=agentName,windowName=sanitizeWindowName2(chatId),{paneId,created}=await ensureTeamWindow(tmuxSession,windowName,entry.dir);if(created){let envVars={...env,GENIE_OMNI_CHAT_ID:chatId,GENIE_OMNI_AGENT:agentName},envPrefix=Object.entries(envVars).map(([k,v])=>`${k}=${shellQuote(v)}`).join(" "),systemPromptFile=join48(entry.dir,"AGENTS.md"),promptFlag=entry.promptMode==="system"?"--system-prompt-file":"--append-system-prompt-file",modelFlag=entry.model?`--model ${shellQuote(entry.model)}`:"",sessionId=randomUUID8(),cmd=[envPrefix,"claude",promptFlag,shellQuote(systemPromptFile),modelFlag,"--session-id",shellQuote(sessionId),"--dangerously-skip-permissions"].filter(Boolean).join(" ");await executeTmux2(`send-keys -t '${paneId}' ${shellQuote(cmd)} Enter`)}let sessionKey2=`${agentName}:${chatId}`,executorId=await this.registerInWorldA(agentName,chatId,env.OMNI_INSTANCE??"",tmuxSession,windowName,paneId);if(this.sessions.set(sessionKey2,{executorId}),executorId)await this.updateState(executorId,"running",chatId);let now=Date.now();return{id:sessionKey2,agentName,chatId,tmuxSession,tmuxWindow:windowName,paneId,createdAt:now,lastActivityAt:now}}async registerInWorldA(agentName,chatId,instanceId,tmuxSession,tmuxWindow,tmuxPaneId){if(!this.safePgCall)return null;let agent=await this.safePgCall("tmux-find-or-create-agent",()=>findOrCreateAgent(agentName,"omni","omni"),null,{chatId});if(!agent)return null;return(await this.safePgCall("tmux-create-executor",()=>createAndLinkExecutor(agent.id,"claude","tmux",{tmuxSession,tmuxWindow,tmuxPaneId,tmuxWindowId:null,metadata:{source:"omni",chat_id:chatId,instance_id:instanceId}}),null,{chatId}))?.id??null}async updateState(executorId,state,chatId){if(!this.safePgCall)return;await this.safePgCall("tmux-update-executor-state",()=>updateExecutorState(executorId,state),void 0,{executorId,chatId})}async deliver(session,message){let state=this.sessions.get(session.id);if(state?.executorId)await this.updateState(state.executorId,"working",session.chatId);let inboxDir=join48(process.env.CLAUDE_CONFIG_DIR??join48(homedir28(),".claude"),"teams",session.tmuxSession,"inboxes");mkdirSync18(inboxDir,{recursive:!0});let inboxFile=join48(inboxDir,`${sanitizeWindowName2(session.chatId)}.json`),messages2=[];try{let{readFileSync:readFileSync22}=await import("fs");messages2=JSON.parse(readFileSync22(inboxFile,"utf-8"))}catch{}if(messages2.push({from:message.sender||"whatsapp-user",text:message.content,summary:message.content.slice(0,120),timestamp:message.timestamp||new Date().toISOString(),read:!1}),writeFileSync19(inboxFile,JSON.stringify(messages2,null,2)),session.lastActivityAt=Date.now(),state?.executorId)await this.updateState(state.executorId,"idle",session.chatId)}async shutdown(session){let state=this.sessions.get(session.id);try{await killWindow(session.tmuxSession,session.tmuxWindow)}finally{if(state?.executorId&&this.safePgCall)await this.safePgCall("tmux-terminate-executor",()=>terminateExecutor(state.executorId),void 0,{executorId:state.executorId,chatId:session.chatId});this.sessions.delete(session.id)}}async isAlive(session){try{if(!await isPaneAlive(session.paneId))return!1;return await isPaneProcessRunning(session.paneId,"claude")}catch{return!1}}}var init_claude_code2=__esm(()=>{init_agent_directory();init_agent_registry();init_executor_registry();init_team_lead_command();init_tmux()});async function recordAuditEvent2(safePgCall,type2,attrs){let entityType=attrs.entity_type??"executor",entityId=attrs.entity_id??attrs.executor_id??"",actor=attrs.actor??attrs.agent_id??null,{entity_type:_et,entity_id:_eid,actor:_a,...details}=attrs;await safePgCall(`audit:${type2}`,(sql)=>sql`INSERT INTO audit_events (entity_type, entity_id, event_type, actor, details)
1989
1989
  VALUES (${entityType}, ${entityId}, ${type2}, ${actor}, ${JSON.stringify(details)})`,void 0,{executorId:entityId,chatId:attrs.chat_id??""})}async function startSession(safePgCall,executorId,claudeSessionId,agentId,team,role,wishSlug){let sessionId=claudeSessionId??`sdk-${executorId}-${Date.now()}`;if(!await safePgCall("sdk-session-start",(sql)=>sql`INSERT INTO sessions (id, agent_id, executor_id, team, role, wish_slug, status, jsonl_path, project_path)
1990
1990
  VALUES (${sessionId}, ${agentId}, ${executorId}, ${team??null}, ${role??null}, ${wishSlug??null}, 'active', '', '')
1991
1991
  ON CONFLICT (id) DO NOTHING
1992
1992
  RETURNING id`,null,{executorId,chatId:""}))return null;return sessionId}async function recordTurn(safePgCall,sessionId,turnIndex,role,content,toolName,timestamp2){let ts3=timestamp2??new Date().toISOString();await safePgCall("sdk-session-turn",(sql)=>sql`INSERT INTO session_content (session_id, turn_index, role, content, tool_name, timestamp)
1993
1993
  VALUES (${sessionId}, ${turnIndex}, ${role}, ${content}, ${toolName??null}, ${ts3})
1994
- ON CONFLICT (session_id, turn_index) DO NOTHING`,void 0,{executorId:"",chatId:""})}async function updateTurnCount(safePgCall,sessionId,totalTurns){await safePgCall("sdk-session-turn-count",(sql)=>sql`UPDATE sessions SET total_turns = ${totalTurns}, updated_at = now() WHERE id = ${sessionId}`,void 0,{executorId:"",chatId:""})}async function endSession(safePgCall,sessionId,status="completed"){await safePgCall("sdk-session-end",(sql)=>sql`UPDATE sessions SET ended_at = now(), status = ${status}, updated_at = now() WHERE id = ${sessionId}`,void 0,{executorId:"",chatId:""})}import{execFile as execFileCb}from"child_process";import{promisify as promisify3}from"util";async function loadSystemPrompt(entry){let identityPath=loadIdentity(entry);if(!identityPath)return;let{readFileSync:readFileSync22}=await import("fs");try{return readFileSync22(identityPath,"utf-8")}catch{return}}function extractTextFromAssistant(msg){if(!msg.message)return[];return msg.message.content.filter((b2)=>b2.type==="text"&&b2.text).map((b2)=>b2.text)}async function collectQueryResult(queryMessages){let textParts=[],sessionId;try{for await(let msg of queryMessages){if(msg.type==="assistant")textParts.push(...extractTextFromAssistant(msg));if(msg.type==="result"&&msg.subtype==="success")sessionId=msg.session_id}}catch(err){if(err.name==="AbortError")return{text:""};throw err}return{text:textParts.join(`
1995
- `).trim(),sessionId}}async function handleDoneTool(params,env){let args=["done"];if(params.skip){if(args.push("--skip"),params.reason)args.push("--reason",String(params.reason))}else if(params.react)args.push("--react",String(params.react));else if(params.media){if(args.push("--media",String(params.media)),params.caption)args.push("--caption",String(params.caption));if(params.text)args.push(String(params.text))}else if(params.text)args.push(String(params.text));else args.push("--skip");try{return await execFileAsync("omni",args,{env:{...process.env,...env}}),"Turn closed. Message delivered."}catch(err){let msg=err instanceof Error?err.message:String(err);return console.warn(`[claude-sdk] omni done failed: ${msg}`),`Turn close attempted but omni done failed: ${msg}`}}async function createDoneMcpServer(env){let{createSdkMcpServer,tool}=await import("@anthropic-ai/claude-agent-sdk");return createSdkMcpServer({name:"genie-omni-tools",tools:[tool("done","Close this turn. REQUIRED after processing the user message. Sends a final response, reacts, or skips. Call exactly once per turn.",{text:exports_external.string().optional().describe("Final message to the user"),media:exports_external.string().optional().describe("File path for media attachment"),caption:exports_external.string().optional().describe("Caption for media"),react:exports_external.string().optional().describe("Emoji reaction (instead of text)"),skip:exports_external.boolean().optional().describe("Close turn without sending anything"),reason:exports_external.string().optional().describe("Internal reason for skipping")},async(args)=>{return{content:[{type:"text",text:await handleDoneTool(args,env)}]}})]})}class ClaudeSdkOmniExecutor{sessions=new Map;safePgCall=null;deliveryQueues=new Map;pendingNudges=new Map;setSafePgCall(fn){this.safePgCall=fn}async injectNudge(session,text){if(!this.sessions.has(session.id))return;this.pendingNudges.set(session.id,text)}async spawn(agentName,chatId,env){if(!await resolve3(agentName))throw Error(`Agent "${agentName}" not found in genie directory`);let provider=new ClaudeSdkProvider,abortController=new AbortController,sessionId=`${agentName}:${chatId}`,registration=await this.registerInWorldA(agentName,chatId,env.OMNI_INSTANCE??"");if(this.sessions.set(sessionId,{abortController,running:!0,provider,executorId:registration?.executorId??null,claudeSessionId:registration?.claudeSessionId,dbSessionId:null,turnIndex:0,env}),registration?.executorId)await this.updateState(registration.executorId,"running",chatId);let now=Date.now();return{id:sessionId,agentName,chatId,tmuxSession:"",tmuxWindow:"",paneId:`sdk-${chatId}`,createdAt:now,lastActivityAt:now}}async registerInWorldA(agentName,chatId,instanceId){if(!this.safePgCall)return null;let agent=await this.safePgCall("sdk-find-or-create-agent",()=>findOrCreateAgent(agentName,"omni","omni"),null,{chatId});if(!agent)return null;let existing=await this.safePgCall("sdk-find-existing-executor",()=>findLatestByMetadata({agentId:agent.id,source:"omni",chatId}),null,{chatId});if(existing)return await this.safePgCall("sdk-relink-executor",()=>relinkExecutorToAgent(existing.id,agent.id),void 0,{executorId:existing.id,chatId}),await recordAuditEvent2(this.safePgCall,"session.resumed",{executor_id:existing.id,agent_id:agentName,chat_id:chatId,claude_session_id:existing.claudeSessionId}),{executorId:existing.id,claudeSessionId:existing.claudeSessionId??void 0};let executor=await this.safePgCall("sdk-create-executor",()=>createAndLinkExecutor(agent.id,"claude","api",{claudeSessionId:void 0,metadata:{source:"omni",chat_id:chatId,instance_id:instanceId}}),null,{chatId});if(executor)await recordAuditEvent2(this.safePgCall,"session.created_fresh",{executor_id:executor.id,agent_id:agentName,chat_id:chatId});return executor?{executorId:executor.id}:null}async updateState(executorId,state,chatId){if(!this.safePgCall)return;await this.safePgCall("sdk-update-executor-state",()=>updateExecutorState(executorId,state),void 0,{executorId,chatId})}async deliver(session,message){let state=this.sessions.get(session.id);if(!state)throw Error(`No SDK session found for ${session.id}`);let current=(this.deliveryQueues.get(session.id)??Promise.resolve()).then(()=>this._processDelivery(session,state,message));this.deliveryQueues.set(session.id,current.catch(()=>{}))}async _processDelivery(session,state,message){let resolved=await resolve3(session.agentName);if(!resolved)throw Error(`Agent "${session.agentName}" not found in genie directory`);let entry=resolved.entry,permissionConfig=resolvePermissionConfig(entry.permissions),systemPrompt=await loadSystemPrompt(entry);if(state.executorId)await this.updateState(state.executorId,"working",session.chatId);if(this.safePgCall)await recordAuditEvent2(this.safePgCall,"deliver.start",{executor_id:state.executorId??session.id,agent_id:session.agentName,chat_id:message.chatId,instance_id:message.instanceId});let doneMcp=await createDoneMcpServer(state.env),extraOptions={abortController:state.abortController,mcpServers:{"genie-omni-tools":doneMcp}};if(state.claudeSessionId)extraOptions.resume=state.claudeSessionId;let queryContent=message.content,pendingNudge=this.pendingNudges.get(session.id);if(pendingNudge)queryContent=`[system] ${pendingNudge}
1994
+ ON CONFLICT (session_id, turn_index) DO NOTHING`,void 0,{executorId:"",chatId:""})}async function updateTurnCount(safePgCall,sessionId,totalTurns){await safePgCall("sdk-session-turn-count",(sql)=>sql`UPDATE sessions SET total_turns = ${totalTurns}, updated_at = now() WHERE id = ${sessionId}`,void 0,{executorId:"",chatId:""})}async function endSession(safePgCall,sessionId,status="completed"){await safePgCall("sdk-session-end",(sql)=>sql`UPDATE sessions SET ended_at = now(), status = ${status}, updated_at = now() WHERE id = ${sessionId}`,void 0,{executorId:"",chatId:""})}async function loadSystemPrompt(entry){let identityPath=loadIdentity(entry);if(!identityPath)return;let{readFileSync:readFileSync22}=await import("fs");try{return readFileSync22(identityPath,"utf-8")}catch{return}}function extractTextFromAssistant(msg){if(!msg.message)return[];return msg.message.content.filter((b2)=>b2.type==="text"&&b2.text).map((b2)=>b2.text)}async function collectQueryResult(queryMessages){let textParts=[],sessionId;try{for await(let msg of queryMessages){if(msg.type==="assistant")textParts.push(...extractTextFromAssistant(msg));if(msg.type==="result"&&msg.subtype==="success")sessionId=msg.session_id}}catch(err){if(err.name==="AbortError")return{text:""};throw err}return{text:textParts.join(`
1995
+ `).trim(),sessionId}}function buildReplyPayload(agent,chatId,instanceId,extra={}){return JSON.stringify({content:"",agent,chat_id:chatId,instance_id:instanceId,timestamp:new Date().toISOString(),...extra})}function resolveAction(params,env){if(params.skip)return{type:"skip",extra:{reason:params.reason},label:"Turn closed (skip)."};if(params.react)return{type:"react",extra:{react:String(params.react),message_id:env.OMNI_MESSAGE??""},label:`Reacted ${params.react} + turn closed.`};if(params.media)return{type:"media",extra:{content:params.caption?String(params.caption):params.text?String(params.text):"",media:String(params.media)},label:"Media sent + turn closed."};if(params.text)return{type:"text",extra:{content:String(params.text)},label:"Turn closed. Message delivered."};return{type:"skip",extra:{},label:"Turn closed (skip)."}}function handleDoneTool(params,env,natsPublish){let instanceId=env.OMNI_INSTANCE??"",chatId=env.OMNI_CHAT??"",agent=env.OMNI_AGENT??"",action=resolveAction(params,env);if(action.type==="skip"){if(natsPublish&&instanceId&&chatId)natsPublish(`omni.turn.done.${instanceId}.${chatId}`,JSON.stringify({action:"skip",...action.extra}));return action.label}if(!natsPublish||!instanceId||!chatId)return console.warn("[claude-sdk] No NATS publish available \u2014 reply dropped"),"Turn close attempted but NATS publish not available.";return natsPublish(`omni.reply.${instanceId}.${chatId}`,buildReplyPayload(agent,chatId,instanceId,action.extra)),action.label}async function createDoneMcpServer(env,natsPublish){let{createSdkMcpServer,tool}=await import("@anthropic-ai/claude-agent-sdk");return createSdkMcpServer({name:"genie-omni-tools",tools:[tool("done","Close this turn. REQUIRED after processing the user message. Sends a final response, reacts, or skips. Call exactly once per turn.",{text:exports_external.string().optional().describe("Final message to the user"),media:exports_external.string().optional().describe("File path for media attachment"),caption:exports_external.string().optional().describe("Caption for media"),react:exports_external.string().optional().describe("Emoji reaction (instead of text)"),skip:exports_external.boolean().optional().describe("Close turn without sending anything"),reason:exports_external.string().optional().describe("Internal reason for skipping")},async(args)=>{return{content:[{type:"text",text:handleDoneTool(args,env,natsPublish)}]}})]})}class ClaudeSdkOmniExecutor{sessions=new Map;safePgCall=null;natsPublish=null;deliveryQueues=new Map;pendingNudges=new Map;setSafePgCall(fn){this.safePgCall=fn}setNatsPublish(fn){this.natsPublish=fn}async injectNudge(session,text){if(!this.sessions.has(session.id))return;this.pendingNudges.set(session.id,text)}async spawn(agentName,chatId,env){if(!await resolve3(agentName))throw Error(`Agent "${agentName}" not found in genie directory`);let provider=new ClaudeSdkProvider,abortController=new AbortController,sessionId=`${agentName}:${chatId}`,registration=await this.registerInWorldA(agentName,chatId,env.OMNI_INSTANCE??"");if(this.sessions.set(sessionId,{abortController,running:!0,provider,executorId:registration?.executorId??null,claudeSessionId:registration?.claudeSessionId,dbSessionId:null,turnIndex:0,env}),registration?.executorId)await this.updateState(registration.executorId,"running",chatId);let now=Date.now();return{id:sessionId,agentName,chatId,tmuxSession:"",tmuxWindow:"",paneId:`sdk-${chatId}`,createdAt:now,lastActivityAt:now}}async registerInWorldA(agentName,chatId,instanceId){if(!this.safePgCall)return null;let agent=await this.safePgCall("sdk-find-or-create-agent",()=>findOrCreateAgent(agentName,"omni","omni"),null,{chatId});if(!agent)return null;let existing=await this.safePgCall("sdk-find-existing-executor",()=>findLatestByMetadata({agentId:agent.id,source:"omni",chatId}),null,{chatId});if(existing)return await this.safePgCall("sdk-relink-executor",()=>relinkExecutorToAgent(existing.id,agent.id),void 0,{executorId:existing.id,chatId}),await recordAuditEvent2(this.safePgCall,"session.resumed",{executor_id:existing.id,agent_id:agentName,chat_id:chatId,claude_session_id:existing.claudeSessionId}),{executorId:existing.id,claudeSessionId:existing.claudeSessionId??void 0};let executor=await this.safePgCall("sdk-create-executor",()=>createAndLinkExecutor(agent.id,"claude","api",{claudeSessionId:void 0,metadata:{source:"omni",chat_id:chatId,instance_id:instanceId}}),null,{chatId});if(executor)await recordAuditEvent2(this.safePgCall,"session.created_fresh",{executor_id:executor.id,agent_id:agentName,chat_id:chatId});return executor?{executorId:executor.id}:null}async updateState(executorId,state,chatId){if(!this.safePgCall)return;await this.safePgCall("sdk-update-executor-state",()=>updateExecutorState(executorId,state),void 0,{executorId,chatId})}async deliver(session,message){let state=this.sessions.get(session.id);if(!state)throw Error(`No SDK session found for ${session.id}`);let current=(this.deliveryQueues.get(session.id)??Promise.resolve()).then(()=>this._processDelivery(session,state,message));this.deliveryQueues.set(session.id,current.catch(()=>{}))}async _processDelivery(session,state,message){let resolved=await resolve3(session.agentName);if(!resolved)throw Error(`Agent "${session.agentName}" not found in genie directory`);let entry=resolved.entry,permissionConfig=resolvePermissionConfig(entry.permissions),systemPrompt=await loadSystemPrompt(entry);if(state.executorId)await this.updateState(state.executorId,"working",session.chatId);if(this.safePgCall)await recordAuditEvent2(this.safePgCall,"deliver.start",{executor_id:state.executorId??session.id,agent_id:session.agentName,chat_id:message.chatId,instance_id:message.instanceId});let doneMcp=await createDoneMcpServer(state.env,this.natsPublish),extraOptions={abortController:state.abortController,mcpServers:{"genie-omni-tools":doneMcp}};if(state.claudeSessionId)extraOptions.resume=state.claudeSessionId;let queryContent=message.content,pendingNudge=this.pendingNudges.get(session.id);if(pendingNudge)queryContent=`[system] ${pendingNudge}
1996
1996
 
1997
- ${message.content}`,this.pendingNudges.delete(session.id);let{messages:queryMessages}=state.provider.runQuery({agentId:session.agentName,executorId:session.id,team:"",role:session.agentName,cwd:entry.dir||process.cwd(),model:entry.model,systemPrompt:state.claudeSessionId?void 0:systemPrompt},queryContent,permissionConfig,extraOptions,entry.sdk);await this.captureUserTurn(state,session.agentName,session.id,message.content);let result2=await collectQueryResult(queryMessages);if(result2.sessionId)await this.reconcileSessionId(state,session,result2.sessionId);if(await this.captureAssistantTurn(state,session.id,result2.sessionId,session.agentName,result2.text),session.lastActivityAt=Date.now(),this.safePgCall)await recordAuditEvent2(this.safePgCall,"deliver.end",{executor_id:state.executorId??session.id,agent_id:session.agentName,chat_id:message.chatId,instance_id:message.instanceId,turn_count:state.turnIndex});if(state.executorId)await this.updateState(state.executorId,"idle",session.chatId)}async reconcileSessionId(state,session,returnedSessionId){if(state.claudeSessionId&&returnedSessionId!==state.claudeSessionId&&this.safePgCall)await recordAuditEvent2(this.safePgCall,"session.resume_rejected",{executor_id:state.executorId??session.id,agent_id:session.agentName,chat_id:session.chatId,old_session_id:state.claudeSessionId,new_session_id:returnedSessionId});let execId=state.executorId;if(execId&&this.safePgCall&&returnedSessionId!==state.claudeSessionId)await this.safePgCall("sdk-update-claude-session",()=>updateClaudeSessionId(execId,returnedSessionId),void 0,{executorId:execId,chatId:session.chatId});state.claudeSessionId=returnedSessionId}async captureUserTurn(state,agentName,_sessionKey,content){if(!this.safePgCall)return;if(!state.dbSessionId&&state.executorId)state.dbSessionId=await startSession(this.safePgCall,state.executorId,state.claudeSessionId,agentName);if(state.dbSessionId)await recordTurn(this.safePgCall,state.dbSessionId,state.turnIndex++,"user",content)}async captureAssistantTurn(state,sessionKey2,claudeSessionId,agentName,replyText){if(!this.safePgCall)return;if(claudeSessionId&&state.dbSessionId?.startsWith("sdk-")){let newId=await startSession(this.safePgCall,state.executorId??sessionKey2,claudeSessionId,agentName);if(newId)state.dbSessionId=newId}if(state.dbSessionId&&replyText)await recordTurn(this.safePgCall,state.dbSessionId,state.turnIndex++,"assistant",replyText),await updateTurnCount(this.safePgCall,state.dbSessionId,state.turnIndex)}async waitForDeliveries(sessionId){if(sessionId)await this.deliveryQueues.get(sessionId);else await Promise.all([...this.deliveryQueues.values()])}async shutdown(session){let state=this.sessions.get(session.id);if(!state)return;if(state.abortController.abort(),state.running=!1,state.dbSessionId&&this.safePgCall)await endSession(this.safePgCall,state.dbSessionId,"completed");if(state.executorId&&this.safePgCall)await this.safePgCall("sdk-terminate-executor",()=>terminateExecutor(state.executorId),void 0,{executorId:state.executorId,chatId:session.chatId});this.sessions.delete(session.id),this.deliveryQueues.delete(session.id)}async isAlive(session){let state=this.sessions.get(session.id);if(!state)return!1;return state.running&&!state.abortController.signal.aborted}}var execFileAsync;var init_claude_sdk2=__esm(()=>{init_zod();init_agent_directory();init_agent_registry();init_executor_registry();init_claude_sdk_permissions();init_claude_sdk();execFileAsync=promisify3(execFileCb)});class TurnTracker{turns=new Map;open(sessionKey2,turnId,messageId){this.turns.set(sessionKey2,{turnId,sessionKey:sessionKey2,messageId,startedAt:Date.now(),closed:!1})}close(sessionKey2,action){let turn=this.turns.get(sessionKey2);if(turn&&!turn.closed)turn.closed=!0,turn.closedAction=action}isOpen(sessionKey2){let turn=this.turns.get(sessionKey2);return turn!==void 0&&!turn.closed}getTurnId(sessionKey2){return this.turns.get(sessionKey2)?.turnId}getByTurnId(turnId){for(let turn of this.turns.values())if(turn.turnId===turnId)return turn;return}delete(sessionKey2){this.turns.delete(sessionKey2)}}var exports_omni_bridge={};__export(exports_omni_bridge,{getBridge:()=>getBridge,OmniBridge:()=>OmniBridge});function getBridge(){return bridgeInstance}function withTimeout(p,ms,label){return new Promise((resolve9,reject)=>{let timer2=setTimeout(()=>reject(Error(`${label} timed out after ${ms}ms`)),ms);timer2.unref?.(),p.then((v)=>{clearTimeout(timer2),resolve9(v)},(err)=>{clearTimeout(timer2),reject(err)})})}function isPgConnectionError(err){if(!err||typeof err!=="object")return!1;let e=err,code=e.code??"";if(["ECONNREFUSED","ECONNRESET","ETIMEDOUT","ENOTFOUND","EPIPE","EHOSTUNREACH"].includes(code))return!0;let msg=e.message??String(err);return/ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENOTFOUND|EPIPE|connection terminated|connection closed|server closed the connection|the database system is shutting down/i.test(msg)}class OmniBridge{nc=null;sub=null;executor;turnTracker=new TurnTracker;sessions=new Map;messageQueue=[];idleCheckTimer=null;sc=import_nats3.StringCodec();sql=null;pgAvailable=!1;pgProvider;natsConnectFn;natsUrl;idleTimeoutMs;maxConcurrent;executorType;constructor(config={}){if(this.natsUrl=config.natsUrl??process.env.GENIE_NATS_URL??DEFAULT_NATS_URL,this.idleTimeoutMs=config.idleTimeoutMs??(process.env.GENIE_IDLE_TIMEOUT_MS?Number(process.env.GENIE_IDLE_TIMEOUT_MS):DEFAULT_IDLE_TIMEOUT_MS2),this.maxConcurrent=config.maxConcurrent??(process.env.GENIE_MAX_CONCURRENT?Number(process.env.GENIE_MAX_CONCURRENT):DEFAULT_MAX_CONCURRENT),this.pgProvider=config.pgProvider??(async()=>{let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db));return await getConnection2()}),this.natsConnectFn=config.natsConnectFn??import_nats3.connect,this.executorType=resolveExecutorType(config.executorType),this.executorType==="sdk")this.executor=new ClaudeSdkOmniExecutor;else this.executor=new ClaudeCodeOmniExecutor}async start(){if(this.nc){console.log("[omni-bridge] Already running");return}console.log(`[omni-bridge] Connecting to NATS at ${this.natsUrl}...`),this.nc=await this.natsConnectFn({servers:this.natsUrl,name:"genie-omni-bridge",reconnect:!0,maxReconnectAttempts:-1,reconnectTimeWait:2000}),console.log("[omni-bridge] Connected to NATS"),await this.probePg(),this.executor.setSafePgCall(this.safePgCall.bind(this)),this.sub=this.nc.subscribe("omni.message.>"),this.processSubscription();let turnSubs=["omni.turn.open.>","omni.turn.done.>","omni.turn.nudge.>","omni.turn.timeout.>"];for(let topic of turnSubs){let sub=this.nc.subscribe(topic);this.processTurnEvents(sub)}this.idleCheckTimer=setInterval(()=>this.checkIdleSessions(),IDLE_CHECK_INTERVAL_MS),bridgeInstance=this,console.log(`[omni-bridge] Listening on omni.message.> (max_concurrent=${this.maxConcurrent}, idle_timeout=${this.idleTimeoutMs}ms)`)}async stop(){if(!this.nc){console.log("[omni-bridge] Not running");return}if(console.log("[omni-bridge] Shutting down..."),this.idleCheckTimer)clearInterval(this.idleCheckTimer),this.idleCheckTimer=null;for(let[key,entry]of this.sessions){if(entry.idleTimer)clearTimeout(entry.idleTimer);if(!entry.spawning&&entry.session)try{await this.executor.shutdown(entry.session)}catch(err){console.warn(`[omni-bridge] Error shutting down session ${key}:`,err)}}if(this.sessions.clear(),this.sub)this.sub.unsubscribe(),this.sub=null;try{await this.nc.drain()}catch{}this.nc=null,this.sql=null,this.pgAvailable=!1,bridgeInstance=null,console.log("[omni-bridge] Stopped")}async status(){let now=Date.now(),activeFromPg=null,executorIds=[];if(this.pgAvailable&&this.sql){let rows=await this.safePgCall("status_active_count",async(sql)=>sql`
1997
+ ${message.content}`,this.pendingNudges.delete(session.id);let{messages:queryMessages}=state.provider.runQuery({agentId:session.agentName,executorId:session.id,team:"",role:session.agentName,cwd:entry.dir||process.cwd(),model:entry.model,systemPrompt:state.claudeSessionId?void 0:systemPrompt},queryContent,permissionConfig,extraOptions,entry.sdk);await this.captureUserTurn(state,session.agentName,session.id,message.content);let result2=await collectQueryResult(queryMessages);if(result2.sessionId)await this.reconcileSessionId(state,session,result2.sessionId);if(await this.captureAssistantTurn(state,session.id,result2.sessionId,session.agentName,result2.text),session.lastActivityAt=Date.now(),this.safePgCall)await recordAuditEvent2(this.safePgCall,"deliver.end",{executor_id:state.executorId??session.id,agent_id:session.agentName,chat_id:message.chatId,instance_id:message.instanceId,turn_count:state.turnIndex});if(state.executorId)await this.updateState(state.executorId,"idle",session.chatId)}async reconcileSessionId(state,session,returnedSessionId){if(state.claudeSessionId&&returnedSessionId!==state.claudeSessionId&&this.safePgCall)await recordAuditEvent2(this.safePgCall,"session.resume_rejected",{executor_id:state.executorId??session.id,agent_id:session.agentName,chat_id:session.chatId,old_session_id:state.claudeSessionId,new_session_id:returnedSessionId});let execId=state.executorId;if(execId&&this.safePgCall&&returnedSessionId!==state.claudeSessionId)await this.safePgCall("sdk-update-claude-session",()=>updateClaudeSessionId(execId,returnedSessionId),void 0,{executorId:execId,chatId:session.chatId});state.claudeSessionId=returnedSessionId}async captureUserTurn(state,agentName,_sessionKey,content){if(!this.safePgCall)return;if(!state.dbSessionId&&state.executorId)state.dbSessionId=await startSession(this.safePgCall,state.executorId,state.claudeSessionId,agentName);if(state.dbSessionId)await recordTurn(this.safePgCall,state.dbSessionId,state.turnIndex++,"user",content)}async captureAssistantTurn(state,sessionKey2,claudeSessionId,agentName,replyText){if(!this.safePgCall)return;if(claudeSessionId&&state.dbSessionId?.startsWith("sdk-")){let newId=await startSession(this.safePgCall,state.executorId??sessionKey2,claudeSessionId,agentName);if(newId)state.dbSessionId=newId}if(state.dbSessionId&&replyText)await recordTurn(this.safePgCall,state.dbSessionId,state.turnIndex++,"assistant",replyText),await updateTurnCount(this.safePgCall,state.dbSessionId,state.turnIndex)}async waitForDeliveries(sessionId){if(sessionId)await this.deliveryQueues.get(sessionId);else await Promise.all([...this.deliveryQueues.values()])}async shutdown(session){let state=this.sessions.get(session.id);if(!state)return;if(state.abortController.abort(),state.running=!1,state.dbSessionId&&this.safePgCall)await endSession(this.safePgCall,state.dbSessionId,"completed");if(state.executorId&&this.safePgCall)await this.safePgCall("sdk-terminate-executor",()=>terminateExecutor(state.executorId),void 0,{executorId:state.executorId,chatId:session.chatId});this.sessions.delete(session.id),this.deliveryQueues.delete(session.id)}async isAlive(session){let state=this.sessions.get(session.id);if(!state)return!1;return state.running&&!state.abortController.signal.aborted}}var init_claude_sdk2=__esm(()=>{init_zod();init_agent_directory();init_agent_registry();init_executor_registry();init_claude_sdk_permissions();init_claude_sdk()});class TurnTracker{turns=new Map;open(sessionKey2,turnId,messageId){this.turns.set(sessionKey2,{turnId,sessionKey:sessionKey2,messageId,startedAt:Date.now(),closed:!1})}close(sessionKey2,action){let turn=this.turns.get(sessionKey2);if(turn&&!turn.closed)turn.closed=!0,turn.closedAction=action}isOpen(sessionKey2){let turn=this.turns.get(sessionKey2);return turn!==void 0&&!turn.closed}getTurnId(sessionKey2){return this.turns.get(sessionKey2)?.turnId}getByTurnId(turnId){for(let turn of this.turns.values())if(turn.turnId===turnId)return turn;return}delete(sessionKey2){this.turns.delete(sessionKey2)}}var exports_omni_bridge={};__export(exports_omni_bridge,{getBridge:()=>getBridge,OmniBridge:()=>OmniBridge});function getBridge(){return bridgeInstance}function withTimeout(p,ms,label){return new Promise((resolve9,reject)=>{let timer2=setTimeout(()=>reject(Error(`${label} timed out after ${ms}ms`)),ms);timer2.unref?.(),p.then((v)=>{clearTimeout(timer2),resolve9(v)},(err)=>{clearTimeout(timer2),reject(err)})})}function isPgConnectionError(err){if(!err||typeof err!=="object")return!1;let e=err,code=e.code??"";if(["ECONNREFUSED","ECONNRESET","ETIMEDOUT","ENOTFOUND","EPIPE","EHOSTUNREACH"].includes(code))return!0;let msg=e.message??String(err);return/ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENOTFOUND|EPIPE|connection terminated|connection closed|server closed the connection|the database system is shutting down/i.test(msg)}class OmniBridge{nc=null;sub=null;executor;turnTracker=new TurnTracker;sessions=new Map;messageQueue=[];idleCheckTimer=null;sc=import_nats3.StringCodec();sql=null;pgAvailable=!1;pgProvider;natsConnectFn;natsUrl;idleTimeoutMs;maxConcurrent;executorType;constructor(config={}){if(this.natsUrl=config.natsUrl??process.env.GENIE_NATS_URL??DEFAULT_NATS_URL,this.idleTimeoutMs=config.idleTimeoutMs??(process.env.GENIE_IDLE_TIMEOUT_MS?Number(process.env.GENIE_IDLE_TIMEOUT_MS):DEFAULT_IDLE_TIMEOUT_MS2),this.maxConcurrent=config.maxConcurrent??(process.env.GENIE_MAX_CONCURRENT?Number(process.env.GENIE_MAX_CONCURRENT):DEFAULT_MAX_CONCURRENT),this.pgProvider=config.pgProvider??(async()=>{let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db));return await getConnection2()}),this.natsConnectFn=config.natsConnectFn??import_nats3.connect,this.executorType=resolveExecutorType(config.executorType),this.executorType==="sdk")this.executor=new ClaudeSdkOmniExecutor;else this.executor=new ClaudeCodeOmniExecutor}async start(){if(this.nc){console.log("[omni-bridge] Already running");return}console.log(`[omni-bridge] Connecting to NATS at ${this.natsUrl}...`),this.nc=await this.natsConnectFn({servers:this.natsUrl,name:"genie-omni-bridge",reconnect:!0,maxReconnectAttempts:-1,reconnectTimeWait:2000}),console.log("[omni-bridge] Connected to NATS"),await this.probePg(),this.executor.setSafePgCall(this.safePgCall.bind(this));let sc3=this.sc,nc2=this.nc;this.executor.setNatsPublish((topic,payload)=>{nc2.publish(topic,sc3.encode(payload))}),this.sub=this.nc.subscribe("omni.message.>"),this.processSubscription();let turnSubs=["omni.turn.open.>","omni.turn.done.>","omni.turn.nudge.>","omni.turn.timeout.>"];for(let topic of turnSubs){let sub=this.nc.subscribe(topic);this.processTurnEvents(sub)}this.idleCheckTimer=setInterval(()=>this.checkIdleSessions(),IDLE_CHECK_INTERVAL_MS),bridgeInstance=this,console.log(`[omni-bridge] Listening on omni.message.> (max_concurrent=${this.maxConcurrent}, idle_timeout=${this.idleTimeoutMs}ms)`)}async stop(){if(!this.nc){console.log("[omni-bridge] Not running");return}if(console.log("[omni-bridge] Shutting down..."),this.idleCheckTimer)clearInterval(this.idleCheckTimer),this.idleCheckTimer=null;for(let[key,entry]of this.sessions){if(entry.idleTimer)clearTimeout(entry.idleTimer);if(!entry.spawning&&entry.session)try{await this.executor.shutdown(entry.session)}catch(err){console.warn(`[omni-bridge] Error shutting down session ${key}:`,err)}}if(this.sessions.clear(),this.sub)this.sub.unsubscribe(),this.sub=null;try{await this.nc.drain()}catch{}this.nc=null,this.sql=null,this.pgAvailable=!1,bridgeInstance=null,console.log("[omni-bridge] Stopped")}async status(){let now=Date.now(),activeFromPg=null,executorIds=[];if(this.pgAvailable&&this.sql){let rows=await this.safePgCall("status_active_count",async(sql)=>sql`
1998
1998
  SELECT id FROM executors
1999
1999
  WHERE ended_at IS NULL AND metadata->>'source' = 'omni'
2000
2000
  `,null);if(rows)activeFromPg=rows.length,executorIds=rows.map((r)=>r.id)}return{connected:this.nc!==null,natsUrl:this.natsUrl,pgAvailable:this.pgAvailable,activeSessions:activeFromPg??this.sessions.size,maxConcurrent:this.maxConcurrent,idleTimeoutMs:this.idleTimeoutMs,queueDepth:this.messageQueue.length,executorType:this.executorType,executorIds,sessions:Array.from(this.sessions.entries()).map(([key,entry])=>({id:key,agentName:entry.session.agentName,chatId:entry.session.chatId,instanceId:entry.instanceId,paneId:entry.session.paneId,spawning:entry.spawning,idleMs:now-entry.session.lastActivityAt,bufferSize:entry.buffer.length}))}}async probePg(){try{let sql=await withTimeout(this.pgProvider(),PG_STARTUP_PROBE_TIMEOUT_MS,"PG provider startup");await withTimeout(Promise.resolve(sql`SELECT 1`),PG_STARTUP_PROBE_TIMEOUT_MS,"PG SELECT 1 probe"),this.sql=sql,this.pgAvailable=!0,console.log("[omni-bridge] PG reachable \u2014 session recovery enabled")}catch(err){this.sql=null,this.pgAvailable=!1;let msg=err instanceof Error?err.message:String(err);if(isPgConnectionError(err)){console.warn(`[omni-bridge] PG unavailable \u2014 session recovery disabled (${msg})`);return}throw Error(`[omni-bridge] PG schema mismatch or setup error: ${msg}. ${"Run `bun run migrate` (or the equivalent migration command) and retry."}`)}}async safePgCall(op,fn,fallback,ctx){if(!this.pgAvailable||!this.sql)return fallback;let sql=this.sql;try{return await withTimeout(fn(sql),PG_RUNTIME_QUERY_TIMEOUT_MS,`safePgCall(${op})`)}catch(err){let msg=err instanceof Error?err.message:String(err),execPart=ctx?.executorId?` executor_id=${ctx.executorId}`:"",chatPart=ctx?.chatId?` chat_id=${ctx.chatId}`:"";if(console.warn(`[omni-bridge] safePgCall(${op}) failed${execPart}${chatPart}: ${msg}`),isPgConnectionError(err))this.pgAvailable=!1,this.sql=null,console.warn("[omni-bridge] PG connection lost \u2014 switching to degraded mode");return fallback}}async processSubscription(){if(!this.sub)return;for await(let msg of this.sub)try{let data=this.sc.decode(msg.data),parsed=JSON.parse(data),parts=msg.subject.split(".");if(parts.length>=4)parsed.instanceId=parsed.instanceId||parts[2],parsed.chatId=parsed.chatId||parts[3];if(!parsed.chatId||!parsed.agent){console.warn("[omni-bridge] Dropping message: missing chatId or agent",msg.subject);continue}await this.routeMessage(parsed)}catch(err){console.error("[omni-bridge] Error processing message:",err)}}async processTurnEvents(sub){for await(let msg of sub)try{let payload=JSON.parse(this.sc.decode(msg.data)),parts=msg.subject.split("."),eventType=parts[2],instanceId=parts[3],chatId=parts.slice(4).join("."),sessionKey2=this.findSessionKey(instanceId,chatId);if(sessionKey2)await this.routeTurnEvent(eventType,sessionKey2,payload)}catch(err){console.warn("[omni-bridge] Error processing turn event:",err)}}async routeTurnEvent(eventType,sessionKey2,payload){switch(eventType){case"open":this.turnTracker.open(sessionKey2,payload.turnId,payload.messageId);break;case"done":this.turnTracker.close(sessionKey2,payload.action);break;case"nudge":await this.handleTurnNudge(sessionKey2,payload.message);break;case"timeout":await this.handleTurnTimeout(sessionKey2);break}}findSessionKey(instanceId,chatId){for(let[key,entry]of this.sessions)if(entry.instanceId===instanceId&&entry.session?.chatId===chatId)return key;return}async handleTurnNudge(sessionKey2,nudgeText){let entry=this.sessions.get(sessionKey2);if(!entry?.session)return;try{await this.executor.injectNudge(entry.session,nudgeText)}catch(err){console.warn(`[omni-bridge] Failed to inject nudge for ${sessionKey2}:`,err)}}async handleTurnTimeout(sessionKey2){let entry=this.sessions.get(sessionKey2);if(!entry?.session)return;console.warn(`[omni-bridge] Turn timed out for ${sessionKey2}, evicting session`),this.turnTracker.close(sessionKey2,"timeout");try{await this.executor.shutdown(entry.session)}catch(err){console.warn(`[omni-bridge] Error shutting down timed-out session ${sessionKey2}:`,err)}this.sessions.delete(sessionKey2)}async routeMessage(message){let key=`${message.agent}:${message.chatId}`,entry=this.sessions.get(key);if(entry){if(entry.spawning){if(entry.buffer.length<MAX_BUFFER_PER_CHAT)entry.buffer.push(message);else console.warn(`[omni-bridge] Buffer full (${MAX_BUFFER_PER_CHAT}) for ${key}, dropping message from ${message.sender}`),await this.publishBufferFullReply(message);return}if(await this.executor.isAlive(entry.session)){await this.executor.deliver(entry.session,message),this.resetIdleTimer(key);return}this.removeSession(key)}await this.spawnSession(message)}async spawnSession(message){let key=`${message.agent}:${message.chatId}`;if(this.sessions.size>=this.maxConcurrent){this.messageQueue.push(message),await this.publishAutoReply(message),console.log(`[omni-bridge] Max concurrent (${this.maxConcurrent}) reached, queued message for ${key}`);return}let placeholder={session:null,instanceId:message.instanceId,spawning:!0,buffer:[message],idleTimer:null};this.sessions.set(key,placeholder);try{let raw=message,payloadEnv=raw.env,spawnEnv={OMNI_API_KEY:payloadEnv?.OMNI_API_KEY??process.env.OMNI_API_KEY??"",OMNI_INSTANCE:payloadEnv?.OMNI_INSTANCE??message.instanceId,OMNI_CHAT:payloadEnv?.OMNI_CHAT??message.chatId,OMNI_MESSAGE:payloadEnv?.OMNI_MESSAGE??raw.messageId??"",OMNI_TURN_ID:payloadEnv?.OMNI_TURN_ID??""};console.log(`[omni-bridge] Spawning session for ${key}...`);let session=await this.executor.spawn(message.agent,message.chatId,spawnEnv);placeholder.session=session,placeholder.spawning=!1;for(let buffered of placeholder.buffer)await this.executor.deliver(session,buffered);placeholder.buffer=[],this.resetIdleTimer(key),console.log(`[omni-bridge] Session active: ${key} (pane=${session.paneId})`)}catch(err){console.error(`[omni-bridge] Failed to spawn session for ${key}:`,err);let lostMessages=placeholder.buffer;if(lostMessages.length>0)console.warn(`[omni-bridge] Re-queuing ${lostMessages.length} buffered message(s) from failed spawn for ${key}`),this.messageQueue.push(...lostMessages);this.sessions.delete(key)}}resetIdleTimer(key){let entry=this.sessions.get(key);if(!entry)return;if(entry.idleTimer)clearTimeout(entry.idleTimer);entry.idleTimer=setTimeout(async()=>{console.log(`[omni-bridge] Idle timeout for ${key}, shutting down...`);try{await this.executor.shutdown(entry.session)}catch{}this.removeSession(key),await this.drainQueue()},this.idleTimeoutMs)}async checkIdleSessions(){let now=Date.now();for(let[key,entry]of this.sessions){if(entry.spawning)continue;if(!await this.executor.isAlive(entry.session)){console.log(`[omni-bridge] Dead session detected: ${key}`),this.removeSession(key);continue}let idleMs=now-entry.session.lastActivityAt;if(idleMs>this.idleTimeoutMs){console.log(`[omni-bridge] Forcing idle shutdown: ${key} (idle ${Math.round(idleMs/1000)}s)`);try{await this.executor.shutdown(entry.session)}catch{}this.removeSession(key)}}}removeSession(key){let entry=this.sessions.get(key);if(entry?.idleTimer)clearTimeout(entry.idleTimer);this.sessions.delete(key)}async drainQueue(){while(this.messageQueue.length>0){if(this.sessions.size>=this.maxConcurrent)break;let message=this.messageQueue.shift();if(message)await this.spawnSession(message)}}async publishBufferFullReply(message){if(!this.nc)return;let topic=`omni.reply.${message.instanceId}.${message.chatId}`,reply2={content:"Fila de mensagens cheia, por favor aguarde e tente novamente.",agent:message.agent,chat_id:message.chatId,instance_id:message.instanceId,timestamp:new Date().toISOString(),auto_reply:!0};this.nc.publish(topic,this.sc.encode(JSON.stringify(reply2)))}async publishAutoReply(message){if(!this.nc)return;let topic=`omni.reply.${message.instanceId}.${message.chatId}`,reply2={content:"Aguarde um momento, estou atendendo outros clientes.",agent:message.agent,chat_id:message.chatId,instance_id:message.instanceId,timestamp:new Date().toISOString(),auto_reply:!0};this.nc.publish(topic,this.sc.encode(JSON.stringify(reply2)))}}var import_nats3,DEFAULT_NATS_URL="localhost:4222",DEFAULT_IDLE_TIMEOUT_MS2=900000,DEFAULT_MAX_CONCURRENT=20,MAX_BUFFER_PER_CHAT=50,IDLE_CHECK_INTERVAL_MS=30000,PG_STARTUP_PROBE_TIMEOUT_MS=5000,PG_RUNTIME_QUERY_TIMEOUT_MS=2000,bridgeInstance=null;var init_omni_bridge=__esm(()=>{init_executor_config();init_claude_code2();init_claude_sdk2();import_nats3=__toESM(require_mod4(),1)});var exports_task_close_merged={};__export(exports_task_close_merged,{parseSinceDate:()=>parseSinceDate,matchPRsToSlugs:()=>matchPRsToSlugs,fetchMergedPRs:()=>fetchMergedPRs,extractWishSlug:()=>extractWishSlug,extractSlugFromBranch:()=>extractSlugFromBranch,extractSlugFromBody:()=>extractSlugFromBody,closeMergedTasks:()=>closeMergedTasks});import{execSync as execSync15}from"child_process";function extractSlugFromBody(body){if(!body)return null;let match=body.match(/(?:wish|slug):\s*(\S+)/i);return match?match[1]:null}function extractSlugFromBranch(branch){if(!branch)return null;let match=branch.match(/^(?:feat|fix|chore|docs|refactor|test|dream)\/(.+)$/);return match?match[1]:null}function extractWishSlug(pr){return extractSlugFromBody(pr.body)??extractSlugFromBranch(pr.headRefName)}function parseSinceDate(since){let match=since.match(/^(\d+)([hd])$/);if(!match)throw Error(`Invalid --since format: "${since}". Use e.g. "24h" or "7d".`);let amount=Number.parseInt(match[1],10),unit=match[2],now=new Date;if(unit==="h")now.setHours(now.getHours()-amount);else now.setDate(now.getDate()-amount);return now.toISOString()}function fetchMergedPRs(since,repo){let sinceDate=parseSinceDate(since),cmd=`gh pr list --state merged --json number,title,body,headRefName,mergedAt --limit 100 ${repo?`--repo ${repo}`:""}`.trim(),output;try{output=execSync15(cmd,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]})}catch(err){let message=err instanceof Error?err.message:String(err);throw Error(`Failed to fetch merged PRs: ${message}`)}return JSON.parse(output).filter((pr)=>new Date(pr.mergedAt)>=new Date(sinceDate))}function matchPRsToSlugs(prs){let matches=[];for(let pr of prs){let slug=extractWishSlug(pr);if(slug)matches.push({prNumber:pr.number,slug,mergedAt:pr.mergedAt})}return matches}async function closeMergedTasks(options={}){let{since="24h",dryRun=!1,repo,repoPath}=options,ts3=await Promise.resolve().then(() => (init_task_service(),exports_task_service)),prs=fetchMergedPRs(since,repo),slugMatches=matchPRsToSlugs(prs),result2={closed:0,alreadyShipped:0,prsScanned:prs.length,details:[]};if(slugMatches.length===0)return result2;let actor={actorType:"local",actorId:process.env.GENIE_AGENT_NAME??"cli"},processedTaskIds=new Set;for(let{prNumber,slug}of slugMatches){let tasks=await findTasksByWishSlug(slug,repoPath);for(let task of tasks){if(processedTaskIds.has(task.id))continue;if(processedTaskIds.add(task.id),task.stage==="ship"){result2.alreadyShipped++;continue}if(!dryRun)await ts3.moveTask(task.id,"ship",actor,void 0,task.repoPath),await ts3.commentOnTask(task.id,actor,`Auto-closed: PR #${prNumber} merged to dev`,task.repoPath);result2.closed++,result2.details.push({taskSeq:task.seq,taskTitle:task.title,prNumber,slug})}}return result2}async function findTasksByWishSlug(slug,repoPath){let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),sql=await getConnection2(),repo=repoPath??resolveRepoPath(),pattern=`%${slug}%`;return(await sql`
@@ -2476,8 +2476,8 @@ $ bun add react-devtools-core@7 -d
2476
2476
  `),_rpi_cpuinfo=cpuinfo}catch{return!1}let hardware=getValue(cpuinfo,"hardware"),model=getValue(cpuinfo,"model");return hardware&&PI_MODEL_NO.indexOf(hardware)>-1||model&&model.indexOf("Raspberry Pi")>-1}function isRaspbian(){let osrelease=[];try{osrelease=fs3.readFileSync("/etc/os-release",{encoding:"utf8"}).toString().split(`
2477
2477
  `)}catch{return!1}let id=getValue(osrelease,"id","=");return id&&id.indexOf("raspbian")>-1}function execWin(cmd,opts,callback){if(!callback)callback=opts,opts=execOptsWin;let newCmd="chcp 65001 > nul && cmd /C "+cmd+" && chcp "+codepage+" > nul";exec3(newCmd,opts,(error2,stdout)=>{callback(error2,stdout)})}function darwinXcodeExists(){let cmdLineToolsExists=fs3.existsSync("/Library/Developer/CommandLineTools/usr/bin/"),xcodeAppExists=fs3.existsSync("/Applications/Xcode.app/Contents/Developer/Tools"),xcodeExists=fs3.existsSync("/Library/Developer/Xcode/");return cmdLineToolsExists||xcodeExists||xcodeAppExists}function nanoSeconds(){let time=process.hrtime();if(!Array.isArray(time)||time.length!==2)return 0;return+time[0]*1e9+ +time[1]}function countUniqueLines(lines,startingWith){startingWith=startingWith||"";let uniqueLines=[];return lines.forEach((line)=>{if(line.startsWith(startingWith)){if(uniqueLines.indexOf(line)===-1)uniqueLines.push(line)}}),uniqueLines.length}function countLines(lines,startingWith){startingWith=startingWith||"";let uniqueLines=[];return lines.forEach((line)=>{if(line.startsWith(startingWith))uniqueLines.push(line)}),uniqueLines.length}function sanitizeShellString(str5,strict){if(typeof strict>"u")strict=!1;let s2=str5||"",result2="",l=mathMin(s2.length,2000);for(let i2=0;i2<=l;i2++)if(!(s2[i2]===void 0||s2[i2]===">"||s2[i2]==="<"||s2[i2]==="*"||s2[i2]==="?"||s2[i2]==="["||s2[i2]==="]"||s2[i2]==="|"||s2[i2]==="\u02DA"||s2[i2]==="$"||s2[i2]===";"||s2[i2]==="&"||s2[i2]==="]"||s2[i2]==="#"||s2[i2]==="\\"||s2[i2]==="\t"||s2[i2]===`
2478
2478
  `||s2[i2]==="\r"||s2[i2]==="'"||s2[i2]==="`"||s2[i2]==='"'||s2[i2].length>1||strict&&s2[i2]==="("||strict&&s2[i2]===")"||strict&&s2[i2]==="@"||strict&&s2[i2]===" "||strict&&s2[i2]==="{"||strict&&s2[i2]===";"||strict&&s2[i2]==="}"))result2=result2+s2[i2];return result2}function isPrototypePolluted(){let notPolluted=!0,st="";try{st.__proto__.replace=stringReplace,st.__proto__.toLowerCase=stringToLower,st.__proto__.toString=stringToString,st.__proto__.substr=stringSubstr,st.__proto__.substring=stringSubstring,st.__proto__.trim=stringTrim,st.__proto__.startsWith=stringStartWith}catch(e){Object.setPrototypeOf(st,stringObj)}notPolluted=notPolluted||!1;let ms=Date.now();if(typeof ms==="number"&&ms>1600000000000){let l=ms%100+15;for(let i2=0;i2<l;i2++){let r=Math.random()*61.99999999+1,rs=parseInt(Math.floor(r).toString(),10),rs2=parseInt(r.toString().split(".")[0],10),q2=Math.random()*61.99999999+1,qs=parseInt(Math.floor(q2).toString(),10),qs2=parseInt(q2.toString().split(".")[0],10);notPolluted=notPolluted&&r!==q2,notPolluted=notPolluted&&rs===rs2&&qs===qs2,st+="1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"[rs-1]}notPolluted=notPolluted&&st.length===l;let p=Math.random()*l*0.9999999999,stm=st.substr(0,p)+" "+st.substr(p,2000);try{stm.__proto__.replace=stringReplace}catch(e){Object.setPrototypeOf(stm,stringObj)}let sto=stm.replace(/ /g,"");notPolluted=notPolluted&&st===sto,p=Math.random()*l*0.9999999999,stm=st.substr(0,p)+"{"+st.substr(p,2000),sto=stm.replace(/{/g,""),notPolluted=notPolluted&&st===sto,p=Math.random()*l*0.9999999999,stm=st.substr(0,p)+"*"+st.substr(p,2000),sto=stm.replace(/\*/g,""),notPolluted=notPolluted&&st===sto,p=Math.random()*l*0.9999999999,stm=st.substr(0,p)+"$"+st.substr(p,2000),sto=stm.replace(/\$/g,""),notPolluted=notPolluted&&st===sto;let stl=st.toLowerCase();notPolluted=notPolluted&&stl.length===l&&stl[l-1]&&!stl[l];for(let i2=0;i2<l;i2++){let s1=st[i2];try{s1.__proto__.toLowerCase=stringToLower}catch{Object.setPrototypeOf(st,stringObj)}let s22=stl?stl[i2]:"",s1l=s1.toLowerCase();notPolluted=notPolluted&&s1l[0]===s22&&s1l[0]&&!s1l[1]}}return!notPolluted}function hex2bin(hex){return("00000000"+parseInt(hex,16).toString(2)).substr(-8)}function getFilesInPath(source){let{lstatSync:lstatSync2,readdirSync:readdirSync9}=fs3,join56=path6.join;function isDirectory2(source2){return lstatSync2(source2).isDirectory()}function isFile2(source2){return lstatSync2(source2).isFile()}function getDirectories(source2){return readdirSync9(source2).map((name)=>{return join56(source2,name)}).filter(isDirectory2)}function getFiles(source2){return readdirSync9(source2).map((name)=>{return join56(source2,name)}).filter(isFile2)}function getFilesRecursively(source2){try{return getDirectories(source2).map((dir)=>{return getFilesRecursively(dir)}).reduce((a,b3)=>{return a.concat(b3)},[]).concat(getFiles(source2))}catch{return[]}}if(fs3.existsSync(source))return getFilesRecursively(source);else return[]}function decodePiCpuinfo(lines){if(_rpi_cpuinfo===null)_rpi_cpuinfo=lines;else if(lines===void 0)lines=_rpi_cpuinfo;let oldRevisionCodes={"0002":{type:"B",revision:"1.0",memory:256,manufacturer:"Egoman",processor:"BCM2835"},"0003":{type:"B",revision:"1.0",memory:256,manufacturer:"Egoman",processor:"BCM2835"},"0004":{type:"B",revision:"2.0",memory:256,manufacturer:"Sony UK",processor:"BCM2835"},"0005":{type:"B",revision:"2.0",memory:256,manufacturer:"Qisda",processor:"BCM2835"},"0006":{type:"B",revision:"2.0",memory:256,manufacturer:"Egoman",processor:"BCM2835"},"0007":{type:"A",revision:"2.0",memory:256,manufacturer:"Egoman",processor:"BCM2835"},"0008":{type:"A",revision:"2.0",memory:256,manufacturer:"Sony UK",processor:"BCM2835"},"0009":{type:"A",revision:"2.0",memory:256,manufacturer:"Qisda",processor:"BCM2835"},"000d":{type:"B",revision:"2.0",memory:512,manufacturer:"Egoman",processor:"BCM2835"},"000e":{type:"B",revision:"2.0",memory:512,manufacturer:"Sony UK",processor:"BCM2835"},"000f":{type:"B",revision:"2.0",memory:512,manufacturer:"Egoman",processor:"BCM2835"},"0010":{type:"B+",revision:"1.2",memory:512,manufacturer:"Sony UK",processor:"BCM2835"},"0011":{type:"CM1",revision:"1.0",memory:512,manufacturer:"Sony UK",processor:"BCM2835"},"0012":{type:"A+",revision:"1.1",memory:256,manufacturer:"Sony UK",processor:"BCM2835"},"0013":{type:"B+",revision:"1.2",memory:512,manufacturer:"Embest",processor:"BCM2835"},"0014":{type:"CM1",revision:"1.0",memory:512,manufacturer:"Embest",processor:"BCM2835"},"0015":{type:"A+",revision:"1.1",memory:256,manufacturer:"512MB\tEmbest",processor:"BCM2835"}},processorList=["BCM2835","BCM2836","BCM2837","BCM2711","BCM2712"],manufacturerList=["Sony UK","Egoman","Embest","Sony Japan","Embest","Stadium"],typeList={"00":"A","01":"B","02":"A+","03":"B+","04":"2B","05":"Alpha (early prototype)","06":"CM1","08":"3B","09":"Zero","0a":"CM3","0c":"Zero W","0d":"3B+","0e":"3A+","0f":"Internal use only",10:"CM3+",11:"4B",12:"Zero 2 W",13:"400",14:"CM4",15:"CM4S",16:"Internal use only",17:"5",18:"CM5",19:"500/500+","1a":"CM5 Lite"},revisionCode=getValue(lines,"revision",":",!0),model=getValue(lines,"model:",":",!0),serial=getValue(lines,"serial",":",!0),result2={};if({}.hasOwnProperty.call(oldRevisionCodes,revisionCode))result2={model,serial,revisionCode,memory:oldRevisionCodes[revisionCode].memory,manufacturer:oldRevisionCodes[revisionCode].manufacturer,processor:oldRevisionCodes[revisionCode].processor,type:oldRevisionCodes[revisionCode].type,revision:oldRevisionCodes[revisionCode].revision};else{let revision=("00000000"+getValue(lines,"revision",":",!0).toLowerCase()).substr(-8),memSizeCode=parseInt(hex2bin(revision.substr(2,1)).substr(5,3),2)||0,manufacturer=manufacturerList[parseInt(revision.substr(3,1),10)],processor=processorList[parseInt(revision.substr(4,1),10)],typeCode=revision.substr(5,2);result2={model,serial,revisionCode,memory:256*Math.pow(2,memSizeCode),manufacturer,processor,type:{}.hasOwnProperty.call(typeList,typeCode)?typeList[typeCode]:"",revision:"1."+revision.substr(7,1)}}return result2}function getRpiGpu(cpuinfo){if(_rpi_cpuinfo===null&&cpuinfo!==void 0)_rpi_cpuinfo=cpuinfo;else if(cpuinfo===void 0&&_rpi_cpuinfo!==null)cpuinfo=_rpi_cpuinfo;else try{cpuinfo=fs3.readFileSync("/proc/cpuinfo",{encoding:"utf8"}).toString().split(`
2479
- `),_rpi_cpuinfo=cpuinfo}catch{return!1}let rpi=decodePiCpuinfo(cpuinfo);if(rpi.type==="4B"||rpi.type==="CM4"||rpi.type==="CM4S"||rpi.type==="400")return"VideoCore VI";if(rpi.type==="5"||rpi.type==="500")return"VideoCore VII";return"VideoCore IV"}function promiseAll(promises){let resolvingPromises=promises.map((promise)=>new Promise((resolve13)=>{let payload=[,,];promise.then((result2)=>{payload[0]=result2}).catch((error2)=>{payload[1]=error2}).then(()=>{resolve13(payload)})})),errors3=[],results=[];return Promise.all(resolvingPromises).then((items)=>{return items.forEach((payload)=>{if(payload[1])errors3.push(payload[1]),results.push(null);else errors3.push(null),results.push(payload[0])}),{errors:errors3,results}})}function promisify4(nodeStyleFunction){return()=>{let args=Array.prototype.slice.call(arguments);return new Promise((resolve13,reject)=>{args.push((err,data)=>{if(err)reject(err);else resolve13(data)}),nodeStyleFunction.apply(null,args)})}}function promisifySave(nodeStyleFunction){return()=>{let args=Array.prototype.slice.call(arguments);return new Promise((resolve13)=>{args.push((err,data)=>{resolve13(data)}),nodeStyleFunction.apply(null,args)})}}function linuxVersion(){let result2="";if(_linux)try{result2=execSync17("uname -v",execOptsLinux).toString()}catch{result2=""}return result2}function plistParser(xmlStr){let tags=["array","dict","key","string","integer","date","real","data","boolean","arrayEmpty"],startStr="<plist version",pos=xmlStr.indexOf("<plist version"),len=xmlStr.length;while(xmlStr[pos]!==">"&&pos<len)pos++;let depth=0,inTagStart=!1,inTagContent=!1,inTagEnd=!1,metaData=[{tagStart:"",tagEnd:"",tagContent:"",key:"",data:null}],c="",cn=xmlStr[pos];while(pos<len){if(c=cn,pos+1<len)cn=xmlStr[pos+1];if(c==="<"){if(inTagContent=!1,cn==="/")inTagEnd=!0;else if(metaData[depth].tagStart){if(metaData[depth].tagContent="",!metaData[depth].data)metaData[depth].data=metaData[depth].tagStart==="array"?[]:{};depth++,metaData.push({tagStart:"",tagEnd:"",tagContent:"",key:null,data:null}),inTagStart=!0,inTagContent=!1}else if(!inTagStart)inTagStart=!0}else if(c===">"){if(metaData[depth].tagStart==="true/")inTagStart=!1,inTagEnd=!0,metaData[depth].tagStart="",metaData[depth].tagEnd="/boolean",metaData[depth].data=!0;if(metaData[depth].tagStart==="false/")inTagStart=!1,inTagEnd=!0,metaData[depth].tagStart="",metaData[depth].tagEnd="/boolean",metaData[depth].data=!1;if(metaData[depth].tagStart==="array/")inTagStart=!1,inTagEnd=!0,metaData[depth].tagStart="",metaData[depth].tagEnd="/arrayEmpty",metaData[depth].data=[];if(inTagContent)inTagContent=!1;if(inTagStart){if(inTagStart=!1,inTagContent=!0,metaData[depth].tagStart==="array")metaData[depth].data=[];if(metaData[depth].tagStart==="dict")metaData[depth].data={}}if(inTagEnd){if(inTagEnd=!1,metaData[depth].tagEnd&&tags.indexOf(metaData[depth].tagEnd.substr(1))>=0)if(metaData[depth].tagEnd==="/dict"||metaData[depth].tagEnd==="/array"){if(depth>1&&metaData[depth-2].tagStart==="array")metaData[depth-2].data.push(metaData[depth-1].data);if(depth>1&&metaData[depth-2].tagStart==="dict")metaData[depth-2].data[metaData[depth-1].key]=metaData[depth-1].data;depth--,metaData.pop(),metaData[depth].tagContent="",metaData[depth].tagStart="",metaData[depth].tagEnd=""}else{if(metaData[depth].tagEnd==="/key"&&metaData[depth].tagContent)metaData[depth].key=metaData[depth].tagContent;else{if(metaData[depth].tagEnd==="/real"&&metaData[depth].tagContent)metaData[depth].data=parseFloat(metaData[depth].tagContent)||0;if(metaData[depth].tagEnd==="/integer"&&metaData[depth].tagContent)metaData[depth].data=parseInt(metaData[depth].tagContent)||0;if(metaData[depth].tagEnd==="/string"&&metaData[depth].tagContent)metaData[depth].data=metaData[depth].tagContent||"";if(metaData[depth].tagEnd==="/boolean")metaData[depth].data=metaData[depth].tagContent||!1;if(metaData[depth].tagEnd==="/arrayEmpty")metaData[depth].data=metaData[depth].tagContent||[];if(depth>0&&metaData[depth-1].tagStart==="array")metaData[depth-1].data.push(metaData[depth].data);if(depth>0&&metaData[depth-1].tagStart==="dict")metaData[depth-1].data[metaData[depth].key]=metaData[depth].data}metaData[depth].tagContent="",metaData[depth].tagStart="",metaData[depth].tagEnd=""}metaData[depth].tagEnd="",inTagStart=!1,inTagContent=!1}}else{if(inTagStart)metaData[depth].tagStart+=c;if(inTagEnd)metaData[depth].tagEnd+=c;if(inTagContent)metaData[depth].tagContent+=c}pos++}return metaData[0].data}function strIsNumeric(str5){return typeof str5==="string"&&!isNaN(str5)&&!isNaN(parseFloat(str5))}function plistReader(output){let lines=output.split(`
2480
- `);for(let i2=0;i2<lines.length;i2++){if(lines[i2].indexOf(" = ")>=0){let lineParts=lines[i2].split(" = ");if(lineParts[0]=lineParts[0].trim(),!lineParts[0].startsWith('"'))lineParts[0]='"'+lineParts[0]+'"';if(lineParts[1]=lineParts[1].trim(),lineParts[1].indexOf('"')===-1&&lineParts[1].endsWith(";")){let valueString=lineParts[1].substring(0,lineParts[1].length-1);if(!strIsNumeric(valueString))lineParts[1]=`"${valueString}";`}if(lineParts[1].indexOf('"')>=0&&lineParts[1].endsWith(";")){let valueString=lineParts[1].substring(0,lineParts[1].length-1).replace(/"/g,"");if(strIsNumeric(valueString))lineParts[1]=`${valueString};`}lines[i2]=lineParts.join(" : ")}if(lines[i2]=lines[i2].replace(/\(/g,"[").replace(/\)/g,"]").replace(/;/g,",").trim(),lines[i2].startsWith("}")&&lines[i2-1]&&lines[i2-1].endsWith(","))lines[i2-1]=lines[i2-1].substring(0,lines[i2-1].length-1)}output=lines.join("");let obj={};try{obj=JSON.parse(output)}catch(e){noop4()}return obj}function semverCompare(v1,v2){let res=0,parts1=v1.split("."),parts2=v2.split(".");if(parts1[0]<parts2[0])res=1;else if(parts1[0]>parts2[0])res=-1;else if(parts1[0]===parts2[0]&&parts1.length>=2&&parts2.length>=2){if(parts1[1]<parts2[1])res=1;else if(parts1[1]>parts2[1])res=-1;else if(parts1[1]===parts2[1]){if(parts1.length>=3&&parts2.length>=3){if(parts1[2]<parts2[2])res=1;else if(parts1[2]>parts2[2])res=-1}else if(parts2.length>=3)res=1}}return res}function getAppleModel(key){let list2=[{key:"Mac17,7",name:"MacBook Pro",size:"16-inch",processor:"M5 Max",year:"2026",additional:""},{key:"Mac17,6",name:"MacBook Pro",size:"14-inch",processor:"M5 Max",year:"2026",additional:""},{key:"Mac17,5",name:"MacBook Pro",size:"16-inch",processor:"M5 Pro",year:"2026",additional:""},{key:"Mac17,4",name:"MacBook Pro",size:"14-inch",processor:"M5 Pro",year:"2026",additional:""},{key:"Mac17,1",name:"MacBook Neo",size:"14-inch",processor:"A18 Pro",year:"2026",additional:""},{key:"Mac17,3",name:"MacBook Pro",size:"16-inch",processor:"M5",year:"2025",additional:""},{key:"Mac17,2",name:"MacBook Pro",size:"14-inch",processor:"M5",year:"2025",additional:""},{key:"Mac16,13",name:"MacBook Air",size:"15-inch",processor:"M4",year:"2025",additional:""},{key:"Mac16,12",name:"MacBook Air",size:"13-inch",processor:"M4",year:"2025",additional:""},{key:"Mac15,13",name:"MacBook Air",size:"15-inch",processor:"M3",year:"2024",additional:""},{key:"Mac15,12",name:"MacBook Air",size:"13-inch",processor:"M3",year:"2024",additional:""},{key:"Mac14,15",name:"MacBook Air",size:"15-inch",processor:"M2",year:"2024",additional:""},{key:"Mac14,2",name:"MacBook Air",size:"13-inch",processor:"M2",year:"2022",additional:""},{key:"MacBookAir10,1",name:"MacBook Air",size:"13-inch",processor:"M1",year:"2020",additional:""},{key:"MacBookAir9,1",name:"MacBook Air",size:"13-inch",processor:"",year:"2020",additional:""},{key:"MacBookAir8,2",name:"MacBook Air",size:"13-inch",processor:"",year:"2019",additional:""},{key:"MacBookAir8,1",name:"MacBook Air",size:"13-inch",processor:"",year:"2018",additional:""},{key:"MacBookAir7,2",name:"MacBook Air",size:"13-inch",processor:"",year:"2017",additional:""},{key:"MacBookAir7,2",name:"MacBook Air",size:"13-inch",processor:"",year:"Early 2015",additional:""},{key:"MacBookAir7,1",name:"MacBook Air",size:"11-inch",processor:"",year:"Early 2015",additional:""},{key:"MacBookAir6,2",name:"MacBook Air",size:"13-inch",processor:"",year:"Early 2014",additional:""},{key:"MacBookAir6,1",name:"MacBook Air",size:"11-inch",processor:"",year:"Early 2014",additional:""},{key:"MacBookAir6,2",name:"MacBook Air",size:"13-inch",processor:"",year:"Mid 2013",additional:""},{key:"MacBookAir6,1",name:"MacBook Air",size:"11-inch",processor:"",year:"Mid 2013",additional:""},{key:"MacBookAir5,2",name:"MacBook Air",size:"13-inch",processor:"",year:"Mid 2012",additional:""},{key:"MacBookAir5,1",name:"MacBook Air",size:"11-inch",processor:"",year:"Mid 2012",additional:""},{key:"MacBookAir4,2",name:"MacBook Air",size:"13-inch",processor:"",year:"Mid 2011",additional:""},{key:"MacBookAir4,1",name:"MacBook Air",size:"11-inch",processor:"",year:"Mid 2011",additional:""},{key:"MacBookAir3,2",name:"MacBook Air",size:"13-inch",processor:"",year:"Late 2010",additional:""},{key:"MacBookAir3,1",name:"MacBook Air",size:"11-inch",processor:"",year:"Late 2010",additional:""},{key:"MacBookAir2,1",name:"MacBook Air",size:"13-inch",processor:"",year:"Mid 2009",additional:""},{key:"Mac16,1",name:"MacBook Pro",size:"14-inch",processor:"M4",year:"2024",additional:""},{key:"Mac16,6",name:"MacBook Pro",size:"14-inch",processor:"M4 Pro",year:"2024",additional:""},{key:"Mac16,8",name:"MacBook Pro",size:"14-inch",processor:"M4 Max",year:"2024",additional:""},{key:"Mac16,5",name:"MacBook Pro",size:"16-inch",processor:"M4 Pro",year:"2024",additional:""},{key:"Mac16,6",name:"MacBook Pro",size:"16-inch",processor:"M4 Max",year:"2024",additional:""},{key:"Mac15,3",name:"MacBook Pro",size:"14-inch",processor:"M3",year:"Nov 2023",additional:""},{key:"Mac15,6",name:"MacBook Pro",size:"14-inch",processor:"M3 Pro",year:"Nov 2023",additional:""},{key:"Mac15,8",name:"MacBook Pro",size:"14-inch",processor:"M3 Pro",year:"Nov 2023",additional:""},{key:"Mac15,10",name:"MacBook Pro",size:"14-inch",processor:"M3 Max",year:"Nov 2023",additional:""},{key:"Mac15,7",name:"MacBook Pro",size:"16-inch",processor:"M3 Pro",year:"Nov 2023",additional:""},{key:"Mac15,9",name:"MacBook Pro",size:"16-inch",processor:"M3 Pro",year:"Nov 2023",additional:""},{key:"Mac15,11",name:"MacBook Pro",size:"16-inch",processor:"M3 Max",year:"Nov 2023",additional:""},{key:"Mac14,5",name:"MacBook Pro",size:"14-inch",processor:"M2 Max",year:"2023",additional:""},{key:"Mac14,9",name:"MacBook Pro",size:"14-inch",processor:"M2 Max",year:"2023",additional:""},{key:"Mac14,6",name:"MacBook Pro",size:"16-inch",processor:"M2 Max",year:"2023",additional:""},{key:"Mac14,10",name:"MacBook Pro",size:"16-inch",processor:"M2 Max",year:"2023",additional:""},{key:"Mac14,7",name:"MacBook Pro",size:"13-inch",processor:"M2",year:"2022",additional:""},{key:"MacBookPro18,3",name:"MacBook Pro",size:"14-inch",processor:"M1 Pro",year:"2021",additional:""},{key:"MacBookPro18,4",name:"MacBook Pro",size:"14-inch",processor:"M1 Max",year:"2021",additional:""},{key:"MacBookPro18,1",name:"MacBook Pro",size:"16-inch",processor:"M1 Pro",year:"2021",additional:""},{key:"MacBookPro18,2",name:"MacBook Pro",size:"16-inch",processor:"M1 Max",year:"2021",additional:""},{key:"MacBookPro17,1",name:"MacBook Pro",size:"13-inch",processor:"M1",year:"2020",additional:""},{key:"MacBookPro16,3",name:"MacBook Pro",size:"13-inch",processor:"",year:"2020",additional:"Two Thunderbolt 3 ports"},{key:"MacBookPro16,2",name:"MacBook Pro",size:"13-inch",processor:"",year:"2020",additional:"Four Thunderbolt 3 ports"},{key:"MacBookPro16,1",name:"MacBook Pro",size:"16-inch",processor:"",year:"2019",additional:""},{key:"MacBookPro16,4",name:"MacBook Pro",size:"16-inch",processor:"",year:"2019",additional:""},{key:"MacBookPro15,3",name:"MacBook Pro",size:"15-inch",processor:"",year:"2019",additional:""},{key:"MacBookPro15,2",name:"MacBook Pro",size:"13-inch",processor:"",year:"2019",additional:""},{key:"MacBookPro15,1",name:"MacBook Pro",size:"15-inch",processor:"",year:"2019",additional:""},{key:"MacBookPro15,4",name:"MacBook Pro",size:"13-inch",processor:"",year:"2019",additional:"Two Thunderbolt 3 ports"},{key:"MacBookPro15,1",name:"MacBook Pro",size:"15-inch",processor:"",year:"2018",additional:""},{key:"MacBookPro15,2",name:"MacBook Pro",size:"13-inch",processor:"",year:"2018",additional:"Four Thunderbolt 3 ports"},{key:"MacBookPro14,1",name:"MacBook Pro",size:"13-inch",processor:"",year:"2017",additional:"Two Thunderbolt 3 ports"},{key:"MacBookPro14,2",name:"MacBook Pro",size:"13-inch",processor:"",year:"2017",additional:"Four Thunderbolt 3 ports"},{key:"MacBookPro14,3",name:"MacBook Pro",size:"15-inch",processor:"",year:"2017",additional:""},{key:"MacBookPro13,1",name:"MacBook Pro",size:"13-inch",processor:"",year:"2016",additional:"Two Thunderbolt 3 ports"},{key:"MacBookPro13,2",name:"MacBook Pro",size:"13-inch",processor:"",year:"2016",additional:"Four Thunderbolt 3 ports"},{key:"MacBookPro13,3",name:"MacBook Pro",size:"15-inch",processor:"",year:"2016",additional:""},{key:"MacBookPro11,4",name:"MacBook Pro",size:"15-inch",processor:"",year:"Mid 2015",additional:""},{key:"MacBookPro11,5",name:"MacBook Pro",size:"15-inch",processor:"",year:"Mid 2015",additional:""},{key:"MacBookPro12,1",name:"MacBook Pro",size:"13-inch",processor:"",year:"Early 2015",additional:""},{key:"MacBookPro11,2",name:"MacBook Pro",size:"15-inch",processor:"",year:"Late 2013",additional:""},{key:"MacBookPro11,3",name:"MacBook Pro",size:"15-inch",processor:"",year:"Late 2013",additional:""},{key:"MacBookPro11,1",name:"MacBook Pro",size:"13-inch",processor:"",year:"Late 2013",additional:""},{key:"MacBookPro10,1",name:"MacBook Pro",size:"15-inch",processor:"",year:"Mid 2012",additional:""},{key:"MacBookPro10,2",name:"MacBook Pro",size:"13-inch",processor:"",year:"Late 2012",additional:""},{key:"MacBookPro9,1",name:"MacBook Pro",size:"15-inch",processor:"",year:"Mid 2012",additional:""},{key:"MacBookPro9,2",name:"MacBook Pro",size:"13-inch",processor:"",year:"Mid 2012",additional:""},{key:"MacBookPro8,3",name:"MacBook Pro",size:"17-inch",processor:"",year:"Early 2011",additional:""},{key:"MacBookPro8,2",name:"MacBook Pro",size:"15-inch",processor:"",year:"Early 2011",additional:""},{key:"MacBookPro8,1",name:"MacBook Pro",size:"13-inch",processor:"",year:"Early 2011",additional:""},{key:"MacBookPro6,1",name:"MacBook Pro",size:"17-inch",processor:"",year:"Mid 2010",additional:""},{key:"MacBookPro6,2",name:"MacBook Pro",size:"15-inch",processor:"",year:"Mid 2010",additional:""},{key:"MacBookPro7,1",name:"MacBook Pro",size:"13-inch",processor:"",year:"Mid 2010",additional:""},{key:"MacBookPro5,2",name:"MacBook Pro",size:"17-inch",processor:"",year:"Early 2009",additional:""},{key:"MacBookPro5,3",name:"MacBook Pro",size:"15-inch",processor:"",year:"Mid 2009",additional:""},{key:"MacBookPro5,5",name:"MacBook Pro",size:"13-inch",processor:"",year:"Mid 2009",additional:""},{key:"MacBookPro5,1",name:"MacBook Pro",size:"15-inch",processor:"",year:"Late 2008",additional:""},{key:"MacBookPro4,1",name:"MacBook Pro",size:"15-inch",processor:"",year:"Early 2008",additional:""},{key:"MacBook10,1",name:"MacBook",size:"12-inch",processor:"",year:"2017",additional:""},{key:"MacBook9,1",name:"MacBook",size:"12-inch",processor:"",year:"Early 2016",additional:""},{key:"MacBook8,1",name:"MacBook",size:"12-inch",processor:"",year:"Early 2015",additional:""},{key:"MacBook7,1",name:"MacBook",size:"13-inch",processor:"",year:"Mid 2010",additional:""},{key:"MacBook6,1",name:"MacBook",size:"13-inch",processor:"",year:"Late 2009",additional:""},{key:"MacBook5,2",name:"MacBook",size:"13-inch",processor:"",year:"Early 2009",additional:""},{key:"Mac14,13",name:"Mac Studio",size:"",processor:"M2 Max",year:"2023",additional:""},{key:"Mac14,14",name:"Mac Studio",size:"",processor:"M2 Ultra",year:"2023",additional:""},{key:"Mac15,14",name:"Mac Studio",size:"",processor:"M3 Ultra",year:"2025",additional:""},{key:"Mac16,9",name:"Mac Studio",size:"",processor:"M4 Max",year:"2025",additional:""},{key:"Mac13,1",name:"Mac Studio",size:"",processor:"M1 Max",year:"2022",additional:""},{key:"Mac13,2",name:"Mac Studio",size:"",processor:"M1 Ultra",year:"2022",additional:""},{key:"Mac16,11",name:"Mac mini",size:"",processor:"M4 Pro",year:"2024",additional:""},{key:"Mac16,10",name:"Mac mini",size:"",processor:"M4",year:"2024",additional:""},{key:"Mac14,3",name:"Mac mini",size:"",processor:"M2",year:"2023",additional:""},{key:"Mac14,12",name:"Mac mini",size:"",processor:"M2 Pro",year:"2023",additional:""},{key:"Macmini9,1",name:"Mac mini",size:"",processor:"M1",year:"2020",additional:""},{key:"Macmini8,1",name:"Mac mini",size:"",processor:"",year:"Late 2018",additional:""},{key:"Macmini7,1",name:"Mac mini",size:"",processor:"",year:"Late 2014",additional:""},{key:"Macmini6,1",name:"Mac mini",size:"",processor:"",year:"Late 2012",additional:""},{key:"Macmini6,2",name:"Mac mini",size:"",processor:"",year:"Late 2012",additional:""},{key:"Macmini5,1",name:"Mac mini",size:"",processor:"",year:"Mid 2011",additional:""},{key:"Macmini5,2",name:"Mac mini",size:"",processor:"",year:"Mid 2011",additional:""},{key:"Macmini4,1",name:"Mac mini",size:"",processor:"",year:"Mid 2010",additional:""},{key:"Macmini3,1",name:"Mac mini",size:"",processor:"",year:"Early 2009",additional:""},{key:"Mac16,3",name:"iMac",size:"24-inch",processor:"M4",year:"2024",additional:"Four ports"},{key:"Mac16,2",name:"iMac",size:"24-inch",processor:"M4",year:"2024",additional:"Two ports"},{key:"Mac15,5",name:"iMac",size:"24-inch",processor:"M3",year:"2023",additional:"Four ports"},{key:"Mac15,4",name:"iMac",size:"24-inch",processor:"M3",year:"2023",additional:"Two ports"},{key:"iMac21,1",name:"iMac",size:"24-inch",processor:"M1",year:"2021",additional:""},{key:"iMac21,2",name:"iMac",size:"24-inch",processor:"M1",year:"2021",additional:""},{key:"iMac20,1",name:"iMac",size:"27-inch",processor:"",year:"2020",additional:"Retina 5K"},{key:"iMac20,2",name:"iMac",size:"27-inch",processor:"",year:"2020",additional:"Retina 5K"},{key:"iMac19,1",name:"iMac",size:"27-inch",processor:"",year:"2019",additional:"Retina 5K"},{key:"iMac19,2",name:"iMac",size:"21.5-inch",processor:"",year:"2019",additional:"Retina 4K"},{key:"iMacPro1,1",name:"iMac Pro",size:"",processor:"",year:"2017",additional:""},{key:"iMac18,3",name:"iMac",size:"27-inch",processor:"",year:"2017",additional:"Retina 5K"},{key:"iMac18,2",name:"iMac",size:"21.5-inch",processor:"",year:"2017",additional:"Retina 4K"},{key:"iMac18,1",name:"iMac",size:"21.5-inch",processor:"",year:"2017",additional:""},{key:"iMac17,1",name:"iMac",size:"27-inch",processor:"",year:"Late 2015",additional:"Retina 5K"},{key:"iMac16,2",name:"iMac",size:"21.5-inch",processor:"",year:"Late 2015",additional:"Retina 4K"},{key:"iMac16,1",name:"iMac",size:"21.5-inch",processor:"",year:"Late 2015",additional:""},{key:"iMac15,1",name:"iMac",size:"27-inch",processor:"",year:"Late 2014",additional:"Retina 5K"},{key:"iMac14,4",name:"iMac",size:"21.5-inch",processor:"",year:"Mid 2014",additional:""},{key:"iMac14,2",name:"iMac",size:"27-inch",processor:"",year:"Late 2013",additional:""},{key:"iMac14,1",name:"iMac",size:"21.5-inch",processor:"",year:"Late 2013",additional:""},{key:"iMac13,2",name:"iMac",size:"27-inch",processor:"",year:"Late 2012",additional:""},{key:"iMac13,1",name:"iMac",size:"21.5-inch",processor:"",year:"Late 2012",additional:""},{key:"iMac12,2",name:"iMac",size:"27-inch",processor:"",year:"Mid 2011",additional:""},{key:"iMac12,1",name:"iMac",size:"21.5-inch",processor:"",year:"Mid 2011",additional:""},{key:"iMac11,3",name:"iMac",size:"27-inch",processor:"",year:"Mid 2010",additional:""},{key:"iMac11,2",name:"iMac",size:"21.5-inch",processor:"",year:"Mid 2010",additional:""},{key:"iMac10,1",name:"iMac",size:"21.5-inch",processor:"",year:"Late 2009",additional:""},{key:"iMac9,1",name:"iMac",size:"20-inch",processor:"",year:"Early 2009",additional:""},{key:"Mac14,8",name:"Mac Pro",size:"",processor:"",year:"2023",additional:""},{key:"Mac14,8",name:"Mac Pro",size:"",processor:"",year:"2023",additional:"Rack"},{key:"MacPro7,1",name:"Mac Pro",size:"",processor:"",year:"2019",additional:""},{key:"MacPro7,1",name:"Mac Pro",size:"",processor:"",year:"2019",additional:"Rack"},{key:"MacPro6,1",name:"Mac Pro",size:"",processor:"",year:"Late 2013",additional:""},{key:"MacPro5,1",name:"Mac Pro",size:"",processor:"",year:"Mid 2012",additional:""},{key:"MacPro5,1",name:"Mac Pro Server",size:"",processor:"",year:"Mid 2012",additional:"Server"},{key:"MacPro5,1",name:"Mac Pro",size:"",processor:"",year:"Mid 2010",additional:""},{key:"MacPro5,1",name:"Mac Pro Server",size:"",processor:"",year:"Mid 2010",additional:"Server"},{key:"MacPro4,1",name:"Mac Pro",size:"",processor:"",year:"Early 2009",additional:""}].filter((model)=>model.key===key);if(list2.length===0)return{key,model:"Apple",version:"Unknown"};let features=[];if(list2[0].size)features.push(list2[0].size);if(list2[0].processor)features.push(list2[0].processor);if(list2[0].year)features.push(list2[0].year);if(list2[0].additional)features.push(list2[0].additional);return{key,model:list2[0].name,version:list2[0].name+" ("+features.join(", ")+")"}}function checkWebsite(url,timeout=5000){let http=url.startsWith("https:")||url.indexOf(":443/")>0||url.indexOf(":8443/")>0?__require("https"):__require("http"),t2=Date.now();return new Promise((resolve13)=>{let request=http.get(url,(res)=>{res.on("data",()=>{}),res.on("end",()=>{resolve13({url,statusCode:res.statusCode,message:res.statusMessage,time:Date.now()-t2})})}).on("error",(e)=>{resolve13({url,statusCode:404,message:e.message,time:Date.now()-t2})}).setTimeout(timeout,()=>{request.destroy(),resolve13({url,statusCode:408,message:"Request Timeout",time:Date.now()-t2})})})}function cleanString(str5){return str5.replace(/To Be Filled By O.E.M./g,"")}function noop4(){}exports.toInt=toInt;exports.splitByNumber=splitByNumber;exports.execOptsWin=execOptsWin;exports.execOptsLinux=execOptsLinux;exports.getCodepage=getCodepage;exports.execWin=execWin;exports.isFunction=isFunction;exports.unique=unique;exports.sortByKey=sortByKey;exports.cores=cores;exports.getValue=getValue;exports.decodeEscapeSequence=decodeEscapeSequence;exports.parseDateTime=parseDateTime;exports.parseHead=parseHead;exports.findObjectByKey=findObjectByKey;exports.darwinXcodeExists=darwinXcodeExists;exports.getVboxmanage=getVboxmanage;exports.powerShell=powerShell;exports.powerShellStart=powerShellStart;exports.powerShellRelease=powerShellRelease;exports.execSafe=execSafe;exports.nanoSeconds=nanoSeconds;exports.countUniqueLines=countUniqueLines;exports.countLines=countLines;exports.noop=noop4;exports.isRaspberry=isRaspberry;exports.isRaspbian=isRaspbian;exports.sanitizeShellString=sanitizeShellString;exports.isPrototypePolluted=isPrototypePolluted;exports.decodePiCpuinfo=decodePiCpuinfo;exports.getRpiGpu=getRpiGpu;exports.promiseAll=promiseAll;exports.promisify=promisify4;exports.promisifySave=promisifySave;exports.smartMonToolsInstalled=smartMonToolsInstalled;exports.linuxVersion=linuxVersion;exports.plistParser=plistParser;exports.plistReader=plistReader;exports.stringObj=stringObj;exports.stringReplace=stringReplace;exports.stringToLower=stringToLower;exports.stringToString=stringToString;exports.stringSubstr=stringSubstr;exports.stringSubstring=stringSubstring;exports.stringTrim=stringTrim;exports.stringStartWith=stringStartWith;exports.mathMin=mathMin;exports.WINDIR=WINDIR;exports.getFilesInPath=getFilesInPath;exports.semverCompare=semverCompare;exports.getAppleModel=getAppleModel;exports.checkWebsite=checkWebsite;exports.cleanString=cleanString;exports.getPowershell=getPowershell});var require_osinfo=__commonJS((exports)=>{var os3=__require("os"),fs3=__require("fs"),util4=require_util3(),exec3=__require("child_process").exec,execSync17=__require("child_process").execSync,_platform=process.platform,_linux=_platform==="linux"||_platform==="android",_darwin=_platform==="darwin",_windows=_platform==="win32",_freebsd=_platform==="freebsd",_openbsd=_platform==="openbsd",_netbsd=_platform==="netbsd",_sunos=_platform==="sunos";function time(){let t2=new Date().toString().split(" "),timezoneName="";try{timezoneName=Intl.DateTimeFormat().resolvedOptions().timeZone}catch{timezoneName=t2.length>=7?t2.slice(6).join(" ").replace(/\(/g,"").replace(/\)/g,""):""}let result2={current:Date.now(),uptime:os3.uptime(),timezone:t2.length>=7?t2[5]:"",timezoneName};if(_darwin||_linux)try{let lines=execSync17("date +%Z && date +%z && ls -l /etc/localtime 2>/dev/null",util4.execOptsLinux).toString().split(os3.EOL);if(lines.length>3&&!lines[0])lines.shift();let timezone=lines[0]||"";if(timezone.startsWith("+")||timezone.startsWith("-"))timezone="GMT";return{current:Date.now(),uptime:os3.uptime(),timezone:lines[1]?timezone+lines[1]:timezone,timezoneName:lines[2]&&lines[2].indexOf("/zoneinfo/")>0?lines[2].split("/zoneinfo/")[1]||"":""}}catch{util4.noop()}return result2}exports.time=time;function getLogoFile(distro){distro=distro||"",distro=distro.toLowerCase();let result2=_platform;if(_windows)result2="windows";else if(distro.indexOf("mac os")!==-1||distro.indexOf("macos")!==-1)result2="apple";else if(distro.indexOf("arch")!==-1)result2="arch";else if(distro.indexOf("cachy")!==-1)result2="cachy";else if(distro.indexOf("centos")!==-1)result2="centos";else if(distro.indexOf("coreos")!==-1)result2="coreos";else if(distro.indexOf("debian")!==-1)result2="debian";else if(distro.indexOf("deepin")!==-1)result2="deepin";else if(distro.indexOf("elementary")!==-1)result2="elementary";else if(distro.indexOf("endeavour")!==-1)result2="endeavour";else if(distro.indexOf("fedora")!==-1)result2="fedora";else if(distro.indexOf("gentoo")!==-1)result2="gentoo";else if(distro.indexOf("mageia")!==-1)result2="mageia";else if(distro.indexOf("mandriva")!==-1)result2="mandriva";else if(distro.indexOf("manjaro")!==-1)result2="manjaro";else if(distro.indexOf("mint")!==-1)result2="mint";else if(distro.indexOf("mx")!==-1)result2="mx";else if(distro.indexOf("openbsd")!==-1)result2="openbsd";else if(distro.indexOf("freebsd")!==-1)result2="freebsd";else if(distro.indexOf("opensuse")!==-1)result2="opensuse";else if(distro.indexOf("pclinuxos")!==-1)result2="pclinuxos";else if(distro.indexOf("puppy")!==-1)result2="puppy";else if(distro.indexOf("popos")!==-1)result2="popos";else if(distro.indexOf("raspbian")!==-1)result2="raspbian";else if(distro.indexOf("reactos")!==-1)result2="reactos";else if(distro.indexOf("redhat")!==-1)result2="redhat";else if(distro.indexOf("slackware")!==-1)result2="slackware";else if(distro.indexOf("sugar")!==-1)result2="sugar";else if(distro.indexOf("steam")!==-1)result2="steam";else if(distro.indexOf("suse")!==-1)result2="suse";else if(distro.indexOf("mate")!==-1)result2="ubuntu-mate";else if(distro.indexOf("lubuntu")!==-1)result2="lubuntu";else if(distro.indexOf("xubuntu")!==-1)result2="xubuntu";else if(distro.indexOf("ubuntu")!==-1)result2="ubuntu";else if(distro.indexOf("solaris")!==-1)result2="solaris";else if(distro.indexOf("tails")!==-1)result2="tails";else if(distro.indexOf("feren")!==-1)result2="ferenos";else if(distro.indexOf("robolinux")!==-1)result2="robolinux";else if(_linux&&distro)result2=distro.toLowerCase().trim().replace(/\s+/g,"-");return result2}var WINDOWS_RELEASES=[[26200,"25H2"],[26100,"24H2"],[22631,"23H2"],[22621,"22H2"],[19045,"22H2"],[22000,"21H2"],[19044,"21H2"],[19043,"21H1"],[19042,"20H2"],[19041,"2004"],[18363,"1909"],[18362,"1903"],[17763,"1809"],[17134,"1803"]];function getWindowsRelease(build){for(let[minBuild,label]of WINDOWS_RELEASES)if(build>=minBuild)return label;return""}function getFQDN(){let fqdn=os3.hostname;if(_linux||_darwin)try{fqdn=execSync17("hostname -f 2>/dev/null",util4.execOptsLinux).toString().split(os3.EOL)[0]}catch{util4.noop()}if(_freebsd||_openbsd||_netbsd)try{fqdn=execSync17("hostname 2>/dev/null").toString().split(os3.EOL)[0]}catch{util4.noop()}if(_windows)try{fqdn=execSync17("echo %COMPUTERNAME%.%USERDNSDOMAIN%",util4.execOptsWin).toString().replace(".%USERDNSDOMAIN%","").split(os3.EOL)[0]}catch{util4.noop()}return fqdn}function osInfo(callback){return new Promise((resolve13)=>{process.nextTick(()=>{let result2={platform:_platform==="win32"?"Windows":_platform,distro:"unknown",release:"unknown",codename:"",kernel:os3.release(),arch:os3.arch(),hostname:os3.hostname(),fqdn:getFQDN(),codepage:"",logofile:"",serial:"",build:"",servicepack:"",uefi:!1};if(_linux)exec3("cat /etc/*-release; cat /usr/lib/os-release; cat /etc/openwrt_release",(error2,stdout)=>{let release={};stdout.toString().split(`
2479
+ `),_rpi_cpuinfo=cpuinfo}catch{return!1}let rpi=decodePiCpuinfo(cpuinfo);if(rpi.type==="4B"||rpi.type==="CM4"||rpi.type==="CM4S"||rpi.type==="400")return"VideoCore VI";if(rpi.type==="5"||rpi.type==="500")return"VideoCore VII";return"VideoCore IV"}function promiseAll(promises){let resolvingPromises=promises.map((promise)=>new Promise((resolve13)=>{let payload=[,,];promise.then((result2)=>{payload[0]=result2}).catch((error2)=>{payload[1]=error2}).then(()=>{resolve13(payload)})})),errors3=[],results=[];return Promise.all(resolvingPromises).then((items)=>{return items.forEach((payload)=>{if(payload[1])errors3.push(payload[1]),results.push(null);else errors3.push(null),results.push(payload[0])}),{errors:errors3,results}})}function promisify3(nodeStyleFunction){return()=>{let args=Array.prototype.slice.call(arguments);return new Promise((resolve13,reject)=>{args.push((err,data)=>{if(err)reject(err);else resolve13(data)}),nodeStyleFunction.apply(null,args)})}}function promisifySave(nodeStyleFunction){return()=>{let args=Array.prototype.slice.call(arguments);return new Promise((resolve13)=>{args.push((err,data)=>{resolve13(data)}),nodeStyleFunction.apply(null,args)})}}function linuxVersion(){let result2="";if(_linux)try{result2=execSync17("uname -v",execOptsLinux).toString()}catch{result2=""}return result2}function plistParser(xmlStr){let tags=["array","dict","key","string","integer","date","real","data","boolean","arrayEmpty"],startStr="<plist version",pos=xmlStr.indexOf("<plist version"),len=xmlStr.length;while(xmlStr[pos]!==">"&&pos<len)pos++;let depth=0,inTagStart=!1,inTagContent=!1,inTagEnd=!1,metaData=[{tagStart:"",tagEnd:"",tagContent:"",key:"",data:null}],c="",cn=xmlStr[pos];while(pos<len){if(c=cn,pos+1<len)cn=xmlStr[pos+1];if(c==="<"){if(inTagContent=!1,cn==="/")inTagEnd=!0;else if(metaData[depth].tagStart){if(metaData[depth].tagContent="",!metaData[depth].data)metaData[depth].data=metaData[depth].tagStart==="array"?[]:{};depth++,metaData.push({tagStart:"",tagEnd:"",tagContent:"",key:null,data:null}),inTagStart=!0,inTagContent=!1}else if(!inTagStart)inTagStart=!0}else if(c===">"){if(metaData[depth].tagStart==="true/")inTagStart=!1,inTagEnd=!0,metaData[depth].tagStart="",metaData[depth].tagEnd="/boolean",metaData[depth].data=!0;if(metaData[depth].tagStart==="false/")inTagStart=!1,inTagEnd=!0,metaData[depth].tagStart="",metaData[depth].tagEnd="/boolean",metaData[depth].data=!1;if(metaData[depth].tagStart==="array/")inTagStart=!1,inTagEnd=!0,metaData[depth].tagStart="",metaData[depth].tagEnd="/arrayEmpty",metaData[depth].data=[];if(inTagContent)inTagContent=!1;if(inTagStart){if(inTagStart=!1,inTagContent=!0,metaData[depth].tagStart==="array")metaData[depth].data=[];if(metaData[depth].tagStart==="dict")metaData[depth].data={}}if(inTagEnd){if(inTagEnd=!1,metaData[depth].tagEnd&&tags.indexOf(metaData[depth].tagEnd.substr(1))>=0)if(metaData[depth].tagEnd==="/dict"||metaData[depth].tagEnd==="/array"){if(depth>1&&metaData[depth-2].tagStart==="array")metaData[depth-2].data.push(metaData[depth-1].data);if(depth>1&&metaData[depth-2].tagStart==="dict")metaData[depth-2].data[metaData[depth-1].key]=metaData[depth-1].data;depth--,metaData.pop(),metaData[depth].tagContent="",metaData[depth].tagStart="",metaData[depth].tagEnd=""}else{if(metaData[depth].tagEnd==="/key"&&metaData[depth].tagContent)metaData[depth].key=metaData[depth].tagContent;else{if(metaData[depth].tagEnd==="/real"&&metaData[depth].tagContent)metaData[depth].data=parseFloat(metaData[depth].tagContent)||0;if(metaData[depth].tagEnd==="/integer"&&metaData[depth].tagContent)metaData[depth].data=parseInt(metaData[depth].tagContent)||0;if(metaData[depth].tagEnd==="/string"&&metaData[depth].tagContent)metaData[depth].data=metaData[depth].tagContent||"";if(metaData[depth].tagEnd==="/boolean")metaData[depth].data=metaData[depth].tagContent||!1;if(metaData[depth].tagEnd==="/arrayEmpty")metaData[depth].data=metaData[depth].tagContent||[];if(depth>0&&metaData[depth-1].tagStart==="array")metaData[depth-1].data.push(metaData[depth].data);if(depth>0&&metaData[depth-1].tagStart==="dict")metaData[depth-1].data[metaData[depth].key]=metaData[depth].data}metaData[depth].tagContent="",metaData[depth].tagStart="",metaData[depth].tagEnd=""}metaData[depth].tagEnd="",inTagStart=!1,inTagContent=!1}}else{if(inTagStart)metaData[depth].tagStart+=c;if(inTagEnd)metaData[depth].tagEnd+=c;if(inTagContent)metaData[depth].tagContent+=c}pos++}return metaData[0].data}function strIsNumeric(str5){return typeof str5==="string"&&!isNaN(str5)&&!isNaN(parseFloat(str5))}function plistReader(output){let lines=output.split(`
2480
+ `);for(let i2=0;i2<lines.length;i2++){if(lines[i2].indexOf(" = ")>=0){let lineParts=lines[i2].split(" = ");if(lineParts[0]=lineParts[0].trim(),!lineParts[0].startsWith('"'))lineParts[0]='"'+lineParts[0]+'"';if(lineParts[1]=lineParts[1].trim(),lineParts[1].indexOf('"')===-1&&lineParts[1].endsWith(";")){let valueString=lineParts[1].substring(0,lineParts[1].length-1);if(!strIsNumeric(valueString))lineParts[1]=`"${valueString}";`}if(lineParts[1].indexOf('"')>=0&&lineParts[1].endsWith(";")){let valueString=lineParts[1].substring(0,lineParts[1].length-1).replace(/"/g,"");if(strIsNumeric(valueString))lineParts[1]=`${valueString};`}lines[i2]=lineParts.join(" : ")}if(lines[i2]=lines[i2].replace(/\(/g,"[").replace(/\)/g,"]").replace(/;/g,",").trim(),lines[i2].startsWith("}")&&lines[i2-1]&&lines[i2-1].endsWith(","))lines[i2-1]=lines[i2-1].substring(0,lines[i2-1].length-1)}output=lines.join("");let obj={};try{obj=JSON.parse(output)}catch(e){noop4()}return obj}function semverCompare(v1,v2){let res=0,parts1=v1.split("."),parts2=v2.split(".");if(parts1[0]<parts2[0])res=1;else if(parts1[0]>parts2[0])res=-1;else if(parts1[0]===parts2[0]&&parts1.length>=2&&parts2.length>=2){if(parts1[1]<parts2[1])res=1;else if(parts1[1]>parts2[1])res=-1;else if(parts1[1]===parts2[1]){if(parts1.length>=3&&parts2.length>=3){if(parts1[2]<parts2[2])res=1;else if(parts1[2]>parts2[2])res=-1}else if(parts2.length>=3)res=1}}return res}function getAppleModel(key){let list2=[{key:"Mac17,7",name:"MacBook Pro",size:"16-inch",processor:"M5 Max",year:"2026",additional:""},{key:"Mac17,6",name:"MacBook Pro",size:"14-inch",processor:"M5 Max",year:"2026",additional:""},{key:"Mac17,5",name:"MacBook Pro",size:"16-inch",processor:"M5 Pro",year:"2026",additional:""},{key:"Mac17,4",name:"MacBook Pro",size:"14-inch",processor:"M5 Pro",year:"2026",additional:""},{key:"Mac17,1",name:"MacBook Neo",size:"14-inch",processor:"A18 Pro",year:"2026",additional:""},{key:"Mac17,3",name:"MacBook Pro",size:"16-inch",processor:"M5",year:"2025",additional:""},{key:"Mac17,2",name:"MacBook Pro",size:"14-inch",processor:"M5",year:"2025",additional:""},{key:"Mac16,13",name:"MacBook Air",size:"15-inch",processor:"M4",year:"2025",additional:""},{key:"Mac16,12",name:"MacBook Air",size:"13-inch",processor:"M4",year:"2025",additional:""},{key:"Mac15,13",name:"MacBook Air",size:"15-inch",processor:"M3",year:"2024",additional:""},{key:"Mac15,12",name:"MacBook Air",size:"13-inch",processor:"M3",year:"2024",additional:""},{key:"Mac14,15",name:"MacBook Air",size:"15-inch",processor:"M2",year:"2024",additional:""},{key:"Mac14,2",name:"MacBook Air",size:"13-inch",processor:"M2",year:"2022",additional:""},{key:"MacBookAir10,1",name:"MacBook Air",size:"13-inch",processor:"M1",year:"2020",additional:""},{key:"MacBookAir9,1",name:"MacBook Air",size:"13-inch",processor:"",year:"2020",additional:""},{key:"MacBookAir8,2",name:"MacBook Air",size:"13-inch",processor:"",year:"2019",additional:""},{key:"MacBookAir8,1",name:"MacBook Air",size:"13-inch",processor:"",year:"2018",additional:""},{key:"MacBookAir7,2",name:"MacBook Air",size:"13-inch",processor:"",year:"2017",additional:""},{key:"MacBookAir7,2",name:"MacBook Air",size:"13-inch",processor:"",year:"Early 2015",additional:""},{key:"MacBookAir7,1",name:"MacBook Air",size:"11-inch",processor:"",year:"Early 2015",additional:""},{key:"MacBookAir6,2",name:"MacBook Air",size:"13-inch",processor:"",year:"Early 2014",additional:""},{key:"MacBookAir6,1",name:"MacBook Air",size:"11-inch",processor:"",year:"Early 2014",additional:""},{key:"MacBookAir6,2",name:"MacBook Air",size:"13-inch",processor:"",year:"Mid 2013",additional:""},{key:"MacBookAir6,1",name:"MacBook Air",size:"11-inch",processor:"",year:"Mid 2013",additional:""},{key:"MacBookAir5,2",name:"MacBook Air",size:"13-inch",processor:"",year:"Mid 2012",additional:""},{key:"MacBookAir5,1",name:"MacBook Air",size:"11-inch",processor:"",year:"Mid 2012",additional:""},{key:"MacBookAir4,2",name:"MacBook Air",size:"13-inch",processor:"",year:"Mid 2011",additional:""},{key:"MacBookAir4,1",name:"MacBook Air",size:"11-inch",processor:"",year:"Mid 2011",additional:""},{key:"MacBookAir3,2",name:"MacBook Air",size:"13-inch",processor:"",year:"Late 2010",additional:""},{key:"MacBookAir3,1",name:"MacBook Air",size:"11-inch",processor:"",year:"Late 2010",additional:""},{key:"MacBookAir2,1",name:"MacBook Air",size:"13-inch",processor:"",year:"Mid 2009",additional:""},{key:"Mac16,1",name:"MacBook Pro",size:"14-inch",processor:"M4",year:"2024",additional:""},{key:"Mac16,6",name:"MacBook Pro",size:"14-inch",processor:"M4 Pro",year:"2024",additional:""},{key:"Mac16,8",name:"MacBook Pro",size:"14-inch",processor:"M4 Max",year:"2024",additional:""},{key:"Mac16,5",name:"MacBook Pro",size:"16-inch",processor:"M4 Pro",year:"2024",additional:""},{key:"Mac16,6",name:"MacBook Pro",size:"16-inch",processor:"M4 Max",year:"2024",additional:""},{key:"Mac15,3",name:"MacBook Pro",size:"14-inch",processor:"M3",year:"Nov 2023",additional:""},{key:"Mac15,6",name:"MacBook Pro",size:"14-inch",processor:"M3 Pro",year:"Nov 2023",additional:""},{key:"Mac15,8",name:"MacBook Pro",size:"14-inch",processor:"M3 Pro",year:"Nov 2023",additional:""},{key:"Mac15,10",name:"MacBook Pro",size:"14-inch",processor:"M3 Max",year:"Nov 2023",additional:""},{key:"Mac15,7",name:"MacBook Pro",size:"16-inch",processor:"M3 Pro",year:"Nov 2023",additional:""},{key:"Mac15,9",name:"MacBook Pro",size:"16-inch",processor:"M3 Pro",year:"Nov 2023",additional:""},{key:"Mac15,11",name:"MacBook Pro",size:"16-inch",processor:"M3 Max",year:"Nov 2023",additional:""},{key:"Mac14,5",name:"MacBook Pro",size:"14-inch",processor:"M2 Max",year:"2023",additional:""},{key:"Mac14,9",name:"MacBook Pro",size:"14-inch",processor:"M2 Max",year:"2023",additional:""},{key:"Mac14,6",name:"MacBook Pro",size:"16-inch",processor:"M2 Max",year:"2023",additional:""},{key:"Mac14,10",name:"MacBook Pro",size:"16-inch",processor:"M2 Max",year:"2023",additional:""},{key:"Mac14,7",name:"MacBook Pro",size:"13-inch",processor:"M2",year:"2022",additional:""},{key:"MacBookPro18,3",name:"MacBook Pro",size:"14-inch",processor:"M1 Pro",year:"2021",additional:""},{key:"MacBookPro18,4",name:"MacBook Pro",size:"14-inch",processor:"M1 Max",year:"2021",additional:""},{key:"MacBookPro18,1",name:"MacBook Pro",size:"16-inch",processor:"M1 Pro",year:"2021",additional:""},{key:"MacBookPro18,2",name:"MacBook Pro",size:"16-inch",processor:"M1 Max",year:"2021",additional:""},{key:"MacBookPro17,1",name:"MacBook Pro",size:"13-inch",processor:"M1",year:"2020",additional:""},{key:"MacBookPro16,3",name:"MacBook Pro",size:"13-inch",processor:"",year:"2020",additional:"Two Thunderbolt 3 ports"},{key:"MacBookPro16,2",name:"MacBook Pro",size:"13-inch",processor:"",year:"2020",additional:"Four Thunderbolt 3 ports"},{key:"MacBookPro16,1",name:"MacBook Pro",size:"16-inch",processor:"",year:"2019",additional:""},{key:"MacBookPro16,4",name:"MacBook Pro",size:"16-inch",processor:"",year:"2019",additional:""},{key:"MacBookPro15,3",name:"MacBook Pro",size:"15-inch",processor:"",year:"2019",additional:""},{key:"MacBookPro15,2",name:"MacBook Pro",size:"13-inch",processor:"",year:"2019",additional:""},{key:"MacBookPro15,1",name:"MacBook Pro",size:"15-inch",processor:"",year:"2019",additional:""},{key:"MacBookPro15,4",name:"MacBook Pro",size:"13-inch",processor:"",year:"2019",additional:"Two Thunderbolt 3 ports"},{key:"MacBookPro15,1",name:"MacBook Pro",size:"15-inch",processor:"",year:"2018",additional:""},{key:"MacBookPro15,2",name:"MacBook Pro",size:"13-inch",processor:"",year:"2018",additional:"Four Thunderbolt 3 ports"},{key:"MacBookPro14,1",name:"MacBook Pro",size:"13-inch",processor:"",year:"2017",additional:"Two Thunderbolt 3 ports"},{key:"MacBookPro14,2",name:"MacBook Pro",size:"13-inch",processor:"",year:"2017",additional:"Four Thunderbolt 3 ports"},{key:"MacBookPro14,3",name:"MacBook Pro",size:"15-inch",processor:"",year:"2017",additional:""},{key:"MacBookPro13,1",name:"MacBook Pro",size:"13-inch",processor:"",year:"2016",additional:"Two Thunderbolt 3 ports"},{key:"MacBookPro13,2",name:"MacBook Pro",size:"13-inch",processor:"",year:"2016",additional:"Four Thunderbolt 3 ports"},{key:"MacBookPro13,3",name:"MacBook Pro",size:"15-inch",processor:"",year:"2016",additional:""},{key:"MacBookPro11,4",name:"MacBook Pro",size:"15-inch",processor:"",year:"Mid 2015",additional:""},{key:"MacBookPro11,5",name:"MacBook Pro",size:"15-inch",processor:"",year:"Mid 2015",additional:""},{key:"MacBookPro12,1",name:"MacBook Pro",size:"13-inch",processor:"",year:"Early 2015",additional:""},{key:"MacBookPro11,2",name:"MacBook Pro",size:"15-inch",processor:"",year:"Late 2013",additional:""},{key:"MacBookPro11,3",name:"MacBook Pro",size:"15-inch",processor:"",year:"Late 2013",additional:""},{key:"MacBookPro11,1",name:"MacBook Pro",size:"13-inch",processor:"",year:"Late 2013",additional:""},{key:"MacBookPro10,1",name:"MacBook Pro",size:"15-inch",processor:"",year:"Mid 2012",additional:""},{key:"MacBookPro10,2",name:"MacBook Pro",size:"13-inch",processor:"",year:"Late 2012",additional:""},{key:"MacBookPro9,1",name:"MacBook Pro",size:"15-inch",processor:"",year:"Mid 2012",additional:""},{key:"MacBookPro9,2",name:"MacBook Pro",size:"13-inch",processor:"",year:"Mid 2012",additional:""},{key:"MacBookPro8,3",name:"MacBook Pro",size:"17-inch",processor:"",year:"Early 2011",additional:""},{key:"MacBookPro8,2",name:"MacBook Pro",size:"15-inch",processor:"",year:"Early 2011",additional:""},{key:"MacBookPro8,1",name:"MacBook Pro",size:"13-inch",processor:"",year:"Early 2011",additional:""},{key:"MacBookPro6,1",name:"MacBook Pro",size:"17-inch",processor:"",year:"Mid 2010",additional:""},{key:"MacBookPro6,2",name:"MacBook Pro",size:"15-inch",processor:"",year:"Mid 2010",additional:""},{key:"MacBookPro7,1",name:"MacBook Pro",size:"13-inch",processor:"",year:"Mid 2010",additional:""},{key:"MacBookPro5,2",name:"MacBook Pro",size:"17-inch",processor:"",year:"Early 2009",additional:""},{key:"MacBookPro5,3",name:"MacBook Pro",size:"15-inch",processor:"",year:"Mid 2009",additional:""},{key:"MacBookPro5,5",name:"MacBook Pro",size:"13-inch",processor:"",year:"Mid 2009",additional:""},{key:"MacBookPro5,1",name:"MacBook Pro",size:"15-inch",processor:"",year:"Late 2008",additional:""},{key:"MacBookPro4,1",name:"MacBook Pro",size:"15-inch",processor:"",year:"Early 2008",additional:""},{key:"MacBook10,1",name:"MacBook",size:"12-inch",processor:"",year:"2017",additional:""},{key:"MacBook9,1",name:"MacBook",size:"12-inch",processor:"",year:"Early 2016",additional:""},{key:"MacBook8,1",name:"MacBook",size:"12-inch",processor:"",year:"Early 2015",additional:""},{key:"MacBook7,1",name:"MacBook",size:"13-inch",processor:"",year:"Mid 2010",additional:""},{key:"MacBook6,1",name:"MacBook",size:"13-inch",processor:"",year:"Late 2009",additional:""},{key:"MacBook5,2",name:"MacBook",size:"13-inch",processor:"",year:"Early 2009",additional:""},{key:"Mac14,13",name:"Mac Studio",size:"",processor:"M2 Max",year:"2023",additional:""},{key:"Mac14,14",name:"Mac Studio",size:"",processor:"M2 Ultra",year:"2023",additional:""},{key:"Mac15,14",name:"Mac Studio",size:"",processor:"M3 Ultra",year:"2025",additional:""},{key:"Mac16,9",name:"Mac Studio",size:"",processor:"M4 Max",year:"2025",additional:""},{key:"Mac13,1",name:"Mac Studio",size:"",processor:"M1 Max",year:"2022",additional:""},{key:"Mac13,2",name:"Mac Studio",size:"",processor:"M1 Ultra",year:"2022",additional:""},{key:"Mac16,11",name:"Mac mini",size:"",processor:"M4 Pro",year:"2024",additional:""},{key:"Mac16,10",name:"Mac mini",size:"",processor:"M4",year:"2024",additional:""},{key:"Mac14,3",name:"Mac mini",size:"",processor:"M2",year:"2023",additional:""},{key:"Mac14,12",name:"Mac mini",size:"",processor:"M2 Pro",year:"2023",additional:""},{key:"Macmini9,1",name:"Mac mini",size:"",processor:"M1",year:"2020",additional:""},{key:"Macmini8,1",name:"Mac mini",size:"",processor:"",year:"Late 2018",additional:""},{key:"Macmini7,1",name:"Mac mini",size:"",processor:"",year:"Late 2014",additional:""},{key:"Macmini6,1",name:"Mac mini",size:"",processor:"",year:"Late 2012",additional:""},{key:"Macmini6,2",name:"Mac mini",size:"",processor:"",year:"Late 2012",additional:""},{key:"Macmini5,1",name:"Mac mini",size:"",processor:"",year:"Mid 2011",additional:""},{key:"Macmini5,2",name:"Mac mini",size:"",processor:"",year:"Mid 2011",additional:""},{key:"Macmini4,1",name:"Mac mini",size:"",processor:"",year:"Mid 2010",additional:""},{key:"Macmini3,1",name:"Mac mini",size:"",processor:"",year:"Early 2009",additional:""},{key:"Mac16,3",name:"iMac",size:"24-inch",processor:"M4",year:"2024",additional:"Four ports"},{key:"Mac16,2",name:"iMac",size:"24-inch",processor:"M4",year:"2024",additional:"Two ports"},{key:"Mac15,5",name:"iMac",size:"24-inch",processor:"M3",year:"2023",additional:"Four ports"},{key:"Mac15,4",name:"iMac",size:"24-inch",processor:"M3",year:"2023",additional:"Two ports"},{key:"iMac21,1",name:"iMac",size:"24-inch",processor:"M1",year:"2021",additional:""},{key:"iMac21,2",name:"iMac",size:"24-inch",processor:"M1",year:"2021",additional:""},{key:"iMac20,1",name:"iMac",size:"27-inch",processor:"",year:"2020",additional:"Retina 5K"},{key:"iMac20,2",name:"iMac",size:"27-inch",processor:"",year:"2020",additional:"Retina 5K"},{key:"iMac19,1",name:"iMac",size:"27-inch",processor:"",year:"2019",additional:"Retina 5K"},{key:"iMac19,2",name:"iMac",size:"21.5-inch",processor:"",year:"2019",additional:"Retina 4K"},{key:"iMacPro1,1",name:"iMac Pro",size:"",processor:"",year:"2017",additional:""},{key:"iMac18,3",name:"iMac",size:"27-inch",processor:"",year:"2017",additional:"Retina 5K"},{key:"iMac18,2",name:"iMac",size:"21.5-inch",processor:"",year:"2017",additional:"Retina 4K"},{key:"iMac18,1",name:"iMac",size:"21.5-inch",processor:"",year:"2017",additional:""},{key:"iMac17,1",name:"iMac",size:"27-inch",processor:"",year:"Late 2015",additional:"Retina 5K"},{key:"iMac16,2",name:"iMac",size:"21.5-inch",processor:"",year:"Late 2015",additional:"Retina 4K"},{key:"iMac16,1",name:"iMac",size:"21.5-inch",processor:"",year:"Late 2015",additional:""},{key:"iMac15,1",name:"iMac",size:"27-inch",processor:"",year:"Late 2014",additional:"Retina 5K"},{key:"iMac14,4",name:"iMac",size:"21.5-inch",processor:"",year:"Mid 2014",additional:""},{key:"iMac14,2",name:"iMac",size:"27-inch",processor:"",year:"Late 2013",additional:""},{key:"iMac14,1",name:"iMac",size:"21.5-inch",processor:"",year:"Late 2013",additional:""},{key:"iMac13,2",name:"iMac",size:"27-inch",processor:"",year:"Late 2012",additional:""},{key:"iMac13,1",name:"iMac",size:"21.5-inch",processor:"",year:"Late 2012",additional:""},{key:"iMac12,2",name:"iMac",size:"27-inch",processor:"",year:"Mid 2011",additional:""},{key:"iMac12,1",name:"iMac",size:"21.5-inch",processor:"",year:"Mid 2011",additional:""},{key:"iMac11,3",name:"iMac",size:"27-inch",processor:"",year:"Mid 2010",additional:""},{key:"iMac11,2",name:"iMac",size:"21.5-inch",processor:"",year:"Mid 2010",additional:""},{key:"iMac10,1",name:"iMac",size:"21.5-inch",processor:"",year:"Late 2009",additional:""},{key:"iMac9,1",name:"iMac",size:"20-inch",processor:"",year:"Early 2009",additional:""},{key:"Mac14,8",name:"Mac Pro",size:"",processor:"",year:"2023",additional:""},{key:"Mac14,8",name:"Mac Pro",size:"",processor:"",year:"2023",additional:"Rack"},{key:"MacPro7,1",name:"Mac Pro",size:"",processor:"",year:"2019",additional:""},{key:"MacPro7,1",name:"Mac Pro",size:"",processor:"",year:"2019",additional:"Rack"},{key:"MacPro6,1",name:"Mac Pro",size:"",processor:"",year:"Late 2013",additional:""},{key:"MacPro5,1",name:"Mac Pro",size:"",processor:"",year:"Mid 2012",additional:""},{key:"MacPro5,1",name:"Mac Pro Server",size:"",processor:"",year:"Mid 2012",additional:"Server"},{key:"MacPro5,1",name:"Mac Pro",size:"",processor:"",year:"Mid 2010",additional:""},{key:"MacPro5,1",name:"Mac Pro Server",size:"",processor:"",year:"Mid 2010",additional:"Server"},{key:"MacPro4,1",name:"Mac Pro",size:"",processor:"",year:"Early 2009",additional:""}].filter((model)=>model.key===key);if(list2.length===0)return{key,model:"Apple",version:"Unknown"};let features=[];if(list2[0].size)features.push(list2[0].size);if(list2[0].processor)features.push(list2[0].processor);if(list2[0].year)features.push(list2[0].year);if(list2[0].additional)features.push(list2[0].additional);return{key,model:list2[0].name,version:list2[0].name+" ("+features.join(", ")+")"}}function checkWebsite(url,timeout=5000){let http=url.startsWith("https:")||url.indexOf(":443/")>0||url.indexOf(":8443/")>0?__require("https"):__require("http"),t2=Date.now();return new Promise((resolve13)=>{let request=http.get(url,(res)=>{res.on("data",()=>{}),res.on("end",()=>{resolve13({url,statusCode:res.statusCode,message:res.statusMessage,time:Date.now()-t2})})}).on("error",(e)=>{resolve13({url,statusCode:404,message:e.message,time:Date.now()-t2})}).setTimeout(timeout,()=>{request.destroy(),resolve13({url,statusCode:408,message:"Request Timeout",time:Date.now()-t2})})})}function cleanString(str5){return str5.replace(/To Be Filled By O.E.M./g,"")}function noop4(){}exports.toInt=toInt;exports.splitByNumber=splitByNumber;exports.execOptsWin=execOptsWin;exports.execOptsLinux=execOptsLinux;exports.getCodepage=getCodepage;exports.execWin=execWin;exports.isFunction=isFunction;exports.unique=unique;exports.sortByKey=sortByKey;exports.cores=cores;exports.getValue=getValue;exports.decodeEscapeSequence=decodeEscapeSequence;exports.parseDateTime=parseDateTime;exports.parseHead=parseHead;exports.findObjectByKey=findObjectByKey;exports.darwinXcodeExists=darwinXcodeExists;exports.getVboxmanage=getVboxmanage;exports.powerShell=powerShell;exports.powerShellStart=powerShellStart;exports.powerShellRelease=powerShellRelease;exports.execSafe=execSafe;exports.nanoSeconds=nanoSeconds;exports.countUniqueLines=countUniqueLines;exports.countLines=countLines;exports.noop=noop4;exports.isRaspberry=isRaspberry;exports.isRaspbian=isRaspbian;exports.sanitizeShellString=sanitizeShellString;exports.isPrototypePolluted=isPrototypePolluted;exports.decodePiCpuinfo=decodePiCpuinfo;exports.getRpiGpu=getRpiGpu;exports.promiseAll=promiseAll;exports.promisify=promisify3;exports.promisifySave=promisifySave;exports.smartMonToolsInstalled=smartMonToolsInstalled;exports.linuxVersion=linuxVersion;exports.plistParser=plistParser;exports.plistReader=plistReader;exports.stringObj=stringObj;exports.stringReplace=stringReplace;exports.stringToLower=stringToLower;exports.stringToString=stringToString;exports.stringSubstr=stringSubstr;exports.stringSubstring=stringSubstring;exports.stringTrim=stringTrim;exports.stringStartWith=stringStartWith;exports.mathMin=mathMin;exports.WINDIR=WINDIR;exports.getFilesInPath=getFilesInPath;exports.semverCompare=semverCompare;exports.getAppleModel=getAppleModel;exports.checkWebsite=checkWebsite;exports.cleanString=cleanString;exports.getPowershell=getPowershell});var require_osinfo=__commonJS((exports)=>{var os3=__require("os"),fs3=__require("fs"),util4=require_util3(),exec3=__require("child_process").exec,execSync17=__require("child_process").execSync,_platform=process.platform,_linux=_platform==="linux"||_platform==="android",_darwin=_platform==="darwin",_windows=_platform==="win32",_freebsd=_platform==="freebsd",_openbsd=_platform==="openbsd",_netbsd=_platform==="netbsd",_sunos=_platform==="sunos";function time(){let t2=new Date().toString().split(" "),timezoneName="";try{timezoneName=Intl.DateTimeFormat().resolvedOptions().timeZone}catch{timezoneName=t2.length>=7?t2.slice(6).join(" ").replace(/\(/g,"").replace(/\)/g,""):""}let result2={current:Date.now(),uptime:os3.uptime(),timezone:t2.length>=7?t2[5]:"",timezoneName};if(_darwin||_linux)try{let lines=execSync17("date +%Z && date +%z && ls -l /etc/localtime 2>/dev/null",util4.execOptsLinux).toString().split(os3.EOL);if(lines.length>3&&!lines[0])lines.shift();let timezone=lines[0]||"";if(timezone.startsWith("+")||timezone.startsWith("-"))timezone="GMT";return{current:Date.now(),uptime:os3.uptime(),timezone:lines[1]?timezone+lines[1]:timezone,timezoneName:lines[2]&&lines[2].indexOf("/zoneinfo/")>0?lines[2].split("/zoneinfo/")[1]||"":""}}catch{util4.noop()}return result2}exports.time=time;function getLogoFile(distro){distro=distro||"",distro=distro.toLowerCase();let result2=_platform;if(_windows)result2="windows";else if(distro.indexOf("mac os")!==-1||distro.indexOf("macos")!==-1)result2="apple";else if(distro.indexOf("arch")!==-1)result2="arch";else if(distro.indexOf("cachy")!==-1)result2="cachy";else if(distro.indexOf("centos")!==-1)result2="centos";else if(distro.indexOf("coreos")!==-1)result2="coreos";else if(distro.indexOf("debian")!==-1)result2="debian";else if(distro.indexOf("deepin")!==-1)result2="deepin";else if(distro.indexOf("elementary")!==-1)result2="elementary";else if(distro.indexOf("endeavour")!==-1)result2="endeavour";else if(distro.indexOf("fedora")!==-1)result2="fedora";else if(distro.indexOf("gentoo")!==-1)result2="gentoo";else if(distro.indexOf("mageia")!==-1)result2="mageia";else if(distro.indexOf("mandriva")!==-1)result2="mandriva";else if(distro.indexOf("manjaro")!==-1)result2="manjaro";else if(distro.indexOf("mint")!==-1)result2="mint";else if(distro.indexOf("mx")!==-1)result2="mx";else if(distro.indexOf("openbsd")!==-1)result2="openbsd";else if(distro.indexOf("freebsd")!==-1)result2="freebsd";else if(distro.indexOf("opensuse")!==-1)result2="opensuse";else if(distro.indexOf("pclinuxos")!==-1)result2="pclinuxos";else if(distro.indexOf("puppy")!==-1)result2="puppy";else if(distro.indexOf("popos")!==-1)result2="popos";else if(distro.indexOf("raspbian")!==-1)result2="raspbian";else if(distro.indexOf("reactos")!==-1)result2="reactos";else if(distro.indexOf("redhat")!==-1)result2="redhat";else if(distro.indexOf("slackware")!==-1)result2="slackware";else if(distro.indexOf("sugar")!==-1)result2="sugar";else if(distro.indexOf("steam")!==-1)result2="steam";else if(distro.indexOf("suse")!==-1)result2="suse";else if(distro.indexOf("mate")!==-1)result2="ubuntu-mate";else if(distro.indexOf("lubuntu")!==-1)result2="lubuntu";else if(distro.indexOf("xubuntu")!==-1)result2="xubuntu";else if(distro.indexOf("ubuntu")!==-1)result2="ubuntu";else if(distro.indexOf("solaris")!==-1)result2="solaris";else if(distro.indexOf("tails")!==-1)result2="tails";else if(distro.indexOf("feren")!==-1)result2="ferenos";else if(distro.indexOf("robolinux")!==-1)result2="robolinux";else if(_linux&&distro)result2=distro.toLowerCase().trim().replace(/\s+/g,"-");return result2}var WINDOWS_RELEASES=[[26200,"25H2"],[26100,"24H2"],[22631,"23H2"],[22621,"22H2"],[19045,"22H2"],[22000,"21H2"],[19044,"21H2"],[19043,"21H1"],[19042,"20H2"],[19041,"2004"],[18363,"1909"],[18362,"1903"],[17763,"1809"],[17134,"1803"]];function getWindowsRelease(build){for(let[minBuild,label]of WINDOWS_RELEASES)if(build>=minBuild)return label;return""}function getFQDN(){let fqdn=os3.hostname;if(_linux||_darwin)try{fqdn=execSync17("hostname -f 2>/dev/null",util4.execOptsLinux).toString().split(os3.EOL)[0]}catch{util4.noop()}if(_freebsd||_openbsd||_netbsd)try{fqdn=execSync17("hostname 2>/dev/null").toString().split(os3.EOL)[0]}catch{util4.noop()}if(_windows)try{fqdn=execSync17("echo %COMPUTERNAME%.%USERDNSDOMAIN%",util4.execOptsWin).toString().replace(".%USERDNSDOMAIN%","").split(os3.EOL)[0]}catch{util4.noop()}return fqdn}function osInfo(callback){return new Promise((resolve13)=>{process.nextTick(()=>{let result2={platform:_platform==="win32"?"Windows":_platform,distro:"unknown",release:"unknown",codename:"",kernel:os3.release(),arch:os3.arch(),hostname:os3.hostname(),fqdn:getFQDN(),codepage:"",logofile:"",serial:"",build:"",servicepack:"",uefi:!1};if(_linux)exec3("cat /etc/*-release; cat /usr/lib/os-release; cat /etc/openwrt_release",(error2,stdout)=>{let release={};stdout.toString().split(`
2481
2481
  `).forEach((line)=>{if(line.indexOf("=")!==-1)release[line.split("=")[0].trim().toUpperCase()]=line.split("=")[1].trim()}),result2.distro=(release.DISTRIB_ID||release.NAME||"unknown").replace(/"/g,""),result2.logofile=getLogoFile(result2.distro);let releaseVersion=(release.VERSION||"").replace(/"/g,""),codename=(release.DISTRIB_CODENAME||release.VERSION_CODENAME||"").replace(/"/g,""),prettyName=(release.PRETTY_NAME||"").replace(/"/g,"");if(prettyName.indexOf(result2.distro+" ")===0)releaseVersion=prettyName.replace(result2.distro+" ","").trim();if(releaseVersion.indexOf("(")>=0)codename=releaseVersion.split("(")[1].replace(/[()]/g,"").trim(),releaseVersion=releaseVersion.split("(")[0].trim();result2.release=(releaseVersion||release.DISTRIB_RELEASE||release.VERSION_ID||"unknown").replace(/"/g,""),result2.codename=codename,result2.codepage=util4.getCodepage(),result2.build=(release.BUILD_ID||"").replace(/"/g,"").trim(),isUefiLinux().then((uefi)=>{result2.uefi=uefi,uuid().then((data)=>{if(result2.serial=data.os,callback)callback(result2);resolve13(result2)})})});if(_freebsd||_openbsd||_netbsd)exec3("sysctl kern.ostype kern.osrelease kern.osrevision kern.hostuuid machdep.bootmethod kern.geom.confxml",(error2,stdout)=>{let lines=stdout.toString().split(`
2482
2482
  `),distro=util4.getValue(lines,"kern.ostype"),logofile=getLogoFile(distro),release=util4.getValue(lines,"kern.osrelease").split("-")[0],serial=util4.getValue(lines,"kern.uuid"),bootmethod=util4.getValue(lines,"machdep.bootmethod"),uefiConf=stdout.toString().indexOf("<type>efi</type>")>=0,uefi=bootmethod?bootmethod.toLowerCase().indexOf("uefi")>=0:uefiConf?uefiConf:null;if(result2.distro=distro||result2.distro,result2.logofile=logofile||result2.logofile,result2.release=release||result2.release,result2.serial=serial||result2.serial,result2.codename="",result2.codepage=util4.getCodepage(),result2.uefi=uefi||null,callback)callback(result2);resolve13(result2)});if(_darwin)exec3("sw_vers; sysctl kern.ostype kern.osrelease kern.osrevision kern.uuid",(error2,stdout)=>{let lines=stdout.toString().split(`
2483
2483
  `);if(result2.serial=util4.getValue(lines,"kern.uuid"),result2.distro=util4.getValue(lines,"ProductName"),result2.release=(util4.getValue(lines,"ProductVersion",":",!0,!0)+" "+util4.getValue(lines,"ProductVersionExtra",":",!0,!0)).trim(),result2.build=util4.getValue(lines,"BuildVersion"),result2.logofile=getLogoFile(result2.distro),result2.codename="macOS",result2.codename=result2.release.indexOf("10.4")>-1?"OS X Tiger":result2.codename,result2.codename=result2.release.indexOf("10.5")>-1?"OS X Leopard":result2.codename,result2.codename=result2.release.indexOf("10.6")>-1?"OS X Snow Leopard":result2.codename,result2.codename=result2.release.indexOf("10.7")>-1?"OS X Lion":result2.codename,result2.codename=result2.release.indexOf("10.8")>-1?"OS X Mountain Lion":result2.codename,result2.codename=result2.release.indexOf("10.9")>-1?"OS X Mavericks":result2.codename,result2.codename=result2.release.indexOf("10.10")>-1?"OS X Yosemite":result2.codename,result2.codename=result2.release.indexOf("10.11")>-1?"OS X El Capitan":result2.codename,result2.codename=result2.release.indexOf("10.12")>-1?"Sierra":result2.codename,result2.codename=result2.release.indexOf("10.13")>-1?"High Sierra":result2.codename,result2.codename=result2.release.indexOf("10.14")>-1?"Mojave":result2.codename,result2.codename=result2.release.indexOf("10.15")>-1?"Catalina":result2.codename,result2.codename=result2.release.startsWith("11.")?"Big Sur":result2.codename,result2.codename=result2.release.startsWith("12.")?"Monterey":result2.codename,result2.codename=result2.release.startsWith("13.")?"Ventura":result2.codename,result2.codename=result2.release.startsWith("14.")?"Sonoma":result2.codename,result2.codename=result2.release.startsWith("15.")?"Sequoia":result2.codename,result2.codename=result2.release.startsWith("26.")?"Tahoe":result2.codename,result2.uefi=!0,result2.codepage=util4.getCodepage(),callback)callback(result2);resolve13(result2)});if(_sunos)result2.release=result2.kernel,exec3("uname -o",(error2,stdout)=>{let lines=stdout.toString().split(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/genie",
3
- "version": "4.260405.16",
3
+ "version": "4.260406.1",
4
4
  "description": "Collaborative terminal toolkit for human + AI workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genie",
3
- "version": "4.260405.16",
3
+ "version": "4.260406.1",
4
4
  "description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, turn them into wishes, execute with /work, validate with /review, and ship as one team.",
5
5
  "author": {
6
6
  "name": "Namastex Labs"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genie-plugin",
3
- "version": "4.260405.16",
3
+ "version": "4.260406.1",
4
4
  "private": true,
5
5
  "description": "Runtime dependencies for genie bundled CLIs",
6
6
  "type": "module",
@@ -427,6 +427,7 @@ function makeMockExecutor(overrides?: {
427
427
  return overrides?.isAliveResult ?? true;
428
428
  },
429
429
  setSafePgCall() {},
430
+ setNatsPublish() {},
430
431
  async injectNudge() {},
431
432
  };
432
433
 
@@ -32,6 +32,9 @@ export interface OmniMessage {
32
32
  timestamp?: string;
33
33
  }
34
34
 
35
+ /** Callback for publishing NATS reply messages in-process (replaces subprocess fork). */
36
+ export type NatsPublishFn = (topic: string, payload: string) => void;
37
+
35
38
  /** Pluggable executor backend for the Omni bridge. TODO: merge into ExecutorProvider. */
36
39
  export interface IExecutor {
37
40
  spawn(agentName: string, chatId: string, env: Record<string, string>): Promise<OmniSession>;
@@ -39,6 +42,8 @@ export interface IExecutor {
39
42
  shutdown(session: OmniSession): Promise<void>;
40
43
  isAlive(session: OmniSession): Promise<boolean>;
41
44
  setSafePgCall(fn: import('../lib/safe-pg-call.js').SafePgCallFn): void;
45
+ /** Inject NATS publish function for in-process reply delivery. */
46
+ setNatsPublish(fn: NatsPublishFn): void;
42
47
  /** Inject a nudge message into an active session (for turn timeout warnings). */
43
48
  injectNudge(session: OmniSession, text: string): Promise<void>;
44
49
  }
@@ -35,6 +35,10 @@ export class ClaudeCodeOmniExecutor implements IExecutor {
35
35
  this.safePgCall = fn;
36
36
  }
37
37
 
38
+ setNatsPublish(_fn: import('../executor.js').NatsPublishFn): void {
39
+ // No-op: tmux executor replies via tmux pane, not NATS
40
+ }
41
+
38
42
  async injectNudge(session: OmniSession, text: string): Promise<void> {
39
43
  const nudgeText = `[system] ${text}`;
40
44
  await executeTmux(`send-keys -t '${session.paneId}' ${shellQuote(nudgeText)} Enter`);
@@ -1,5 +1,3 @@
1
- import { execFile as execFileCb } from 'node:child_process';
2
- import { promisify } from 'node:util';
3
1
  import type { Query } from '@anthropic-ai/claude-agent-sdk';
4
2
 
5
3
  import { z } from 'zod';
@@ -9,11 +7,9 @@ import { recordAuditEvent } from '../../lib/audit-events.js';
9
7
  import * as registry from '../../lib/executor-registry.js';
10
8
  import { resolvePermissionConfig } from '../../lib/providers/claude-sdk-permissions.js';
11
9
  import { ClaudeSdkProvider } from '../../lib/providers/claude-sdk.js';
12
- import type { IExecutor, OmniMessage, OmniSession, SafePgCallFn } from '../executor.js';
10
+ import type { IExecutor, NatsPublishFn, OmniMessage, OmniSession, SafePgCallFn } from '../executor.js';
13
11
  import { endSession, recordTurn, startSession, updateTurnCount } from './sdk-session-capture.js';
14
12
 
15
- const execFileAsync = promisify(execFileCb);
16
-
17
13
  // ============================================================================
18
14
  // Types
19
15
  // ============================================================================
@@ -74,36 +70,67 @@ async function collectQueryResult(queryMessages: Query): Promise<QueryResult> {
74
70
  }
75
71
 
76
72
  // ============================================================================
77
- // Done tool
73
+ // Done tool — NATS reply (in-process, no subprocess fork)
78
74
  // ============================================================================
79
75
 
80
- export async function handleDoneTool(params: Record<string, unknown>, env: Record<string, string>): Promise<string> {
81
- const args = ['done'];
82
- if (params.skip) {
83
- args.push('--skip');
84
- if (params.reason) args.push('--reason', String(params.reason));
85
- } else if (params.react) {
86
- args.push('--react', String(params.react));
87
- } else if (params.media) {
88
- args.push('--media', String(params.media));
89
- if (params.caption) args.push('--caption', String(params.caption));
90
- if (params.text) args.push(String(params.text));
91
- } else if (params.text) {
92
- args.push(String(params.text));
93
- } else {
94
- args.push('--skip');
76
+ function buildReplyPayload(agent: string, chatId: string, instanceId: string, extra: Record<string, unknown> = {}) {
77
+ return JSON.stringify({
78
+ content: '',
79
+ agent,
80
+ chat_id: chatId,
81
+ instance_id: instanceId,
82
+ timestamp: new Date().toISOString(),
83
+ ...extra,
84
+ });
85
+ }
86
+
87
+ function resolveAction(
88
+ params: Record<string, unknown>,
89
+ env: Record<string, string>,
90
+ ): { type: 'skip' | 'react' | 'media' | 'text'; extra: Record<string, unknown>; label: string } {
91
+ if (params.skip) return { type: 'skip', extra: { reason: params.reason }, label: 'Turn closed (skip).' };
92
+ if (params.react)
93
+ return {
94
+ type: 'react',
95
+ extra: { react: String(params.react), message_id: env.OMNI_MESSAGE ?? '' },
96
+ label: `Reacted ${params.react} + turn closed.`,
97
+ };
98
+ if (params.media) {
99
+ const text = params.caption ? String(params.caption) : params.text ? String(params.text) : '';
100
+ return { type: 'media', extra: { content: text, media: String(params.media) }, label: 'Media sent + turn closed.' };
95
101
  }
96
- try {
97
- await execFileAsync('omni', args, { env: { ...process.env, ...env } });
98
- return 'Turn closed. Message delivered.';
99
- } catch (err) {
100
- const msg = err instanceof Error ? err.message : String(err);
101
- console.warn(`[claude-sdk] omni done failed: ${msg}`);
102
- return `Turn close attempted but omni done failed: ${msg}`;
102
+ if (params.text)
103
+ return { type: 'text', extra: { content: String(params.text) }, label: 'Turn closed. Message delivered.' };
104
+ return { type: 'skip', extra: {}, label: 'Turn closed (skip).' };
105
+ }
106
+
107
+ export function handleDoneTool(
108
+ params: Record<string, unknown>,
109
+ env: Record<string, string>,
110
+ natsPublish: NatsPublishFn | null,
111
+ ): string {
112
+ const instanceId = env.OMNI_INSTANCE ?? '';
113
+ const chatId = env.OMNI_CHAT ?? '';
114
+ const agent = env.OMNI_AGENT ?? '';
115
+ const action = resolveAction(params, env);
116
+
117
+ if (action.type === 'skip') {
118
+ if (natsPublish && instanceId && chatId) {
119
+ natsPublish(`omni.turn.done.${instanceId}.${chatId}`, JSON.stringify({ action: 'skip', ...action.extra }));
120
+ }
121
+ return action.label;
122
+ }
123
+
124
+ if (!natsPublish || !instanceId || !chatId) {
125
+ console.warn('[claude-sdk] No NATS publish available — reply dropped');
126
+ return 'Turn close attempted but NATS publish not available.';
103
127
  }
128
+
129
+ natsPublish(`omni.reply.${instanceId}.${chatId}`, buildReplyPayload(agent, chatId, instanceId, action.extra));
130
+ return action.label;
104
131
  }
105
132
 
106
- async function createDoneMcpServer(env: Record<string, string>) {
133
+ async function createDoneMcpServer(env: Record<string, string>, natsPublish: NatsPublishFn | null) {
107
134
  const { createSdkMcpServer, tool } = await import('@anthropic-ai/claude-agent-sdk');
108
135
  return createSdkMcpServer({
109
136
  name: 'genie-omni-tools',
@@ -120,7 +147,7 @@ async function createDoneMcpServer(env: Record<string, string>) {
120
147
  reason: z.string().optional().describe('Internal reason for skipping'),
121
148
  },
122
149
  async (args) => {
123
- const result = await handleDoneTool(args as Record<string, unknown>, env);
150
+ const result = handleDoneTool(args as Record<string, unknown>, env, natsPublish);
124
151
  return { content: [{ type: 'text' as const, text: result }] };
125
152
  },
126
153
  ),
@@ -135,6 +162,7 @@ async function createDoneMcpServer(env: Record<string, string>) {
135
162
  export class ClaudeSdkOmniExecutor implements IExecutor {
136
163
  private sessions = new Map<string, SdkSessionState>();
137
164
  private safePgCall: SafePgCallFn | null = null;
165
+ private natsPublish: NatsPublishFn | null = null;
138
166
  private deliveryQueues = new Map<string, Promise<void>>();
139
167
  private pendingNudges = new Map<string, string>();
140
168
 
@@ -142,6 +170,10 @@ export class ClaudeSdkOmniExecutor implements IExecutor {
142
170
  this.safePgCall = fn;
143
171
  }
144
172
 
173
+ setNatsPublish(fn: NatsPublishFn): void {
174
+ this.natsPublish = fn;
175
+ }
176
+
145
177
  async injectNudge(session: OmniSession, text: string): Promise<void> {
146
178
  if (!this.sessions.has(session.id)) return;
147
179
  this.pendingNudges.set(session.id, text);
@@ -294,7 +326,7 @@ export class ClaudeSdkOmniExecutor implements IExecutor {
294
326
  });
295
327
  }
296
328
 
297
- const doneMcp = await createDoneMcpServer(state.env);
329
+ const doneMcp = await createDoneMcpServer(state.env, this.natsPublish);
298
330
  const extraOptions: Record<string, unknown> = {
299
331
  abortController: state.abortController,
300
332
  mcpServers: { 'genie-omni-tools': doneMcp },
@@ -245,6 +245,13 @@ export class OmniBridge {
245
245
  // Decision 2 in WISH Post-Audit).
246
246
  this.executor.setSafePgCall(this.safePgCall.bind(this));
247
247
 
248
+ // Inject NATS publish for in-process reply delivery (replaces subprocess fork).
249
+ const sc = this.sc;
250
+ const nc = this.nc;
251
+ this.executor.setNatsPublish((topic: string, payload: string) => {
252
+ nc.publish(topic, sc.encode(payload));
253
+ });
254
+
248
255
  // Subscribe to all omni messages
249
256
  this.sub = this.nc.subscribe('omni.message.>');
250
257
  this.processSubscription();