@automagik/genie 4.260421.31 → 4.260421.32
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
|
@@ -403,7 +403,7 @@ ${bin} set-option -w pane-active-border-style "fg=$COLOR"
|
|
|
403
403
|
UPDATE teams SET status = ${status}
|
|
404
404
|
WHERE name = ${teamName}
|
|
405
405
|
`).count===0)throw Error(`Team "${teamName}" not found.`)}var init_team_manager=__esm(()=>{init_agent_registry();init_audit();init_builtin_agents();init_claude_native_teams();init_db();init_executor_registry();init_genie_config2();init_tmux()});var exports_claude_native_teams={};__export(exports_claude_native_teams,{writeNativeInbox:()=>writeNativeInbox,unregisterNativeMember:()=>unregisterNativeMember,sanitizeTeamName:()=>sanitizeTeamName,resolveOrMintLeadSessionId:()=>resolveOrMintLeadSessionId,resolveNativeMemberName:()=>resolveNativeMemberName,registerNativeMember:()=>registerNativeMember,registerAsTeamLead:()=>registerAsTeamLead,loadNativeTeamConfig:()=>loadNativeTeamConfig,loadConfig:()=>loadConfig,loadAllNativeTeamConfigs:()=>loadAllNativeTeamConfigs,listTeamsWithUnreadInbox:()=>listTeamsWithUnreadInbox,listTeams:()=>listTeams2,isInsideClaudeCode:()=>isInsideClaudeCode,findTeamsContainingAgent:()=>findTeamsContainingAgent,ensureNativeTeamWithSessionId:()=>ensureNativeTeamWithSessionId,ensureNativeTeam:()=>ensureNativeTeam,discoverTeamName:()=>discoverTeamName,discoverClaudeParentSessionId:()=>discoverClaudeParentSessionId,deleteNativeTeam:()=>deleteNativeTeam,clearNativeInbox:()=>clearNativeInbox,assignColor:()=>assignColor});import{randomUUID as randomUUID3}from"crypto";import{existsSync as existsSync11}from"fs";import{mkdir as mkdir3,open,readFile as readFile3,readdir,rm as rm2,stat,writeFile as writeFile3}from"fs/promises";import{homedir as homedir8}from"os";import{join as join13}from"path";function claudeConfigDir2(){return process.env.CLAUDE_CONFIG_DIR??join13(homedir8(),".claude")}function teamsBaseDir(){return join13(claudeConfigDir2(),"teams")}function sanitizeTeamName(name){return name.replace(/[^a-zA-Z0-9]/g,"-").toLowerCase()}async function listTeams2(){try{return(await readdir(teamsBaseDir())).filter((e)=>!e.startsWith("."))}catch{return[]}}function teamDir(teamName){return join13(teamsBaseDir(),sanitizeTeamName(teamName))}function configPath(teamName){return join13(teamDir(teamName),"config.json")}function inboxesDir(teamName){return join13(teamDir(teamName),"inboxes")}function inboxPath(teamName,agentName){return join13(inboxesDir(teamName),`${sanitizeTeamName(agentName)}.json`)}async function loadConfig(teamName){try{let content=await readFile3(configPath(teamName),"utf-8");return JSON.parse(content)}catch(err){if(err instanceof Error&&"code"in err&&err.code==="ENOENT")return null;let message=err instanceof Error?err.message:String(err);return console.warn(`[claude-native-teams] Failed to load config for "${teamName}": ${message}`),null}}async function loadNativeTeamConfig(teamName){return loadConfig(teamName)}async function loadAllNativeTeamConfigs(){let teamNames=await listTeams2(),configs=[];for(let name of teamNames){let cfg=await loadConfig(name);if(cfg)configs.push(cfg)}return configs}async function findTeamsContainingAgent(agentName){let teams=await listTeams2(),matches=[];for(let teamName of teams){let config=await loadConfig(teamName);if(!config)continue;if(config.members.some((m)=>m.name===agentName||m.agentType===agentName))matches.push(teamName)}return matches}async function saveConfig(teamName,config){await writeFile3(configPath(teamName),JSON.stringify(config,null,2))}async function countLeadSessionRefs(){let counts=new Map,teams=await listTeams2();for(let team of teams){let leadSessionId=(await loadConfig(team))?.leadSessionId;if(!leadSessionId)continue;counts.set(leadSessionId,(counts.get(leadSessionId)??0)+1)}return counts}async function ensureNativeTeam(teamName,description,leadSessionId,leaderName){let dir=teamDir(teamName),inboxDir=inboxesDir(teamName);await mkdir3(dir,{recursive:!0}),await mkdir3(inboxDir,{recursive:!0}),ensureTeammateBypassPermissions();let existing=await loadConfig(teamName);if(existing)return await backfillTeamRow(sanitizeTeamName(teamName),existing),existing;let sanitized=sanitizeTeamName(teamName),resolvedLeader=sanitizeTeamName(leaderName??teamName),config={name:sanitized,description,createdAt:Date.now(),leadAgentId:`${resolvedLeader}@${sanitized}`,leadSessionId,members:[]};return await saveConfig(teamName,config),await backfillTeamRow(sanitized,config),config}async function backfillTeamRow(name,nativeConfig){try{let{ensureTeamRow:ensureTeamRow2}=await Promise.resolve().then(() => (init_team_manager(),exports_team_manager));await ensureTeamRow2(name,{nativeConfig})}catch{}}function isHealthyLeadSessionId(id){if(typeof id!=="string"||id.length===0)return!1;return/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id)}async function ensureNativeTeamWithSessionId(teamName,description,sessionId,leaderName){let config=await ensureNativeTeam(teamName,description,sessionId,leaderName);if(config.leadSessionId===sessionId)return config;if(isHealthyLeadSessionId(config.leadSessionId))return config;return config.leadSessionId=sessionId,await saveConfig(teamName,config),config}async function resolveOrMintLeadSessionId(teamName,cwd){let priorId=await findNewestSessionIdForTeam(teamName,cwd);if(priorId)return{sessionId:priorId,shouldResume:!0};return{sessionId:randomUUID3(),shouldResume:!1}}async function findNewestSessionIdForTeam(teamName,cwd){let projectDir=join13(claudeConfigDir2(),"projects",sanitizePath(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 needle=sanitizeTeamName(teamName),best=null;for(let name of jsonls){let full=join13(projectDir,name);if(!await jsonlMatchesTitle(full,needle))continue;try{let s=await stat(full);if(!best||s.mtimeMs>best.mtime)best={name,mtime:s.mtimeMs}}catch{}}if(!best)return null;return best.name.replace(".jsonl","")}async function jsonlMatchesTitle(filePath,needle){let handle=null;try{handle=await open(filePath,"r");let buffer=Buffer.alloc(8192),{bytesRead}=await handle.read(buffer,0,buffer.length,0),head=buffer.toString("utf-8",0,bytesRead);for(let line of head.split(`
|
|
406
|
-
`).slice(0,10)){let trimmed=line.trim();if(!trimmed||!trimmed.includes("custom-title"))continue;try{let entry=JSON.parse(trimmed);if(entry.type!=="custom-title"||typeof entry.customTitle!=="string")continue;if(entry.customTitle.toLowerCase()===needle)return!0}catch{}}}catch{return!1}finally{await handle?.close().catch(()=>{})}return!1}async function registerNativeMember(teamName,member){let config=await loadConfig(teamName);if(!config)throw Error(`Native team "${teamName}" not found`);let sanitized=sanitizeTeamName(teamName),agentId=`${sanitizeTeamName(member.agentName)}@${sanitized}`;config.members=config.members.filter((m)=>m.agentId!==agentId),config.members.push({agentId,name:sanitizeTeamName(member.agentName),agentType:member.agentType??"general-purpose",joinedAt:Date.now(),tmuxPaneId:member.tmuxPaneId,cwd:member.cwd??process.cwd(),backendType:"tmux",color:member.color,planModeRequired:member.planModeRequired??!1,isActive:!0}),await saveConfig(teamName,config);let inbox=inboxPath(teamName,member.agentName);if(!existsSync11(inbox))await writeFile3(inbox,"[]")}async function unregisterNativeMember(teamName,agentName){let config=await loadConfig(teamName);if(!config)return;let sanitized=sanitizeTeamName(teamName),agentId=`${sanitizeTeamName(agentName)}@${sanitized}`,before=config.members.length;if(config.members=config.members.filter((m)=>m.agentId!==agentId),config.members.length===before)return;await saveConfig(teamName,config)}async function writeNativeInbox(teamName,agentName,message){let path2=inboxPath(teamName,agentName);await mkdir3(inboxesDir(teamName),{recursive:!0}),await acquireLock(path2);try{let messages=[];try{let content=await readFile3(path2,"utf-8");messages=JSON.parse(content)}catch{}messages.push(message),await writeFile3(path2,JSON.stringify(messages,null,2))}finally{await releaseLock(path2)}}async function resolveNativeMemberName(teamName,genieWorkerId){let config=await loadConfig(teamName);if(!config||config.members.length===0)return null;let sanitizedId=sanitizeTeamName(genieWorkerId),sanitizedTeam=sanitizeTeamName(teamName),exactMatch=config.members.find((m)=>m.name===sanitizedId&&m.isActive);if(exactMatch)return exactMatch.name;let agentIdMatch=config.members.find((m)=>m.agentId===`${sanitizedId}@${sanitizedTeam}`&&m.isActive);if(agentIdMatch)return agentIdMatch.name;let teamPrefix=`${sanitizedTeam}-`;if(sanitizedId.startsWith(teamPrefix)){let stripped=sanitizedId.slice(teamPrefix.length),prefixMatch=config.members.find((m)=>m.name===stripped&&m.isActive);if(prefixMatch)return prefixMatch.name}let inactiveMatch=config.members.find((m)=>m.name===sanitizedId);if(inactiveMatch)return inactiveMatch.name;return null}async function assignColor(teamName){let config=await loadConfig(teamName);if(!config)return CLAUDE_TEAM_COLORS[0];let usedColors=new Set(config.members.map((m)=>m.color));for(let color of CLAUDE_TEAM_COLORS)if(!usedColors.has(color))return color;return CLAUDE_TEAM_COLORS[config.members.length%CLAUDE_TEAM_COLORS.length]}async function clearNativeInbox(teamName,agentName){let path2=inboxPath(teamName,agentName);await acquireLock(path2);try{await writeFile3(path2,"[]")}finally{await releaseLock(path2)}}async function deleteNativeTeam(teamName){let dir=teamDir(teamName);if(!existsSync11(dir))return!1;return await rm2(dir,{recursive:!0,force:!0}),!0}function extractLeaderInboxName(config,teamName){if(!config?.leadAgentId)return teamName??"unknown";let atIdx=config.leadAgentId.indexOf("@");return atIdx>0?config.leadAgentId.slice(0,atIdx):teamName??"unknown"}async function scanTeamInbox(base,name){let config=null;try{let cfgContent=await readFile3(join13(base,name,"config.json"),"utf-8");config=JSON.parse(cfgContent)}catch{}let leaderInboxName=extractLeaderInboxName(config,name),inboxFile=join13(base,name,"inboxes",`${leaderInboxName}.json`),messages;try{let content=await readFile3(inboxFile,"utf-8");messages=JSON.parse(content)}catch{return null}if(!Array.isArray(messages))return null;let unread=messages.filter((m)=>m.read===!1);if(unread.length===0)return null;let workingDir=
|
|
406
|
+
`).slice(0,10)){let trimmed=line.trim();if(!trimmed||!trimmed.includes("custom-title"))continue;try{let entry=JSON.parse(trimmed);if(entry.type!=="custom-title"||typeof entry.customTitle!=="string")continue;if(entry.customTitle.toLowerCase()===needle)return!0}catch{}}}catch{return!1}finally{await handle?.close().catch(()=>{})}return!1}async function registerNativeMember(teamName,member){let config=await loadConfig(teamName);if(!config)throw Error(`Native team "${teamName}" not found`);let sanitized=sanitizeTeamName(teamName),agentId=`${sanitizeTeamName(member.agentName)}@${sanitized}`;config.members=config.members.filter((m)=>m.agentId!==agentId),config.members.push({agentId,name:sanitizeTeamName(member.agentName),agentType:member.agentType??"general-purpose",joinedAt:Date.now(),tmuxPaneId:member.tmuxPaneId,cwd:member.cwd??process.cwd(),backendType:"tmux",color:member.color,planModeRequired:member.planModeRequired??!1,isActive:!0}),await saveConfig(teamName,config);let inbox=inboxPath(teamName,member.agentName);if(!existsSync11(inbox))await writeFile3(inbox,"[]")}async function unregisterNativeMember(teamName,agentName){let config=await loadConfig(teamName);if(!config)return;let sanitized=sanitizeTeamName(teamName),agentId=`${sanitizeTeamName(agentName)}@${sanitized}`,before=config.members.length;if(config.members=config.members.filter((m)=>m.agentId!==agentId),config.members.length===before)return;await saveConfig(teamName,config)}async function writeNativeInbox(teamName,agentName,message){let path2=inboxPath(teamName,agentName);await mkdir3(inboxesDir(teamName),{recursive:!0}),await acquireLock(path2);try{let messages=[];try{let content=await readFile3(path2,"utf-8");messages=JSON.parse(content)}catch{}messages.push(message),await writeFile3(path2,JSON.stringify(messages,null,2))}finally{await releaseLock(path2)}}async function resolveNativeMemberName(teamName,genieWorkerId){let config=await loadConfig(teamName);if(!config||config.members.length===0)return null;let sanitizedId=sanitizeTeamName(genieWorkerId),sanitizedTeam=sanitizeTeamName(teamName),exactMatch=config.members.find((m)=>m.name===sanitizedId&&m.isActive);if(exactMatch)return exactMatch.name;let agentIdMatch=config.members.find((m)=>m.agentId===`${sanitizedId}@${sanitizedTeam}`&&m.isActive);if(agentIdMatch)return agentIdMatch.name;let teamPrefix=`${sanitizedTeam}-`;if(sanitizedId.startsWith(teamPrefix)){let stripped=sanitizedId.slice(teamPrefix.length),prefixMatch=config.members.find((m)=>m.name===stripped&&m.isActive);if(prefixMatch)return prefixMatch.name}let inactiveMatch=config.members.find((m)=>m.name===sanitizedId);if(inactiveMatch)return inactiveMatch.name;return null}async function assignColor(teamName){let config=await loadConfig(teamName);if(!config)return CLAUDE_TEAM_COLORS[0];let usedColors=new Set(config.members.map((m)=>m.color));for(let color of CLAUDE_TEAM_COLORS)if(!usedColors.has(color))return color;return CLAUDE_TEAM_COLORS[config.members.length%CLAUDE_TEAM_COLORS.length]}async function clearNativeInbox(teamName,agentName){let path2=inboxPath(teamName,agentName);await acquireLock(path2);try{await writeFile3(path2,"[]")}finally{await releaseLock(path2)}}async function deleteNativeTeam(teamName){let dir=teamDir(teamName);if(!existsSync11(dir))return!1;return await rm2(dir,{recursive:!0,force:!0}),!0}function extractLeaderInboxName(config,teamName){if(!config?.leadAgentId)return teamName??"unknown";let atIdx=config.leadAgentId.indexOf("@");return atIdx>0?config.leadAgentId.slice(0,atIdx):teamName??"unknown"}function resolveLeadWorkingDir(config,leaderInboxName){let leadMember=config.members.find((m)=>m.agentId===config.leadAgentId||m.name===leaderInboxName);if(leadMember?.cwd)return leadMember.cwd;if(config.worktreePath)return config.worktreePath;if(config.repo)return config.repo;return config.members.find((m)=>m.cwd)?.cwd??null}async function scanTeamInbox(base,name){let config=null;try{let cfgContent=await readFile3(join13(base,name,"config.json"),"utf-8");config=JSON.parse(cfgContent)}catch{}let leaderInboxName=extractLeaderInboxName(config,name),inboxFile=join13(base,name,"inboxes",`${leaderInboxName}.json`),messages;try{let content=await readFile3(inboxFile,"utf-8");messages=JSON.parse(content)}catch{return null}if(!Array.isArray(messages))return null;let unread=messages.filter((m)=>m.read===!1);if(unread.length===0)return null;let workingDir=config?resolveLeadWorkingDir(config,leaderInboxName):null;return{teamName:name,unreadCount:unread.length,workingDir,firstUnreadText:unread[0]?.text??null}}async function listTeamsWithUnreadInbox(){let base=teamsBaseDir(),teamDirs;try{teamDirs=await readdir(base)}catch{return[]}let results=[];for(let name of teamDirs){let entry=await scanTeamInbox(base,name);if(entry)results.push(entry)}return results}function sanitizePath(p){return p.replace(/[^a-zA-Z0-9]/g,"-")}async function discoverClaudeSessionId(cwd){let envSessionId=process.env.CLAUDE_CODE_SESSION_ID;if(envSessionId)return envSessionId;let projectDir=join13(claudeConfigDir2(),"projects",sanitizePath(cwd??process.cwd()));try{let jsonls=(await readdir(projectDir)).filter((e)=>e.endsWith(".jsonl"));if(jsonls.length===0)return null;let newest=null;for(let name of jsonls){let s=await stat(join13(projectDir,name));if(!newest||s.mtimeMs>newest.mtime)newest={name,mtime:s.mtimeMs}}if(!newest)return null;return newest.name.replace(".jsonl","")}catch{return null}}async function readSessionMetadata(filePath){let handle=null;try{handle=await open(filePath,"r");let buffer=Buffer.alloc(8192),{bytesRead}=await handle.read(buffer,0,buffer.length,0),head=buffer.toString("utf-8",0,bytesRead);for(let line of head.split(`
|
|
407
407
|
`).slice(0,20)){let trimmed=line.trim();if(!trimmed)continue;try{let entry=JSON.parse(trimmed),teamName=typeof entry.teamName==="string"?entry.teamName:void 0,agentName=typeof entry.agentName==="string"?entry.agentName:void 0;if(teamName||agentName)return{teamName,agentName}}catch{}}}catch{return{}}finally{await handle?.close().catch(()=>{})}return{}}function rootScore(metadata){if(!metadata.teamName&&!metadata.agentName)return 2;if(metadata.teamName&&!metadata.agentName)return 1;return 0}function compareSessionRanking(a,b,leadRefs){let aLeadRefs=leadRefs.get(a.name.replace(".jsonl",""))??0,bLeadRefs=leadRefs.get(b.name.replace(".jsonl",""))??0;if(aLeadRefs!==bLeadRefs)return bLeadRefs-aLeadRefs;let aRoot=rootScore(a.metadata),bRoot=rootScore(b.metadata);if(aRoot!==bRoot)return bRoot-aRoot;return b.mtime-a.mtime}async function discoverClaudeParentSessionId(cwd){let envSessionId=process.env.CLAUDE_CODE_SESSION_ID;if(envSessionId)return envSessionId;let projectDir=join13(claudeConfigDir2(),"projects",sanitizePath(cwd??process.cwd()));try{let jsonls=(await readdir(projectDir)).filter((e)=>e.endsWith(".jsonl"));if(jsonls.length===0)return null;let ranked=await Promise.all(jsonls.map(async(name)=>{let filePath=join13(projectDir,name),s=await stat(filePath),metadata=await readSessionMetadata(filePath);return{name,mtime:s.mtimeMs,metadata}})),leadRefs=await countLeadSessionRefs();return ranked.sort((a,b)=>compareSessionRanking(a,b,leadRefs)),ranked[0]?.name.replace(".jsonl","")??null}catch{return null}}function isInsideClaudeCode(){return process.env.CLAUDECODE==="1"}async function discoverTeamName(cwd){let envTeam=process.env.GENIE_TEAM;if(envTeam)return envTeam;let base=teamsBaseDir(),sessionId=await discoverClaudeSessionId(cwd);if(sessionId)try{let teams=await readdir(base);for(let name of teams){let cfgPath=join13(base,name,"config.json");try{let content=await readFile3(cfgPath,"utf-8"),config=JSON.parse(content);if(config.leadSessionId===sessionId)return config.name}catch{}}}catch{}let tmuxSessionName=await currentTmuxSessionName();if(tmuxSessionName){let cfgPath=join13(base,tmuxSessionName,"config.json");try{let content=await readFile3(cfgPath,"utf-8");return JSON.parse(content).name}catch{}}return null}async function currentTmuxSessionName(){if(!process.env.TMUX)return null;try{let{getCurrentSessionName:getCurrentSessionName2}=await Promise.resolve().then(() => (init_tmux(),exports_tmux));return await getCurrentSessionName2()}catch{return null}}async function registerAsTeamLead(teamName,opts){let sessionId=await discoverClaudeSessionId(opts?.cwd);if(!sessionId)throw Error("Could not discover Claude Code session ID. Are you running inside Claude Code with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1?");let resolvedLeaderName=opts?.leaderName??teamName,config=await ensureNativeTeam(teamName,`Genie team: ${teamName}`,sessionId,resolvedLeaderName);if(config.leadSessionId!==sessionId)config.leadSessionId=sessionId,await saveConfig(teamName,config);let sanitized=sanitizeTeamName(teamName),leadAgentId=`${sanitizeTeamName(resolvedLeaderName)}@${sanitized}`,existingLead=config.members.find((m)=>m.agentId===leadAgentId),resolvedPaneId=opts?.tmuxPaneId??process.env.TMUX_PANE;if(!existingLead||!existingLead.isActive)await registerNativeMember(teamName,{agentName:resolvedLeaderName,agentType:"general-purpose",color:opts?.color??"blue",tmuxPaneId:resolvedPaneId,cwd:opts?.cwd??process.cwd()});else if(resolvedPaneId&&existingLead.tmuxPaneId!==resolvedPaneId)existingLead.tmuxPaneId=resolvedPaneId,await saveConfig(teamName,config);let inbox=inboxPath(teamName,resolvedLeaderName);if(!existsSync11(inbox))await writeFile3(inbox,"[]");let finalConfig=await loadConfig(teamName);if(!finalConfig)throw Error(`Failed to load config for team "${teamName}" after creation`);return{sessionId,config:finalConfig}}var init_claude_native_teams=__esm(()=>{init_claude_settings();init_lockfile();init_provider_adapters()});import{existsSync as existsSync12}from"fs";import{readFile as readFile4,readdir as readdir2,rename}from"fs/promises";import{homedir as homedir9}from"os";import{join as join14}from"path";function getGenieHome(){return process.env.GENIE_HOME??join14(homedir9(),".genie")}function workersJsonPath(){return join14(getGenieHome(),"workers.json")}function needsMigration(filePath){return existsSync12(filePath)&&!existsSync12(`${filePath}.migrated`)}async function readJson(filePath){try{let content=await readFile4(filePath,"utf-8");return JSON.parse(content)}catch{return null}}async function renameMatchingFiles(dir,filter){if(!existsSync12(dir))return;try{let files=await readdir2(dir);for(let f of files){if(!filter(f))continue;let fp=join14(dir,f);if(needsMigration(fp))await rename(fp,`${fp}.migrated`)}}catch{}}function needsSeed(){if(needsMigration(workersJsonPath()))return!0;let claudeTeamsDir=join14(process.env.CLAUDE_CONFIG_DIR??join14(homedir9(),".claude"),"teams");if(!existsSync12(claudeTeamsDir))return!1;try{return __require("fs").readdirSync(claudeTeamsDir).some((e)=>!e.startsWith("."))}catch{return!1}}function toAgentRow(a){let now=new Date().toISOString();return{id:a.id,pane_id:a.paneId??"",session:a.session??"",worktree:a.worktree??null,task_id:a.taskId??null,task_title:a.taskTitle??null,wish_slug:a.wishSlug??null,group_number:a.groupNumber??null,started_at:a.startedAt??now,state:a.state??"spawning",last_state_change:a.lastStateChange??now,repo_path:a.repoPath??"",claude_session_id:a.claudeSessionId??null,window_name:a.windowName??null,window_id:a.windowId??null,role:a.role??null,custom_name:a.customName??null,sub_panes:a.subPanes??[],provider:a.provider??null,transport:a.transport??"tmux",skill:a.skill??null,team:a.team??null,tmux_window:a.window??null,native_agent_id:a.nativeAgentId??null,native_color:a.nativeColor??null,native_team_enabled:a.nativeTeamEnabled??!1,parent_session_id:a.parentSessionId??null,suspended_at:a.suspendedAt??null,auto_resume:a.autoResume??!0,resume_attempts:a.resumeAttempts??0,last_resume_attempt:a.lastResumeAttempt??null,max_resume_attempts:a.maxResumeAttempts??3,pane_color:null}}async function upsertAgent(sql,a){let r=toAgentRow(a);await sql`
|
|
408
408
|
INSERT INTO agents (
|
|
409
409
|
id, pane_id, session, worktree, task_id, task_title,
|
|
@@ -789,7 +789,7 @@ Next steps:`),console.log(" 1. Reload tmux: tmux source ~/.tmux.conf"),console.
|
|
|
789
789
|
`,[...values2,limit])).map(rowToRuntimeEvent)}async function getLatestRuntimeEventId(){let rows=await(await getConnection())`
|
|
790
790
|
SELECT COALESCE(MAX(id), 0) AS max_id FROM genie_runtime_events
|
|
791
791
|
`;return Number(rows[0]?.max_id??0)}async function followRuntimeEvents(query,onEvent,options){let sql=await getConnection(),active=!0,lastSeenId=query.afterId??await getLatestRuntimeEventId(),drainChain=Promise.resolve(),drain=async()=>{if(!active)return;let events=await listRuntimeEvents({...query,afterId:lastSeenId});for(let event of events)lastSeenId=event.id,onEvent(event)},queueDrain=(context)=>{drainChain=drainChain.then(drain).catch((error2)=>{logFollowDrainError(context,error2,active)})},listener=await sql.listen("genie_runtime_event",()=>{queueDrain("notify")});await drain();let pollIntervalMs=options?.pollIntervalMs??1000,pollTimer=setInterval(()=>{queueDrain("poll")},pollIntervalMs);return{mode:"pg",stop:async()=>{active=!1,clearInterval(pollTimer);try{await drainChain}catch{}try{await listener.unlisten()}catch{}}}}async function waitForRuntimeEvent(query,timeoutMs,predicate){let afterId=query.afterId??0;return new Promise((resolve5,reject)=>{let settled=!1,handle=null,timer2=null,finish=async(event)=>{if(settled)return;if(settled=!0,timer2)clearTimeout(timer2);try{if(handle)await handle.stop()}catch{}resolve5(event)};(async()=>{try{if(handle=await followRuntimeEvents({...query,afterId},(event)=>{if(predicate&&!predicate(event))return;finish(event)},{pollIntervalMs:250}),settled){try{await handle.stop()}catch{}return}timer2=setTimeout(()=>{finish(null)},timeoutMs)}catch(err){if(!settled)settled=!0,reject(err)}})()})}var circuitBreaker;var init_runtime_events=__esm(()=>{init_db();circuitBreaker=new EventCircuitBreaker});var exports_interactivity={};__export(exports_interactivity,{isInteractive:()=>isInteractive,installWorkspaceCheck:()=>installWorkspaceCheck,ensureWorkspace:()=>ensureWorkspace,commandRequiresWorkspace:()=>commandRequiresWorkspace});function isInteractive(){if(!process.stdout.isTTY)return!1;if(process.env.CI)return!1;if(process.argv.includes("--no-interactive"))return!1;return!0}function getRootCommandName(cmd){let current=cmd;while(current.parent?.parent)current=current.parent;return current.name()}function commandRequiresWorkspace(cmd){return!WORKSPACE_EXEMPT.has(getRootCommandName(cmd))}async function ensureWorkspace(){if(findWorkspace())return;if(!isInteractive())console.error("No workspace found. Run `genie init` to set up."),process.exit(2);let{confirm}=await Promise.resolve().then(() => (init_esm14(),exports_esm));if(!await confirm({message:"No workspace found. Initialize? [Y/n]",default:!0}))console.error("No workspace found. Run `genie init` to set up."),process.exit(2);let{mkdirSync:mkdirSync11,writeFileSync:writeFileSync10}=await import("fs"),{basename:basename5,join:join29}=await import("path"),cwd=process.cwd(),genieDir=join29(cwd,".genie");mkdirSync11(genieDir,{recursive:!0});let config={name:basename5(cwd),agents:{defaults:{}},tmux:{socket:"genie"},sdk:{}};writeFileSync10(join29(genieDir,"workspace.json"),`${JSON.stringify(config,null,2)}
|
|
792
|
-
`),console.log(`Workspace initialized: ${cwd}`)}function installWorkspaceCheck(program2){program2.hook("preAction",async(_thisCommand,actionCommand)=>{if(!commandRequiresWorkspace(actionCommand))return;await ensureWorkspace()})}var WORKSPACE_EXEMPT;var init_interactivity=__esm(()=>{init_workspace();WORKSPACE_EXEMPT=new Set(["init","setup","doctor","update","uninstall","shortcuts","team","version","help"])});function extractValue(kv){let v=kv.value;if(v.stringValue!==void 0)return v.stringValue;if(v.intValue!==void 0)return typeof v.intValue==="string"?Number.parseInt(v.intValue,10):v.intValue;if(v.doubleValue!==void 0)return v.doubleValue;if(v.boolValue!==void 0)return v.boolValue;return}function attrsToObject(attrs){if(!attrs)return{};let obj={};for(let kv of attrs)obj[kv.key]=extractValue(kv);return obj}function extractResourceContext(resource){let attrs=attrsToObject(resource?.attributes);return{agentName:attrs["agent.name"],teamName:attrs["team.name"],wishSlug:attrs["wish.slug"],sessionId:attrs["session.id"],agentRole:attrs["agent.role"]}}function mapEventToEntityType(eventName){if(eventName.includes("tool_result"))return"otel_tool";if(eventName.includes("api_request")||eventName.includes("api_error"))return"otel_api";if(eventName.includes("user_prompt"))return"otel_prompt";if(eventName.includes("tool_decision"))return"otel_decision";return"otel_event"}function resolveEntityId(ctx){return ctx.sessionId??(ctx.agentName?`agent:${ctx.agentName}`:"unknown")}function mergeContext(details,ctx){if(ctx.teamName)details.team=ctx.teamName;if(ctx.wishSlug)details.wish_slug=ctx.wishSlug;if(ctx.agentRole)details.agent_role=ctx.agentRole;if(ctx.sessionId)details.session_id=ctx.sessionId}function logRecordToRow(record,ctx){let logAttrs=attrsToObject(record.attributes),eventName=logAttrs["event.name"]??record.body?.stringValue??"unknown",details={...logAttrs,event_name:eventName};if(mergeContext(details,ctx),record.severityText)details.severity=record.severityText;if(record.body?.kvlistValue?.values)Object.assign(details,attrsToObject(record.body.kvlistValue.values));return{entity_type:mapEventToEntityType(eventName),entity_id:resolveEntityId(ctx),event_type:eventName,actor:ctx.agentName??null,details}}function processLogs(payload){let rows=[];for(let resourceLog of payload.resourceLogs??[]){let ctx=extractResourceContext(resourceLog.resource);for(let scopeLog of resourceLog.scopeLogs??[])for(let record of scopeLog.logRecords??[])rows.push(logRecordToRow(record,ctx))}return rows}function buildMetricRow(metricName,entityId,actor,details){return{entity_type:"otel_metric",entity_id:entityId,event_type:metricName,actor,details}}function processSumGaugePoints(dataPoints,metricName,unit,entityId,ctx){return dataPoints.map((dp)=>{let dpAttrs=attrsToObject(dp.attributes),value=dp.asDouble??(dp.asInt!==void 0?Number(dp.asInt):void 0),details={metric_name:metricName,value,...dpAttrs};if(unit)details.unit=unit;return mergeContext(details,ctx),buildMetricRow(metricName,entityId,ctx.agentName??null,details)})}function metricToRows(metric,ctx){let metricName=metric.name??"unknown_metric",entityId=resolveEntityId(ctx),dataPoints=metric.sum?.dataPoints??metric.gauge?.dataPoints??[],rows=processSumGaugePoints(dataPoints,metricName,metric.unit,entityId,ctx);for(let dp of metric.histogram?.dataPoints??[]){let dpAttrs=attrsToObject(dp.attributes),details={metric_name:metricName,sum:dp.sum,count:dp.count!==void 0?Number(dp.count):void 0,...dpAttrs};if(metric.unit)details.unit=metric.unit;mergeContext(details,ctx),rows.push(buildMetricRow(metricName,entityId,ctx.agentName??null,details))}return rows}function processMetrics(payload){let rows=[];for(let resourceMetric of payload.resourceMetrics??[]){let ctx=extractResourceContext(resourceMetric.resource);for(let scopeMetric of resourceMetric.scopeMetrics??[])for(let metric of scopeMetric.metrics??[])rows.push(...metricToRows(metric,ctx))}return rows}async function flushToPg(rows){if(rows.length===0)return;try{let{getConnection:getConnection2,isAvailable:isAvailable2}=await Promise.resolve().then(() => (init_db(),exports_db));if(!await isAvailable2())return;let sql=await getConnection2();await sql`
|
|
792
|
+
`),console.log(`Workspace initialized: ${cwd}`)}function installWorkspaceCheck(program2){program2.hook("preAction",async(_thisCommand,actionCommand)=>{if(!commandRequiresWorkspace(actionCommand))return;await ensureWorkspace()})}var WORKSPACE_EXEMPT;var init_interactivity=__esm(()=>{init_workspace();WORKSPACE_EXEMPT=new Set(["init","setup","doctor","update","uninstall","shortcuts","team","version","help","hook"])});function extractValue(kv){let v=kv.value;if(v.stringValue!==void 0)return v.stringValue;if(v.intValue!==void 0)return typeof v.intValue==="string"?Number.parseInt(v.intValue,10):v.intValue;if(v.doubleValue!==void 0)return v.doubleValue;if(v.boolValue!==void 0)return v.boolValue;return}function attrsToObject(attrs){if(!attrs)return{};let obj={};for(let kv of attrs)obj[kv.key]=extractValue(kv);return obj}function extractResourceContext(resource){let attrs=attrsToObject(resource?.attributes);return{agentName:attrs["agent.name"],teamName:attrs["team.name"],wishSlug:attrs["wish.slug"],sessionId:attrs["session.id"],agentRole:attrs["agent.role"]}}function mapEventToEntityType(eventName){if(eventName.includes("tool_result"))return"otel_tool";if(eventName.includes("api_request")||eventName.includes("api_error"))return"otel_api";if(eventName.includes("user_prompt"))return"otel_prompt";if(eventName.includes("tool_decision"))return"otel_decision";return"otel_event"}function resolveEntityId(ctx){return ctx.sessionId??(ctx.agentName?`agent:${ctx.agentName}`:"unknown")}function mergeContext(details,ctx){if(ctx.teamName)details.team=ctx.teamName;if(ctx.wishSlug)details.wish_slug=ctx.wishSlug;if(ctx.agentRole)details.agent_role=ctx.agentRole;if(ctx.sessionId)details.session_id=ctx.sessionId}function logRecordToRow(record,ctx){let logAttrs=attrsToObject(record.attributes),eventName=logAttrs["event.name"]??record.body?.stringValue??"unknown",details={...logAttrs,event_name:eventName};if(mergeContext(details,ctx),record.severityText)details.severity=record.severityText;if(record.body?.kvlistValue?.values)Object.assign(details,attrsToObject(record.body.kvlistValue.values));return{entity_type:mapEventToEntityType(eventName),entity_id:resolveEntityId(ctx),event_type:eventName,actor:ctx.agentName??null,details}}function processLogs(payload){let rows=[];for(let resourceLog of payload.resourceLogs??[]){let ctx=extractResourceContext(resourceLog.resource);for(let scopeLog of resourceLog.scopeLogs??[])for(let record of scopeLog.logRecords??[])rows.push(logRecordToRow(record,ctx))}return rows}function buildMetricRow(metricName,entityId,actor,details){return{entity_type:"otel_metric",entity_id:entityId,event_type:metricName,actor,details}}function processSumGaugePoints(dataPoints,metricName,unit,entityId,ctx){return dataPoints.map((dp)=>{let dpAttrs=attrsToObject(dp.attributes),value=dp.asDouble??(dp.asInt!==void 0?Number(dp.asInt):void 0),details={metric_name:metricName,value,...dpAttrs};if(unit)details.unit=unit;return mergeContext(details,ctx),buildMetricRow(metricName,entityId,ctx.agentName??null,details)})}function metricToRows(metric,ctx){let metricName=metric.name??"unknown_metric",entityId=resolveEntityId(ctx),dataPoints=metric.sum?.dataPoints??metric.gauge?.dataPoints??[],rows=processSumGaugePoints(dataPoints,metricName,metric.unit,entityId,ctx);for(let dp of metric.histogram?.dataPoints??[]){let dpAttrs=attrsToObject(dp.attributes),details={metric_name:metricName,sum:dp.sum,count:dp.count!==void 0?Number(dp.count):void 0,...dpAttrs};if(metric.unit)details.unit=metric.unit;mergeContext(details,ctx),rows.push(buildMetricRow(metricName,entityId,ctx.agentName??null,details))}return rows}function processMetrics(payload){let rows=[];for(let resourceMetric of payload.resourceMetrics??[]){let ctx=extractResourceContext(resourceMetric.resource);for(let scopeMetric of resourceMetric.scopeMetrics??[])for(let metric of scopeMetric.metrics??[])rows.push(...metricToRows(metric,ctx))}return rows}async function flushToPg(rows){if(rows.length===0)return;try{let{getConnection:getConnection2,isAvailable:isAvailable2}=await Promise.resolve().then(() => (init_db(),exports_db));if(!await isAvailable2())return;let sql=await getConnection2();await sql`
|
|
793
793
|
INSERT INTO audit_events (entity_type, entity_id, event_type, actor, details)
|
|
794
794
|
SELECT * FROM unnest(
|
|
795
795
|
${sql.array(rows.map((r)=>r.entity_type))}::text[],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genie",
|
|
3
|
-
"version": "4.260421.
|
|
3
|
+
"version": "4.260421.32",
|
|
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"
|