@automagik/genie 4.260429.23 → 4.260429.24

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
@@ -422,7 +422,7 @@ ${bin} set-option -w pane-active-border-style "fg=$COLOR"
422
422
  WHERE (${includeArchived} OR state IS DISTINCT FROM 'archived')
423
423
  `;return rows.map(rowToAgentIdentity)}async function listAgentsForRender(filters){let all=await listAgents(filters);return dedupeShadowRows(all,{keyFor:(a)=>shadowKey(a.customName,a.id,a.team),hasExecutor:(a)=>a.currentExecutorId!=null,startedAt:(a)=>a.startedAt})}async function auditAgentKind(){let rows=await(await getConnection())`
424
424
  SELECT id, kind, reports_to FROM agents
425
- `,drifted=[];for(let row of rows){let expected=row.id.startsWith("dir:")||row.reports_to===null?"permanent":"task";if(row.kind!==expected)drifted.push({id:row.id,kind:row.kind,expected})}for(let drift of drifted)recordAuditEvent("worker",drift.id,"agents.kind.audit_drift","auditor",{stored:drift.kind,expected:drift.expected}).catch(()=>{});return{total:rows.length,drifted}}var DEAD_PANE_ZOMBIE_TTL_HOURS=24;var init_agent_registry=__esm(()=>{init_audit();init_db();init_tmux()});function ts2(v){if(!v)return new Date().toISOString();return v instanceof Date?v.toISOString():v}function rowToExecutor(r){return{id:r.id,agentId:r.agent_id,provider:r.provider,transport:r.transport,pid:r.pid,tmuxSession:r.tmux_session,tmuxPaneId:r.tmux_pane_id,tmuxWindow:r.tmux_window,tmuxWindowId:r.tmux_window_id,claudeSessionId:r.claude_session_id,state:r.state,metadata:typeof r.metadata==="string"?JSON.parse(r.metadata):r.metadata??{},worktree:r.worktree,repoPath:r.repo_path,paneColor:r.pane_color,startedAt:ts2(r.started_at),endedAt:r.ended_at?ts2(r.ended_at):null,createdAt:ts2(r.created_at),updatedAt:ts2(r.updated_at),turnId:r.turn_id??null,outcome:r.outcome??null,closedAt:r.closed_at?ts2(r.closed_at):null,closeReason:r.close_reason??null}}function rowToAssignment(r){return{id:r.id,executorId:r.executor_id,taskId:r.task_id,wishSlug:r.wish_slug,groupNumber:r.group_number,startedAt:ts2(r.started_at),endedAt:r.ended_at?ts2(r.ended_at):null,outcome:r.outcome,createdAt:ts2(r.created_at)}}var exports_executor_registry={};__export(exports_executor_registry,{updateExecutorState:()=>updateExecutorState,updateClaudeSessionId:()=>updateClaudeSessionId,terminateExecutor:()=>terminateExecutor,terminateActiveExecutor:()=>terminateActiveExecutor,resolveWorkerLivenessByTransport:()=>resolveWorkerLivenessByTransport,relinkExecutorToAgent:()=>relinkExecutorToAgent,recordResumeProviderRejected:()=>recordResumeProviderRejected,listExecutors:()=>listExecutors,isExecutorAlive:()=>isExecutorAlive,getResumeSessionId:()=>getResumeSessionId,getLiveExecutorState:()=>getLiveExecutorState,getExecutor:()=>getExecutor,getCurrentExecutor:()=>getCurrentExecutor,findLatestByMetadata:()=>findLatestByMetadata,findExecutorBySession:()=>findExecutorBySession,findExecutorByPane:()=>findExecutorByPane,createExecutor:()=>createExecutor,createAndLinkExecutor:()=>createAndLinkExecutor,_resumeJsonlScannerDeps:()=>_resumeJsonlScannerDeps,_resetMissingSessionDedupeForTests:()=>_resetMissingSessionDedupeForTests});import{randomUUID as randomUUID2}from"crypto";import{open,readdir,stat}from"fs/promises";import{homedir as homedir7}from"os";import{join as join13}from"path";async function createExecutor(agentId,provider,transport,opts={}){let sql=await getConnection(),id=opts.id??randomUUID2(),now=new Date().toISOString(),rows=await sql`
425
+ `,drifted=[];for(let row of rows){let expected=row.id.startsWith("dir:")||row.reports_to===null?"permanent":"task";if(row.kind!==expected)drifted.push({id:row.id,kind:row.kind,expected})}for(let drift of drifted)recordAuditEvent("worker",drift.id,"agents.kind.audit_drift","auditor",{stored:drift.kind,expected:drift.expected}).catch(()=>{});return{total:rows.length,drifted}}var DEAD_PANE_ZOMBIE_TTL_HOURS=24;var init_agent_registry=__esm(()=>{init_audit();init_db();init_tmux()});function ts2(v){if(!v)return new Date().toISOString();return v instanceof Date?v.toISOString():v}function rowToExecutor(r){return{id:r.id,agentId:r.agent_id,provider:r.provider,transport:r.transport,pid:r.pid,tmuxSession:r.tmux_session,tmuxPaneId:r.tmux_pane_id,tmuxWindow:r.tmux_window,tmuxWindowId:r.tmux_window_id,claudeSessionId:r.claude_session_id,state:r.state,metadata:typeof r.metadata==="string"?JSON.parse(r.metadata):r.metadata??{},worktree:r.worktree,repoPath:r.repo_path,paneColor:r.pane_color,startedAt:ts2(r.started_at),endedAt:r.ended_at?ts2(r.ended_at):null,createdAt:ts2(r.created_at),updatedAt:ts2(r.updated_at),turnId:r.turn_id??null,outcome:r.outcome??null,closedAt:r.closed_at?ts2(r.closed_at):null,closeReason:r.close_reason??null}}function rowToAssignment(r){return{id:r.id,executorId:r.executor_id,taskId:r.task_id,wishSlug:r.wish_slug,groupNumber:r.group_number,startedAt:ts2(r.started_at),endedAt:r.ended_at?ts2(r.ended_at):null,outcome:r.outcome,createdAt:ts2(r.created_at)}}var exports_executor_registry={};__export(exports_executor_registry,{updateExecutorState:()=>updateExecutorState,updateClaudeSessionId:()=>updateClaudeSessionId,terminateExecutor:()=>terminateExecutor,terminateActiveExecutor:()=>terminateActiveExecutor,resolveWorkerLivenessByTransport:()=>resolveWorkerLivenessByTransport,relinkExecutorToAgent:()=>relinkExecutorToAgent,recordResumeProviderRejected:()=>recordResumeProviderRejected,recordResumeMissingSession:()=>recordResumeMissingSession,listExecutors:()=>listExecutors,isExecutorAlive:()=>isExecutorAlive,getResumeSessionId:()=>getResumeSessionId,getLiveExecutorState:()=>getLiveExecutorState,getExecutor:()=>getExecutor,getCurrentExecutor:()=>getCurrentExecutor,findLatestByMetadata:()=>findLatestByMetadata,findExecutorBySession:()=>findExecutorBySession,findExecutorByPane:()=>findExecutorByPane,createExecutor:()=>createExecutor,createAndLinkExecutor:()=>createAndLinkExecutor,_resumeJsonlScannerDeps:()=>_resumeJsonlScannerDeps,_resetMissingSessionDedupeForTests:()=>_resetMissingSessionDedupeForTests});import{randomUUID as randomUUID2}from"crypto";import{open,readdir,stat}from"fs/promises";import{homedir as homedir7}from"os";import{join as join13}from"path";async function createExecutor(agentId,provider,transport,opts={}){let sql=await getConnection(),id=opts.id??randomUUID2(),now=new Date().toISOString(),rows=await sql`
426
426
  INSERT INTO executors (
427
427
  id, agent_id, provider, transport, pid,
428
428
  tmux_session, tmux_pane_id, tmux_window, tmux_window_id,
@@ -477,7 +477,7 @@ ${bin} set-option -w pane-active-border-style "fg=$COLOR"
477
477
  ORDER BY started_at DESC
478
478
  LIMIT 1
479
479
  `;return rows.length>0?rowToExecutor(rows[0]):null}async function relinkExecutorToAgent(executorId,agentId){await(await getConnection())`UPDATE agents SET current_executor_id = ${executorId} WHERE id = ${agentId}`}async function updateClaudeSessionId(executorId,sessionId){await(await getConnection())`UPDATE executors SET claude_session_id = ${sessionId} WHERE id = ${executorId}`}function sanitizeCwdForProjects(p){return p.replace(/[^a-zA-Z0-9]/g,"-")}function resolveClaudeConfigDir(){return process.env.CLAUDE_CONFIG_DIR??join13(homedir7(),".claude")}async function readJsonlIdentity(filePath){let handle=null;try{handle=await open(filePath,"r");let buffer=Buffer.alloc(16384),{bytesRead}=await handle.read(buffer,0,buffer.length,0),head=buffer.toString("utf-8",0,bytesRead);for(let line of head.split(`
480
- `).slice(0,40)){let trimmed=line.trim();if(!trimmed)continue;try{let entry=JSON.parse(trimmed),teamName=typeof entry.teamName==="string"?entry.teamName:null,agentName=typeof entry.agentName==="string"?entry.agentName:null;if(teamName!==null&&agentName!==null)return{teamName,agentName}}catch{}}}catch{return{teamName:null,agentName:null}}finally{await handle?.close().catch(()=>{})}return{teamName:null,agentName:null}}async function mapWithConcurrency(items,cap,fn){let results=Array(items.length),cursor=0,workers=[],workerCount=Math.min(cap,items.length);for(let w=0;w<workerCount;w++)workers.push((async()=>{while(cursor<items.length){let i2=cursor++;if(i2>=items.length)return;results[i2]=await fn(items[i2])}})());return await Promise.all(workers),results}async function defaultScanForSession(cwd,identity){if(!identity)return null;let projectDir=join13(resolveClaudeConfigDir(),"projects",sanitizeCwdForProjects(cwd)),entries;try{entries=await readdir(projectDir)}catch{return null}let jsonls=entries.filter((e)=>e.endsWith(".jsonl"));if(jsonls.length===0)return null;let sorted=(await mapWithConcurrency(jsonls,STAT_CONCURRENCY_CAP,async(name)=>{let full=join13(projectDir,name);try{let s=await stat(full);return{name,full,mtime:s.mtimeMs}}catch{return null}})).filter((x)=>x!==null).sort((a,b)=>b.mtime-a.mtime);for(let candidate of sorted){let{teamName,agentName}=await readJsonlIdentity(candidate.full);if(teamName!==identity.team||agentName!==identity.customName)continue;return candidate.name.replace(/\.jsonl$/,"")}return null}async function tryJsonlFallback(agentId,row,actor){let cwd=row?.repo_path??null;if(!cwd)return null;let team=row?.team??null,customName=row?.custom_name??null,identity=team&&customName?{team,customName}:null;if(!identity)return null;let recoveredSessionId=await(_resumeJsonlScannerDeps.scanForSession??defaultScanForSession)(cwd,identity);if(!recoveredSessionId)return null;let reason=row&&row.executor_id!==null?"null_session":"no_executor";return await recordAuditEvent("agent",agentId,"resume.recovered_via_jsonl",actor,{sessionId:recoveredSessionId,executorId:row?.executor_id??null,cwd,team:identity.team,customName:identity.customName,recoveredFrom:reason}),recoveredSessionId}function shouldEmitMissingSession(agentId,actor,reason){let key=`${agentId}:${actor}:${reason}`,now=Date.now(),last=missingSessionLastEmit.get(key);if(last!==void 0&&now-last<MISSING_SESSION_DEDUPE_WINDOW_MS)return!1;if(missingSessionLastEmit.size>=MISSING_SESSION_DEDUPE_MAX_KEYS){let entries=Array.from(missingSessionLastEmit.entries()).sort((a,b)=>a[1]-b[1]),drop=Math.floor(entries.length/4);for(let i2=0;i2<drop;i2++)missingSessionLastEmit.delete(entries[i2][0])}return missingSessionLastEmit.set(key,now),!0}function _resetMissingSessionDedupeForTests(){missingSessionLastEmit.clear()}async function emitMissingSession(agentId,row,actor){if(row===null||row.executor_id===null){if(!shouldEmitMissingSession(agentId,actor,"no_executor"))return;await recordAuditEvent("agent",agentId,"resume.missing_session",actor,{reason:"no_executor"});return}if(!shouldEmitMissingSession(agentId,actor,"null_session"))return;await recordAuditEvent("agent",agentId,"resume.missing_session",actor,{reason:"null_session",executorId:row.executor_id})}async function getResumeSessionId(agentId){let rows=await(await getConnection())`
480
+ `).slice(0,40)){let trimmed=line.trim();if(!trimmed)continue;try{let entry=JSON.parse(trimmed),teamName=typeof entry.teamName==="string"?entry.teamName:null,agentName=typeof entry.agentName==="string"?entry.agentName:null;if(teamName!==null&&agentName!==null)return{teamName,agentName}}catch{}}}catch{return{teamName:null,agentName:null}}finally{await handle?.close().catch(()=>{})}return{teamName:null,agentName:null}}async function mapWithConcurrency(items,cap,fn){let results=Array(items.length),cursor=0,workers=[],workerCount=Math.min(cap,items.length);for(let w=0;w<workerCount;w++)workers.push((async()=>{while(cursor<items.length){let i2=cursor++;if(i2>=items.length)return;results[i2]=await fn(items[i2])}})());return await Promise.all(workers),results}async function defaultScanForSession(cwd,identity){if(!identity)return null;let projectDir=join13(resolveClaudeConfigDir(),"projects",sanitizeCwdForProjects(cwd)),entries;try{entries=await readdir(projectDir)}catch{return null}let jsonls=entries.filter((e)=>e.endsWith(".jsonl"));if(jsonls.length===0)return null;let sorted=(await mapWithConcurrency(jsonls,STAT_CONCURRENCY_CAP,async(name)=>{let full=join13(projectDir,name);try{let s=await stat(full);return{name,full,mtime:s.mtimeMs}}catch{return null}})).filter((x)=>x!==null).sort((a,b)=>b.mtime-a.mtime);for(let candidate of sorted){let{teamName,agentName}=await readJsonlIdentity(candidate.full);if(teamName!==identity.team||agentName!==identity.customName)continue;return candidate.name.replace(/\.jsonl$/,"")}return null}async function tryJsonlFallback(agentId,row,actor){let cwd=row?.repo_path??null;if(!cwd)return null;let team=row?.team??null,customName=row?.custom_name??null,identity=team&&customName?{team,customName}:null;if(!identity)return null;let recoveredSessionId=await(_resumeJsonlScannerDeps.scanForSession??defaultScanForSession)(cwd,identity);if(!recoveredSessionId)return null;let reason=row&&row.executor_id!==null?"null_session":"no_executor";return await recordAuditEvent("agent",agentId,"resume.recovered_via_jsonl",actor,{sessionId:recoveredSessionId,executorId:row?.executor_id??null,cwd,team:identity.team,customName:identity.customName,recoveredFrom:reason}),recoveredSessionId}function _resetMissingSessionDedupeForTests(){}async function recordResumeMissingSession(agentId,actor,details){await recordAuditEvent("agent",agentId,"resume.missing_session",actor,details)}async function getResumeSessionId(agentId){let rows=await(await getConnection())`
481
481
  SELECT a.current_executor_id AS executor_id,
482
482
  e.claude_session_id,
483
483
  a.repo_path,
@@ -486,13 +486,13 @@ ${bin} set-option -w pane-active-border-style "fg=$COLOR"
486
486
  FROM agents a
487
487
  LEFT JOIN executors e ON e.id = a.current_executor_id
488
488
  WHERE a.id = ${agentId}
489
- `,actor=process.env.GENIE_AGENT_NAME??"cli",row=rows[0]??null;if(row&&row.executor_id!==null&&row.claude_session_id)return await recordAuditEvent("agent",agentId,"resume.found",actor,{executorId:row.executor_id,sessionId:row.claude_session_id}),row.claude_session_id;let recovered=await tryJsonlFallback(agentId,row,actor);if(recovered)return recovered;return await emitMissingSession(agentId,row,actor),null}async function recordResumeProviderRejected(agentId,sessionId,reason){await recordAuditEvent("agent",agentId,"resume.provider_rejected",process.env.GENIE_AGENT_NAME??"cli",{sessionId,reason})}async function getLiveExecutorState(agentId){let rows=await(await getConnection())`
489
+ `,actor=process.env.GENIE_AGENT_NAME??"cli",row=rows[0]??null;if(row&&row.executor_id!==null&&row.claude_session_id)return await recordAuditEvent("agent",agentId,"resume.found",actor,{executorId:row.executor_id,sessionId:row.claude_session_id}),row.claude_session_id;let recovered=await tryJsonlFallback(agentId,row,actor);if(recovered)return recovered;return null}async function recordResumeProviderRejected(agentId,sessionId,reason){await recordAuditEvent("agent",agentId,"resume.provider_rejected",process.env.GENIE_AGENT_NAME??"cli",{sessionId,reason})}async function getLiveExecutorState(agentId){let rows=await(await getConnection())`
490
490
  SELECT e.state FROM executors e
491
491
  JOIN agents a ON a.current_executor_id = e.id
492
492
  WHERE a.id = ${agentId}
493
493
  AND e.state IN ('spawning', 'running', 'working', 'idle', 'permission', 'question')
494
494
  LIMIT 1
495
- `;return rows.length>0?rows[0].state:null}async function isExecutorAlive(agentId){return await getLiveExecutorState(agentId)!==null}async function resolveWorkerLivenessByTransport(worker,opts){if(/^%\d+$/.test(worker.paneId))return(opts?.isPaneAliveFn??(async(pane)=>{let{isPaneAlive:isPaneAlive2}=await Promise.resolve().then(() => (init_tmux(),exports_tmux));return isPaneAlive2(pane)}))(worker.paneId);return(opts?.isExecutorAliveFn??isExecutorAlive)(worker.id)}var STAT_CONCURRENCY_CAP=32,_resumeJsonlScannerDeps,MISSING_SESSION_DEDUPE_WINDOW_MS=60000,missingSessionLastEmit,MISSING_SESSION_DEDUPE_MAX_KEYS=4096;var init_executor_registry=__esm(()=>{init_audit();init_db();_resumeJsonlScannerDeps={scanForSession:null};missingSessionLastEmit=new Map});var exports_team_manager={};__export(exports_team_manager,{validateBranchName:()=>validateBranchName,updateTeamConfig:()=>updateTeamConfig,unarchiveTeam:()=>unarchiveTeam,setTeamStatus:()=>setTeamStatus,resolveLeaderName:()=>resolveLeaderName,listTeams:()=>listTeams,listMembers:()=>listMembers,killTeamMembers:()=>killTeamMembers,hireAgent:()=>hireAgent,getTeam:()=>getTeam,fireAgent:()=>fireAgent,ensureTeamRow:()=>ensureTeamRow,disbandTeam:()=>disbandTeam,createTeam:()=>createTeam,archiveTeam:()=>archiveTeam});import{existsSync as existsSync10}from"fs";import{mkdir as mkdir2,rm,symlink}from"fs/promises";import{homedir as homedir8}from"os";import path,{join as join14}from"path";var{$:$2}=globalThis.Bun;function parseMembers(raw){if(Array.isArray(raw))return raw;if(typeof raw==="string")try{let parsed=JSON.parse(raw);return Array.isArray(parsed)?parsed:[]}catch{return[]}return[]}function rowToTeamConfig(row){let config={name:row.name,repo:row.repo,baseBranch:row.base_branch,worktreePath:row.worktree_path,members:parseMembers(row.members),status:row.status,createdAt:row.created_at instanceof Date?row.created_at.toISOString():String(row.created_at)};if(row.leader)config.leader=row.leader;if(row.native_team_parent_session_id)config.nativeTeamParentSessionId=row.native_team_parent_session_id;if(row.native_teams_enabled)config.nativeTeamsEnabled=row.native_teams_enabled;if(row.tmux_session_name)config.tmuxSessionName=row.tmux_session_name;if(row.wish_slug)config.wishSlug=row.wish_slug;if(row.spawner)config.spawner=row.spawner;if(row.archived_at)config.archivedAt=row.archived_at instanceof Date?row.archived_at.toISOString():String(row.archived_at);if(row.parent_team)config.parentTeam=row.parent_team;let allow=parseAllowChildReachback(row.allow_child_reachback);if(allow.length>0)config.allowChildReachback=allow;return config}function parseAllowChildReachback(raw){if(Array.isArray(raw))return raw.filter((x)=>typeof x==="string");if(typeof raw==="string")try{let parsed=JSON.parse(raw);return Array.isArray(parsed)?parsed.filter((x)=>typeof x==="string"):[]}catch{return[]}return[]}function getGenieDir2(){return process.env.GENIE_HOME??join14(homedir8(),".genie")}function getWorktreeBase(repoPath){let base=loadGenieConfigSync().terminal?.worktreeBase;if(base&&base!==".worktrees"){if(path.isAbsolute(base))return base;return join14(repoPath,base)}let projectName=path.basename(repoPath);return join14(getGenieDir2(),"worktrees",projectName)}function validateBranchName(name){let errors2=[];if(/\s/.test(name))errors2.push("contains spaces");if(name.includes(".."))errors2.push('contains ".."');if(name.includes("~"))errors2.push('contains "~"');if(name.includes("^"))errors2.push('contains "^"');if(name.includes(":"))errors2.push('contains ":"');if(name.includes("?"))errors2.push('contains "?"');if(name.includes("*"))errors2.push('contains "*"');if(name.includes("["))errors2.push('contains "["');if(name.includes("\\"))errors2.push('contains "\\"');if(/[\x00-\x1f\x7f]/.test(name))errors2.push("contains control characters");if(name.endsWith(".lock"))errors2.push('ends with ".lock"');if(name.endsWith("/"))errors2.push('ends with "/"');if(name.endsWith("."))errors2.push('ends with "."');if(name.startsWith("-"))errors2.push('starts with "-"');if(errors2.length>0)throw Error(`Invalid team name '${name}': must be a valid git branch name (${errors2.join(", ")})`)}async function killWorkersByName(agentName,teamName){let matches=(await list()).filter((w)=>(w.role===agentName||w.id===agentName)&&(!teamName||w.team===teamName));for(let w of matches){if(w.currentExecutorId)try{await terminateExecutor(w.currentExecutorId),await setCurrentExecutor(w.id,null)}catch{}try{if(w.paneId&&w.paneId!=="inline"){let{execSync:execSync2}=__require("child_process"),{genieTmuxCmd:genieTmuxCmd2}=(init_tmux_wrapper(),__toCommonJS(exports_tmux_wrapper));execSync2(genieTmuxCmd2(`kill-pane -t ${w.paneId}`),{stdio:"ignore"})}}catch{}await unregister(w.id)}}async function postCloneInit(repoPath,worktreePath){let parentNodeModules=join14(repoPath,"node_modules"),worktreeNodeModules=join14(worktreePath,"node_modules");if(existsSync10(parentNodeModules)&&!existsSync10(worktreeNodeModules))try{await symlink(parentNodeModules,worktreeNodeModules,"dir")}catch{}let initScript=join14(repoPath,".genie","init.sh");if(existsSync10(initScript))try{await $2`bash ${initScript}`.cwd(worktreePath).quiet()}catch{}}async function ensureWorktree(repoPath,branchName,worktreePath,baseBranch){try{await $2`git -C ${repoPath} fetch origin ${baseBranch}`.quiet()}catch{}if(await mkdir2(path.dirname(worktreePath),{recursive:!0}),existsSync10(worktreePath))return;let branchExists=!1;try{await $2`git -C ${repoPath} rev-parse --verify ${branchName}`.quiet(),branchExists=!0}catch{if(!branchExists)try{await $2`git -C ${repoPath} branch ${branchName} origin/${baseBranch}`.quiet()}catch{try{await $2`git -C ${repoPath} branch ${branchName} ${baseBranch}`.quiet()}catch{await $2`git -C ${repoPath} branch ${branchName}`.quiet()}}}await $2`git clone --shared --branch ${branchName} ${repoPath} ${worktreePath}`.quiet();try{let userName=(await $2`git -C ${repoPath} config user.name`.quiet()).text().trim(),userEmail=(await $2`git -C ${repoPath} config user.email`.quiet()).text().trim();if(userName)await $2`git -C ${worktreePath} config user.name ${userName}`.quiet();if(userEmail)await $2`git -C ${worktreePath} config user.email ${userEmail}`.quiet()}catch{}await postCloneInit(repoPath,worktreePath)}async function detectSpawnerParentTeam(newTeamName){let envTeam=process.env.GENIE_TEAM,spawnerName=process.env.GENIE_AGENT_NAME;if(!envTeam||!spawnerName)return null;if(spawnerName==="cli")return null;if(envTeam===newTeamName)return null;try{return await getTeam(envTeam)?envTeam:null}catch{return null}}async function createTeam(name,repo,baseBranch="dev"){validateBranchName(name);let repoPath=path.resolve(repo),existing=await getTeam(name);if(existing)return existing;let worktreeBase=getWorktreeBase(repoPath),worktreePath=join14(worktreeBase,name);await ensureWorktree(repoPath,name,worktreePath,baseBranch);let now=new Date().toISOString(),config={name,repo:repoPath,baseBranch,worktreePath,members:[],status:"in_progress",createdAt:now},promoted=await detectSpawnerParentTeam(name);if(promoted)config.parentTeam=promoted;if(isInsideClaudeCode()){config.nativeTeamsEnabled=!0;try{let result2=await registerAsTeamLead(name);config.nativeTeamParentSessionId=result2.sessionId}catch{}}return await(await getConnection())`
495
+ `;return rows.length>0?rows[0].state:null}async function isExecutorAlive(agentId){return await getLiveExecutorState(agentId)!==null}async function resolveWorkerLivenessByTransport(worker,opts){if(/^%\d+$/.test(worker.paneId))return(opts?.isPaneAliveFn??(async(pane)=>{let{isPaneAlive:isPaneAlive2}=await Promise.resolve().then(() => (init_tmux(),exports_tmux));return isPaneAlive2(pane)}))(worker.paneId);return(opts?.isExecutorAliveFn??isExecutorAlive)(worker.id)}var STAT_CONCURRENCY_CAP=32,_resumeJsonlScannerDeps;var init_executor_registry=__esm(()=>{init_audit();init_db();_resumeJsonlScannerDeps={scanForSession:null}});var exports_team_manager={};__export(exports_team_manager,{validateBranchName:()=>validateBranchName,updateTeamConfig:()=>updateTeamConfig,unarchiveTeam:()=>unarchiveTeam,setTeamStatus:()=>setTeamStatus,resolveLeaderName:()=>resolveLeaderName,listTeams:()=>listTeams,listMembers:()=>listMembers,killTeamMembers:()=>killTeamMembers,hireAgent:()=>hireAgent,getTeam:()=>getTeam,fireAgent:()=>fireAgent,ensureTeamRow:()=>ensureTeamRow,disbandTeam:()=>disbandTeam,createTeam:()=>createTeam,archiveTeam:()=>archiveTeam});import{existsSync as existsSync10}from"fs";import{mkdir as mkdir2,rm,symlink}from"fs/promises";import{homedir as homedir8}from"os";import path,{join as join14}from"path";var{$:$2}=globalThis.Bun;function parseMembers(raw){if(Array.isArray(raw))return raw;if(typeof raw==="string")try{let parsed=JSON.parse(raw);return Array.isArray(parsed)?parsed:[]}catch{return[]}return[]}function rowToTeamConfig(row){let config={name:row.name,repo:row.repo,baseBranch:row.base_branch,worktreePath:row.worktree_path,members:parseMembers(row.members),status:row.status,createdAt:row.created_at instanceof Date?row.created_at.toISOString():String(row.created_at)};if(row.leader)config.leader=row.leader;if(row.native_team_parent_session_id)config.nativeTeamParentSessionId=row.native_team_parent_session_id;if(row.native_teams_enabled)config.nativeTeamsEnabled=row.native_teams_enabled;if(row.tmux_session_name)config.tmuxSessionName=row.tmux_session_name;if(row.wish_slug)config.wishSlug=row.wish_slug;if(row.spawner)config.spawner=row.spawner;if(row.archived_at)config.archivedAt=row.archived_at instanceof Date?row.archived_at.toISOString():String(row.archived_at);if(row.parent_team)config.parentTeam=row.parent_team;let allow=parseAllowChildReachback(row.allow_child_reachback);if(allow.length>0)config.allowChildReachback=allow;return config}function parseAllowChildReachback(raw){if(Array.isArray(raw))return raw.filter((x)=>typeof x==="string");if(typeof raw==="string")try{let parsed=JSON.parse(raw);return Array.isArray(parsed)?parsed.filter((x)=>typeof x==="string"):[]}catch{return[]}return[]}function getGenieDir2(){return process.env.GENIE_HOME??join14(homedir8(),".genie")}function getWorktreeBase(repoPath){let base=loadGenieConfigSync().terminal?.worktreeBase;if(base&&base!==".worktrees"){if(path.isAbsolute(base))return base;return join14(repoPath,base)}let projectName=path.basename(repoPath);return join14(getGenieDir2(),"worktrees",projectName)}function validateBranchName(name){let errors2=[];if(/\s/.test(name))errors2.push("contains spaces");if(name.includes(".."))errors2.push('contains ".."');if(name.includes("~"))errors2.push('contains "~"');if(name.includes("^"))errors2.push('contains "^"');if(name.includes(":"))errors2.push('contains ":"');if(name.includes("?"))errors2.push('contains "?"');if(name.includes("*"))errors2.push('contains "*"');if(name.includes("["))errors2.push('contains "["');if(name.includes("\\"))errors2.push('contains "\\"');if(/[\x00-\x1f\x7f]/.test(name))errors2.push("contains control characters");if(name.endsWith(".lock"))errors2.push('ends with ".lock"');if(name.endsWith("/"))errors2.push('ends with "/"');if(name.endsWith("."))errors2.push('ends with "."');if(name.startsWith("-"))errors2.push('starts with "-"');if(errors2.length>0)throw Error(`Invalid team name '${name}': must be a valid git branch name (${errors2.join(", ")})`)}async function killWorkersByName(agentName,teamName){let matches=(await list()).filter((w)=>(w.role===agentName||w.id===agentName)&&(!teamName||w.team===teamName));for(let w of matches){if(w.currentExecutorId)try{await terminateExecutor(w.currentExecutorId),await setCurrentExecutor(w.id,null)}catch{}try{if(w.paneId&&w.paneId!=="inline"){let{execSync:execSync2}=__require("child_process"),{genieTmuxCmd:genieTmuxCmd2}=(init_tmux_wrapper(),__toCommonJS(exports_tmux_wrapper));execSync2(genieTmuxCmd2(`kill-pane -t ${w.paneId}`),{stdio:"ignore"})}}catch{}await unregister(w.id)}}async function postCloneInit(repoPath,worktreePath){let parentNodeModules=join14(repoPath,"node_modules"),worktreeNodeModules=join14(worktreePath,"node_modules");if(existsSync10(parentNodeModules)&&!existsSync10(worktreeNodeModules))try{await symlink(parentNodeModules,worktreeNodeModules,"dir")}catch{}let initScript=join14(repoPath,".genie","init.sh");if(existsSync10(initScript))try{await $2`bash ${initScript}`.cwd(worktreePath).quiet()}catch{}}async function ensureWorktree(repoPath,branchName,worktreePath,baseBranch){try{await $2`git -C ${repoPath} fetch origin ${baseBranch}`.quiet()}catch{}if(await mkdir2(path.dirname(worktreePath),{recursive:!0}),existsSync10(worktreePath))return;let branchExists=!1;try{await $2`git -C ${repoPath} rev-parse --verify ${branchName}`.quiet(),branchExists=!0}catch{if(!branchExists)try{await $2`git -C ${repoPath} branch ${branchName} origin/${baseBranch}`.quiet()}catch{try{await $2`git -C ${repoPath} branch ${branchName} ${baseBranch}`.quiet()}catch{await $2`git -C ${repoPath} branch ${branchName}`.quiet()}}}await $2`git clone --shared --branch ${branchName} ${repoPath} ${worktreePath}`.quiet();try{let userName=(await $2`git -C ${repoPath} config user.name`.quiet()).text().trim(),userEmail=(await $2`git -C ${repoPath} config user.email`.quiet()).text().trim();if(userName)await $2`git -C ${worktreePath} config user.name ${userName}`.quiet();if(userEmail)await $2`git -C ${worktreePath} config user.email ${userEmail}`.quiet()}catch{}await postCloneInit(repoPath,worktreePath)}async function detectSpawnerParentTeam(newTeamName){let envTeam=process.env.GENIE_TEAM,spawnerName=process.env.GENIE_AGENT_NAME;if(!envTeam||!spawnerName)return null;if(spawnerName==="cli")return null;if(envTeam===newTeamName)return null;try{return await getTeam(envTeam)?envTeam:null}catch{return null}}async function createTeam(name,repo,baseBranch="dev"){validateBranchName(name);let repoPath=path.resolve(repo),existing=await getTeam(name);if(existing)return existing;let worktreeBase=getWorktreeBase(repoPath),worktreePath=join14(worktreeBase,name);await ensureWorktree(repoPath,name,worktreePath,baseBranch);let now=new Date().toISOString(),config={name,repo:repoPath,baseBranch,worktreePath,members:[],status:"in_progress",createdAt:now},promoted=await detectSpawnerParentTeam(name);if(promoted)config.parentTeam=promoted;if(isInsideClaudeCode()){config.nativeTeamsEnabled=!0;try{let result2=await registerAsTeamLead(name);config.nativeTeamParentSessionId=result2.sessionId}catch{}}return await(await getConnection())`
496
496
  INSERT INTO teams (
497
497
  name, repo, base_branch, worktree_path, leader,
498
498
  members, status, native_team_parent_session_id,
@@ -2208,7 +2208,7 @@ ${body}`;writeFileSync14(filePath,output,"utf-8")}function serializeSdkConfig(sd
2208
2208
  'scheduler',
2209
2209
  ${tx.json({agent_id:worker.id,reason,outcome:"clean_exit_unverified"})}
2210
2210
  )
2211
- `,{terminalized:!0,executorId}})}catch(err){let message=err instanceof Error?err.message:String(err);return deps.log({timestamp:deps.now().toISOString(),level:"error",event:"terminalize_clean_exit_unverified_failed",agent_id:worker.id,error:message}),{terminalized:!1,executorId:null}}}async function reconcileUnresumable(deps){let workers=await deps.listWorkers(),flipped=0;for(let worker of workers){if(worker.state!=="error")continue;if(worker.autoResume===!1)continue;if(worker.currentSessionId)continue;try{await deps.updateAgent(worker.id,{autoResume:!1}),deps.log({timestamp:deps.now().toISOString(),level:"warn",event:"agent_marked_unresumable",agent_id:worker.id,reason:"no_session_id",state:worker.state}),flipped++}catch(err){let message=err instanceof Error?err.message:String(err);deps.log({timestamp:deps.now().toISOString(),level:"warn",event:"agent_marked_unresumable_failed",agent_id:worker.id,error:message})}}return flipped}async function countActiveWorkers(workers,isPaneAlive2){let count=0;for(let w of workers){if(w.state==null||INACTIVE_WORKER_STATES.has(w.state))continue;if(/^%\d+$/.test(w.paneId))try{if(!await isPaneAlive2(w.paneId))continue}catch{}count++}return count}function telemetryState(raw){return raw&&TELEMETRY_STATES.has(raw)?raw:"unknown"}function recordResumeTelemetry(eventType,payload,actor){recordAuditEvent("agent.resume",payload.entity_id,eventType,actor,payload).catch(()=>{});try{let v2Payload={entity_id:payload.entity_id,attempt_number:payload.attempt_number,state_before:payload.state_before,state_after:payload.state_after,trigger:payload.trigger};if(payload.last_error)v2Payload.last_error=payload.last_error.slice(0,500);if(eventType==="agent.resume.failed")v2Payload.exhausted=payload.exhausted??!1;emitEvent(eventType,v2Payload,{severity:eventType==="agent.resume.failed"?"warn":"info",source_subsystem:"scheduler.auto-resume"})}catch{}}async function attemptAgentResume(deps,config,agent){let now=deps.now(),agentId=agent.id;if(agent.autoResume===!1)return deps.log({timestamp:now.toISOString(),level:"debug",event:"agent_resume_skipped",agent_id:agentId,reason:"auto_resume_disabled"}),"skipped";let maxAttempts=agent.maxResumeAttempts??DEFAULT_MAX_RESUME_ATTEMPTS,attempts=agent.resumeAttempts??0;if(!agent.currentSessionId){let newAttempts2=attempts+1;if(await deps.updateAgent(agentId,{resumeAttempts:newAttempts2,lastResumeAttempt:now.toISOString()}),deps.log({timestamp:now.toISOString(),level:"debug",event:"agent_resume_skipped",agent_id:agentId,reason:"no_session_id",resume_attempts:newAttempts2,max_resume_attempts:maxAttempts}),newAttempts2>=maxAttempts)return await deps.updateAgent(agentId,{autoResume:!1}),deps.log({timestamp:now.toISOString(),level:"warn",event:"agent_resume_exhausted",agent_id:agentId,resume_attempts:newAttempts2,max_resume_attempts:maxAttempts,reason:"no_session_id_orphan"}),"exhausted";return"skipped"}if(attempts>=maxAttempts)return await deps.updateAgent(agentId,{autoResume:!1}),deps.log({timestamp:now.toISOString(),level:"warn",event:"agent_resume_exhausted",agent_id:agentId,resume_attempts:attempts,max_resume_attempts:maxAttempts}),"exhausted";if(agent.lastResumeAttempt){let lastAttempt=new Date(agent.lastResumeAttempt).getTime();if(now.getTime()-lastAttempt<RESUME_COOLDOWN_MS)return deps.log({timestamp:now.toISOString(),level:"debug",event:"agent_resume_skipped",agent_id:agentId,reason:"cooldown",last_attempt:agent.lastResumeAttempt}),"skipped"}let workers=await deps.listWorkers(),activeCount=await countActiveWorkers(workers,deps.isPaneAlive);if(activeCount>=config.maxConcurrent)return deps.log({timestamp:now.toISOString(),level:"debug",event:"agent_resume_skipped",agent_id:agentId,reason:"concurrency_cap",active:activeCount,max:config.maxConcurrent}),"skipped";let newAttempts=attempts+1;await deps.updateAgent(agentId,{resumeAttempts:newAttempts,lastResumeAttempt:now.toISOString()}),deps.log({timestamp:now.toISOString(),level:"info",event:"agent_resume_attempted",agent_id:agentId,resume_attempts:newAttempts,max_resume_attempts:maxAttempts});let stateBefore=telemetryState(agent.state);if(recordResumeTelemetry("agent.resume.attempted",{entity_id:agentId,attempt_number:newAttempts,state_before:stateBefore,state_after:stateBefore,trigger:"scheduler"},"scheduler"),await deps.resumeAgent(agentId))return await deps.updateAgent(agentId,{resumeAttempts:0}),deps.log({timestamp:now.toISOString(),level:"info",event:"agent_resume_succeeded",agent_id:agentId,resume_attempts:newAttempts}),recordResumeTelemetry("agent.resume.succeeded",{entity_id:agentId,attempt_number:newAttempts,state_before:stateBefore,state_after:"spawning",trigger:"scheduler"},"scheduler"),"resumed";deps.log({timestamp:now.toISOString(),level:"warn",event:"agent_resume_failed",agent_id:agentId,resume_attempts:newAttempts,max_resume_attempts:maxAttempts});let willExhaust=newAttempts>=maxAttempts;if(recordResumeTelemetry("agent.resume.failed",{entity_id:agentId,attempt_number:newAttempts,state_before:stateBefore,state_after:stateBefore,trigger:"scheduler",exhausted:willExhaust},"scheduler"),newAttempts>=maxAttempts)return await deps.updateAgent(agentId,{autoResume:!1}),deps.log({timestamp:now.toISOString(),level:"warn",event:"agent_resume_exhausted",agent_id:agentId,resume_attempts:newAttempts,max_resume_attempts:maxAttempts}),"exhausted";return"skipped"}async function collectHeartbeats(deps){let sql=await deps.getConnection(),now=deps.now(),activeRuns=await sql`
2211
+ `,{terminalized:!0,executorId}})}catch(err){let message=err instanceof Error?err.message:String(err);return deps.log({timestamp:deps.now().toISOString(),level:"error",event:"terminalize_clean_exit_unverified_failed",agent_id:worker.id,error:message}),{terminalized:!1,executorId:null}}}async function reconcileUnresumable(deps){let workers=await deps.listWorkers(),flipped=0;for(let worker of workers){if(worker.state!=="error")continue;if(worker.autoResume===!1)continue;if(worker.currentSessionId)continue;try{await deps.updateAgent(worker.id,{autoResume:!1}),deps.log({timestamp:deps.now().toISOString(),level:"warn",event:"agent_marked_unresumable",agent_id:worker.id,reason:"no_session_id",state:worker.state}),flipped++}catch(err){let message=err instanceof Error?err.message:String(err);deps.log({timestamp:deps.now().toISOString(),level:"warn",event:"agent_marked_unresumable_failed",agent_id:worker.id,error:message})}}return flipped}async function countActiveWorkers(workers,isPaneAlive2){let count=0;for(let w of workers){if(w.state==null||INACTIVE_WORKER_STATES.has(w.state))continue;if(/^%\d+$/.test(w.paneId))try{if(!await isPaneAlive2(w.paneId))continue}catch{}count++}return count}function telemetryState(raw){return raw&&TELEMETRY_STATES.has(raw)?raw:"unknown"}function recordResumeTelemetry(eventType,payload,actor){recordAuditEvent("agent.resume",payload.entity_id,eventType,actor,payload).catch(()=>{});try{let v2Payload={entity_id:payload.entity_id,attempt_number:payload.attempt_number,state_before:payload.state_before,state_after:payload.state_after,trigger:payload.trigger};if(payload.last_error)v2Payload.last_error=payload.last_error.slice(0,500);if(eventType==="agent.resume.failed")v2Payload.exhausted=payload.exhausted??!1;emitEvent(eventType,v2Payload,{severity:eventType==="agent.resume.failed"?"warn":"info",source_subsystem:"scheduler.auto-resume"})}catch{}}async function attemptAgentResume(deps,config,agent){let now=deps.now(),agentId=agent.id;if(agent.autoResume===!1)return deps.log({timestamp:now.toISOString(),level:"debug",event:"agent_resume_skipped",agent_id:agentId,reason:"auto_resume_disabled"}),"skipped";let maxAttempts=agent.maxResumeAttempts??DEFAULT_MAX_RESUME_ATTEMPTS,attempts=agent.resumeAttempts??0;if(!agent.currentSessionId){let newAttempts2=attempts+1;await deps.updateAgent(agentId,{resumeAttempts:newAttempts2,lastResumeAttempt:now.toISOString()}),deps.log({timestamp:now.toISOString(),level:"debug",event:"agent_resume_skipped",agent_id:agentId,reason:"no_session_id",resume_attempts:newAttempts2,max_resume_attempts:maxAttempts});try{let{recordResumeMissingSession:recordResumeMissingSession2}=await Promise.resolve().then(() => (init_executor_registry(),exports_executor_registry)),actor=process.env.GENIE_AGENT_NAME??"scheduler";await recordResumeMissingSession2(agentId,actor,{reason:"no_session_id"})}catch{}if(newAttempts2>=maxAttempts)return await deps.updateAgent(agentId,{autoResume:!1}),deps.log({timestamp:now.toISOString(),level:"warn",event:"agent_resume_exhausted",agent_id:agentId,resume_attempts:newAttempts2,max_resume_attempts:maxAttempts,reason:"no_session_id_orphan"}),"exhausted";return"skipped"}if(attempts>=maxAttempts)return await deps.updateAgent(agentId,{autoResume:!1}),deps.log({timestamp:now.toISOString(),level:"warn",event:"agent_resume_exhausted",agent_id:agentId,resume_attempts:attempts,max_resume_attempts:maxAttempts}),"exhausted";if(agent.lastResumeAttempt){let lastAttempt=new Date(agent.lastResumeAttempt).getTime();if(now.getTime()-lastAttempt<RESUME_COOLDOWN_MS)return deps.log({timestamp:now.toISOString(),level:"debug",event:"agent_resume_skipped",agent_id:agentId,reason:"cooldown",last_attempt:agent.lastResumeAttempt}),"skipped"}let workers=await deps.listWorkers(),activeCount=await countActiveWorkers(workers,deps.isPaneAlive);if(activeCount>=config.maxConcurrent)return deps.log({timestamp:now.toISOString(),level:"debug",event:"agent_resume_skipped",agent_id:agentId,reason:"concurrency_cap",active:activeCount,max:config.maxConcurrent}),"skipped";let newAttempts=attempts+1;await deps.updateAgent(agentId,{resumeAttempts:newAttempts,lastResumeAttempt:now.toISOString()}),deps.log({timestamp:now.toISOString(),level:"info",event:"agent_resume_attempted",agent_id:agentId,resume_attempts:newAttempts,max_resume_attempts:maxAttempts});let stateBefore=telemetryState(agent.state);if(recordResumeTelemetry("agent.resume.attempted",{entity_id:agentId,attempt_number:newAttempts,state_before:stateBefore,state_after:stateBefore,trigger:"scheduler"},"scheduler"),await deps.resumeAgent(agentId))return await deps.updateAgent(agentId,{resumeAttempts:0}),deps.log({timestamp:now.toISOString(),level:"info",event:"agent_resume_succeeded",agent_id:agentId,resume_attempts:newAttempts}),recordResumeTelemetry("agent.resume.succeeded",{entity_id:agentId,attempt_number:newAttempts,state_before:stateBefore,state_after:"spawning",trigger:"scheduler"},"scheduler"),"resumed";deps.log({timestamp:now.toISOString(),level:"warn",event:"agent_resume_failed",agent_id:agentId,resume_attempts:newAttempts,max_resume_attempts:maxAttempts});let willExhaust=newAttempts>=maxAttempts;if(recordResumeTelemetry("agent.resume.failed",{entity_id:agentId,attempt_number:newAttempts,state_before:stateBefore,state_after:stateBefore,trigger:"scheduler",exhausted:willExhaust},"scheduler"),newAttempts>=maxAttempts)return await deps.updateAgent(agentId,{autoResume:!1}),deps.log({timestamp:now.toISOString(),level:"warn",event:"agent_resume_exhausted",agent_id:agentId,resume_attempts:newAttempts,max_resume_attempts:maxAttempts}),"exhausted";return"skipped"}async function collectHeartbeats(deps){let sql=await deps.getConnection(),now=deps.now(),activeRuns=await sql`
2212
2212
  SELECT id, worker_id, status, trigger_id FROM runs WHERE status = 'running'
2213
2213
  `,workers=await deps.listWorkers(),workerById=new Map(workers.map((w)=>[w.id,w])),collected=0;for(let run of activeRuns){let{alive,isPid}=await checkWorkerAlive(deps,run.worker_id),heartbeatStatus=alive?isPid?"busy":"alive":"dead",worker=workerById.get(run.worker_id),context={alive,pid_check:isPid,worker_id:run.worker_id,team:worker?.team??null,wish_slug:worker?.wishSlug??null,group_number:worker?.groupNumber??null,state:worker?.state??null},heartbeatId=deps.generateId();await sql`
2214
2214
  INSERT INTO heartbeats (id, worker_id, run_id, status, context, last_seen_at, created_at)
@@ -3855,7 +3855,7 @@ Bus `);for(let i2=1;i2<parts.length;i2++){let usb2=parseLinuxUsb(parts[i2]);resu
3855
3855
  `,lastBannerIndex);if(afterBannerNewline<0)return"";return text.slice(afterBannerNewline+1).trim()}catch{return""}finally{if(fd!==null)try{closeSync6(fd)}catch{}}}async function ingestPreviousRunCrash(logPath){let body=extractPreviousRunCrashOutput(logPath);if(!body)return;let truncated=body.length>TUI_CRASH_LOG_RECOVERY_MAX_MSG_CHARS?`${body.slice(0,TUI_CRASH_LOG_RECOVERY_MAX_MSG_CHARS)}
3856
3856
  \u2026[truncated]`:body;try{let{emitEvent:emitEvent2}=await Promise.resolve().then(() => (init_emit(),exports_emit));emitEvent2("error.raised",{error_class:"TuiCrash",message:truncated,subsystem:"tui",severity:"error",retryable:!0})}catch{}}async function recordTuiLaunchBreadcrumb(){try{let logsDir=join83(genieHome6(),"logs");mkdirSync28(logsDir,{recursive:!0});let logPath=join83(logsDir,"tui-crash.log");await ingestPreviousRunCrash(logPath);let ts3=new Date().toISOString(),line=`${TUI_CRASH_LOG_BANNER_PREFIX}${ts3} pid=${process.pid} platform=${process.platform} arch=${process.arch} ---
3857
3857
  `;appendFileSync4(logPath,line,{mode:420})}catch{}}async function launchTui(){await recordTuiLaunchBreadcrumb();let{renderNav:renderNav2}=await init_render().then(() => exports_render);await renderNav2()}var TUI_CRASH_LOG_BANNER_PREFIX="--- tui-launch ",TUI_CRASH_LOG_RECOVERY_MAX_BYTES=65536,TUI_CRASH_LOG_RECOVERY_MAX_MSG_CHARS=3000;var init_tui=()=>{};var exports_resolve_agent_cwd={};__export(exports_resolve_agent_cwd,{resolveAgentFromCwd:()=>resolveAgentFromCwd});import{existsSync as existsSync67}from"fs";import{basename as basename16,dirname as dirname25,join as join84,relative as relative10,sep as sep3}from"path";function isRelativeWithin(rel,original){return!rel.startsWith("..")&&rel!==original}function resolveFromCanonicalDir(cwd,agentsDir){let relToAgents=relative10(agentsDir,cwd);if(!isRelativeWithin(relToAgents,cwd))return null;let segments=relToAgents.split(sep3).filter(Boolean);if(segments.length===0)return null;let agentName=segments[0];if(!existsSync67(join84(agentsDir,agentName,"AGENTS.md")))return null;let source=segments.length===1?"exact":"parent";return{agent:agentName,source}}function resolveFromWalkUp(cwd,workspaceRoot){let wsRel=relative10(workspaceRoot,cwd);if(!isRelativeWithin(wsRel,cwd))return null;let current=cwd;while(current!==workspaceRoot&&current!==dirname25(current)){if(existsSync67(join84(current,"AGENTS.md")))return{agent:basename16(current),source:"parent"};current=dirname25(current)}return null}function resolveAgentFromCwd(cwd,workspaceRoot){return resolveFromCanonicalDir(cwd,join84(workspaceRoot,"agents"))??resolveFromWalkUp(cwd,workspaceRoot)??{agent:"genie",source:"default"}}var init_resolve_agent_cwd=()=>{};var import__=__toESM(require_commander(),1),{program,createCommand,createArgument,createOption,CommanderError,InvalidArgumentError,InvalidOptionArgumentError,Command,Argument,Option,Help}=import__.default;init_doctor();init_setup();init_shortcuts();import{existsSync as existsSync23}from"fs";import{homedir as homedir24}from"os";import{join as join29}from"path";async function shortcutsShowCommand(){displayShortcuts();let home=homedir24(),tmuxConf=join29(home,".tmux.conf"),zshrc=join29(home,".zshrc"),bashrc=join29(home,".bashrc");if(console.log("Installation status:"),isShortcutsInstalled(tmuxConf))console.log(" \x1B[32m\u2713\x1B[0m tmux.conf");else console.log(" \x1B[33m-\x1B[0m tmux.conf");let shellRc=existsSync23(zshrc)?zshrc:bashrc;if(isShortcutsInstalled(shellRc))console.log(` \x1B[32m\u2713\x1B[0m ${shellRc.replace(home,"~")}`);else console.log(` \x1B[33m-\x1B[0m ${shellRc.replace(home,"~")}`);console.log(),console.log("Run \x1B[36mgenie shortcuts install\x1B[0m to install shortcuts."),console.log("Run \x1B[36mgenie shortcuts uninstall\x1B[0m to remove shortcuts."),console.log()}async function shortcutsInstallCommand(){await installShortcuts()}async function shortcutsUninstallCommand(){await uninstallShortcuts()}init_esm14();init_claude_settings();init_genie_config2();import{existsSync as existsSync24,lstatSync,rmSync as rmSync2,unlinkSync as unlinkSync8}from"fs";import{homedir as homedir25}from"os";import{join as join30}from"path";var ORCHESTRATION_RULES_PATH=join30(homedir25(),".claude","rules","genie-orchestration.md"),LOCAL_BIN=join30(homedir25(),".local","bin"),SYMLINKS=["genie","term"];function isGenieSymlink(path3){try{if(!existsSync24(path3))return!1;if(!lstatSync(path3).isSymbolicLink())return!1;return!0}catch{return!1}}function removeSymlinks(){let removed=[];for(let name of SYMLINKS){let symlinkPath=join30(LOCAL_BIN,name);if(isGenieSymlink(symlinkPath))try{unlinkSync8(symlinkPath),removed.push(name)}catch{}}return removed}function tryRemoveStep(label,successMsg,fn){console.log(`\x1B[2m${label}\x1B[0m`);try{fn(),console.log(` \x1B[32m+\x1B[0m ${successMsg}`)}catch(error){let message=error instanceof Error?error.message:String(error);console.log(` \x1B[33m!\x1B[0m ${label.replace("...","")} failed: ${message}`)}}function performUninstall(hasHookScript,existingSymlinks,genieDir,hasGenieDir){if(hasHookScript)tryRemoveStep("Removing hook script...","Hook script removed",()=>removeHookScript());if(existingSymlinks.length>0){console.log("\x1B[2mRemoving symlinks...\x1B[0m");let removed=removeSymlinks();if(removed.length>0)console.log(` \x1B[32m+\x1B[0m Removed: ${removed.join(", ")}`)}if(existsSync24(ORCHESTRATION_RULES_PATH))tryRemoveStep("Removing orchestration rules...","Orchestration rules removed (~/.claude/rules/genie-orchestration.md)",()=>unlinkSync8(ORCHESTRATION_RULES_PATH));if(hasGenieDir)tryRemoveStep("Removing genie directory...","Directory removed",()=>rmSync2(genieDir,{recursive:!0,force:!0}))}async function uninstallCommand(){console.log(),console.log("\x1B[1m\x1B[33m Uninstall Genie CLI\x1B[0m"),console.log();let genieDir=getGenieDir(),hasGenieDir=existsSync24(genieDir),hasHookScript=hookScriptExists(),hasOrchestrationRules=existsSync24(ORCHESTRATION_RULES_PATH),existingSymlinks=SYMLINKS.filter((name)=>isGenieSymlink(join30(LOCAL_BIN,name)));if(console.log("\x1B[2mThis will remove:\x1B[0m"),hasHookScript)console.log(" \x1B[31m-\x1B[0m Hook script (~/.claude/hooks/genie-bash-hook.sh)");if(hasOrchestrationRules)console.log(" \x1B[31m-\x1B[0m Orchestration rules (~/.claude/rules/genie-orchestration.md)");if(hasGenieDir)console.log(` \x1B[31m-\x1B[0m Genie directory (${contractPath(genieDir)})`);if(existingSymlinks.length>0)console.log(` \x1B[31m-\x1B[0m Symlinks from ~/.local/bin: ${existingSymlinks.join(", ")}`);if(console.log(),!hasGenieDir&&!hasHookScript&&!hasOrchestrationRules&&existingSymlinks.length===0){console.log("\x1B[33mNothing to uninstall.\x1B[0m"),console.log();return}if(!await esm_default4({message:"Are you sure you want to uninstall Genie CLI?",default:!1})){console.log(),console.log("\x1B[2mUninstall cancelled.\x1B[0m"),console.log();return}console.log(),performUninstall(hasHookScript,existingSymlinks,genieDir,hasGenieDir),console.log(),console.log("\x1B[32m+\x1B[0m Genie CLI uninstalled."),console.log(),console.log("\x1B[2mNote: If you installed via npm/bun, also run:\x1B[0m"),console.log(" \x1B[36mbun remove -g @automagik/genie\x1B[0m"),console.log(" \x1B[2mor\x1B[0m"),console.log(" \x1B[36mnpm uninstall -g @automagik/genie\x1B[0m"),console.log()}init_genie_config2();import{execSync as execSync4,spawn as spawn3}from"child_process";import{chmodSync as chmodSync2,closeSync as closeSync3,copyFileSync as copyFileSync3,existsSync as existsSync25,mkdirSync as mkdirSync13,openSync as openSync3,readFileSync as readFileSync17,readSync as readSync2,readdirSync as readdirSync8,rmSync as rmSync3,statSync as statSync7,writeFileSync as writeFileSync11}from"fs";import{chmod,copyFile,mkdir as mkdir5,unlink as unlink2}from"fs/promises";import{homedir as homedir26}from"os";import{join as join31}from"path";var GENIE_HOME2=process.env.GENIE_HOME||join31(homedir26(),".genie"),GENIE_SRC=join31(GENIE_HOME2,"src"),GENIE_BIN=join31(GENIE_HOME2,"bin"),LOCAL_BIN2=join31(homedir26(),".local","bin"),TRUTHY=new Set(["1","true","yes","on"]),UPDATE_DIAGNOSTIC_SCHEMA_VERSION=1;function log(message){console.log(`\x1B[32m\u25B8\x1B[0m ${message}`)}function success(message){console.log(`\x1B[32m\u2714\x1B[0m ${message}`)}function error(message){console.log(`\x1B[31m\u2716\x1B[0m ${message}`)}function formatDuration2(ms){if(ms<1000)return`${ms}ms`;return`${(ms/1000).toFixed(1)}s`}function isTruthyEnv(value){return value!==void 0&&TRUTHY.has(value.trim().toLowerCase())}async function withTemporaryEnv(key,value,fn){let previous=process.env[key];process.env[key]=value;try{return await fn()}finally{if(previous===void 0)delete process.env[key];else process.env[key]=previous}}function safeExec(command,timeoutMs=1500){try{return execSync4(command,{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:timeoutMs}).trim()}catch(err){let stdout=err.stdout;if(typeof stdout==="string"&&stdout.trim())return stdout.trim();return""}}function safeRead(path3,maxChars=4000){try{let value=readFileSync17(path3,"utf-8");if(value.length<=maxChars)return value;return value.slice(value.length-maxChars)}catch{return null}}function tailLines(path3,maxBytes=64000,maxLines=200){let fd=null;try{let stat4=statSync7(path3),bytesToRead=Math.min(stat4.size,maxBytes),buffer2=Buffer.alloc(bytesToRead);return fd=openSync3(path3,"r"),readSync2(fd,buffer2,0,bytesToRead,Math.max(0,stat4.size-bytesToRead)),buffer2.toString("utf-8").split(/\r?\n/).map((line)=>line.trim()).filter(Boolean).slice(-maxLines)}catch{return[]}finally{if(fd!==null)try{closeSync3(fd)}catch{}}}function summarizeJsonlSignals(path3){let signals2=new Map;for(let line of tailLines(path3))try{let event=JSON.parse(line),level=typeof event.level==="string"?event.level:"unknown";if(level!=="error"&&level!=="warn")continue;let name=typeof event.event==="string"?event.event:"unknown",key=`${level}:${name}`,existing=signals2.get(key)??{level,event:name,count:0};if(existing.count++,typeof event.timestamp==="string")existing.lastTimestamp=event.timestamp;if(typeof event.error==="string")existing.lastError=event.error;signals2.set(key,existing)}catch{}return[...signals2.values()].sort((a,b2)=>b2.count-a.count).slice(0,10)}async function collectUpdateDiagnostics(ctx,maintenance){let logsDir=join31(GENIE_HOME2,"logs");mkdirSync13(logsDir,{recursive:!0});let generatedAt=new Date().toISOString(),safeStamp=generatedAt.replace(/[:.]/g,"-"),path3=join31(logsDir,`update-diagnostics-${safeStamp}.json`),schedulerLog=join31(logsDir,"scheduler.log"),tuiCrashLog=join31(logsDir,"tui-crash.log"),signals2=summarizeJsonlSignals(schedulerLog),diagnostics={schemaVersion:UPDATE_DIAGNOSTIC_SCHEMA_VERSION,generatedAt,update:ctx,runtime:{platform:process.platform,arch:process.arch,cwd:process.cwd(),node:process.version,bun:(await runCommandSilent("bun",["--version"])).output.trim()||null,npm:(await runCommandSilent("npm",["--version"])).output.trim()||null,genie:{which:(await runCommandSilent("which",["genie"])).output.trim()||null,tuiDisabled:isTruthyEnv(process.env.GENIE_TUI_DISABLE),updateSkipMaintenance:isTruthyEnv(process.env.GENIE_UPDATE_SKIP_MAINTENANCE)}},paths:{genieHome:GENIE_HOME2,logsDir,servePid:safeRead(join31(GENIE_HOME2,"serve.pid"),200),pgservePort:safeRead(join31(GENIE_HOME2,"pgserve.port"),200),schedulerLog,tuiCrashLog},processSnapshot:{genie:safeExec("ps -axo pid,ppid,pgid,stat,pcpu,pmem,etime,command -r | rg -i 'dist/genie.js|/src/genie.ts|pgserve|postgres -D .*\\.genie/data/pgserve|tmux -L genie-tui|bun' || true",2000)||null,tuiTmux:safeExec("tmux -L genie-tui ls 2>/dev/null || true",1000)||null},maintenance:{...maintenance,pgAutostartDisabled:!0,legend:{"[ok]":"healthy","[fix]":"fixed during maintenance","[--]":"skipped/non-blocking","[!!]":"operator action needed; update still completed"}},recentLogSignals:{scheduler:signals2,schedulerTail:tailLines(schedulerLog,32000,80),tuiCrashTail:tailLines(tuiCrashLog,32000,80)}};return writeFileSync11(path3,`${JSON.stringify(diagnostics,null,2)}
3858
- `),{path:path3,signals:signals2}}async function runCommand(command,args,cwd){return new Promise((resolve4)=>{let output=[],child=spawn3(command,args,{cwd,stdio:["inherit","pipe","pipe"],env:{...process.env,FORCE_COLOR:"1"}});child.stdout?.on("data",(data)=>{let str2=data.toString();output.push(str2),process.stdout.write(str2)}),child.stderr?.on("data",(data)=>{let str2=data.toString();output.push(str2),process.stderr.write(str2)}),child.on("close",(code)=>{resolve4({success:code===0,output:output.join("")})}),child.on("error",(err)=>{error(err.message),resolve4({success:!1,output:err.message})})})}async function getGitInfo(cwd){try{let branchResult=await runCommandSilent("git",["rev-parse","--abbrev-ref","HEAD"],cwd),commitResult=await runCommandSilent("git",["rev-parse","--short","HEAD"],cwd),dateResult=await runCommandSilent("git",["log","-1","--format=%ci"],cwd);if(branchResult.success&&commitResult.success&&dateResult.success)return{branch:branchResult.output.trim(),commit:commitResult.output.trim(),commitDate:dateResult.output.trim().split(" ")[0]}}catch{}return null}async function runCommandSilent(command,args,cwd,timeoutMs=4000){return new Promise((resolve4)=>{let output=[],settled=!1,child=spawn3(command,args,{cwd,stdio:["inherit","pipe","pipe"]}),timer2=setTimeout(()=>{if(settled)return;settled=!0,child.kill("SIGTERM"),resolve4({success:!1,output:`Timed out after ${timeoutMs}ms`})},timeoutMs);child.stdout?.on("data",(data)=>{output.push(data.toString())}),child.stderr?.on("data",(data)=>{output.push(data.toString())}),child.on("close",(code)=>{if(settled)return;settled=!0,clearTimeout(timer2),resolve4({success:code===0,output:output.join("")})}),child.on("error",(err)=>{if(settled)return;settled=!0,clearTimeout(timer2),resolve4({success:!1,output:err.message})})})}function detectFromBinaryPath(path3){let resolved=path3;try{resolved=__require("fs").realpathSync(path3)}catch{}if(resolved.includes(".bun"))return"bun";if(resolved.includes("node_modules"))return"npm";if(path3===join31(LOCAL_BIN2,"genie")||resolved.startsWith(GENIE_BIN))return"source";return null}async function detectInstallationType(){let whichResult=await runCommandSilent("which",["genie"]);if(whichResult.success){let detected=detectFromBinaryPath(whichResult.output.trim());if(detected)return detected}if(genieConfigExists())try{let config=await loadGenieConfig();if(config.installMethod)return config.installMethod}catch{}if(existsSync25(join31(GENIE_SRC,".git")))return"source";return(await runCommandSilent("which",["bun"])).success?"bun":"npm"}async function updateViaBun(channel){try{__require("fs").unlinkSync(join31(homedir26(),".bun","install","global","bun.lock"))}catch{}if(log(`Updating via bun (channel: ${channel})...`),!(await runCommand("bun",["add","-g",`@automagik/genie@${channel}`])).success)return error("Failed to update via bun"),!1;return console.log(),success(`Genie CLI updated via bun (${channel})!`),!0}async function updateViaNpm(channel){if(log(`Updating via npm (channel: ${channel})...`),!(await runCommand("npm",["install","-g",`@automagik/genie@${channel}`])).success)return error("Failed to update via npm"),!1;return console.log(),success(`Genie CLI updated via npm (${channel})!`),!0}async function detectGlobalInstalls(){let found=new Set,[npmResult,bunResult]=await Promise.all([runCommandSilent("npm",["list","-g","@automagik/genie"]),runCommandSilent("bun",["pm","ls","-g"])]);if(npmResult.success&&!npmResult.output.includes("(empty)"))found.add("npm");if(bunResult.success&&bunResult.output.includes("@automagik/genie"))found.add("bun");return found}async function updateSource(){let beforeInfo=await getGitInfo(GENIE_SRC);if(beforeInfo)console.log(`Current: \x1B[2m${beforeInfo.branch}@${beforeInfo.commit} (${beforeInfo.commitDate})\x1B[0m`),console.log();if(log("Fetching latest changes..."),!(await runCommand("git",["fetch","origin"],GENIE_SRC)).success)error("Failed to fetch from origin"),process.exit(1);if(log("Resetting to origin/main..."),!(await runCommand("git",["reset","--hard","origin/main"],GENIE_SRC)).success)error("Failed to reset to origin/main"),process.exit(1);console.log();let afterInfo=await getGitInfo(GENIE_SRC);if(beforeInfo&&afterInfo&&beforeInfo.commit===afterInfo.commit){success("Already up to date!"),console.log();return}if(log("Installing dependencies..."),!(await runCommand("bun",["install"],GENIE_SRC)).success)error("Failed to install dependencies"),process.exit(1);if(console.log(),log("Building..."),!(await runCommand("bun",["run","build"],GENIE_SRC)).success)error("Failed to build"),process.exit(1);console.log(),log("Installing binaries...");try{await mkdir5(GENIE_BIN,{recursive:!0}),await mkdir5(LOCAL_BIN2,{recursive:!0});let binaries=["genie.js","term.js"],names=["genie","term"];for(let i2=0;i2<binaries.length;i2++){let src=join31(GENIE_SRC,"dist",binaries[i2]),binDest=join31(GENIE_BIN,binaries[i2]),linkDest=join31(LOCAL_BIN2,names[i2]);await copyFile(src,binDest),await chmod(binDest,493),await symlinkOrCopy(binDest,linkDest)}for(let legacy of["claudio.js","claudio"]){let legacyBin=join31(GENIE_BIN,legacy),legacyLink=join31(LOCAL_BIN2,legacy);try{await unlink2(legacyBin)}catch{}try{await unlink2(legacyLink)}catch{}}success("Binaries installed")}catch(err){error(`Failed to install binaries: ${err}`),process.exit(1)}if(console.log(),console.log("\x1B[2m\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m"),success("Genie CLI updated successfully!"),console.log(),afterInfo)console.log(`Version: \x1B[36m${afterInfo.branch}@${afterInfo.commit}\x1B[0m (${afterInfo.commitDate})`),console.log()}async function symlinkOrCopy(src,dest){let{symlink:symlink2,unlink:unlink3}=await import("fs/promises");try{if(existsSync25(dest))await unlink3(dest);await symlink2(src,dest)}catch{await copyFile(src,dest)}}function copyDirSync(src,dest){mkdirSync13(dest,{recursive:!0});for(let entry2 of readdirSync8(src,{withFileTypes:!0})){let srcPath=join31(src,entry2.name),destPath=join31(dest,entry2.name);if(entry2.isDirectory())copyDirSync(srcPath,destPath);else copyFileSync3(srcPath,destPath)}}async function resolveGlobalPkgDir(installType){if(installType==="bun"){let bunPath=join31(homedir26(),".bun","install","global","node_modules","@automagik","genie");if(existsSync25(bunPath))return bunPath}if(installType==="npm"){let npmRootResult=await runCommandSilent("npm",["root","-g"]);if(npmRootResult.success){let npmPath=join31(npmRootResult.output.trim(),"@automagik","genie");if(existsSync25(npmPath))return npmPath}}let bunFallback=join31(homedir26(),".bun","install","global","node_modules","@automagik","genie");if(existsSync25(bunFallback))return bunFallback;let npmRootFallback=await runCommandSilent("npm",["root","-g"]);if(npmRootFallback.success){let npmPath=join31(npmRootFallback.output.trim(),"@automagik","genie");if(existsSync25(npmPath))return npmPath}return null}function updatePluginRegistry(claudePlugins,cacheDir,version){let registryPath=join31(claudePlugins,"installed_plugins.json");try{if(!existsSync25(registryPath))return;let registry=JSON.parse(readFileSync17(registryPath,"utf-8")),entries=registry.plugins?.["genie@automagik"];if(!Array.isArray(entries))return;for(let entry2 of entries)if(entry2.scope==="user")entry2.installPath=cacheDir,entry2.version=version,entry2.lastUpdated=new Date().toISOString();writeFileSync11(registryPath,JSON.stringify(registry,null,2))}catch(err){log(`Registry update failed (non-fatal): ${err}`)}}function syncTmuxConf(tmuxScriptsSrc){mkdirSync13(GENIE_HOME2,{recursive:!0});let tmuxConfSrc=join31(tmuxScriptsSrc,"genie.tmux.conf"),tmuxConfDest=join31(GENIE_HOME2,"tmux.conf");if(existsSync25(tmuxConfSrc))try{copyFileSync3(tmuxConfSrc,tmuxConfDest),success(`Installed tmux config to ${tmuxConfDest}`);try{let{tmuxBin:tmuxBin2}=(init_ensure_tmux(),__toCommonJS(exports_ensure_tmux));execSync4(`${tmuxBin2()} -L genie source-file '${tmuxConfDest}'`,{stdio:"ignore"}),success("Reloaded genie tmux server configuration")}catch{}}catch{}let tuiConfSrc=join31(tmuxScriptsSrc,"tui-tmux.conf"),tuiConfDest=join31(GENIE_HOME2,"tui-tmux.conf");if(existsSync25(tuiConfSrc))try{copyFileSync3(tuiConfSrc,tuiConfDest),success(`Installed TUI tmux config to ${tuiConfDest}`)}catch{}let themeSrc=join31(tmuxScriptsSrc,".generated.theme.conf"),themeDest=join31(GENIE_HOME2,".generated.theme.conf");if(existsSync25(themeSrc))try{copyFileSync3(themeSrc,themeDest),success(`Installed tmux theme to ${themeDest}`)}catch{}let osc52Src=join31(tmuxScriptsSrc,"osc52-copy.sh"),osc52Dest=join31(GENIE_HOME2,"scripts","osc52-copy.sh");if(existsSync25(osc52Src))try{copyFileSync3(osc52Src,osc52Dest),chmodSync2(osc52Dest,493),success(`Installed OSC 52 clipboard helper to ${osc52Dest}`)}catch{}}function syncTmuxScripts(globalPkgDir){let tmuxScriptsSrc=join31(globalPkgDir,"scripts","tmux");if(!existsSync25(tmuxScriptsSrc))return;let scriptsDir=join31(GENIE_HOME2,"scripts");mkdirSync13(scriptsDir,{recursive:!0});let scriptCount=0;for(let entry2 of readdirSync8(tmuxScriptsSrc))if(entry2.endsWith(".sh")||entry2==="genie.tmux.conf"||entry2==="tui-tmux.conf"||entry2===".generated.theme.conf"){let src=join31(tmuxScriptsSrc,entry2),dest=join31(scriptsDir,entry2);copyFileSync3(src,dest);try{chmodSync2(dest,entry2.endsWith(".sh")?493:420)}catch{}scriptCount++}if(scriptCount>0)success(`Refreshed ${scriptCount} tmux scripts at ${scriptsDir}`);syncTmuxConf(tmuxScriptsSrc)}function syncMarketplaceVersion(claudePlugins,version){let marketplacePath=join31(claudePlugins,"marketplaces","automagik",".claude-plugin","marketplace.json");try{if(!existsSync25(marketplacePath))return;let data=JSON.parse(readFileSync17(marketplacePath,"utf-8"));if(Array.isArray(data.plugins)){for(let plugin of data.plugins)if(plugin.name==="genie")plugin.version=version}writeFileSync11(marketplacePath,JSON.stringify(data,null,2)),success(`Updated marketplace.json to v${version}`)}catch(err){log(`Marketplace version update failed (non-fatal): ${err}`)}}function syncPluginPackageVersion(claudePlugins,version){let pkgPath=join31(claudePlugins,"marketplaces","automagik","plugins","genie","package.json");try{if(!existsSync25(pkgPath))return;let data=JSON.parse(readFileSync17(pkgPath,"utf-8"));data.version=version,writeFileSync11(pkgPath,JSON.stringify(data,null,2)),success(`Updated plugin package.json to v${version}`)}catch(err){log(`Plugin package.json update failed (non-fatal): ${err}`)}}function syncSkillsSymlink(claudePlugins,version){let skillsLink=join31(claudePlugins,"marketplaces","automagik","plugins","genie","skills"),cacheSkills=join31("..","..","..","..","cache","automagik","genie",version,"skills");try{let{symlinkSync,unlinkSync:unlinkSync9,lstatSync:lstatSync2}=__require("fs");try{lstatSync2(skillsLink),unlinkSync9(skillsLink)}catch{}symlinkSync(cacheSkills,skillsLink),success(`Skills symlink \u2192 cache/${version}/skills`)}catch(err){log(`Skills symlink update failed (non-fatal): ${err}`)}}async function syncPlugin(installType){log("Syncing Claude Code plugin...");let globalPkgDir=await resolveGlobalPkgDir(installType);if(!globalPkgDir)return log("Could not find installed package \u2014 skipping plugin sync"),{skippedReason:"installed package not found"};let pluginSrc=join31(globalPkgDir,"plugins","genie");if(!existsSync25(pluginSrc))return log("Plugin source not found in package \u2014 skipping plugin sync"),{globalPkgDir,skippedReason:"plugin source not found in package"};let version;try{version=JSON.parse(readFileSync17(join31(globalPkgDir,"package.json"),"utf-8")).version}catch{return log("Could not read package version \u2014 skipping plugin sync"),{globalPkgDir,skippedReason:"could not read package version"}}let claudePlugins=join31(homedir26(),".claude","plugins"),cacheDir=join31(claudePlugins,"cache","automagik","genie",version);try{if(existsSync25(cacheDir))rmSync3(cacheDir,{recursive:!0,force:!0});copyDirSync(pluginSrc,cacheDir);let skillsSrc=join31(globalPkgDir,"skills");if(existsSync25(skillsSrc)&&!existsSync25(join31(cacheDir,"skills")))copyDirSync(skillsSrc,join31(cacheDir,"skills"))}catch(err){return error(`Failed to copy plugin: ${err}`),{version,globalPkgDir,cacheDir,skippedReason:`failed to copy plugin: ${err}`}}return updatePluginRegistry(claudePlugins,cacheDir,version),syncMarketplaceVersion(claudePlugins,version),syncPluginPackageVersion(claudePlugins,version),syncSkillsSymlink(claudePlugins,version),syncTmuxScripts(globalPkgDir),success(`Plugin synced to v${version}`),{version,globalPkgDir,cacheDir}}async function resolveChannel(options){if(options.next)return"next";if(options.stable)return"latest";if(genieConfigExists())try{let config=await loadGenieConfig();if(config.updateChannel)return config.updateChannel}catch{}return"latest"}async function persistChannel(channel){try{let config=await loadGenieConfig();config.updateChannel=channel,await saveGenieConfig(config)}catch{}}async function updateCommand(options={}){console.log(),console.log("\x1B[1m\uD83E\uDDDE Genie CLI Update\x1B[0m"),console.log("\x1B[2m\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m"),console.log();let channel=await resolveChannel(options);if(options.next||options.stable)await persistChannel(channel);let installType=await detectInstallationType();if(log(`Detected installation: ${installType}`),log(`Channel: ${channel}${channel==="next"?" (dev builds)":" (stable)"}`),console.log(),installType==="unknown")error("No Genie CLI installation found"),console.log(),console.log("Install method not configured. Please reinstall genie:"),console.log("\x1B[36m curl -fsSL https://raw.githubusercontent.com/automagik-dev/genie/main/install.sh | bash\x1B[0m"),console.log(),process.exit(1);if(installType==="source"){await updateSource();return}let globalInstalls=await detectGlobalInstalls(),primaryMethod=installType;if(!(primaryMethod==="bun"?await updateViaBun(channel):await updateViaNpm(channel)))process.exit(1);let secondaryMethod=primaryMethod==="bun"?"npm":"bun";if(globalInstalls.has(secondaryMethod)){if(console.log(),log(`Also updating ${secondaryMethod}-global install...`),!(secondaryMethod==="bun"?await updateViaBun(channel):await updateViaNpm(channel)))error(`Secondary update via ${secondaryMethod} failed (non-blocking)`)}let plugin=await syncPlugin(installType);await runPostUpdateMaintenanceSafe(options,{channel,installType,primaryMethod,globalInstalls:[...globalInstalls].sort(),plugin})}function printPostUpdateMaintenanceIntro(){console.log(),log("Running post-update maintenance..."),console.log(" Purpose: make first launch after update fast and collect upgrade health signals."),console.log(" Checks: runtime partitions, watchdog status, session backfill drift, zombie rows, team config orphans."),console.log(" PG policy: read-only; uses an already-running pgserve when available and will not auto-start it."),console.log(" Legend: [ok]=healthy, [fix]=fixed, [--]=skipped/non-blocking, [!!]=operator action needed.")}async function runMaintenanceWithCapturedLines(maintenanceLines){let{runPostUpdateMaintenance:runPostUpdateMaintenance2}=await Promise.resolve().then(() => (init_doctor(),exports_doctor));await withTemporaryEnv("GENIE_PG_NO_AUTOSTART","1",()=>runPostUpdateMaintenance2({log:(line)=>{maintenanceLines.push(line),console.log(line)}}))}function printDiagnosticsSummary(diagnostics){if(log("Post-update diagnostics captured."),console.log(` Report: ${diagnostics.path}`),console.log(" Include this file when opening a GitHub issue; it contains install metadata, step output,"),console.log(" local process state, and recent scheduler/TUI log signals."),diagnostics.signals.length===0)return;console.log(" Recent scheduler signals:");for(let signal of diagnostics.signals.slice(0,3)){let errorDetail=signal.lastError?` \u2014 ${signal.lastError}`:"";console.log(` ${signal.level}:${signal.event} \xD7${signal.count}${errorDetail}`)}}async function capturePostUpdateDiagnostics(diagnosticsCtx,maintenance){if(!diagnosticsCtx)return;try{let diagnostics=await collectUpdateDiagnostics(diagnosticsCtx,maintenance);printDiagnosticsSummary(diagnostics)}catch(err){let msg=err instanceof Error?err.message:String(err);log(`Post-update diagnostics capture failed (non-fatal): ${msg}`)}}async function runPostUpdateMaintenanceSafe(options={},diagnosticsCtx){if(options.skipMaintenance||isTruthyEnv(process.env.GENIE_UPDATE_SKIP_MAINTENANCE)){log("Skipping post-update maintenance (requested).");return}let startedAt=Date.now(),maintenanceLines=[],outcome="completed",maintenanceError;try{printPostUpdateMaintenanceIntro(),await runMaintenanceWithCapturedLines(maintenanceLines),success(`Post-update maintenance complete (${formatDuration2(Date.now()-startedAt)}).`)}catch(err){outcome="failed",maintenanceError=err instanceof Error?err.message:String(err),error(`Post-update maintenance skipped: ${maintenanceError}`)}await capturePostUpdateDiagnostics(diagnosticsCtx,{outcome,durationMs:Date.now()-startedAt,lines:maintenanceLines,error:maintenanceError})}init_version();init_hooks();async function readStdin(){let chunks=[];for await(let chunk of Bun.stdin.stream())chunks.push(Buffer.from(chunk));return Buffer.concat(chunks).toString("utf-8")}async function dispatchAction(){process.env.GENIE_SKIP_DB_BOOT="1";let stdin=await readStdin();if(!stdin.trim())process.exit(0);let result2=await dispatch(stdin);if(result2)process.stdout.write(result2)}function registerHookNamespace(program2){program2.command("hook").description("Hook middleware for Claude Code integration").command("dispatch").description("Dispatch a CC hook event (reads JSON from stdin, writes decision to stdout)").action(dispatchAction)}init_audit();init_db();init_interactivity();init_otel_receiver();init_target_resolver();init_tmux();init_orchestrator();async function resolveOrcTarget(target){let resolved=await resolveTarget(target);return{paneId:resolved.paneId,session:resolved.session||target,label:formatResolvedLabel(resolved,target)}}async function sendTextChoice(paneId,text){await executeTmux2(`send-keys -t '${paneId}' End`),await sleep2(100),await executeTmux2(`send-keys -t '${paneId}' Enter`),await sleep2(100),await executeTmux2(`send-keys -t '${paneId}' ${shellEscape(text)}`),await sleep2(100),await executeTmux2(`send-keys -t '${paneId}' Enter`)}function findCurrentOption(output){let lines=stripAnsi(output).split(`
3858
+ `),{path:path3,signals:signals2}}async function runCommand(command,args,cwd){return new Promise((resolve4)=>{let output=[],child=spawn3(command,args,{cwd,stdio:["inherit","pipe","pipe"],env:{...process.env,FORCE_COLOR:"1"}});child.stdout?.on("data",(data)=>{let str2=data.toString();output.push(str2),process.stdout.write(str2)}),child.stderr?.on("data",(data)=>{let str2=data.toString();output.push(str2),process.stderr.write(str2)}),child.on("close",(code)=>{resolve4({success:code===0,output:output.join("")})}),child.on("error",(err)=>{error(err.message),resolve4({success:!1,output:err.message})})})}async function getGitInfo(cwd){try{let branchResult=await runCommandSilent("git",["rev-parse","--abbrev-ref","HEAD"],cwd),commitResult=await runCommandSilent("git",["rev-parse","--short","HEAD"],cwd),dateResult=await runCommandSilent("git",["log","-1","--format=%ci"],cwd);if(branchResult.success&&commitResult.success&&dateResult.success)return{branch:branchResult.output.trim(),commit:commitResult.output.trim(),commitDate:dateResult.output.trim().split(" ")[0]}}catch{}return null}async function runCommandSilent(command,args,cwd,timeoutMs=4000){return new Promise((resolve4)=>{let output=[],settled=!1,child=spawn3(command,args,{cwd,stdio:["inherit","pipe","pipe"]}),timer2=setTimeout(()=>{if(settled)return;settled=!0,child.kill("SIGTERM"),resolve4({success:!1,output:`Timed out after ${timeoutMs}ms`})},timeoutMs);child.stdout?.on("data",(data)=>{output.push(data.toString())}),child.stderr?.on("data",(data)=>{output.push(data.toString())}),child.on("close",(code)=>{if(settled)return;settled=!0,clearTimeout(timer2),resolve4({success:code===0,output:output.join("")})}),child.on("error",(err)=>{if(settled)return;settled=!0,clearTimeout(timer2),resolve4({success:!1,output:err.message})})})}function detectFromBinaryPath(path3){let resolved=path3;try{resolved=__require("fs").realpathSync(path3)}catch{}if(resolved.includes(".bun"))return"bun";if(resolved.includes("node_modules"))return"npm";if(path3===join31(LOCAL_BIN2,"genie")||resolved.startsWith(GENIE_BIN))return"source";return null}async function detectInstallationType(){let whichResult=await runCommandSilent("which",["genie"]);if(whichResult.success){let detected=detectFromBinaryPath(whichResult.output.trim());if(detected)return detected}if(genieConfigExists())try{let config=await loadGenieConfig();if(config.installMethod)return config.installMethod}catch{}if(existsSync25(join31(GENIE_SRC,".git")))return"source";return(await runCommandSilent("which",["bun"])).success?"bun":"npm"}async function updateViaBun(channel){try{__require("fs").unlinkSync(join31(homedir26(),".bun","install","global","bun.lock"))}catch{}if(log(`Updating via bun (channel: ${channel})...`),!(await runCommand("bun",["add","-g",`@automagik/genie@${channel}`])).success)return error("Failed to update via bun"),!1;return console.log(),success(`Genie CLI updated via bun (${channel})!`),!0}async function updateViaNpm(channel){if(log(`Updating via npm (channel: ${channel})...`),!(await runCommand("npm",["install","-g",`@automagik/genie@${channel}`])).success)return error("Failed to update via npm"),!1;return console.log(),success(`Genie CLI updated via npm (${channel})!`),!0}async function detectGlobalInstalls(){let found=new Set,[npmResult,bunResult]=await Promise.all([runCommandSilent("npm",["list","-g","@automagik/genie"]),runCommandSilent("bun",["pm","ls","-g"])]);if(npmResult.success&&!npmResult.output.includes("(empty)"))found.add("npm");if(bunResult.success&&bunResult.output.includes("@automagik/genie"))found.add("bun");return found}async function updateSource(){if(!existsSync25(GENIE_SRC))error(`Source install path not found: ${GENIE_SRC}`),console.error(" Detection picked the source-install path, but the directory does not exist."),console.error(" This usually means a stale install hint (config or ~/.genie/src/.git) is"),console.error(" pointing somewhere genuine. Either:"),console.error(` 1. Re-clone the source: git clone https://github.com/automagik-dev/genie ${GENIE_SRC}`),console.error(" 2. Update via package manager instead: genie update --next --via bun"),console.error(" 3. Inspect detection: genie doctor --update-detection"),process.exit(1);if(!existsSync25(join31(GENIE_SRC,".git")))error(`Source install path is not a git checkout: ${GENIE_SRC}`),console.error(` ${GENIE_SRC} exists but has no .git/. Cannot run \`git fetch\` from it.`),console.error(` Either delete ${GENIE_SRC} and re-clone, or update via package manager:`),console.error(" genie update --next --via bun"),process.exit(1);let beforeInfo=await getGitInfo(GENIE_SRC);if(beforeInfo)console.log(`Current: \x1B[2m${beforeInfo.branch}@${beforeInfo.commit} (${beforeInfo.commitDate})\x1B[0m`),console.log();if(log("Fetching latest changes..."),!(await runCommand("git",["fetch","origin"],GENIE_SRC)).success)error("Failed to fetch from origin"),process.exit(1);if(log("Resetting to origin/main..."),!(await runCommand("git",["reset","--hard","origin/main"],GENIE_SRC)).success)error("Failed to reset to origin/main"),process.exit(1);console.log();let afterInfo=await getGitInfo(GENIE_SRC);if(beforeInfo&&afterInfo&&beforeInfo.commit===afterInfo.commit){success("Already up to date!"),console.log();return}if(log("Installing dependencies..."),!(await runCommand("bun",["install"],GENIE_SRC)).success)error("Failed to install dependencies"),process.exit(1);if(console.log(),log("Building..."),!(await runCommand("bun",["run","build"],GENIE_SRC)).success)error("Failed to build"),process.exit(1);console.log(),log("Installing binaries...");try{await mkdir5(GENIE_BIN,{recursive:!0}),await mkdir5(LOCAL_BIN2,{recursive:!0});let binaries=["genie.js","term.js"],names=["genie","term"];for(let i2=0;i2<binaries.length;i2++){let src=join31(GENIE_SRC,"dist",binaries[i2]),binDest=join31(GENIE_BIN,binaries[i2]),linkDest=join31(LOCAL_BIN2,names[i2]);await copyFile(src,binDest),await chmod(binDest,493),await symlinkOrCopy(binDest,linkDest)}for(let legacy of["claudio.js","claudio"]){let legacyBin=join31(GENIE_BIN,legacy),legacyLink=join31(LOCAL_BIN2,legacy);try{await unlink2(legacyBin)}catch{}try{await unlink2(legacyLink)}catch{}}success("Binaries installed")}catch(err){error(`Failed to install binaries: ${err}`),process.exit(1)}if(console.log(),console.log("\x1B[2m\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m"),success("Genie CLI updated successfully!"),console.log(),afterInfo)console.log(`Version: \x1B[36m${afterInfo.branch}@${afterInfo.commit}\x1B[0m (${afterInfo.commitDate})`),console.log()}async function symlinkOrCopy(src,dest){let{symlink:symlink2,unlink:unlink3}=await import("fs/promises");try{if(existsSync25(dest))await unlink3(dest);await symlink2(src,dest)}catch{await copyFile(src,dest)}}function copyDirSync(src,dest){mkdirSync13(dest,{recursive:!0});for(let entry2 of readdirSync8(src,{withFileTypes:!0})){let srcPath=join31(src,entry2.name),destPath=join31(dest,entry2.name);if(entry2.isDirectory())copyDirSync(srcPath,destPath);else copyFileSync3(srcPath,destPath)}}async function resolveGlobalPkgDir(installType){if(installType==="bun"){let bunPath=join31(homedir26(),".bun","install","global","node_modules","@automagik","genie");if(existsSync25(bunPath))return bunPath}if(installType==="npm"){let npmRootResult=await runCommandSilent("npm",["root","-g"]);if(npmRootResult.success){let npmPath=join31(npmRootResult.output.trim(),"@automagik","genie");if(existsSync25(npmPath))return npmPath}}let bunFallback=join31(homedir26(),".bun","install","global","node_modules","@automagik","genie");if(existsSync25(bunFallback))return bunFallback;let npmRootFallback=await runCommandSilent("npm",["root","-g"]);if(npmRootFallback.success){let npmPath=join31(npmRootFallback.output.trim(),"@automagik","genie");if(existsSync25(npmPath))return npmPath}return null}function updatePluginRegistry(claudePlugins,cacheDir,version){let registryPath=join31(claudePlugins,"installed_plugins.json");try{if(!existsSync25(registryPath))return;let registry=JSON.parse(readFileSync17(registryPath,"utf-8")),entries=registry.plugins?.["genie@automagik"];if(!Array.isArray(entries))return;for(let entry2 of entries)if(entry2.scope==="user")entry2.installPath=cacheDir,entry2.version=version,entry2.lastUpdated=new Date().toISOString();writeFileSync11(registryPath,JSON.stringify(registry,null,2))}catch(err){log(`Registry update failed (non-fatal): ${err}`)}}function syncTmuxConf(tmuxScriptsSrc){mkdirSync13(GENIE_HOME2,{recursive:!0});let tmuxConfSrc=join31(tmuxScriptsSrc,"genie.tmux.conf"),tmuxConfDest=join31(GENIE_HOME2,"tmux.conf");if(existsSync25(tmuxConfSrc))try{copyFileSync3(tmuxConfSrc,tmuxConfDest),success(`Installed tmux config to ${tmuxConfDest}`);try{let{tmuxBin:tmuxBin2}=(init_ensure_tmux(),__toCommonJS(exports_ensure_tmux));execSync4(`${tmuxBin2()} -L genie source-file '${tmuxConfDest}'`,{stdio:"ignore"}),success("Reloaded genie tmux server configuration")}catch{}}catch{}let tuiConfSrc=join31(tmuxScriptsSrc,"tui-tmux.conf"),tuiConfDest=join31(GENIE_HOME2,"tui-tmux.conf");if(existsSync25(tuiConfSrc))try{copyFileSync3(tuiConfSrc,tuiConfDest),success(`Installed TUI tmux config to ${tuiConfDest}`)}catch{}let themeSrc=join31(tmuxScriptsSrc,".generated.theme.conf"),themeDest=join31(GENIE_HOME2,".generated.theme.conf");if(existsSync25(themeSrc))try{copyFileSync3(themeSrc,themeDest),success(`Installed tmux theme to ${themeDest}`)}catch{}let osc52Src=join31(tmuxScriptsSrc,"osc52-copy.sh"),osc52Dest=join31(GENIE_HOME2,"scripts","osc52-copy.sh");if(existsSync25(osc52Src))try{copyFileSync3(osc52Src,osc52Dest),chmodSync2(osc52Dest,493),success(`Installed OSC 52 clipboard helper to ${osc52Dest}`)}catch{}}function syncTmuxScripts(globalPkgDir){let tmuxScriptsSrc=join31(globalPkgDir,"scripts","tmux");if(!existsSync25(tmuxScriptsSrc))return;let scriptsDir=join31(GENIE_HOME2,"scripts");mkdirSync13(scriptsDir,{recursive:!0});let scriptCount=0;for(let entry2 of readdirSync8(tmuxScriptsSrc))if(entry2.endsWith(".sh")||entry2==="genie.tmux.conf"||entry2==="tui-tmux.conf"||entry2===".generated.theme.conf"){let src=join31(tmuxScriptsSrc,entry2),dest=join31(scriptsDir,entry2);copyFileSync3(src,dest);try{chmodSync2(dest,entry2.endsWith(".sh")?493:420)}catch{}scriptCount++}if(scriptCount>0)success(`Refreshed ${scriptCount} tmux scripts at ${scriptsDir}`);syncTmuxConf(tmuxScriptsSrc)}function syncMarketplaceVersion(claudePlugins,version){let marketplacePath=join31(claudePlugins,"marketplaces","automagik",".claude-plugin","marketplace.json");try{if(!existsSync25(marketplacePath))return;let data=JSON.parse(readFileSync17(marketplacePath,"utf-8"));if(Array.isArray(data.plugins)){for(let plugin of data.plugins)if(plugin.name==="genie")plugin.version=version}writeFileSync11(marketplacePath,JSON.stringify(data,null,2)),success(`Updated marketplace.json to v${version}`)}catch(err){log(`Marketplace version update failed (non-fatal): ${err}`)}}function syncPluginPackageVersion(claudePlugins,version){let pkgPath=join31(claudePlugins,"marketplaces","automagik","plugins","genie","package.json");try{if(!existsSync25(pkgPath))return;let data=JSON.parse(readFileSync17(pkgPath,"utf-8"));data.version=version,writeFileSync11(pkgPath,JSON.stringify(data,null,2)),success(`Updated plugin package.json to v${version}`)}catch(err){log(`Plugin package.json update failed (non-fatal): ${err}`)}}function syncSkillsSymlink(claudePlugins,version){let skillsLink=join31(claudePlugins,"marketplaces","automagik","plugins","genie","skills"),cacheSkills=join31("..","..","..","..","cache","automagik","genie",version,"skills");try{let{symlinkSync,unlinkSync:unlinkSync9,lstatSync:lstatSync2}=__require("fs");try{lstatSync2(skillsLink),unlinkSync9(skillsLink)}catch{}symlinkSync(cacheSkills,skillsLink),success(`Skills symlink \u2192 cache/${version}/skills`)}catch(err){log(`Skills symlink update failed (non-fatal): ${err}`)}}async function syncPlugin(installType){log("Syncing Claude Code plugin...");let globalPkgDir=await resolveGlobalPkgDir(installType);if(!globalPkgDir)return log("Could not find installed package \u2014 skipping plugin sync"),{skippedReason:"installed package not found"};let pluginSrc=join31(globalPkgDir,"plugins","genie");if(!existsSync25(pluginSrc))return log("Plugin source not found in package \u2014 skipping plugin sync"),{globalPkgDir,skippedReason:"plugin source not found in package"};let version;try{version=JSON.parse(readFileSync17(join31(globalPkgDir,"package.json"),"utf-8")).version}catch{return log("Could not read package version \u2014 skipping plugin sync"),{globalPkgDir,skippedReason:"could not read package version"}}let claudePlugins=join31(homedir26(),".claude","plugins"),cacheDir=join31(claudePlugins,"cache","automagik","genie",version);try{if(existsSync25(cacheDir))rmSync3(cacheDir,{recursive:!0,force:!0});copyDirSync(pluginSrc,cacheDir);let skillsSrc=join31(globalPkgDir,"skills");if(existsSync25(skillsSrc)&&!existsSync25(join31(cacheDir,"skills")))copyDirSync(skillsSrc,join31(cacheDir,"skills"))}catch(err){return error(`Failed to copy plugin: ${err}`),{version,globalPkgDir,cacheDir,skippedReason:`failed to copy plugin: ${err}`}}return updatePluginRegistry(claudePlugins,cacheDir,version),syncMarketplaceVersion(claudePlugins,version),syncPluginPackageVersion(claudePlugins,version),syncSkillsSymlink(claudePlugins,version),syncTmuxScripts(globalPkgDir),success(`Plugin synced to v${version}`),{version,globalPkgDir,cacheDir}}async function resolveChannel(options){if(options.next)return"next";if(options.stable)return"latest";if(genieConfigExists())try{let config=await loadGenieConfig();if(config.updateChannel)return config.updateChannel}catch{}return"latest"}async function persistChannel(channel){try{let config=await loadGenieConfig();config.updateChannel=channel,await saveGenieConfig(config)}catch{}}async function updateCommand(options={}){console.log(),console.log("\x1B[1m\uD83E\uDDDE Genie CLI Update\x1B[0m"),console.log("\x1B[2m\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m"),console.log();let channel=await resolveChannel(options);if(options.next||options.stable)await persistChannel(channel);let installType=await detectInstallationType();if(log(`Detected installation: ${installType}`),log(`Channel: ${channel}${channel==="next"?" (dev builds)":" (stable)"}`),console.log(),installType==="unknown")error("No Genie CLI installation found"),console.log(),console.log("Install method not configured. Please reinstall genie:"),console.log("\x1B[36m curl -fsSL https://raw.githubusercontent.com/automagik-dev/genie/main/install.sh | bash\x1B[0m"),console.log(),process.exit(1);if(installType==="source"){await updateSource();return}let globalInstalls=await detectGlobalInstalls(),primaryMethod=installType;if(!(primaryMethod==="bun"?await updateViaBun(channel):await updateViaNpm(channel)))process.exit(1);let secondaryMethod=primaryMethod==="bun"?"npm":"bun";if(globalInstalls.has(secondaryMethod)){if(console.log(),log(`Also updating ${secondaryMethod}-global install...`),!(secondaryMethod==="bun"?await updateViaBun(channel):await updateViaNpm(channel)))error(`Secondary update via ${secondaryMethod} failed (non-blocking)`)}let plugin=await syncPlugin(installType);await runPostUpdateMaintenanceSafe(options,{channel,installType,primaryMethod,globalInstalls:[...globalInstalls].sort(),plugin})}function printPostUpdateMaintenanceIntro(){console.log(),log("Running post-update maintenance..."),console.log(" Purpose: make first launch after update fast and collect upgrade health signals."),console.log(" Checks: runtime partitions, watchdog status, session backfill drift, zombie rows, team config orphans."),console.log(" PG policy: read-only; uses an already-running pgserve when available and will not auto-start it."),console.log(" Legend: [ok]=healthy, [fix]=fixed, [--]=skipped/non-blocking, [!!]=operator action needed.")}async function runMaintenanceWithCapturedLines(maintenanceLines){let{runPostUpdateMaintenance:runPostUpdateMaintenance2}=await Promise.resolve().then(() => (init_doctor(),exports_doctor));await withTemporaryEnv("GENIE_PG_NO_AUTOSTART","1",()=>runPostUpdateMaintenance2({log:(line)=>{maintenanceLines.push(line),console.log(line)}}))}function printDiagnosticsSummary(diagnostics){if(log("Post-update diagnostics captured."),console.log(` Report: ${diagnostics.path}`),console.log(" Include this file when opening a GitHub issue; it contains install metadata, step output,"),console.log(" local process state, and recent scheduler/TUI log signals."),diagnostics.signals.length===0)return;console.log(" Recent scheduler signals:");for(let signal of diagnostics.signals.slice(0,3)){let errorDetail=signal.lastError?` \u2014 ${signal.lastError}`:"";console.log(` ${signal.level}:${signal.event} \xD7${signal.count}${errorDetail}`)}}async function capturePostUpdateDiagnostics(diagnosticsCtx,maintenance){if(!diagnosticsCtx)return;try{let diagnostics=await collectUpdateDiagnostics(diagnosticsCtx,maintenance);printDiagnosticsSummary(diagnostics)}catch(err){let msg=err instanceof Error?err.message:String(err);log(`Post-update diagnostics capture failed (non-fatal): ${msg}`)}}async function runPostUpdateMaintenanceSafe(options={},diagnosticsCtx){if(options.skipMaintenance||isTruthyEnv(process.env.GENIE_UPDATE_SKIP_MAINTENANCE)){log("Skipping post-update maintenance (requested).");return}let startedAt=Date.now(),maintenanceLines=[],outcome="completed",maintenanceError;try{printPostUpdateMaintenanceIntro(),await runMaintenanceWithCapturedLines(maintenanceLines),success(`Post-update maintenance complete (${formatDuration2(Date.now()-startedAt)}).`)}catch(err){outcome="failed",maintenanceError=err instanceof Error?err.message:String(err),error(`Post-update maintenance skipped: ${maintenanceError}`)}await capturePostUpdateDiagnostics(diagnosticsCtx,{outcome,durationMs:Date.now()-startedAt,lines:maintenanceLines,error:maintenanceError})}init_version();init_hooks();async function readStdin(){let chunks=[];for await(let chunk of Bun.stdin.stream())chunks.push(Buffer.from(chunk));return Buffer.concat(chunks).toString("utf-8")}async function dispatchAction(){process.env.GENIE_SKIP_DB_BOOT="1";let stdin=await readStdin();if(!stdin.trim())process.exit(0);let result2=await dispatch(stdin);if(result2)process.stdout.write(result2)}function registerHookNamespace(program2){program2.command("hook").description("Hook middleware for Claude Code integration").command("dispatch").description("Dispatch a CC hook event (reads JSON from stdin, writes decision to stdout)").action(dispatchAction)}init_audit();init_db();init_interactivity();init_otel_receiver();init_target_resolver();init_tmux();init_orchestrator();async function resolveOrcTarget(target){let resolved=await resolveTarget(target);return{paneId:resolved.paneId,session:resolved.session||target,label:formatResolvedLabel(resolved,target)}}async function sendTextChoice(paneId,text){await executeTmux2(`send-keys -t '${paneId}' End`),await sleep2(100),await executeTmux2(`send-keys -t '${paneId}' Enter`),await sleep2(100),await executeTmux2(`send-keys -t '${paneId}' ${shellEscape(text)}`),await sleep2(100),await executeTmux2(`send-keys -t '${paneId}' Enter`)}function findCurrentOption(output){let lines=stripAnsi(output).split(`
3859
3859
  `);for(let line of lines){let match=line.match(/^\s*\u276F\s*(\d+)\./);if(match)return Number.parseInt(match[1],10)}return 1}async function navigateToOption(paneId,targetOption,currentOption){let diff=targetOption-currentOption,key=diff>0?"Down":"Up";for(let i2=0;i2<Math.abs(diff);i2++)await executeTmux2(`send-keys -t '${paneId}' ${key}`),await sleep2(50);await sleep2(100),await executeTmux2(`send-keys -t '${paneId}' Enter`)}async function answerQuestion(target,choice){try{let{paneId,label}=await resolveOrcTarget(target),output=await capturePaneContent(paneId,50),state=detectState(output);if(state.type!=="question"){console.log(`No question pending (state: ${state.type})`);return}if(choice.startsWith("text:")){let text=choice.slice(5);await sendTextChoice(paneId,text),console.log(`Sent feedback: "${text.substring(0,50)}${text.length>50?"...":""}"`)}else if(/^\d+$/.test(choice)){let targetOption=Number.parseInt(choice,10);await navigateToOption(paneId,targetOption,findCurrentOption(output)),console.log(`Selected option ${targetOption} for ${label}`)}else await executeTmux2(`send-keys -t '${paneId}' '${choice}'`),console.log(`Sent '${choice}' to ${label}`)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}function shellEscape(str2){return`"${str2.replace(/"/g,"\\\"").replace(/\$/g,"\\$")}"`}function sleep2(ms){return new Promise((resolve6)=>setTimeout(resolve6,ms))}function registerAgentAnswer(parent){parent.command("answer <name> <choice>").description('Answer a question for an agent (use "text:..." for text input)').action(async(name,choice)=>{try{await answerQuestion(name,choice)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}})}var _brief;async function getBrief(){if(!_brief)_brief=await Promise.resolve().then(() => (init_brief(),exports_brief));return _brief}async function handleBrief(options){let team=options.team??process.env.GENIE_TEAM;if(!team)console.error("Error: --team is required (or set GENIE_TEAM)"),process.exit(1);let agent=options.agent??process.env.GENIE_AGENT_NAME,briefService=await getBrief(),brief=await briefService.generateBrief({team,agent,since:options.since,repoPath:process.cwd()});console.log(briefService.formatBrief(brief))}function registerAgentBrief(parent){parent.command("brief").description("Show startup brief \u2014 aggregated context since last session").option("--team <name>","Team name (default: GENIE_TEAM)").option("--agent <name>","Agent name (default: GENIE_AGENT_NAME)").option("--since <iso>","Start timestamp (default: last executor end)").action(async(options)=>{try{await handleBrief(options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}})}init_agent_directory();init_agent_sync();init_builtin_agents();init_genie_config2();async function showEntry(name,json2){let resolved=await resolve5(name);if(!resolved)console.error(`Agent "${name}" not found in directory or built-ins.`),process.exit(1);if(json2){console.log(JSON.stringify({...resolved.entry,builtin:resolved.builtin},null,2));return}if(resolved.builtin)console.log(`
3860
3860
  (built-in agent)`);if(console.log(""),console.log(` Name: ${resolved.entry.name}`),console.log(` Dir: ${contractPath(resolved.entry.dir)}`),resolved.entry.repo)console.log(` Repo: ${contractPath(resolved.entry.repo)}`);if(console.log(` Prompt mode: ${resolved.entry.promptMode}`),resolved.entry.model)console.log(` Model: ${resolved.entry.model}`);if(resolved.entry.roles?.length)console.log(` Roles: ${resolved.entry.roles.join(", ")}`);console.log(` Registered: ${resolved.entry.registeredAt}`),console.log("")}function printRegisteredAgentsTable(entries){let termW=process.stdout.columns||120,repoValues=entries.map((e)=>e.repo?contractPath(e.repo):contractPath(e.dir)),maxRepoLen=Math.max(4,...repoValues.map((v)=>v.length)),fixedW=42,repoW=Math.min(maxRepoLen+2,Math.max(30,termW-42-20));console.log(""),console.log("REGISTERED AGENTS"),console.log("-".repeat(Math.max(90,42+repoW+20))),console.log(` ${"NAME".padEnd(22)}${"SCOPE".padEnd(10)}${"REPO".padEnd(repoW)}${"MODEL".padEnd(8)}ROLES`);for(let i2=0;i2<entries.length;i2++){let entry2=entries[i2],repo=repoValues[i2],roles=entry2.roles?.join(", ")||"-";console.log(` ${entry2.name.padEnd(22)}${entry2.scope.padEnd(10)}${repo.padEnd(repoW)}${(entry2.model||"-").padEnd(8)}${roles}`)}console.log("")}function printBuiltinAgentsTable(){console.log("BUILT-IN AGENTS"),console.log("-".repeat(80)),console.log(` ${"NAME".padEnd(22)}${"TYPE".padEnd(10)}${"MODEL".padEnd(8)}DESCRIPTION`);for(let agent of ALL_BUILTINS)console.log(` ${agent.name.padEnd(22)}${agent.category.padEnd(10)}${(agent.model||"-").padEnd(8)}${agent.description}`);console.log("")}async function listEntries(json2,includeBuiltins,_includeArchived){let entries=await ls();if(json2){let result2=entries.map((e)=>({...e,builtin:!1}));if(includeBuiltins)for(let b2 of ALL_BUILTINS)result2.push({name:b2.name,description:b2.description,model:b2.model,category:b2.category,scope:"built-in",builtin:!0});console.log(JSON.stringify(result2,null,2));return}if(entries.length===0&&!includeBuiltins){console.log(`
3861
3861
  No agents registered. Add one with: genie agent register <name> --dir <path>`),console.log(`Use --builtins to also see built-in roles and council members.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/genie",
3
- "version": "4.260429.23",
3
+ "version": "4.260429.24",
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.23",
3
+ "version": "4.260429.24",
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.23",
3
+ "version": "4.260429.24",
4
4
  "private": true,
5
5
  "description": "Runtime dependencies for genie bundled CLIs",
6
6
  "type": "module",