@automagik/genie 4.260429.25 → 4.260429.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/genie.js CHANGED
@@ -2419,7 +2419,7 @@ The user's message:
2419
2419
 
2420
2420
  ---
2421
2421
 
2422
- ${initialMessage}`:turnContext,permissions=entry2.permissions?.allow?.length||entry2.permissions?.deny?.length?{allow:entry2.permissions.allow,deny:entry2.permissions.deny}:void 0;return{provider:entry2.provider??"claude",team:agentName,role:agentName,sessionId:resumeClaudeSessionId?void 0:randomUUID9(),resume:resumeClaudeSessionId,model:entry2.model,promptMode:entry2.promptMode,systemPromptFile:join53(entry2.dir,"AGENTS.md"),initialPrompt:fullInitialPrompt,skipHooks:!0,permissions,disallowedTools:entry2.disallowedTools,nativeTeam:{enabled:!0,agentName,color:entry2.color??void 0}}}class ClaudeCodeOmniExecutor{sessions=new Map;safePgCall=null;setSafePgCall(fn){this.safePgCall=fn}setNatsPublish(_fn){}async injectNudge(session,text){let paneId=session.tmux?.paneId;if(!paneId)return;let nudgeText=`[system] ${text}`;await executeTmux2(`send-keys -t '${paneId}' ${shellQuote(nudgeText)} Enter`)}async spawn(agentName,chatId,env,initialMessage){let resolved=await resolve5(agentName);if(!resolved)throw Error(`Agent "${agentName}" not found in genie directory`);let entry2=resolved.entry,tmuxSession=resolveBridgeTmuxSession(agentName,entry2.bridgeTmuxSession,env.GENIE_TMUX_SESSION),chatName=await lookupChatName(chatId,env.OMNI_INSTANCE??""),windowName=sanitizeWindowName2(chatId,chatName??void 0),{paneId,created}=await ensureTeamWindow(tmuxSession,windowName,entry2.dir),instanceId=env.OMNI_INSTANCE??"",agent=this.safePgCall?await this.safePgCall("tmux-find-or-create-agent",()=>findOrCreateAgent(`${agentName}:${chatId}`,"omni","omni"),null,{chatId}):null,existingExecutor=agent?await this.safePgCall?.("tmux-find-existing-executor",()=>findLatestByMetadata({agentId:agent.id,source:"omni",chatId}),null,{chatId})??null:null,resumeClaudeSessionId=existingExecutor?.claudeSessionId??void 0,claudeSessionId=resumeClaudeSessionId;if(created){let omniEnv={...env,GENIE_OMNI_CHAT_ID:chatId,GENIE_OMNI_AGENT:agentName},params=buildOmniSpawnParams(agentName,chatId,entry2,omniEnv,initialMessage,resumeClaudeSessionId);claudeSessionId=resumeClaudeSessionId??params.sessionId??void 0;let launch=buildLaunchCommand(params),allEnv={...omniEnv,...launch.env},envPrefix=Object.entries(allEnv).map(([k,v])=>`${k}=${shellQuote(v)}`).join(" "),cmd=envPrefix?`${envPrefix} ${launch.command}`:launch.command;await executeTmux2(`send-keys -t '${paneId}' ${shellQuote(cmd)} Enter`)}let sessionKey2=`${agentName}:${chatId}`,registration=await this.registerOrRelinkExecutor(agent,existingExecutor,chatId,instanceId,tmuxSession,windowName,paneId,entry2.dir,claudeSessionId);if(this.sessions.set(sessionKey2,{executorId:registration?.executorId??null,agentId:registration?.agentId??null,repoPath:entry2.dir}),registration?.executorId)await this.updateState(registration.executorId,"running",chatId);let now=Date.now();return{id:sessionKey2,agentName,chatId,executorType:"tmux",createdAt:now,lastActivityAt:now,tmux:{session:tmuxSession,window:windowName,paneId,claudeSessionId}}}async registerOrRelinkExecutor(agent,existingExecutor,chatId,instanceId,tmuxSession,tmuxWindow,tmuxPaneId,repoPath,claudeSessionId){if(!this.safePgCall||!agent)return null;if(await this.safePgCall("tmux-update-agent-pane",async()=>{await(await Promise.resolve().then(() => (init_db(),exports_db)).then((m)=>m.getConnection()))`
2422
+ ${initialMessage}`:turnContext,permissions=entry2.permissions?.allow?.length||entry2.permissions?.deny?.length?{allow:entry2.permissions.allow,deny:entry2.permissions.deny}:void 0;return{provider:entry2.provider??"claude",team:agentName,role:agentName,sessionId:resumeClaudeSessionId?void 0:randomUUID9(),resume:resumeClaudeSessionId,model:entry2.model,promptMode:entry2.promptMode,systemPromptFile:join53(entry2.dir,"AGENTS.md"),initialPrompt:fullInitialPrompt,skipHooks:!0,permissions,disallowedTools:entry2.disallowedTools,nativeTeam:{enabled:!0,agentName,color:entry2.color??void 0}}}function resolveOmniPaneProcessName(provider){return provider==="codex"?"codex":"claude"}class ClaudeCodeOmniExecutor{sessions=new Map;safePgCall=null;setSafePgCall(fn){this.safePgCall=fn}setNatsPublish(_fn){}async injectNudge(session,text){let paneId=session.tmux?.paneId;if(!paneId)return;let nudgeText=`[system] ${text}`;await executeTmux2(`send-keys -t '${paneId}' ${shellQuote(nudgeText)} Enter`)}async launchOmniProcessInPane(agentName,chatId,entry2,env,paneId,initialMessage,resumeClaudeSessionId){let omniEnv={...env,GENIE_OMNI_CHAT_ID:chatId,GENIE_OMNI_AGENT:agentName},params=buildOmniSpawnParams(agentName,chatId,entry2,omniEnv,initialMessage,resumeClaudeSessionId),claudeSessionId=resumeClaudeSessionId??params.sessionId??void 0,launch=buildLaunchCommand(params),allEnv={...omniEnv,...launch.env},envPrefix=Object.entries(allEnv).map(([k,v])=>`${k}=${shellQuote(v)}`).join(" "),cmd=envPrefix?`${envPrefix} ${launch.command}`:launch.command;return await executeTmux2(`send-keys -t '${paneId}' ${shellQuote(cmd)} Enter`),claudeSessionId}async spawn(agentName,chatId,env,initialMessage){let resolved=await resolve5(agentName);if(!resolved)throw Error(`Agent "${agentName}" not found in genie directory`);let entry2=resolved.entry,tmuxSession=resolveBridgeTmuxSession(agentName,entry2.bridgeTmuxSession,env.GENIE_TMUX_SESSION),chatName=await lookupChatName(chatId,env.OMNI_INSTANCE??""),windowName=sanitizeWindowName2(chatId,chatName??void 0),{paneId,created}=await ensureTeamWindow(tmuxSession,windowName,entry2.dir),instanceId=env.OMNI_INSTANCE??"",agent=this.safePgCall?await this.safePgCall("tmux-find-or-create-agent",()=>findOrCreateAgent(`${agentName}:${chatId}`,"omni","omni"),null,{chatId}):null,existingExecutor=agent?await this.safePgCall?.("tmux-find-existing-executor",()=>findLatestByMetadata({agentId:agent.id,source:"omni",chatId}),null,{chatId})??null:null,resumeClaudeSessionId=existingExecutor?.claudeSessionId??void 0,processName=resolveOmniPaneProcessName(entry2.provider),processRunning=!created&&await isPaneProcessRunning(paneId,processName),claudeSessionId=created||!processRunning?await this.launchOmniProcessInPane(agentName,chatId,entry2,env,paneId,initialMessage,resumeClaudeSessionId):resumeClaudeSessionId,sessionKey2=`${agentName}:${chatId}`,registration=await this.registerOrRelinkExecutor(agent,existingExecutor,chatId,instanceId,tmuxSession,windowName,paneId,entry2.dir,claudeSessionId);if(this.sessions.set(sessionKey2,{executorId:registration?.executorId??null,agentId:registration?.agentId??null,repoPath:entry2.dir}),registration?.executorId)await this.updateState(registration.executorId,"running",chatId);let now=Date.now();return{id:sessionKey2,agentName,chatId,executorType:"tmux",createdAt:now,lastActivityAt:now,tmux:{session:tmuxSession,window:windowName,paneId,claudeSessionId,processName}}}async registerOrRelinkExecutor(agent,existingExecutor,chatId,instanceId,tmuxSession,tmuxWindow,tmuxPaneId,repoPath,claudeSessionId){if(!this.safePgCall||!agent)return null;if(await this.safePgCall("tmux-update-agent-pane",async()=>{await(await Promise.resolve().then(() => (init_db(),exports_db)).then((m)=>m.getConnection()))`
2423
2423
  UPDATE agents
2424
2424
  SET pane_id = ${tmuxPaneId},
2425
2425
  session = ${tmuxSession},
@@ -2441,7 +2441,7 @@ ${initialMessage}`:turnContext,permissions=entry2.permissions?.allow?.length||en
2441
2441
 
2442
2442
  ---
2443
2443
 
2444
- [${senderName}]: ${message.content}`,paneId=session.tmux?.paneId;if(paneId&&/^%\d+$/.test(paneId)&&await isPaneAlive(paneId))try{await executeTmux2(`send-keys -t '${paneId}' ${shellQuote(body)}`),await new Promise((resolve10)=>setTimeout(resolve10,200)),await executeTmux2(`send-keys -t '${paneId}' Enter`)}catch(err){console.error(`[claude-code] deliver: send-keys failed for ${session.id} (pane ${paneId}):`,err instanceof Error?err.message:err)}else console.error(`[claude-code] deliver: pane unavailable for ${session.id} (paneId=${paneId??"null"}), message lost`);if(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{if(session.tmux)await killWindow(session.tmux.session,session.tmux.window)}finally{if(state?.executorId&&this.safePgCall)await this.safePgCall("tmux-terminate-executor",()=>terminateExecutor(state.executorId),void 0,{executorId:state.executorId,chatId:session.chatId});if(state?.agentId&&this.safePgCall)await this.safePgCall("tmux-unregister-agent",()=>unregister(state.agentId),void 0,{chatId:session.chatId});this.sessions.delete(session.id)}}async isAlive(session){let paneId=session.tmux?.paneId;if(!paneId)return!1;try{if(!await isPaneAlive(paneId))return!1;return await isPaneProcessRunning(paneId,"claude")}catch{return!1}}}var init_claude_code2=__esm(()=>{init_agent_directory();init_agent_registry();init_executor_registry();init_provider_adapters();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)
2444
+ [${senderName}]: ${message.content}`,paneId=session.tmux?.paneId;if(paneId&&/^%\d+$/.test(paneId)&&await isPaneAlive(paneId))try{await executeTmux2(`send-keys -t '${paneId}' ${shellQuote(body)}`),await new Promise((resolve10)=>setTimeout(resolve10,200)),await executeTmux2(`send-keys -t '${paneId}' Enter`)}catch(err){console.error(`[claude-code] deliver: send-keys failed for ${session.id} (pane ${paneId}):`,err instanceof Error?err.message:err)}else console.error(`[claude-code] deliver: pane unavailable for ${session.id} (paneId=${paneId??"null"}), message lost`);if(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{if(session.tmux)await killWindow(session.tmux.session,session.tmux.window)}finally{if(state?.executorId&&this.safePgCall)await this.safePgCall("tmux-terminate-executor",()=>terminateExecutor(state.executorId),void 0,{executorId:state.executorId,chatId:session.chatId});if(state?.agentId&&this.safePgCall)await this.safePgCall("tmux-unregister-agent",()=>unregister(state.agentId),void 0,{chatId:session.chatId});this.sessions.delete(session.id)}}async isAlive(session){let paneId=session.tmux?.paneId;if(!paneId)return!1;try{if(!await isPaneAlive(paneId))return!1;return await isPaneProcessRunning(paneId,session.tmux?.processName??"claude")}catch{return!1}}}var init_claude_code2=__esm(()=>{init_agent_directory();init_agent_registry();init_executor_registry();init_provider_adapters();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)
2445
2445
  VALUES (${entityType}, ${entityId}, ${type2}, ${actor}, ${JSON.stringify(details)})`,void 0,{executorId:entityId,chatId:attrs.chat_id??""})}async function loadSystemPrompt(entry2){let identityPath=loadIdentity(entry2);if(!identityPath)return;let{readFileSync:readFileSync25}=await import("fs");try{return readFileSync25(identityPath,"utf-8")}catch{return}}async function resolveSystemPrompt(entry2,state){let prompt2=await loadSystemPrompt(entry2),isTurnBased=Boolean(state.env.OMNI_INSTANCE);return{prompt:prompt2,isTurnBased}}function buildTurnContextPrefix(state,message,chatId){if(!state.env.OMNI_INSTANCE)return"";return buildTurnBasedPrompt(message.sender,state.env.OMNI_INSTANCE,state.env.OMNI_CHAT??chatId)}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(`
2446
2446
  `).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}function parseSendMessageInput(input){if(!input||typeof input!=="object")return{};let obj=input,recipient=typeof obj.recipient==="string"?obj.recipient:typeof obj.to==="string"?obj.to:void 0,body=typeof obj.message==="string"?obj.message:typeof obj.content==="string"?obj.content:void 0;return{recipient,body}}function createSendMessageOmniHook(env,natsPublish){return async(input)=>{let hookInput=input;if(hookInput.tool_name!=="SendMessage")return{};let{recipient,body}=parseSendMessageInput(hookInput.tool_input);if(recipient!=="omni")return{};let instanceId=env.OMNI_INSTANCE??"",chatId=env.OMNI_CHAT??"",agent=env.OMNI_AGENT??"";if(!instanceId||!chatId)return{};if(!body||body.trim()==="")return{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:'SendMessage(recipient: "omni") requires a non-empty `message` field. Retry with the reply text.'}};if(!natsPublish)return console.warn("[claude-sdk] SendMessage(to: omni) intercepted but NATS publish unavailable \u2014 message dropped"),{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:"Omni bridge unavailable \u2014 message could not be delivered."}};return natsPublish(`omni.reply.${instanceId}.${chatId}`,buildReplyPayload(agent,chatId,instanceId,{content:body})),{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:"Message delivered to user via omni bridge."}}}}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,_initialMessage){if(!await resolve5(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,executorType:"sdk",createdAt:now,lastActivityAt:now,sdk:{claudeSessionId:registration?.claudeSessionId,executorId:registration?.executorId}}}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 resolve5(session.agentName);if(!resolved)throw Error(`Agent "${session.agentName}" not found in genie directory`);let entry2=resolved.entry,permissionConfig=resolvePermissionConfig(entry2.permissions),{prompt:systemPrompt,isTurnBased}=await resolveSystemPrompt(entry2,state);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),sendMessageHooks=isTurnBased?{PreToolUse:[{matcher:"SendMessage",hooks:[createSendMessageOmniHook(state.env,this.natsPublish)]}]}:void 0,extraOptions={abortController:state.abortController,mcpServers:{"genie-omni-tools":doneMcp},...sendMessageHooks&&{hooks:sendMessageHooks}};if(state.claudeSessionId)extraOptions.resume=state.claudeSessionId;let turnPrefix=buildTurnContextPrefix(state,message,session.chatId),queryContent=message.content,pendingNudge=this.pendingNudges.get(session.id);if(pendingNudge)queryContent=`[system] ${pendingNudge}
2447
2447
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/genie",
3
- "version": "4.260429.25",
3
+ "version": "4.260429.26",
4
4
  "description": "Collaborative terminal toolkit for human + AI workflows. NOTE: the npm distribution is being soft-deprecated — the canonical install is `curl -fsSL https://get.automagik.dev/genie | bash` (cosign + SLSA verified). See https://automagik.dev/genie/security/distribution-sovereignty",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genie",
3
- "version": "4.260429.25",
3
+ "version": "4.260429.26",
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.260429.25",
3
+ "version": "4.260429.26",
4
4
  "private": true,
5
5
  "description": "Runtime dependencies for genie bundled CLIs",
6
6
  "type": "module",