@automagik/genie 4.260418.5 → 4.260418.7

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
@@ -392,7 +392,17 @@ ${bin} set-option -w pane-active-border-style "fg=$COLOR"
392
392
  UPDATE agents
393
393
  SET state = 'error', last_state_change = now()
394
394
  WHERE id = ${row.id} AND state = 'spawning'
395
- `,console.error(`[reconcile] Reset stuck agent ${row.id} (dead pane ${row.pane_id}) from spawning \u2192 error`),recordAuditEvent("worker",row.id,"state_changed","reconciler",{state:"error",reason:"stale_spawn_dead_pane"}).catch(()=>{}),resetIds.push(row.id)}catch{}return resetIds}catch{return[]}}async function filterBySession(sessionName){return(await(await getConnection())`SELECT * FROM agents WHERE session = ${sessionName}`).map(rowToAgent)}async function update(id,updates){let sql=await getConnection(),s={};if(updates.paneId!==void 0)s.pane_id=updates.paneId;if(updates.session!==void 0)s.session=updates.session;if(updates.worktree!==void 0)s.worktree=updates.worktree;if(updates.taskId!==void 0)s.task_id=updates.taskId;if(updates.taskTitle!==void 0)s.task_title=updates.taskTitle;if(updates.wishSlug!==void 0)s.wish_slug=updates.wishSlug;if(updates.groupNumber!==void 0)s.group_number=updates.groupNumber;if(updates.startedAt!==void 0)s.started_at=updates.startedAt;if(updates.state!==void 0)s.state=updates.state,s.last_state_change=new Date().toISOString(),recordAuditEvent("worker",id,"state_changed",process.env.GENIE_AGENT_NAME??"cli",{state:updates.state}).catch(()=>{});if(updates.lastStateChange!==void 0)s.last_state_change=updates.lastStateChange;if(updates.repoPath!==void 0)s.repo_path=updates.repoPath;if(updates.claudeSessionId!==void 0)s.claude_session_id=updates.claudeSessionId;if(updates.windowName!==void 0)s.window_name=updates.windowName;if(updates.windowId!==void 0)s.window_id=updates.windowId;if(updates.role!==void 0)s.role=updates.role;if(updates.customName!==void 0)s.custom_name=updates.customName;if(updates.subPanes!==void 0)s.sub_panes=sql.json(updates.subPanes);if(updates.provider!==void 0)s.provider=updates.provider;if(updates.transport!==void 0)s.transport=updates.transport;if(updates.skill!==void 0)s.skill=updates.skill;if(updates.team!==void 0)s.team=updates.team;if(updates.window!==void 0)s.tmux_window=updates.window;if(updates.nativeAgentId!==void 0)s.native_agent_id=updates.nativeAgentId;if(updates.nativeColor!==void 0)s.native_color=updates.nativeColor;if(updates.nativeTeamEnabled!==void 0)s.native_team_enabled=updates.nativeTeamEnabled;if(updates.parentSessionId!==void 0)s.parent_session_id=updates.parentSessionId;if(updates.suspendedAt!==void 0)s.suspended_at=updates.suspendedAt;if(updates.autoResume!==void 0)s.auto_resume=updates.autoResume;if(updates.resumeAttempts!==void 0)s.resume_attempts=updates.resumeAttempts;if(updates.lastResumeAttempt!==void 0)s.last_resume_attempt=updates.lastResumeAttempt;if(updates.maxResumeAttempts!==void 0)s.max_resume_attempts=updates.maxResumeAttempts;if(updates.paneColor!==void 0)s.pane_color=updates.paneColor;if(Object.keys(s).length===0)return;await sql`UPDATE agents SET ${sql(s)} WHERE id = ${id}`}async function findByPane(paneId){let sql=await getConnection(),n=paneId.startsWith("%")?paneId:`%${paneId}`,rows=await sql`SELECT * FROM agents WHERE pane_id = ${n}`;return rows.length>0?rowToAgent(rows[0]):null}async function findByWindow(windowId){let sql=await getConnection(),n=windowId.startsWith("@")?windowId:`@${windowId}`,rows=await sql`SELECT * FROM agents WHERE window_id = ${n}`;return rows.length>0?rowToAgent(rows[0]):null}async function findByTask(taskId){let rows=await(await getConnection())`SELECT * FROM agents WHERE task_id = ${taskId} LIMIT 1`;return rows.length>0?rowToAgent(rows[0]):null}function getElapsedTime(agent){let ms=Date.now()-new Date(agent.startedAt).getTime(),m=Math.floor(ms/60000),h=Math.floor(m/60),formatted;if(h>0)formatted=`${h}h ${m%60}m`;else if(m>0)formatted=`${m}m`;else formatted="<1m";return{ms,formatted}}async function addSubPane(workerId,paneId,_registryPath){let agent=await get(workerId);if(!agent)return;let subPanes=[...agent.subPanes??[],paneId],sql=await getConnection();await sql`UPDATE agents SET sub_panes = ${sql.json(subPanes)} WHERE id = ${workerId}`}async function getPane(workerId,index,_registryPath){let agent=await get(workerId);if(!agent)return null;if(index===0)return agent.paneId;let si=index-1;if(!agent.subPanes||si>=agent.subPanes.length||si<0)return null;return agent.subPanes[si]}async function removeSubPane(workerId,paneId,_registryPath){let agent=await get(workerId);if(!agent?.subPanes)return;let filtered=agent.subPanes.filter((p)=>p!==paneId),sql=await getConnection();await sql`UPDATE agents SET sub_panes = ${sql.json(filtered)} WHERE id = ${workerId}`}async function resolveDynamicLeaderName(teamName){try{let{resolveLeaderName}=await Promise.resolve().then(() => (init_team_manager(),exports_team_manager)),name=await resolveLeaderName(teamName);return name!==teamName?name:null}catch{return null}}async function getTeamLeadEntry(teamName,session,repoPath){let sql=await getConnection();if(session)return findTeamLeadBySession(sql,teamName,session,repoPath);let legacyId=buildLegacyTeamLeadEntryId(teamName),lr=await sql`SELECT * FROM agents WHERE id = ${legacyId}`;if(lr.length>0)return rowToAgent(lr[0]);let leaderName=await resolveDynamicLeaderName(teamName),sr=leaderName?await sql`SELECT * FROM agents WHERE (role = 'team-lead' OR role = ${leaderName}) AND team = ${teamName} ORDER BY started_at DESC LIMIT 1`:await sql`SELECT * FROM agents WHERE role = 'team-lead' AND team = ${teamName} ORDER BY started_at DESC LIMIT 1`;return sr.length>0?rowToAgent(sr[0]):null}async function findLeadById(sql,id,repoPath,matchSession){let rows=await sql`SELECT * FROM agents WHERE id = ${id}`;if(rows.length===0)return null;let a=rowToAgent(rows[0]);if(matchSession&&a.session!==matchSession)return null;if(repoPath&&a.repoPath!==repoPath)return null;return a}async function scanForTeamLead(sql,teamName,session,repoPath){let leaderName=await resolveDynamicLeaderName(teamName),scanRows=leaderName?await sql`SELECT * FROM agents WHERE (role = 'team-lead' OR role = ${leaderName}) AND team = ${teamName} AND session = ${session} ${repoPath?sql`AND repo_path = ${repoPath}`:sql``} LIMIT 1`:await sql`SELECT * FROM agents WHERE role = 'team-lead' AND team = ${teamName} AND session = ${session} ${repoPath?sql`AND repo_path = ${repoPath}`:sql``} LIMIT 1`;return scanRows.length>0?rowToAgent(scanRows[0]):null}async function findTeamLeadBySession(sql,teamName,session,repoPath){if(repoPath){let byProject=await findLeadById(sql,buildProjectTeamLeadEntryId(teamName,session,repoPath));if(byProject)return byProject}let bySession=await findLeadById(sql,buildSessionTeamLeadEntryId(teamName,session),repoPath);if(bySession)return bySession;let byLegacy=await findLeadById(sql,buildLegacyTeamLeadEntryId(teamName),repoPath,session);if(byLegacy)return byLegacy;return scanForTeamLead(sql,teamName,session,repoPath)}async function saveTemplate(template){let sql=await getConnection();await sql`INSERT INTO agent_templates (id, provider, team, role, skill, cwd, extra_args, native_team_enabled, last_spawned_at) VALUES (${template.id}, ${template.provider}, ${template.team}, ${template.role??null}, ${template.skill??null}, ${template.cwd}, ${sql.json(template.extraArgs??[])}, ${template.nativeTeamEnabled??!1}, ${template.lastSpawnedAt}) ON CONFLICT (id) DO UPDATE SET provider = EXCLUDED.provider, team = EXCLUDED.team, role = EXCLUDED.role, skill = EXCLUDED.skill, cwd = EXCLUDED.cwd, extra_args = EXCLUDED.extra_args, native_team_enabled = EXCLUDED.native_team_enabled, last_spawned_at = EXCLUDED.last_spawned_at`}async function listTemplates(){return(await(await getConnection())`SELECT * FROM agent_templates`).map(rowToTemplate)}function rowToAgentIdentity(r){return{id:r.id,startedAt:ts(r.started_at),role:r.role??void 0,customName:r.custom_name??void 0,team:r.team??void 0,nativeAgentId:r.native_agent_id??void 0,nativeColor:r.native_color??void 0,nativeTeamEnabled:r.native_team_enabled||void 0,parentSessionId:r.parent_session_id??void 0,currentExecutorId:r.current_executor_id??null,reportsTo:r.reports_to??null,title:r.title??null,createdAt:ts(r.created_at),updatedAt:ts(r.updated_at)}}async function findOrCreateAgent(name,team,role){let sql=await getConnection(),existing=await sql`
395
+ `,console.error(`[reconcile] Reset stuck agent ${row.id} (dead pane ${row.pane_id}) from spawning \u2192 error`),recordAuditEvent("worker",row.id,"state_changed","reconciler",{state:"error",reason:"stale_spawn_dead_pane"}).catch(()=>{}),resetIds.push(row.id)}catch{}let activeDeadCandidates=await sql`
396
+ SELECT id, pane_id, state FROM agents
397
+ WHERE state IN ('idle', 'working', 'permission', 'question')
398
+ AND pane_id ~ '^%[0-9]+$'
399
+ AND last_state_change < now() - interval '1 second' * ${thresholdSeconds}
400
+ `;for(let row of activeDeadCandidates)try{if(!await isPaneAlive(row.pane_id)){let prevState=row.state;if((await sql`
401
+ UPDATE agents
402
+ SET state = 'error', last_state_change = now()
403
+ WHERE id = ${row.id} AND state = ${prevState}
404
+ RETURNING id
405
+ `).length>0)console.error(`[reconcile] Reset zombie agent ${row.id} (dead pane ${row.pane_id}) from ${prevState} \u2192 error`),recordAuditEvent("worker",row.id,"state_changed","reconciler",{state:"error",reason:"dead_pane_zombie",previous_state:prevState}).catch(()=>{}),resetIds.push(row.id)}}catch{}return resetIds}catch{return[]}}async function filterBySession(sessionName){return(await(await getConnection())`SELECT * FROM agents WHERE session = ${sessionName}`).map(rowToAgent)}async function update(id,updates){let sql=await getConnection(),s={};if(updates.paneId!==void 0)s.pane_id=updates.paneId;if(updates.session!==void 0)s.session=updates.session;if(updates.worktree!==void 0)s.worktree=updates.worktree;if(updates.taskId!==void 0)s.task_id=updates.taskId;if(updates.taskTitle!==void 0)s.task_title=updates.taskTitle;if(updates.wishSlug!==void 0)s.wish_slug=updates.wishSlug;if(updates.groupNumber!==void 0)s.group_number=updates.groupNumber;if(updates.startedAt!==void 0)s.started_at=updates.startedAt;if(updates.state!==void 0)s.state=updates.state,s.last_state_change=new Date().toISOString(),recordAuditEvent("worker",id,"state_changed",process.env.GENIE_AGENT_NAME??"cli",{state:updates.state}).catch(()=>{});if(updates.lastStateChange!==void 0)s.last_state_change=updates.lastStateChange;if(updates.repoPath!==void 0)s.repo_path=updates.repoPath;if(updates.claudeSessionId!==void 0)s.claude_session_id=updates.claudeSessionId;if(updates.windowName!==void 0)s.window_name=updates.windowName;if(updates.windowId!==void 0)s.window_id=updates.windowId;if(updates.role!==void 0)s.role=updates.role;if(updates.customName!==void 0)s.custom_name=updates.customName;if(updates.subPanes!==void 0)s.sub_panes=sql.json(updates.subPanes);if(updates.provider!==void 0)s.provider=updates.provider;if(updates.transport!==void 0)s.transport=updates.transport;if(updates.skill!==void 0)s.skill=updates.skill;if(updates.team!==void 0)s.team=updates.team;if(updates.window!==void 0)s.tmux_window=updates.window;if(updates.nativeAgentId!==void 0)s.native_agent_id=updates.nativeAgentId;if(updates.nativeColor!==void 0)s.native_color=updates.nativeColor;if(updates.nativeTeamEnabled!==void 0)s.native_team_enabled=updates.nativeTeamEnabled;if(updates.parentSessionId!==void 0)s.parent_session_id=updates.parentSessionId;if(updates.suspendedAt!==void 0)s.suspended_at=updates.suspendedAt;if(updates.autoResume!==void 0)s.auto_resume=updates.autoResume;if(updates.resumeAttempts!==void 0)s.resume_attempts=updates.resumeAttempts;if(updates.lastResumeAttempt!==void 0)s.last_resume_attempt=updates.lastResumeAttempt;if(updates.maxResumeAttempts!==void 0)s.max_resume_attempts=updates.maxResumeAttempts;if(updates.paneColor!==void 0)s.pane_color=updates.paneColor;if(Object.keys(s).length===0)return;await sql`UPDATE agents SET ${sql(s)} WHERE id = ${id}`}async function findByPane(paneId){let sql=await getConnection(),n=paneId.startsWith("%")?paneId:`%${paneId}`,rows=await sql`SELECT * FROM agents WHERE pane_id = ${n}`;return rows.length>0?rowToAgent(rows[0]):null}async function findByWindow(windowId){let sql=await getConnection(),n=windowId.startsWith("@")?windowId:`@${windowId}`,rows=await sql`SELECT * FROM agents WHERE window_id = ${n}`;return rows.length>0?rowToAgent(rows[0]):null}async function findByTask(taskId){let rows=await(await getConnection())`SELECT * FROM agents WHERE task_id = ${taskId} LIMIT 1`;return rows.length>0?rowToAgent(rows[0]):null}function getElapsedTime(agent){let ms=Date.now()-new Date(agent.startedAt).getTime(),m=Math.floor(ms/60000),h=Math.floor(m/60),formatted;if(h>0)formatted=`${h}h ${m%60}m`;else if(m>0)formatted=`${m}m`;else formatted="<1m";return{ms,formatted}}async function addSubPane(workerId,paneId,_registryPath){let agent=await get(workerId);if(!agent)return;let subPanes=[...agent.subPanes??[],paneId],sql=await getConnection();await sql`UPDATE agents SET sub_panes = ${sql.json(subPanes)} WHERE id = ${workerId}`}async function getPane(workerId,index,_registryPath){let agent=await get(workerId);if(!agent)return null;if(index===0)return agent.paneId;let si=index-1;if(!agent.subPanes||si>=agent.subPanes.length||si<0)return null;return agent.subPanes[si]}async function removeSubPane(workerId,paneId,_registryPath){let agent=await get(workerId);if(!agent?.subPanes)return;let filtered=agent.subPanes.filter((p)=>p!==paneId),sql=await getConnection();await sql`UPDATE agents SET sub_panes = ${sql.json(filtered)} WHERE id = ${workerId}`}async function resolveDynamicLeaderName(teamName){try{let{resolveLeaderName}=await Promise.resolve().then(() => (init_team_manager(),exports_team_manager)),name=await resolveLeaderName(teamName);return name!==teamName?name:null}catch{return null}}async function getTeamLeadEntry(teamName,session,repoPath){let sql=await getConnection();if(session)return findTeamLeadBySession(sql,teamName,session,repoPath);let legacyId=buildLegacyTeamLeadEntryId(teamName),lr=await sql`SELECT * FROM agents WHERE id = ${legacyId}`;if(lr.length>0)return rowToAgent(lr[0]);let leaderName=await resolveDynamicLeaderName(teamName),sr=leaderName?await sql`SELECT * FROM agents WHERE (role = 'team-lead' OR role = ${leaderName}) AND team = ${teamName} ORDER BY started_at DESC LIMIT 1`:await sql`SELECT * FROM agents WHERE role = 'team-lead' AND team = ${teamName} ORDER BY started_at DESC LIMIT 1`;return sr.length>0?rowToAgent(sr[0]):null}async function findLeadById(sql,id,repoPath,matchSession){let rows=await sql`SELECT * FROM agents WHERE id = ${id}`;if(rows.length===0)return null;let a=rowToAgent(rows[0]);if(matchSession&&a.session!==matchSession)return null;if(repoPath&&a.repoPath!==repoPath)return null;return a}async function scanForTeamLead(sql,teamName,session,repoPath){let leaderName=await resolveDynamicLeaderName(teamName),scanRows=leaderName?await sql`SELECT * FROM agents WHERE (role = 'team-lead' OR role = ${leaderName}) AND team = ${teamName} AND session = ${session} ${repoPath?sql`AND repo_path = ${repoPath}`:sql``} LIMIT 1`:await sql`SELECT * FROM agents WHERE role = 'team-lead' AND team = ${teamName} AND session = ${session} ${repoPath?sql`AND repo_path = ${repoPath}`:sql``} LIMIT 1`;return scanRows.length>0?rowToAgent(scanRows[0]):null}async function findTeamLeadBySession(sql,teamName,session,repoPath){if(repoPath){let byProject=await findLeadById(sql,buildProjectTeamLeadEntryId(teamName,session,repoPath));if(byProject)return byProject}let bySession=await findLeadById(sql,buildSessionTeamLeadEntryId(teamName,session),repoPath);if(bySession)return bySession;let byLegacy=await findLeadById(sql,buildLegacyTeamLeadEntryId(teamName),repoPath,session);if(byLegacy)return byLegacy;return scanForTeamLead(sql,teamName,session,repoPath)}async function saveTemplate(template){let sql=await getConnection();await sql`INSERT INTO agent_templates (id, provider, team, role, skill, cwd, extra_args, native_team_enabled, last_spawned_at) VALUES (${template.id}, ${template.provider}, ${template.team}, ${template.role??null}, ${template.skill??null}, ${template.cwd}, ${sql.json(template.extraArgs??[])}, ${template.nativeTeamEnabled??!1}, ${template.lastSpawnedAt}) ON CONFLICT (id) DO UPDATE SET provider = EXCLUDED.provider, team = EXCLUDED.team, role = EXCLUDED.role, skill = EXCLUDED.skill, cwd = EXCLUDED.cwd, extra_args = EXCLUDED.extra_args, native_team_enabled = EXCLUDED.native_team_enabled, last_spawned_at = EXCLUDED.last_spawned_at`}async function listTemplates(){return(await(await getConnection())`SELECT * FROM agent_templates`).map(rowToTemplate)}function rowToAgentIdentity(r){return{id:r.id,startedAt:ts(r.started_at),role:r.role??void 0,customName:r.custom_name??void 0,team:r.team??void 0,nativeAgentId:r.native_agent_id??void 0,nativeColor:r.native_color??void 0,nativeTeamEnabled:r.native_team_enabled||void 0,parentSessionId:r.parent_session_id??void 0,currentExecutorId:r.current_executor_id??null,reportsTo:r.reports_to??null,title:r.title??null,createdAt:ts(r.created_at),updatedAt:ts(r.updated_at)}}async function findOrCreateAgent(name,team,role){let sql=await getConnection(),existing=await sql`
396
406
  SELECT id, started_at, role, custom_name, team, native_agent_id, native_color,
397
407
  native_team_enabled, parent_session_id, current_executor_id, reports_to, title, created_at, updated_at
398
408
  FROM agents
@@ -598,12 +608,12 @@ ${body}`;writeFileSync9(filePath,output,"utf-8")}function serializeSdkConfig(sdk
598
608
  INSERT INTO agents (id, role, custom_name, started_at, metadata)
599
609
  VALUES (${`dir:${entry.name}`}, ${entry.name}, ${entry.name}, now(), ${sql.json(metadata)})
600
610
  ON CONFLICT (id) DO UPDATE SET metadata = ${sql.json(metadata)}
601
- `,full}async function rm3(name,_options){let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db));return(await(await getConnection2())`DELETE FROM agents WHERE id = ${`dir:${name}`}`).count>0}async function resolve3(name){let templateTeam=await lookupTemplateTeam(name);try{let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),rows=await(await getConnection2())`
602
- SELECT role, metadata FROM agents
611
+ `,full}async function rm3(name,options){let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),sql=await getConnection2(),dirRemoved=(await sql`DELETE FROM agents WHERE id = ${`dir:${name}`}`).count>0;if(options?.force){let roleDelete=await sql`DELETE FROM agents WHERE role = ${name}`;return{removed:dirRemoved||roleDelete.count>0}}if(dirRemoved)return{removed:!0};let instances=await sql`SELECT id FROM agents WHERE role = ${name}`;if(instances.length===0)return{removed:!1};let idList=instances.map((r)=>r.id).join(", ");return{removed:!1,message:`No directory entry for "${name}". Active instances: ${idList}. Use 'genie kill <id>' to terminate, or re-run with --force to remove all.`}}async function resolve3(name){let templateTeam=await lookupTemplateTeam(name);try{let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),rows=await(await getConnection2())`
612
+ SELECT role, metadata, created_at FROM agents
603
613
  WHERE role = ${name}
604
614
  ORDER BY (CASE WHEN id LIKE 'dir:%' THEN 0 ELSE 1 END), started_at DESC
605
615
  LIMIT 1
606
- `;if(rows.length>0){let meta=parseMetadata(rows[0].metadata),entry=roleToEntry(name,void 0,meta);if(templateTeam)entry.team=templateTeam;return{entry,builtin:!1}}}catch{}let builtinRole=BUILTIN_ROLES.find((r)=>r.name===name);if(builtinRole){let entry=builtinToEntry(builtinRole);if(templateTeam)entry.team=templateTeam;return{entry,builtin:!0}}let councilMember=BUILTIN_COUNCIL_MEMBERS.find((m)=>m.name===name);if(councilMember){let entry=builtinToEntry(councilMember);if(templateTeam)entry.team=templateTeam;return{entry,builtin:!0}}return null}async function lookupTemplateTeam(name){try{let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),rows=await(await getConnection2())`SELECT team FROM agent_templates WHERE id = ${name} LIMIT 1`;if(rows.length===0)return null;let team=rows[0].team;return typeof team==="string"&&team.length>0?team:null}catch{return null}}async function findSessionByRepo(repoPath){try{let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),rows=await(await getConnection2())`
616
+ `;if(rows.length>0){let meta=parseMetadata(rows[0].metadata),createdAt=rows[0].created_at instanceof Date?rows[0].created_at.toISOString():rows[0].created_at,entry=roleToEntry(name,void 0,meta,createdAt);if(templateTeam)entry.team=templateTeam;return{entry,builtin:!1}}}catch{}let builtinRole=BUILTIN_ROLES.find((r)=>r.name===name);if(builtinRole){let entry=builtinToEntry(builtinRole);if(templateTeam)entry.team=templateTeam;return{entry,builtin:!0}}let councilMember=BUILTIN_COUNCIL_MEMBERS.find((m)=>m.name===name);if(councilMember){let entry=builtinToEntry(councilMember);if(templateTeam)entry.team=templateTeam;return{entry,builtin:!0}}return null}async function lookupTemplateTeam(name){try{let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),rows=await(await getConnection2())`SELECT team FROM agent_templates WHERE id = ${name} LIMIT 1`;if(rows.length===0)return null;let team=rows[0].team;return typeof team==="string"&&team.length>0?team:null}catch{return null}}async function findSessionByRepo(repoPath){try{let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),rows=await(await getConnection2())`
607
617
  SELECT session FROM agents
608
618
  WHERE repo_path = ${repoPath}
609
619
  AND session IS NOT NULL
@@ -612,12 +622,12 @@ ${body}`;writeFileSync9(filePath,output,"utf-8")}function serializeSdkConfig(sdk
612
622
  ORDER BY started_at DESC
613
623
  LIMIT 1
614
624
  `;return rows.length>0?rows[0].session:null}catch{return null}}async function ls(){let result2=[],seen=new Set;try{let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),rows=await(await getConnection2())`
615
- SELECT DISTINCT ON (a.role) a.role, a.team, a.metadata, e.repo_path, e.provider
625
+ SELECT DISTINCT ON (a.role) a.role, a.team, a.metadata, a.created_at, e.repo_path, e.provider
616
626
  FROM agents a
617
627
  LEFT JOIN executors e ON a.current_executor_id = e.id
618
628
  WHERE a.role IS NOT NULL
619
629
  ORDER BY a.role, (CASE WHEN a.id LIKE 'dir:%' THEN 0 ELSE 1 END), a.started_at DESC
620
- `;for(let row of rows){let name=row.role;if(!seen.has(name)){let meta=parseMetadata(row.metadata),entry=roleToEntry(name,row.team,meta),repoPath=row.repo_path;if(repoPath)entry.dir=repoPath,entry.repo=repoPath;result2.push({...entry,scope:"global"}),seen.add(name)}}}catch{}return result2}async function get2(name,_options){return(await resolve3(name))?.entry??null}async function edit(name,updates,_options){if(updates.dir){if(!existsSync19(updates.dir))throw Error(`Directory does not exist: ${updates.dir}`);let agentsPath=join21(updates.dir,"AGENTS.md");if(!existsSync19(agentsPath))throw Error(`AGENTS.md not found in ${updates.dir}.`)}let existing=await get2(name);if(!existing)throw Error(`Agent "${name}" not found in directory.`);let updated=Object.assign(existing,updates),metadataPatch=buildMetadata(updated);try{let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),sql=await getConnection2();if((await sql`
630
+ `;for(let row of rows){let name=row.role;if(!seen.has(name)){let meta=parseMetadata(row.metadata),createdAt=row.created_at instanceof Date?row.created_at.toISOString():row.created_at,entry=roleToEntry(name,row.team,meta,createdAt),repoPath=row.repo_path;if(repoPath)entry.dir=repoPath,entry.repo=repoPath;result2.push({...entry,scope:"global"}),seen.add(name)}}}catch{}return result2}async function get2(name,_options){return(await resolve3(name))?.entry??null}async function edit(name,updates,_options){if(updates.dir){if(!existsSync19(updates.dir))throw Error(`Directory does not exist: ${updates.dir}`);let agentsPath=join21(updates.dir,"AGENTS.md");if(!existsSync19(agentsPath))throw Error(`AGENTS.md not found in ${updates.dir}.`)}let existing=await get2(name);if(!existing)throw Error(`Agent "${name}" not found in directory.`);let updated=Object.assign(existing,updates),metadataPatch=buildMetadata(updated);try{let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),sql=await getConnection2();if((await sql`
621
631
  UPDATE agents
622
632
  SET metadata = metadata || ${sql.json(metadataPatch)}
623
633
  WHERE id = ${`dir:${name}`}
@@ -625,7 +635,7 @@ ${body}`;writeFileSync9(filePath,output,"utf-8")}function serializeSdkConfig(sdk
625
635
  UPDATE agents
626
636
  SET metadata = metadata || ${sql.json(metadataPatch)}
627
637
  WHERE role = ${name}
628
- `}catch{}return updated}function loadIdentity(entry){if(!entry.dir)return null;let agentsPath=join21(entry.dir,"AGENTS.md");if(existsSync19(agentsPath))return agentsPath;return null}function builtinToEntry(agent){return{name:agent.name,dir:"",promptMode:agent.promptMode??"append",model:agent.model,roles:[],registeredAt:"(built-in)"}}function roleToEntry(role,team,metadata){if(!(metadata&&Object.keys(metadata).length>0)){let builtin=[...BUILTIN_ROLES,...BUILTIN_COUNCIL_MEMBERS].find((b2)=>b2.name===role);if(builtin)return builtinToEntry(builtin)}return{name:role,dir:metadata?.dir||"",promptMode:metadata?.promptMode||"append",model:metadata?.model,roles:[],registeredAt:new Date().toISOString(),description:metadata?.description,color:metadata?.color,provider:metadata?.provider,permissions:metadata?.permissions,disallowedTools:metadata?.disallowedTools,omniScopes:metadata?.omniScopes,hooks:metadata?.hooks,sdk:metadata?.sdk,...metadata?.repo?{repo:metadata.repo}:team?{repo:team}:{}}}function buildMetadata(entry){let meta={};if(entry.dir)meta.dir=entry.dir;if(entry.repo)meta.repo=entry.repo;if(entry.model)meta.model=entry.model;if(entry.promptMode&&entry.promptMode!=="append")meta.promptMode=entry.promptMode;if(entry.description)meta.description=entry.description;if(entry.color)meta.color=entry.color;if(entry.provider)meta.provider=entry.provider;if(entry.permissions)meta.permissions=entry.permissions;if(entry.disallowedTools)meta.disallowedTools=entry.disallowedTools;if(entry.omniScopes)meta.omniScopes=entry.omniScopes;if(entry.hooks)meta.hooks=entry.hooks;if(entry.sdk)meta.sdk=entry.sdk;return meta}function parseMetadata(raw){if(!raw)return{};if(typeof raw==="object"&&!Array.isArray(raw))return raw;if(typeof raw==="string")try{return JSON.parse(raw)}catch{return{}}return{}}function syncFrontmatterToDisk(entry,updates){try{if(!entry.dir)return;let agentsPath=join21(entry.dir,"AGENTS.md");if(!existsSync19(agentsPath))return;if(!Object.keys(updates).some((k)=>FRONTMATTER_KEYS.has(k)))return;let fmUpdates={};if(updates.model!==void 0)fmUpdates.model=updates.model;if(updates.description!==void 0)fmUpdates.description=updates.description;if(updates.color!==void 0)fmUpdates.color=updates.color;if(updates.promptMode!==void 0)fmUpdates.promptMode=updates.promptMode;if(updates.provider!==void 0)fmUpdates.provider=updates.provider;if(updates.sdk!==void 0)fmUpdates.sdk=serializeSdkConfig(updates.sdk);if(Object.keys(fmUpdates).length===0)return;writeFrontmatter(agentsPath,fmUpdates)}catch{}}var FRONTMATTER_KEYS;var init_agent_directory=__esm(()=>{init_builtin_agents();init_frontmatter_writer();FRONTMATTER_KEYS=new Set(["name","description","model","color","promptMode","provider","sdk"])});var exports_runtime_events={};__export(exports_runtime_events,{waitForRuntimeEvent:()=>waitForRuntimeEvent,publishSubjectEvent:()=>publishSubjectEvent,publishRuntimeEvent:()=>publishRuntimeEvent,listRuntimeEvents:()=>listRuntimeEvents,getLatestRuntimeEventId:()=>getLatestRuntimeEventId,getEventMetrics:()=>getEventMetrics,followRuntimeEvents:()=>followRuntimeEvents});class EventCircuitBreaker{failures=0;lastFailure=0;loggedOpen=!1;threshold=5;cooldown=30000;isOpen(){if(this.failures<this.threshold)return!1;if(Date.now()-this.lastFailure>this.cooldown)return this.failures=0,!1;return!0}recordSuccess(){if(this.failures>=this.threshold)console.warn("[runtime-events] circuit breaker closed \u2014 PG writes resumed");this.failures=0,this.loggedOpen=!1}recordFailure(){if(this.failures++,this.lastFailure=Date.now(),this.failures>=this.threshold&&!this.loggedOpen)console.warn(`[runtime-events] circuit breaker open \u2014 skipping PG writes for ${this.cooldown/1000}s after ${this.threshold} consecutive failures`),this.loggedOpen=!0}get state(){if(this.failures<this.threshold)return"closed";if(Date.now()-this.lastFailure>this.cooldown)return"half-open";return"open"}}function getEventMetrics(){return{eventsEmitted,eventsFailed,lastEmitDuration,circuitState:circuitBreaker.state}}function logFollowDrainError(context,error2,active){if(!active)return;let message=error2 instanceof Error?error2.message:String(error2);console.error(`[runtime-events] ${context} drain failed: ${message}`)}function rowToRuntimeEvent(row){return{id:Number(row.id),repoPath:row.repo_path,timestamp:row.created_at instanceof Date?row.created_at.toISOString():String(row.created_at),kind:row.kind,agent:row.agent,team:row.team??void 0,direction:row.direction??void 0,peer:row.peer??void 0,text:row.text,data:row.data??void 0,source:row.source,subject:row.subject??void 0,threadId:row.thread_id??void 0,traceId:row.trace_id??void 0,parentEventId:row.parent_event_id!=null?Number(row.parent_event_id):void 0}}function nextParam(values2,value){return values2.push(value),`$${values2.length}`}function buildScopeClause(query,values2){let scopeClauses=[];if(query.agentIds&&query.agentIds.length>0)scopeClauses.push(`agent = ANY(${nextParam(values2,query.agentIds)})`);if(query.team)scopeClauses.push(`team = ${nextParam(values2,query.team)}`);if(query.teamPrefix)scopeClauses.push(`team LIKE ${nextParam(values2,`${query.teamPrefix}%`)}`);if(scopeClauses.length===0)return null;if(scopeClauses.length===1)return scopeClauses[0];if(query.scopeMode==="any")return`(${scopeClauses.join(" OR ")})`;return`(${scopeClauses.join(" AND ")})`}function buildWhere(query){let values2=[],clauses=[];if(query.afterId!=null)clauses.push(`id > ${nextParam(values2,query.afterId)}`);if(query.repoPath)clauses.push(`repo_path = ${nextParam(values2,query.repoPath)}`);if(query.subject)clauses.push(`subject = ${nextParam(values2,query.subject)}`);if(query.kinds&&query.kinds.length>0)clauses.push(`kind = ANY(${nextParam(values2,query.kinds)})`);if(query.since)clauses.push(`created_at >= ${nextParam(values2,query.since)}`);if(query.threadId)clauses.push(`thread_id = ${nextParam(values2,query.threadId)}`);if(query.traceId)clauses.push(`trace_id = ${nextParam(values2,query.traceId)}`);let scopeClause=buildScopeClause(query,values2);if(scopeClause)clauses.push(scopeClause);return{clause:clauses.length>0?`WHERE ${clauses.join(" AND ")}`:"",values:values2}}async function publishRuntimeEvent(input){if(circuitBreaker.isOpen())throw eventsFailed++,Error("circuit breaker open \u2014 PG event write skipped");let start=Date.now();try{let sql=await getConnection(),threadId=input.threadId??`agent:${input.agent}`,rows=await sql`
638
+ `}catch{}return updated}function loadIdentity(entry){if(!entry.dir)return null;let agentsPath=join21(entry.dir,"AGENTS.md");if(existsSync19(agentsPath))return agentsPath;return null}function builtinToEntry(agent){return{name:agent.name,dir:"",promptMode:agent.promptMode??"append",model:agent.model,roles:[],registeredAt:"(built-in)"}}function roleToEntry(role,team,metadata,createdAt){if(!(metadata&&Object.keys(metadata).length>0)){let builtin=[...BUILTIN_ROLES,...BUILTIN_COUNCIL_MEMBERS].find((b2)=>b2.name===role);if(builtin)return builtinToEntry(builtin)}let registeredAt=(typeof metadata?.registeredAt==="string"?metadata.registeredAt:void 0)??createdAt??"";return{name:role,dir:metadata?.dir||"",promptMode:metadata?.promptMode||"append",model:metadata?.model,roles:[],registeredAt,description:metadata?.description,color:metadata?.color,provider:metadata?.provider,permissions:metadata?.permissions,disallowedTools:metadata?.disallowedTools,omniScopes:metadata?.omniScopes,hooks:metadata?.hooks,sdk:metadata?.sdk,...metadata?.repo?{repo:metadata.repo}:team?{repo:team}:{}}}function buildMetadata(entry){let meta={};if(entry.dir)meta.dir=entry.dir;if(entry.repo)meta.repo=entry.repo;if(entry.model)meta.model=entry.model;if(entry.promptMode&&entry.promptMode!=="append")meta.promptMode=entry.promptMode;if(entry.description)meta.description=entry.description;if(entry.color)meta.color=entry.color;if(entry.provider)meta.provider=entry.provider;if(entry.permissions)meta.permissions=entry.permissions;if(entry.disallowedTools)meta.disallowedTools=entry.disallowedTools;if(entry.omniScopes)meta.omniScopes=entry.omniScopes;if(entry.hooks)meta.hooks=entry.hooks;if(entry.sdk)meta.sdk=entry.sdk;return meta}function parseMetadata(raw){if(!raw)return{};if(typeof raw==="object"&&!Array.isArray(raw))return raw;if(typeof raw==="string")try{return JSON.parse(raw)}catch{return{}}return{}}function syncFrontmatterToDisk(entry,updates){try{if(!entry.dir)return;let agentsPath=join21(entry.dir,"AGENTS.md");if(!existsSync19(agentsPath))return;if(!Object.keys(updates).some((k)=>FRONTMATTER_KEYS.has(k)))return;let fmUpdates={};if(updates.model!==void 0)fmUpdates.model=updates.model;if(updates.description!==void 0)fmUpdates.description=updates.description;if(updates.color!==void 0)fmUpdates.color=updates.color;if(updates.promptMode!==void 0)fmUpdates.promptMode=updates.promptMode;if(updates.provider!==void 0)fmUpdates.provider=updates.provider;if(updates.sdk!==void 0)fmUpdates.sdk=serializeSdkConfig(updates.sdk);if(Object.keys(fmUpdates).length===0)return;writeFrontmatter(agentsPath,fmUpdates)}catch{}}var FRONTMATTER_KEYS;var init_agent_directory=__esm(()=>{init_builtin_agents();init_frontmatter_writer();FRONTMATTER_KEYS=new Set(["name","description","model","color","promptMode","provider","sdk"])});var exports_runtime_events={};__export(exports_runtime_events,{waitForRuntimeEvent:()=>waitForRuntimeEvent,publishSubjectEvent:()=>publishSubjectEvent,publishRuntimeEvent:()=>publishRuntimeEvent,listRuntimeEvents:()=>listRuntimeEvents,getLatestRuntimeEventId:()=>getLatestRuntimeEventId,getEventMetrics:()=>getEventMetrics,followRuntimeEvents:()=>followRuntimeEvents});class EventCircuitBreaker{failures=0;lastFailure=0;loggedOpen=!1;threshold=5;cooldown=30000;isOpen(){if(this.failures<this.threshold)return!1;if(Date.now()-this.lastFailure>this.cooldown)return this.failures=0,!1;return!0}recordSuccess(){if(this.failures>=this.threshold)console.warn("[runtime-events] circuit breaker closed \u2014 PG writes resumed");this.failures=0,this.loggedOpen=!1}recordFailure(){if(this.failures++,this.lastFailure=Date.now(),this.failures>=this.threshold&&!this.loggedOpen)console.warn(`[runtime-events] circuit breaker open \u2014 skipping PG writes for ${this.cooldown/1000}s after ${this.threshold} consecutive failures`),this.loggedOpen=!0}get state(){if(this.failures<this.threshold)return"closed";if(Date.now()-this.lastFailure>this.cooldown)return"half-open";return"open"}}function getEventMetrics(){return{eventsEmitted,eventsFailed,lastEmitDuration,circuitState:circuitBreaker.state}}function logFollowDrainError(context,error2,active){if(!active)return;let message=error2 instanceof Error?error2.message:String(error2);console.error(`[runtime-events] ${context} drain failed: ${message}`)}function rowToRuntimeEvent(row){return{id:Number(row.id),repoPath:row.repo_path,timestamp:row.created_at instanceof Date?row.created_at.toISOString():String(row.created_at),kind:row.kind,agent:row.agent,team:row.team??void 0,direction:row.direction??void 0,peer:row.peer??void 0,text:row.text,data:row.data??void 0,source:row.source,subject:row.subject??void 0,threadId:row.thread_id??void 0,traceId:row.trace_id??void 0,parentEventId:row.parent_event_id!=null?Number(row.parent_event_id):void 0}}function nextParam(values2,value){return values2.push(value),`$${values2.length}`}function buildScopeClause(query,values2){let scopeClauses=[];if(query.agentIds&&query.agentIds.length>0)scopeClauses.push(`agent = ANY(${nextParam(values2,query.agentIds)})`);if(query.team)scopeClauses.push(`team = ${nextParam(values2,query.team)}`);if(query.teamPrefix)scopeClauses.push(`team LIKE ${nextParam(values2,`${query.teamPrefix}%`)}`);if(scopeClauses.length===0)return null;if(scopeClauses.length===1)return scopeClauses[0];if(query.scopeMode==="any")return`(${scopeClauses.join(" OR ")})`;return`(${scopeClauses.join(" AND ")})`}function buildWhere(query){let values2=[],clauses=[];if(query.afterId!=null)clauses.push(`id > ${nextParam(values2,query.afterId)}`);if(query.repoPath)clauses.push(`repo_path = ${nextParam(values2,query.repoPath)}`);if(query.subject)clauses.push(`subject = ${nextParam(values2,query.subject)}`);if(query.kinds&&query.kinds.length>0)clauses.push(`kind = ANY(${nextParam(values2,query.kinds)})`);if(query.since)clauses.push(`created_at >= ${nextParam(values2,query.since)}`);if(query.threadId)clauses.push(`thread_id = ${nextParam(values2,query.threadId)}`);if(query.traceId)clauses.push(`trace_id = ${nextParam(values2,query.traceId)}`);let scopeClause=buildScopeClause(query,values2);if(scopeClause)clauses.push(scopeClause);return{clause:clauses.length>0?`WHERE ${clauses.join(" AND ")}`:"",values:values2}}async function publishRuntimeEvent(input){if(circuitBreaker.isOpen())throw eventsFailed++,Error("circuit breaker open \u2014 PG event write skipped");let start=Date.now();try{let sql=await getConnection(),threadId=input.threadId??`agent:${input.agent}`,rows=await sql`
629
639
  INSERT INTO genie_runtime_events (
630
640
  repo_path, subject, kind, source, agent, team, direction, peer, text, data, thread_id, trace_id, parent_event_id, created_at
631
641
  )
@@ -757,7 +767,7 @@ Run 'genie agent list' to list agents.`)}async function resolveTarget(target,opt
757
767
  LIMIT 100
758
768
  `).map((r)=>({id:r.id,requestType:r.request_type,senderId:r.sender_id,body:r.body,createdAt:r.created_at instanceof Date?r.created_at.toISOString():String(r.created_at)}))}async function generateBrief(options){let teamConfig=await getTeam(options.team);if(!teamConfig)throw Error(`Team not found: ${options.team}`);let since=await resolveSince(options),repoPath=options.repoPath??teamConfig.repo,agentName=options.agent??teamConfig.leader??null,agentIdentifiers=agentName?[agentName]:[],[unreadMessages,taskMessages,recentEvents,pendingRequests,teamRoster]=await Promise.all([agentIdentifiers.length>0?getUnread(repoPath,agentIdentifiers):Promise.resolve([]),getTaskMessages(options.team,since),listRuntimeEvents({team:options.team,since,limit:100}),getPendingRequestMessages(options.team),getTeamRoster(options.team)]);return{team:options.team,agent:agentName,since,unreadMessages,taskMessages,recentEvents,pendingRequests,teamRoster}}function truncate(text,max){return text.length>max?`${text.slice(0,max)}...`:text}function formatUnreadSection(messages2){if(messages2.length===0)return[];let lines=[`## Unread Messages (${messages2.length})`];for(let msg of messages2)lines.push(`- **${msg.from}**: ${truncate(msg.body,120)}`);return lines.push(""),lines}function formatTaskMessagesSection(messages2){if(messages2.length===0)return[];let lines=[`## Task Updates (${messages2.length})`],byTask=new Map;for(let msg of messages2){let existing=byTask.get(msg.taskId)??[];existing.push(msg),byTask.set(msg.taskId,existing)}for(let[taskId,msgs]of byTask){lines.push(`### ${taskId}: ${msgs[0].taskTitle}`);for(let msg of msgs)lines.push(`- [${msg.senderType}:${msg.senderId}] ${truncate(msg.body,100)}`)}return lines.push(""),lines}function formatRequestsSection(requests){if(requests.length===0)return[];let lines=[`## Pending Requests (${requests.length})`];for(let req of requests)lines.push(`- [${req.requestType}] ${req.senderId}: ${truncate(req.body,80)}`);return lines.push(""),lines}function formatRosterSection(roster){if(roster.length===0)return[];let lines=[`## Team Roster (${roster.length})`];for(let member of roster){let state=member.executorState??"offline",icon=STATE_ICONS[state]??"\u25CC";lines.push(`- ${icon} **${member.agentId}** (${member.role??"unassigned"}): ${state}`)}return lines.push(""),lines}function formatEventsSection(events){if(events.length===0)return[];let lines=[`## Recent Events (${events.length})`],tail=events.slice(-10);for(let evt of tail){let ts3=evt.timestamp.slice(11,16);lines.push(`- ${ts3} [${evt.kind}] ${evt.agent}: ${truncate(evt.text,80)}`)}if(events.length>10)lines.push(` _(${events.length-10} more events)_`);return lines.push(""),lines}function formatBrief(brief){let lines=[`# BRIEF \u2014 ${brief.team}${brief.agent?` ${brief.agent}`:""}`,`Since: ${brief.since}`,"",...formatUnreadSection(brief.unreadMessages),...formatTaskMessagesSection(brief.taskMessages),...formatRequestsSection(brief.pendingRequests),...formatRosterSection(brief.teamRoster),...formatEventsSection(brief.recentEvents)];if(!(brief.unreadMessages.length+brief.taskMessages.length+brief.pendingRequests.length+brief.recentEvents.length>0))lines.push("_No activity since last session._","");return lines.join(`
759
769
  `)}var STATE_ICONS;var init_brief=__esm(()=>{init_db();init_mailbox();init_runtime_events();init_team_manager();STATE_ICONS={working:"\u25CF",idle:"\u25CB",error:"\u2718"}});var exports_agent_sync={};__export(exports_agent_sync,{watchAgentDirectory:()=>watchAgentDirectory,syncAgentDirectory:()=>syncAgentDirectory,printSyncResult:()=>printSyncResult,healAgentFile:()=>healAgentFile});import{execSync as execSync6}from"child_process";import{existsSync as existsSync23,watch as fsWatch,readFileSync as readFileSync15,readdirSync as readdirSync6,realpathSync as realpathSync3,writeFileSync as writeFileSync11}from"fs";import{join as join25}from"path";function getGitRemoteUrl(dir){try{return execSync6(`git -C "${dir}" config --get remote.origin.url`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return null}}function extractOrgRepo(remoteUrl){let sshMatch=remoteUrl.match(/[^/:]+\/[^/]+?(?:\.git)?$/);if(sshMatch)return sshMatch[0].replace(/\.git$/,"");return null}function getRepoPathForAgent(agentDir){let reposLink=join25(agentDir,"repos");try{if(!existsSync23(reposLink))return null;let target=realpathSync3(reposLink);if(!existsSync23(target))return null;return target}catch{return null}}function discoverAgents(workspaceRoot){let agentsDir=join25(workspaceRoot,"agents");if(!existsSync23(agentsDir))return[];let agents=[];try{let entries=readdirSync6(agentsDir,{withFileTypes:!0});for(let entry of entries){if(!entry.isDirectory())continue;let agentDir=join25(agentsDir,entry.name);if(!existsSync23(join25(agentDir,"AGENTS.md")))continue;agents.push({name:entry.name,dir:agentDir,repoUrl:getGitRemoteUrl(agentDir),productRepo:getRepoPathForAgent(agentDir)}),discoverSubAgents(agentDir,entry.name,agents)}}catch{}return agents}function discoverSubAgents(parentDir,parentName,agents){let subAgentsDir=join25(parentDir,".genie","agents");if(!existsSync23(subAgentsDir))return;try{let entries=readdirSync6(subAgentsDir,{withFileTypes:!0});for(let entry of entries){if(!entry.isDirectory())continue;let subDir=join25(subAgentsDir,entry.name);if(!existsSync23(join25(subDir,"AGENTS.md")))continue;agents.push({name:`${parentName}/${entry.name}`,dir:subDir,repoUrl:getGitRemoteUrl(parentDir),productRepo:getRepoPathForAgent(parentDir)})}}catch{}}function discoverSingleAgent(workspaceRoot,agentName){let agentDir=join25(workspaceRoot,"agents",agentName);if(!existsSync23(join25(agentDir,"AGENTS.md")))return null;return{name:agentName,dir:agentDir,repoUrl:getGitRemoteUrl(agentDir),productRepo:getRepoPathForAgent(agentDir)}}function healAgentFile(agentsMdPath,agentName,healResult){let content=readFileSync15(agentsMdPath,"utf-8"),fmMatch=content.match(/^(---\n)([\s\S]*?)(\n---)/);if(!fmMatch)return!1;let prefix=fmMatch[1],fmBlock=fmMatch[2],suffix=fmMatch[3],rest=content.slice(fmMatch[0].length),modified=!1,healedBlock=fmBlock;for(let{field,value}of INVALID_LITERALS)if(new RegExp(`^${field}:\\s*${value}\\s*$`,"m").test(healedBlock))healedBlock=healedBlock.replace(new RegExp(`${field}:\\s*${value}\\s*\\n?`,"m"),""),healResult.healed.push({agent:agentName,field,value}),modified=!0;if(!modified)return!1;let newContent=prefix+healedBlock+suffix+rest,tmpPath=`${agentsMdPath}.tmp.${Date.now()}`;writeFileSync11(tmpPath,newContent,"utf-8");let{renameSync:renameSync2}=__require("fs");return renameSync2(tmpPath,agentsMdPath),!0}function buildResolveContext(workspaceRoot,agentName){let workspaceDefaults;try{workspaceDefaults=getWorkspaceConfig(workspaceRoot).agents?.defaults}catch{}let parent;if(agentName.includes("/")){let parentName=agentName.split("/")[0],parentAgentsMd=join25(workspaceRoot,"agents",parentName,"AGENTS.md");if(existsSync23(parentAgentsMd)){let parentContent=readFileSync15(parentAgentsMd,"utf-8"),parentFm=parseFrontmatter(parentContent);parent={name:parentName,fields:parentFm}}}return{workspaceDefaults,parent}}function computeResolvedMetadata(fm,ctx){let declared={},resolved={};for(let field of Object.keys(BUILTIN_DEFAULTS)){let fmValue=fm[field];if(fmValue!==void 0&&fmValue!==null&&fmValue!==""&&fmValue!=="inherit")declared[field]=fmValue;let result2=resolveFieldWithSource(fm,field,ctx);resolved[field]={value:result2.value,source:result2.source}}return{declared,resolved}}async function syncAgentDirectory(workspaceRoot){let result2={registered:[],updated:[],unchanged:[],archived:[],reactivated:[],healed:[],errors:[]},agents=discoverAgents(workspaceRoot),discoveredNames=new Set(agents.map((a)=>a.name)),healResult={healed:[]};for(let agent of agents){let agentsMdPath=join25(agent.dir,"AGENTS.md");try{healAgentFile(agentsMdPath,agent.name,healResult)}catch{}}result2.healed=healResult.healed;for(let h of healResult.healed)console.log(`[sync] healed ${h.agent}/AGENTS.md: removed invalid '${h.field}: ${h.value}' line`);for(let agent of agents)try{await syncSingleAgent(agent,result2,workspaceRoot)}catch(err){result2.errors.push({name:agent.name,error:err instanceof Error?err.message:String(err)})}return await removeMissingAgents(discoveredNames,result2),result2}function printSyncResult(result2){if(result2.healed.length>0)console.log(` Healed: ${result2.healed.length} invalid literal(s) removed`);if(result2.registered.length>0)console.log(` Registered: ${result2.registered.join(", ")}`);if(result2.updated.length>0)console.log(` Updated: ${result2.updated.join(", ")}`);if(result2.reactivated.length>0)console.log(` Reactivated: ${result2.reactivated.join(", ")}`);if(result2.archived.length>0)console.log(` Removed: ${result2.archived.join(", ")}`);if(result2.unchanged.length>0)console.log(` Unchanged: ${result2.unchanged.join(", ")}`);for(let err of result2.errors)console.error(` Error (${err.name}): ${err.error}`);let total=result2.registered.length+result2.updated.length+result2.unchanged.length+result2.reactivated.length;console.log(`
760
- Sync complete: ${total} active agent(s), ${result2.archived.length} removed.`)}async function removeMissingAgents(discoveredNames,result2){try{let entries=await ls();for(let entry of entries){if(discoveredNames.has(entry.name))continue;if(entry.scope==="built-in")continue;if(!entry.dir||!entry.dir.includes("/agents/"))continue;if(await rm3(entry.name))result2.archived.push(entry.name)}}catch{}}async function syncSingleAgent(agent,result2,workspaceRoot){let repoPath=(agent.repoUrl?extractOrgRepo(agent.repoUrl):null)??agent.repoUrl??agent.dir,agentsMdPath=join25(agent.dir,"AGENTS.md"),content=readFileSync15(agentsMdPath,"utf-8"),fm=parseFrontmatter(content),_resolvedMeta;if(workspaceRoot){let ctx=buildResolveContext(workspaceRoot,agent.name);_resolvedMeta=computeResolvedMetadata(fm,ctx)}let resolved=await resolve3(agent.name),existing=resolved&&!resolved.builtin?resolved.entry:null,sdkConfig=fm.sdk,permissions=fm.permissions,disallowedTools=fm.disallowedTools,omniScopes=fm.omniScopes,hooks=fm.hooks;if(!existing){await add({name:agent.name,dir:agent.dir,repo:repoPath,promptMode:fm.promptMode??"append",model:fm.model,description:fm.description,color:fm.color,provider:fm.provider,permissions,disallowedTools,omniScopes,hooks,sdk:sdkConfig}),result2.registered.push(agent.name);return}let identityUpdate={dir:agent.dir,repo:repoPath,promptMode:fm.promptMode??"append",model:fm.model,description:fm.description,color:fm.color,provider:fm.provider,permissions,disallowedTools,omniScopes,hooks,sdk:sdkConfig},sdkChanged=JSON.stringify(existing.sdk)!==JSON.stringify(sdkConfig),permissionsChanged=JSON.stringify(existing.permissions)!==JSON.stringify(permissions),disallowedToolsChanged=JSON.stringify(existing.disallowedTools)!==JSON.stringify(disallowedTools),omniScopesChanged=JSON.stringify(existing.omniScopes)!==JSON.stringify(omniScopes),hooksChanged=JSON.stringify(existing.hooks)!==JSON.stringify(hooks);if(sdkChanged||permissionsChanged||disallowedToolsChanged||omniScopesChanged||hooksChanged||existing.repo!==repoPath||existing.dir!==agent.dir||existing.promptMode!==(fm.promptMode??"append")||existing.model!==fm.model||existing.description!==fm.description||existing.color!==fm.color||existing.provider!==fm.provider)await edit(agent.name,identityUpdate),result2.updated.push(agent.name);else result2.unchanged.push(agent.name)}async function syncSingleAgentByName(workspaceRoot,agentName){let agent=discoverSingleAgent(workspaceRoot,agentName);if(!agent)return"not-found";let result2={registered:[],updated:[],unchanged:[],archived:[],reactivated:[],healed:[],errors:[]};if(await syncSingleAgent(agent,result2,workspaceRoot),result2.registered.length>0)return"registered";if(result2.updated.length>0)return"updated";return"unchanged"}function watchAgentDirectory(workspaceRoot,options){let agentsDir=join25(workspaceRoot,"agents");if(!existsSync23(agentsDir))return null;let debounceTimer=null,pendingChanges=new Set,processChanges=async()=>{let names=[...pendingChanges];pendingChanges.clear();for(let name of names)try{let action=await processWatchedAgent(workspaceRoot,agentsDir,name);if(action)options?.onSync?.(name,action)}catch{}},watcher=fsWatch(agentsDir,{persistent:!1},(_event,filename)=>{if(!filename)return;let name=filename.split("/")[0];if(!name||name.startsWith("."))return;if(pendingChanges.add(name),debounceTimer)clearTimeout(debounceTimer);debounceTimer=setTimeout(processChanges,2000)});return{close:()=>{if(debounceTimer)clearTimeout(debounceTimer);watcher.close()}}}async function processWatchedAgent(workspaceRoot,agentsDir,name){let agentDir=join25(agentsDir,name);if(existsSync23(agentDir)&&existsSync23(join25(agentDir,"AGENTS.md"))){let action=await syncSingleAgentByName(workspaceRoot,name);return action!=="unchanged"&&action!=="not-found"?action:null}if(!existsSync23(agentDir)){if(await rm3(name))return"removed"}return null}var INVALID_LITERALS;var init_agent_sync=__esm(()=>{init_agent_directory();init_defaults();init_frontmatter();init_workspace();INVALID_LITERALS=[{field:"model",value:"inherit"}]});var exports_term_format={};__export(exports_term_format,{truncate:()=>truncate2,stripAnsi:()=>stripAnsi2,padRight:()=>padRight,formatTimestamp:()=>formatTimestamp,formatTime:()=>formatTime,formatRelativeTimestamp:()=>formatRelativeTimestamp,formatDate:()=>formatDate,color:()=>color});function padRight(str2,len){return str2.length>=len?str2:str2+" ".repeat(len-str2.length)}function truncate2(str2,len){return str2.length<=len?str2:`${str2.slice(0,len-1)}\u2026`}function formatDate(iso){if(!iso)return"-";return new Date(iso).toLocaleDateString("en-US",{month:"short",day:"numeric"})}function formatRelativeTimestamp(ts3){let d=new Date(ts3),diffMs=Date.now()-d.getTime();if(diffMs<60000)return`${Math.floor(diffMs/1000)}s ago`;if(diffMs<3600000)return`${Math.floor(diffMs/60000)}m ago`;if(diffMs<86400000)return`${Math.floor(diffMs/3600000)}h ago`;return d.toISOString().replace("T"," ").slice(0,19)}function formatTimestamp(iso,opts){if(!iso)return opts?.fallback??"-";let d=iso instanceof Date?iso:new Date(iso),fmt={month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",hour12:!1};if(opts?.seconds)fmt.second="2-digit";return d.toLocaleString("en-US",fmt)}function formatTime(iso,opts){try{let date=new Date(iso),fmt={hour:"2-digit",minute:"2-digit",hour12:!1};if(opts?.seconds)fmt.second="2-digit";return date.toLocaleTimeString("en-US",fmt)}catch{return opts?.fallback??"??:??"}}function color(name,text){return isTTY?`${ANSI[name]}${text}${ANSI.reset}`:text}function stripAnsi2(str2){return str2.replace(ANSI_REGEX,"")}var ANSI,isTTY,ANSI_REGEX;var init_term_format=__esm(()=>{ANSI={reset:"\x1B[0m",dim:"\x1B[2m",bold:"\x1B[1m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",cyan:"\x1B[36m",gray:"\x1B[90m",brightRed:"\x1B[91m",brightGreen:"\x1B[92m",brightYellow:"\x1B[93m",brightCyan:"\x1B[96m"},isTTY=process.stdout.isTTY&&!process.env.NO_COLOR;ANSI_REGEX=/\x1b\[[0-9;]*m/g});var exports_task_service={};__export(exports_task_service,{updateTask:()=>updateTask,updateMessage:()=>updateMessage,untagTask:()=>untagTask,unblockTask:()=>unblockTask,unarchiveTask:()=>unarchiveTask,unarchiveProject:()=>unarchiveProject,tagTask:()=>tagTask,setRelease:()=>setRelease,setPreference:()=>setPreference,sendMessage:()=>sendMessage,resolveTaskId:()=>resolveTaskId,resolveChannels:()=>resolveChannels,removeMember:()=>removeMember,removeDependency:()=>removeDependency,removeActor:()=>removeActor,releaseTask:()=>releaseTask,moveTask:()=>moveTask,markDone:()=>markDone,listTypes:()=>listTypes,listTasksForActor:()=>listTasksForActor,listTasks:()=>listTasks,listTags:()=>listTags,listReleases:()=>listReleases,listProjectsFiltered:()=>listProjectsFiltered,listProjects:()=>listProjects,listConversations:()=>listConversations,linkTask:()=>linkTask,getType:()=>getType,getTaskTags:()=>getTaskTags,getTaskActors:()=>getTaskActors,getTask:()=>getTask,getStageLog:()=>getStageLog,getProjectByRepoPath:()=>getProjectByRepoPath,getProjectByName:()=>getProjectByName,getPreferences:()=>getPreferences,getMessages:()=>getMessages,getMessage:()=>getMessage,getMembers:()=>getMembers,getDependents:()=>getDependents,getConversation:()=>getConversation,getCheckoutOwner:()=>getCheckoutOwner,getBlockingDependencies:()=>getBlockingDependencies,getBlockers:()=>getBlockers,forceUnlockTask:()=>forceUnlockTask,findOrCreateConversation:()=>findOrCreateConversation,expireStaleCheckouts:()=>expireStaleCheckouts,ensureProject:()=>ensureProject,deletePreference:()=>deletePreference,createType:()=>createType,createTask:()=>createTask,createTag:()=>createTag,createProject:()=>createProject,commentOnTask:()=>commentOnTask,checkoutTask:()=>checkoutTask,blockTask:()=>blockTask,assignTask:()=>assignTask,archiveTask:()=>archiveTask,archiveProject:()=>archiveProject,archiveBoard:()=>archiveBoard,addMember:()=>addMember,addDependency:()=>addDependency});import{execSync as execSync7}from"child_process";function str2(v){return v!=null?String(v):null}function strOrDefault(v,def){return v!=null?String(v):def}function mapTask(row){return{id:row.id,seq:row.seq,parentId:str2(row.parent_id),repoPath:row.repo_path,projectId:str2(row.project_id),genieOsFolderId:str2(row.genie_os_folder_id),wishFile:str2(row.wish_file),groupName:str2(row.group_name),title:row.title,description:str2(row.description),acceptanceCriteria:str2(row.acceptance_criteria),typeId:row.type_id,stage:row.stage,status:row.status,priority:row.priority,startDate:str2(row.start_date),dueDate:str2(row.due_date),estimatedEffort:str2(row.estimated_effort),startedAt:str2(row.started_at),endedAt:str2(row.ended_at),blockedReason:str2(row.blocked_reason),releaseId:str2(row.release_id),checkoutRunId:str2(row.checkout_run_id),executionLockedAt:str2(row.execution_locked_at),checkoutTimeoutMs:row.checkout_timeout_ms??600000,sessionId:str2(row.session_id),paneId:str2(row.pane_id),traceId:str2(row.trace_id),boardId:str2(row.board_id),columnId:str2(row.column_id),externalId:str2(row.external_id),externalUrl:str2(row.external_url),archivedAt:str2(row.archived_at),metadata:row.metadata??{},createdAt:strOrDefault(row.created_at,""),updatedAt:strOrDefault(row.updated_at,"")}}function mapConversation(row){return{id:row.id,parentMessageId:row.parent_message_id!=null?Number(row.parent_message_id):null,name:row.name??null,type:row.type,linkedEntity:row.linked_entity??null,linkedEntityId:row.linked_entity_id??null,createdByType:row.created_by_type??null,createdById:row.created_by_id??null,metadata:row.metadata??{},createdAt:String(row.created_at),updatedAt:String(row.updated_at)}}function mapMessage(row){return{id:Number(row.id),conversationId:row.conversation_id,replyToId:row.reply_to_id!=null?Number(row.reply_to_id):null,senderType:row.sender_type,senderId:row.sender_id,body:row.body,metadata:row.metadata??{},createdAt:String(row.created_at),updatedAt:String(row.updated_at)}}function mapTaskActor(row){return{taskId:row.task_id,actorType:row.actor_type,actorId:row.actor_id,role:row.role,permissions:row.permissions??{},createdAt:String(row.created_at)}}function mapDependency(row){return{taskId:row.task_id,dependsOnId:row.depends_on_id,depType:row.dep_type,createdAt:String(row.created_at)}}function mapTag(row){return{id:row.id,name:row.name,color:row.color??"#9ca3af",typeId:row.type_id??null,createdAt:String(row.created_at)}}function mapTaskType(row){return{id:row.id,name:row.name,description:row.description??null,icon:row.icon??null,stages:row.stages,isBuiltin:row.is_builtin,createdAt:String(row.created_at),updatedAt:String(row.updated_at)}}function mapNotificationPref(row){return{actorType:row.actor_type,actorId:row.actor_id,channel:row.channel,priorityThreshold:row.priority_threshold,isDefault:row.is_default,enabled:row.enabled,metadata:row.metadata??{},createdAt:String(row.created_at),updatedAt:String(row.updated_at)}}function mapStageLog(row){return{id:Number(row.id),taskId:row.task_id,fromStage:row.from_stage??null,toStage:row.to_stage,actorType:row.actor_type??null,actorId:row.actor_id??null,runId:row.run_id??null,gateType:row.gate_type??null,createdAt:String(row.created_at)}}function mapConversationMember(row){return{conversationId:row.conversation_id,actorType:row.actor_type,actorId:row.actor_id,role:row.role,joinedAt:String(row.joined_at)}}function mapProject(row){return{id:row.id,name:row.name,repoPath:str2(row.repo_path),description:str2(row.description),leaderAgent:str2(row.leader_agent),tmuxSession:str2(row.tmux_session),status:strOrDefault(row.status,"active"),archivedAt:str2(row.archived_at),createdAt:String(row.created_at)}}function getRepoPath(){try{return execSync7("git rev-parse --show-toplevel",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return process.cwd()}}async function resolveTaskId(idOrSeq,repoPath){let sql=await getConnection(),repo=repoPath??getRepoPath(),projectSeqMatch=idOrSeq.match(/^([^#]+)#(\d+)$/);if(projectSeqMatch&&!idOrSeq.startsWith("#")){let[,projectName,seqStr]=projectSeqMatch,seq2=Number.parseInt(seqStr,10);if(Number.isNaN(seq2))return null;let rows2=await sql`
770
+ Sync complete: ${total} active agent(s), ${result2.archived.length} removed.`)}async function removeMissingAgents(discoveredNames,result2){try{let entries=await ls();for(let entry of entries){if(discoveredNames.has(entry.name))continue;if(entry.scope==="built-in")continue;if(!entry.dir||!entry.dir.includes("/agents/"))continue;let{removed}=await rm3(entry.name);if(removed)result2.archived.push(entry.name)}}catch{}}async function syncSingleAgent(agent,result2,workspaceRoot){let repoPath=(agent.repoUrl?extractOrgRepo(agent.repoUrl):null)??agent.repoUrl??agent.dir,agentsMdPath=join25(agent.dir,"AGENTS.md"),content=readFileSync15(agentsMdPath,"utf-8"),fm=parseFrontmatter(content),_resolvedMeta;if(workspaceRoot){let ctx=buildResolveContext(workspaceRoot,agent.name);_resolvedMeta=computeResolvedMetadata(fm,ctx)}let resolved=await resolve3(agent.name),existing=resolved&&!resolved.builtin?resolved.entry:null,sdkConfig=fm.sdk,permissions=fm.permissions,disallowedTools=fm.disallowedTools,omniScopes=fm.omniScopes,hooks=fm.hooks;if(!existing){await add({name:agent.name,dir:agent.dir,repo:repoPath,promptMode:fm.promptMode??"append",model:fm.model,description:fm.description,color:fm.color,provider:fm.provider,permissions,disallowedTools,omniScopes,hooks,sdk:sdkConfig}),result2.registered.push(agent.name);return}let identityUpdate={dir:agent.dir,repo:repoPath,promptMode:fm.promptMode??"append",model:fm.model,description:fm.description,color:fm.color,provider:fm.provider,permissions,disallowedTools,omniScopes,hooks,sdk:sdkConfig},sdkChanged=JSON.stringify(existing.sdk)!==JSON.stringify(sdkConfig),permissionsChanged=JSON.stringify(existing.permissions)!==JSON.stringify(permissions),disallowedToolsChanged=JSON.stringify(existing.disallowedTools)!==JSON.stringify(disallowedTools),omniScopesChanged=JSON.stringify(existing.omniScopes)!==JSON.stringify(omniScopes),hooksChanged=JSON.stringify(existing.hooks)!==JSON.stringify(hooks);if(sdkChanged||permissionsChanged||disallowedToolsChanged||omniScopesChanged||hooksChanged||existing.repo!==repoPath||existing.dir!==agent.dir||existing.promptMode!==(fm.promptMode??"append")||existing.model!==fm.model||existing.description!==fm.description||existing.color!==fm.color||existing.provider!==fm.provider)await edit(agent.name,identityUpdate),result2.updated.push(agent.name);else result2.unchanged.push(agent.name)}async function syncSingleAgentByName(workspaceRoot,agentName){let agent=discoverSingleAgent(workspaceRoot,agentName);if(!agent)return"not-found";let result2={registered:[],updated:[],unchanged:[],archived:[],reactivated:[],healed:[],errors:[]};if(await syncSingleAgent(agent,result2,workspaceRoot),result2.registered.length>0)return"registered";if(result2.updated.length>0)return"updated";return"unchanged"}function watchAgentDirectory(workspaceRoot,options){let agentsDir=join25(workspaceRoot,"agents");if(!existsSync23(agentsDir))return null;let debounceTimer=null,pendingChanges=new Set,processChanges=async()=>{let names=[...pendingChanges];pendingChanges.clear();for(let name of names)try{let action=await processWatchedAgent(workspaceRoot,agentsDir,name);if(action)options?.onSync?.(name,action)}catch{}},watcher=fsWatch(agentsDir,{persistent:!1},(_event,filename)=>{if(!filename)return;let name=filename.split("/")[0];if(!name||name.startsWith("."))return;if(pendingChanges.add(name),debounceTimer)clearTimeout(debounceTimer);debounceTimer=setTimeout(processChanges,2000)});return{close:()=>{if(debounceTimer)clearTimeout(debounceTimer);watcher.close()}}}async function processWatchedAgent(workspaceRoot,agentsDir,name){let agentDir=join25(agentsDir,name);if(existsSync23(agentDir)&&existsSync23(join25(agentDir,"AGENTS.md"))){let action=await syncSingleAgentByName(workspaceRoot,name);return action!=="unchanged"&&action!=="not-found"?action:null}if(!existsSync23(agentDir)){let{removed}=await rm3(name);if(removed)return"removed"}return null}var INVALID_LITERALS;var init_agent_sync=__esm(()=>{init_agent_directory();init_defaults();init_frontmatter();init_workspace();INVALID_LITERALS=[{field:"model",value:"inherit"}]});var exports_term_format={};__export(exports_term_format,{truncate:()=>truncate2,stripAnsi:()=>stripAnsi2,padRight:()=>padRight,formatTimestamp:()=>formatTimestamp,formatTime:()=>formatTime,formatRelativeTimestamp:()=>formatRelativeTimestamp,formatDate:()=>formatDate,color:()=>color});function padRight(str2,len){return str2.length>=len?str2:str2+" ".repeat(len-str2.length)}function truncate2(str2,len){return str2.length<=len?str2:`${str2.slice(0,len-1)}\u2026`}function formatDate(iso){if(!iso)return"-";return new Date(iso).toLocaleDateString("en-US",{month:"short",day:"numeric"})}function formatRelativeTimestamp(ts3){let d=new Date(ts3),diffMs=Date.now()-d.getTime();if(diffMs<60000)return`${Math.floor(diffMs/1000)}s ago`;if(diffMs<3600000)return`${Math.floor(diffMs/60000)}m ago`;if(diffMs<86400000)return`${Math.floor(diffMs/3600000)}h ago`;return d.toISOString().replace("T"," ").slice(0,19)}function formatTimestamp(iso,opts){if(!iso)return opts?.fallback??"-";let d=iso instanceof Date?iso:new Date(iso),fmt={month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",hour12:!1};if(opts?.seconds)fmt.second="2-digit";return d.toLocaleString("en-US",fmt)}function formatTime(iso,opts){try{let date=new Date(iso),fmt={hour:"2-digit",minute:"2-digit",hour12:!1};if(opts?.seconds)fmt.second="2-digit";return date.toLocaleTimeString("en-US",fmt)}catch{return opts?.fallback??"??:??"}}function color(name,text){return isTTY?`${ANSI[name]}${text}${ANSI.reset}`:text}function stripAnsi2(str2){return str2.replace(ANSI_REGEX,"")}var ANSI,isTTY,ANSI_REGEX;var init_term_format=__esm(()=>{ANSI={reset:"\x1B[0m",dim:"\x1B[2m",bold:"\x1B[1m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",cyan:"\x1B[36m",gray:"\x1B[90m",brightRed:"\x1B[91m",brightGreen:"\x1B[92m",brightYellow:"\x1B[93m",brightCyan:"\x1B[96m"},isTTY=process.stdout.isTTY&&!process.env.NO_COLOR;ANSI_REGEX=/\x1b\[[0-9;]*m/g});var exports_task_service={};__export(exports_task_service,{updateTask:()=>updateTask,updateMessage:()=>updateMessage,untagTask:()=>untagTask,unblockTask:()=>unblockTask,unarchiveTask:()=>unarchiveTask,unarchiveProject:()=>unarchiveProject,tagTask:()=>tagTask,setRelease:()=>setRelease,setPreference:()=>setPreference,sendMessage:()=>sendMessage,resolveTaskId:()=>resolveTaskId,resolveChannels:()=>resolveChannels,removeMember:()=>removeMember,removeDependency:()=>removeDependency,removeActor:()=>removeActor,releaseTask:()=>releaseTask,moveTask:()=>moveTask,markDone:()=>markDone,listTypes:()=>listTypes,listTasksForActor:()=>listTasksForActor,listTasks:()=>listTasks,listTags:()=>listTags,listReleases:()=>listReleases,listProjectsFiltered:()=>listProjectsFiltered,listProjects:()=>listProjects,listConversations:()=>listConversations,linkTask:()=>linkTask,getType:()=>getType,getTaskTags:()=>getTaskTags,getTaskActors:()=>getTaskActors,getTask:()=>getTask,getStageLog:()=>getStageLog,getProjectByRepoPath:()=>getProjectByRepoPath,getProjectByName:()=>getProjectByName,getPreferences:()=>getPreferences,getMessages:()=>getMessages,getMessage:()=>getMessage,getMembers:()=>getMembers,getDependents:()=>getDependents,getConversation:()=>getConversation,getCheckoutOwner:()=>getCheckoutOwner,getBlockingDependencies:()=>getBlockingDependencies,getBlockers:()=>getBlockers,forceUnlockTask:()=>forceUnlockTask,findOrCreateConversation:()=>findOrCreateConversation,expireStaleCheckouts:()=>expireStaleCheckouts,ensureProject:()=>ensureProject,deletePreference:()=>deletePreference,createType:()=>createType,createTask:()=>createTask,createTag:()=>createTag,createProject:()=>createProject,commentOnTask:()=>commentOnTask,checkoutTask:()=>checkoutTask,blockTask:()=>blockTask,assignTask:()=>assignTask,archiveTask:()=>archiveTask,archiveProject:()=>archiveProject,archiveBoard:()=>archiveBoard,addMember:()=>addMember,addDependency:()=>addDependency});import{execSync as execSync7}from"child_process";function str2(v){return v!=null?String(v):null}function strOrDefault(v,def){return v!=null?String(v):def}function mapTask(row){return{id:row.id,seq:row.seq,parentId:str2(row.parent_id),repoPath:row.repo_path,projectId:str2(row.project_id),genieOsFolderId:str2(row.genie_os_folder_id),wishFile:str2(row.wish_file),groupName:str2(row.group_name),title:row.title,description:str2(row.description),acceptanceCriteria:str2(row.acceptance_criteria),typeId:row.type_id,stage:row.stage,status:row.status,priority:row.priority,startDate:str2(row.start_date),dueDate:str2(row.due_date),estimatedEffort:str2(row.estimated_effort),startedAt:str2(row.started_at),endedAt:str2(row.ended_at),blockedReason:str2(row.blocked_reason),releaseId:str2(row.release_id),checkoutRunId:str2(row.checkout_run_id),executionLockedAt:str2(row.execution_locked_at),checkoutTimeoutMs:row.checkout_timeout_ms??600000,sessionId:str2(row.session_id),paneId:str2(row.pane_id),traceId:str2(row.trace_id),boardId:str2(row.board_id),columnId:str2(row.column_id),externalId:str2(row.external_id),externalUrl:str2(row.external_url),archivedAt:str2(row.archived_at),metadata:row.metadata??{},createdAt:strOrDefault(row.created_at,""),updatedAt:strOrDefault(row.updated_at,"")}}function mapConversation(row){return{id:row.id,parentMessageId:row.parent_message_id!=null?Number(row.parent_message_id):null,name:row.name??null,type:row.type,linkedEntity:row.linked_entity??null,linkedEntityId:row.linked_entity_id??null,createdByType:row.created_by_type??null,createdById:row.created_by_id??null,metadata:row.metadata??{},createdAt:String(row.created_at),updatedAt:String(row.updated_at)}}function mapMessage(row){return{id:Number(row.id),conversationId:row.conversation_id,replyToId:row.reply_to_id!=null?Number(row.reply_to_id):null,senderType:row.sender_type,senderId:row.sender_id,body:row.body,metadata:row.metadata??{},createdAt:String(row.created_at),updatedAt:String(row.updated_at)}}function mapTaskActor(row){return{taskId:row.task_id,actorType:row.actor_type,actorId:row.actor_id,role:row.role,permissions:row.permissions??{},createdAt:String(row.created_at)}}function mapDependency(row){return{taskId:row.task_id,dependsOnId:row.depends_on_id,depType:row.dep_type,createdAt:String(row.created_at)}}function mapTag(row){return{id:row.id,name:row.name,color:row.color??"#9ca3af",typeId:row.type_id??null,createdAt:String(row.created_at)}}function mapTaskType(row){return{id:row.id,name:row.name,description:row.description??null,icon:row.icon??null,stages:row.stages,isBuiltin:row.is_builtin,createdAt:String(row.created_at),updatedAt:String(row.updated_at)}}function mapNotificationPref(row){return{actorType:row.actor_type,actorId:row.actor_id,channel:row.channel,priorityThreshold:row.priority_threshold,isDefault:row.is_default,enabled:row.enabled,metadata:row.metadata??{},createdAt:String(row.created_at),updatedAt:String(row.updated_at)}}function mapStageLog(row){return{id:Number(row.id),taskId:row.task_id,fromStage:row.from_stage??null,toStage:row.to_stage,actorType:row.actor_type??null,actorId:row.actor_id??null,runId:row.run_id??null,gateType:row.gate_type??null,createdAt:String(row.created_at)}}function mapConversationMember(row){return{conversationId:row.conversation_id,actorType:row.actor_type,actorId:row.actor_id,role:row.role,joinedAt:String(row.joined_at)}}function mapProject(row){return{id:row.id,name:row.name,repoPath:str2(row.repo_path),description:str2(row.description),leaderAgent:str2(row.leader_agent),tmuxSession:str2(row.tmux_session),status:strOrDefault(row.status,"active"),archivedAt:str2(row.archived_at),createdAt:String(row.created_at)}}function getRepoPath(){try{return execSync7("git rev-parse --show-toplevel",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return process.cwd()}}async function resolveTaskId(idOrSeq,repoPath){let sql=await getConnection(),repo=repoPath??getRepoPath(),projectSeqMatch=idOrSeq.match(/^([^#]+)#(\d+)$/);if(projectSeqMatch&&!idOrSeq.startsWith("#")){let[,projectName,seqStr]=projectSeqMatch,seq2=Number.parseInt(seqStr,10);if(Number.isNaN(seq2))return null;let rows2=await sql`
761
771
  SELECT t.id FROM tasks t
762
772
  JOIN projects p ON t.project_id = p.id
763
773
  WHERE p.name = ${projectName} AND t.seq = ${seq2}
@@ -1702,7 +1712,7 @@ Stopped following`),process.exit(0)}),await new Promise(()=>{});return}let conte
1702
1712
  processed_bytes = ${progress.processedBytes},
1703
1713
  errors = ${progress.errors},
1704
1714
  updated_at = now()
1705
- `}async function shouldSkipBackfill(sql){try{let existing=await sql`SELECT status FROM session_sync WHERE id = 'backfill'`;if(existing.length>0&&existing[0].status==="complete")return!0}catch{}try{let[{count}]=await sql`SELECT count(*)::int as count FROM sessions`;if(count>0){let existing=await sql`SELECT status FROM session_sync WHERE id = 'backfill'`;if(existing.length===0||existing[0].status==="complete")return!0}}catch{return!0}return!1}async function yieldToLiveWork(){while(liveWorkPending)await sleep2(LIVE_YIELD_POLL_MS)}async function getFileStartOffset(sql,file){let existing=await sql`SELECT last_ingested_offset FROM sessions WHERE id = ${file.sessionId}`;if(existing.length>0)return existing[0].last_ingested_offset??0;return 0}async function processBackfillFile(sql,file,progress,workerMap){let offset=await getFileStartOffset(sql,file);if(offset>=file.fileSize){progress.processedFiles++,progress.processedBytes+=file.fileSize;return}let currentOffset=offset;while(currentOffset<file.fileSize){await yieldToLiveWork();let result2=await ingestFile(sql,file.sessionId,file.jsonlPath,file.projectPath,currentOffset,{chunkSize:CHUNK_SIZE,parentSessionId:file.parentSessionId,isSubagent:file.isSubagent,fileSize:file.fileSize,mtime:file.mtime,workerMap});if(result2.newOffset<=currentOffset)break;progress.processedBytes+=result2.newOffset-currentOffset,currentOffset=result2.newOffset}progress.processedFiles++}async function processAllFiles(sql,allFiles,progress,workerMap){for(let file of allFiles){if(!running)break;await yieldToLiveWork();try{await processBackfillFile(sql,file,progress,workerMap)}catch(err){progress.errors++;let message=err instanceof Error?err.message:String(err);console.error(`[backfill] error on ${file.jsonlPath}: ${message}`)}if(progress.processedFiles%50===0)await updateSyncState(sql,progress);await sleep2(SLEEP_BETWEEN_FILES_MS)}}function resolveBackfillStatus(progress){if(!running)progress.status="paused",console.log(`[backfill] paused: ${progress.processedFiles}/${progress.totalFiles} files (will resume on next daemon start)`);else if(progress.errors>0&&progress.errors>=progress.totalFiles)progress.status="failed",console.error(`[backfill] failed: ${progress.errors}/${progress.totalFiles} files errored \u2014 will retry on next daemon start`);else progress.status="complete",console.log(`[backfill] complete: ${progress.processedFiles}/${progress.totalFiles} files, ${progress.errors} errors`)}async function startBackfill(sql){if(running)return;if(await shouldSkipBackfill(sql))return;running=!0,console.log("[backfill] starting session backfill...");try{let allFiles=await discoverAllJsonlFiles();allFiles.sort((a,b2)=>b2.mtime-a.mtime);let totalBytes=allFiles.reduce((sum,f)=>sum+f.fileSize,0),progress={totalFiles:allFiles.length,processedFiles:0,totalBytes,processedBytes:0,errors:0,status:"running"};await updateSyncState(sql,progress),console.log(`[backfill] discovered ${allFiles.length} files (${(totalBytes/1024/1024).toFixed(1)} MB)`);let workerMap=await buildWorkerMap(sql);await processAllFiles(sql,allFiles,progress,workerMap),resolveBackfillStatus(progress),await updateSyncState(sql,progress)}catch(err){let message=err instanceof Error?err.message:String(err);console.error(`[backfill] fatal error: ${message}`)}finally{running=!1}}function stopBackfill(){running=!1}async function getBackfillStatus(sql){try{let rows=await sql`SELECT * FROM session_sync WHERE id = 'backfill'`;if(rows.length===0)return null;let row=rows[0];return{totalFiles:row.total_files,processedFiles:row.processed_files,totalBytes:row.total_bytes,processedBytes:row.processed_bytes,errors:row.errors,status:row.status}}catch{return null}}var CHUNK_SIZE=65536,SLEEP_BETWEEN_FILES_MS=100,LIVE_YIELD_POLL_MS=200,running=!1;var init_session_backfill=__esm(()=>{init_session_capture()});var exports_scheduler_daemon={};__export(exports_scheduler_daemon,{startDaemon:()=>startDaemon,recoverOnStartup:()=>recoverOnStartup,reconcileOrphans:()=>reconcileOrphans,reconcileOrphanedRuns:()=>reconcileOrphanedRuns,reclaimExpiredLeases:()=>reclaimExpiredLeases,logToFile:()=>logToFile,fireTrigger:()=>fireTrigger,emitWorkerEvents:()=>emitWorkerEvents,collectMachineSnapshot:()=>collectMachineSnapshot,collectHeartbeats:()=>collectHeartbeats,claimDueTriggers:()=>claimDueTriggers,attemptAgentResume:()=>attemptAgentResume,_resetWorkerStatesForTesting:()=>_resetWorkerStatesForTesting});import{randomUUID as randomUUID8}from"crypto";import{appendFileSync as appendFileSync2,mkdirSync as mkdirSync10}from"fs";import{homedir as homedir23}from"os";import{join as join35}from"path";function getLogDir2(){return join35(process.env.GENIE_HOME??join35(homedir23(),".genie"),"logs")}function getLogFile(){return join35(getLogDir2(),"scheduler.log")}function logToFile(entry){let logDir=getLogDir2();mkdirSync10(logDir,{recursive:!0}),appendFileSync2(getLogFile(),`${JSON.stringify(entry)}
1715
+ `}async function shouldSkipBackfill(sql){try{let existing=await sql`SELECT status FROM session_sync WHERE id = 'backfill'`;if(existing.length>0&&existing[0].status==="complete")return!0}catch{}try{let[{count}]=await sql`SELECT count(*)::int as count FROM sessions`;if(count>0){let existing=await sql`SELECT status FROM session_sync WHERE id = 'backfill'`;if(existing.length===0||existing[0].status==="complete")return!0}}catch{return!0}return!1}async function yieldToLiveWork(){while(liveWorkPending)await sleep2(LIVE_YIELD_POLL_MS)}async function getFileStartOffset(sql,file){let existing=await sql`SELECT last_ingested_offset FROM sessions WHERE id = ${file.sessionId}`;if(existing.length>0)return existing[0].last_ingested_offset??0;return 0}async function processBackfillFile(sql,file,progress,workerMap){let offset=await getFileStartOffset(sql,file);if(offset>=file.fileSize){progress.processedFiles++,progress.processedBytes+=file.fileSize;return}let currentOffset=offset;while(currentOffset<file.fileSize){await yieldToLiveWork();let result2=await ingestFile(sql,file.sessionId,file.jsonlPath,file.projectPath,currentOffset,{chunkSize:CHUNK_SIZE,parentSessionId:file.parentSessionId,isSubagent:file.isSubagent,fileSize:file.fileSize,mtime:file.mtime,workerMap});if(result2.newOffset<=currentOffset)break;progress.processedBytes+=result2.newOffset-currentOffset,currentOffset=result2.newOffset}progress.processedFiles++}async function processAllFiles(sql,allFiles,progress,workerMap){for(let file of allFiles){if(!running)break;await yieldToLiveWork();try{await processBackfillFile(sql,file,progress,workerMap)}catch(err){progress.errors++;let message=err instanceof Error?err.message:String(err);console.error(`[backfill] error on ${file.jsonlPath}: ${message}`)}if(progress.processedFiles%50===0)await updateSyncState(sql,progress);await sleep2(SLEEP_BETWEEN_FILES_MS)}}function resolveBackfillStatus(progress){if(!running)progress.status="paused",console.log(`[backfill] paused: ${progress.processedFiles}/${progress.totalFiles} files (will resume on next daemon start)`);else if(progress.errors>0&&progress.errors>=progress.totalFiles)progress.status="failed",console.error(`[backfill] failed: ${progress.errors}/${progress.totalFiles} files errored \u2014 will retry on next daemon start`);else progress.status="complete",console.log(`[backfill] complete: ${progress.processedFiles}/${progress.totalFiles} files, ${progress.errors} errors`)}async function startBackfill(sql){if(running)return;if(await shouldSkipBackfill(sql))return;running=!0,console.log("[backfill] starting session backfill...");try{let allFiles=await discoverAllJsonlFiles();allFiles.sort((a,b2)=>b2.mtime-a.mtime);let totalBytes=allFiles.reduce((sum,f)=>sum+f.fileSize,0),progress={totalFiles:allFiles.length,processedFiles:0,totalBytes,processedBytes:0,errors:0,status:"running"};await updateSyncState(sql,progress),console.log(`[backfill] discovered ${allFiles.length} files (${(totalBytes/1024/1024).toFixed(1)} MB)`);let workerMap=await buildWorkerMap(sql);await processAllFiles(sql,allFiles,progress,workerMap),resolveBackfillStatus(progress),await updateSyncState(sql,progress)}catch(err){let message=err instanceof Error?err.message:String(err);console.error(`[backfill] fatal error: ${message}`)}finally{running=!1}}function stopBackfill(){running=!1}async function getBackfillStatus(sql){try{let rows=await sql`SELECT * FROM session_sync WHERE id = 'backfill'`;if(rows.length===0)return null;let row=rows[0];return{totalFiles:row.total_files,processedFiles:row.processed_files,totalBytes:row.total_bytes,processedBytes:row.processed_bytes,errors:row.errors,status:row.status}}catch{return null}}var CHUNK_SIZE=65536,SLEEP_BETWEEN_FILES_MS=100,LIVE_YIELD_POLL_MS=200,running=!1;var init_session_backfill=__esm(()=>{init_session_capture()});var exports_scheduler_daemon={};__export(exports_scheduler_daemon,{startDaemon:()=>startDaemon,runAgentRecoveryPass:()=>runAgentRecoveryPass,recoverOnStartup:()=>recoverOnStartup,reconcileOrphans:()=>reconcileOrphans,reconcileOrphanedRuns:()=>reconcileOrphanedRuns,reclaimExpiredLeases:()=>reclaimExpiredLeases,logToFile:()=>logToFile,fireTrigger:()=>fireTrigger,emitWorkerEvents:()=>emitWorkerEvents,collectMachineSnapshot:()=>collectMachineSnapshot,collectHeartbeats:()=>collectHeartbeats,claimDueTriggers:()=>claimDueTriggers,attemptAgentResume:()=>attemptAgentResume,_resetWorkerStatesForTesting:()=>_resetWorkerStatesForTesting});import{randomUUID as randomUUID8}from"crypto";import{appendFileSync as appendFileSync2,mkdirSync as mkdirSync10}from"fs";import{homedir as homedir23}from"os";import{join as join35}from"path";function getLogDir2(){return join35(process.env.GENIE_HOME??join35(homedir23(),".genie"),"logs")}function getLogFile(){return join35(getLogDir2(),"scheduler.log")}function logToFile(entry){let logDir=getLogDir2();mkdirSync10(logDir,{recursive:!0}),appendFileSync2(getLogFile(),`${JSON.stringify(entry)}
1706
1716
  `)}async function defaultSpawnCommand(command,env){return{pid:Bun.spawn(["sh","-c",command],{env:{...process.env,...env},stdio:["ignore","ignore","ignore"]}).pid}}function defaultJitter(maxMs){return Math.floor(Math.random()*maxMs)}function defaultSleep(ms){return new Promise((resolve5)=>setTimeout(resolve5,ms))}async function defaultIsPaneAlive(paneId){let{isPaneAlive:isPaneAlive2}=await Promise.resolve().then(() => (init_tmux(),exports_tmux));return isPaneAlive2(paneId)}async function defaultListWorkers(){let{list:list2}=await Promise.resolve().then(() => (init_agent_registry(),exports_agent_registry));return(await list2()).map((a)=>({id:a.id,paneId:a.paneId,repoPath:a.repoPath,state:a.state,team:a.team,wishSlug:a.wishSlug,groupNumber:a.groupNumber,autoResume:a.autoResume,resumeAttempts:a.resumeAttempts,maxResumeAttempts:a.maxResumeAttempts,lastResumeAttempt:a.lastResumeAttempt,claudeSessionId:a.claudeSessionId}))}async function defaultPublishEvent(subject,data,repoPath){let payload=data,{publishSubjectEvent:publishSubjectEvent2}=await Promise.resolve().then(() => (init_runtime_events(),exports_runtime_events));await publishSubjectEvent2(repoPath,subject,{timestamp:payload.timestamp,kind:payload.kind??"system",agent:payload.agent??"scheduler",team:payload.team,direction:payload.direction,peer:payload.peer,text:payload.text??subject,data:payload.data,source:payload.source??"registry"})}async function defaultCountTmuxSessions(){try{let{execSync:execSync9}=await import("child_process"),{genieTmuxCmd:genieTmuxCmd2}=await Promise.resolve().then(() => (init_tmux_wrapper(),exports_tmux_wrapper));return execSync9(`${genieTmuxCmd2("list-sessions")} 2>/dev/null`,{encoding:"utf-8"}).trim().split(`
1707
1717
  `).filter(Boolean).length}catch{return 0}}async function defaultResumeAgent(agentId){try{let{execSync:execSync9}=await import("child_process");return execSync9(`genie agent resume ${agentId}`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}),!0}catch{return!1}}async function defaultUpdateAgent(agentId,updates){let{update:update2}=await Promise.resolve().then(() => (init_agent_registry(),exports_agent_registry));await update2(agentId,updates)}function createDefaultDeps(){return{getConnection:async()=>{let{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db));return getConnection2()},spawnCommand:defaultSpawnCommand,log:logToFile,generateId:randomUUID8,now:()=>new Date,sleep:defaultSleep,jitter:defaultJitter,isPaneAlive:defaultIsPaneAlive,listWorkers:defaultListWorkers,countTmuxSessions:defaultCountTmuxSessions,publishEvent:defaultPublishEvent,resumeAgent:defaultResumeAgent,updateAgent:defaultUpdateAgent}}function resolveConfig(overrides){let envMax=process.env.GENIE_MAX_CONCURRENT,maxConcurrent=envMax?Number.parseInt(envMax,10):5;return{maxConcurrent:overrides?.maxConcurrent??(Number.isNaN(maxConcurrent)?5:maxConcurrent),pollIntervalMs:overrides?.pollIntervalMs??30000,maxJitterMs:overrides?.maxJitterMs??30000,jitterThreshold:overrides?.jitterThreshold??3,heartbeatIntervalMs:overrides?.heartbeatIntervalMs??60000,orphanCheckIntervalMs:overrides?.orphanCheckIntervalMs??300000,deadHeartbeatThreshold:overrides?.deadHeartbeatThreshold??2,leaseRecoveryIntervalMs:overrides?.leaseRecoveryIntervalMs??60000}}async function claimDueTriggers(deps,config,daemonId){let sql=await deps.getConnection(),now=deps.now(),leaseUntil=new Date(now.getTime()+300000),runningCount=(await sql`
1708
1718
  SELECT count(*)::int AS cnt FROM runs
@@ -1752,7 +1762,7 @@ Stopped following`),process.exit(0)}),await new Promise(()=>{});return}let conte
1752
1762
  `,await sql`
1753
1763
  UPDATE triggers SET status = 'failed', completed_at = ${now}
1754
1764
  WHERE id = ${run.trigger_id} AND status = 'executing'
1755
- `,orphanCount++}if(orphanCount>0)deps.log({timestamp:now.toISOString(),level:"info",event:"orphaned_runs_reconciled",count:orphanCount,daemon_id:daemonId});return orphanCount}async function recoverOnStartup(deps,daemonId,config){let now=deps.now();deps.log({timestamp:now.toISOString(),level:"info",event:"recovery_started",daemon_id:daemonId});let reclaimed=await reclaimExpiredLeases(deps,daemonId),orphans=await reconcileOrphanedRuns(deps,daemonId),{resumed,failed}=await runAgentRecoveryPass(deps,daemonId,config);if(deps.log({timestamp:deps.now().toISOString(),level:"info",event:"recovery_completed",reclaimed_leases:reclaimed,orphaned_runs:orphans,resumed_agents:resumed,failed_agents:failed,daemon_id:daemonId}),failed>0)deps.log({timestamp:deps.now().toISOString(),level:"info",event:"recovery_retry_scheduled",daemon_id:daemonId,failed_agents:failed,delay_ms:RECOVERY_RETRY_DELAY_MS}),scheduleRecoveryRetry(deps,daemonId,config)}function scheduleRecoveryRetry(deps,daemonId,config){setTimeout(async()=>{try{let retry=await runAgentRecoveryPass(deps,daemonId,config);deps.log({timestamp:deps.now().toISOString(),level:"info",event:"recovery_retry_completed",daemon_id:daemonId,resumed_agents:retry.resumed,failed_agents:retry.failed})}catch(err){let message=err instanceof Error?err.message:String(err);deps.log({timestamp:deps.now().toISOString(),level:"error",event:"recovery_retry_error",daemon_id:daemonId,error:message})}},RECOVERY_RETRY_DELAY_MS).unref?.()}async function runAgentRecoveryPass(deps,daemonId,config){let resolvedConfig=config??resolveConfig(),resumable=(await deps.listWorkers()).filter((w)=>w.state!=="suspended"&&w.state!=="done"&&w.claudeSessionId),resumed=0,failed=0;for(let worker of resumable)try{if(!await deps.isPaneAlive(worker.paneId)){if(await attemptAgentResume(deps,resolvedConfig,worker)==="resumed")resumed++}}catch(err){failed++;let message=err instanceof Error?err.message:String(err);deps.log({timestamp:deps.now().toISOString(),level:"warn",event:"recovery_worker_failed",daemon_id:daemonId,worker_id:worker.id,error:message})}return{resumed,failed}}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";if(!agent.claudeSessionId)return deps.log({timestamp:now.toISOString(),level:"debug",event:"agent_resume_skipped",agent_id:agentId,reason:"no_session_id"}),"skipped";let maxAttempts=agent.maxResumeAttempts??DEFAULT_MAX_RESUME_ATTEMPTS,attempts=agent.resumeAttempts??0;if(attempts>=maxAttempts)return 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 activeCount=(await deps.listWorkers()).filter((w)=>!["done","error","suspended","spawning"].includes(w.state)).length;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;if(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}),await deps.resumeAgent(agentId))return deps.log({timestamp:now.toISOString(),level:"info",event:"agent_resume_succeeded",agent_id:agentId,resume_attempts:newAttempts}),"resumed";if(deps.log({timestamp:now.toISOString(),level:"warn",event:"agent_resume_failed",agent_id:agentId,resume_attempts:newAttempts,max_resume_attempts:maxAttempts}),newAttempts>=maxAttempts)return 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`
1765
+ `,orphanCount++}if(orphanCount>0)deps.log({timestamp:now.toISOString(),level:"info",event:"orphaned_runs_reconciled",count:orphanCount,daemon_id:daemonId});return orphanCount}async function recoverOnStartup(deps,daemonId,config){let now=deps.now();deps.log({timestamp:now.toISOString(),level:"info",event:"recovery_started",daemon_id:daemonId});let reclaimed=await reclaimExpiredLeases(deps,daemonId),orphans=await reconcileOrphanedRuns(deps,daemonId),{resumed,failed}=await runAgentRecoveryPass(deps,daemonId,config);if(deps.log({timestamp:deps.now().toISOString(),level:"info",event:"recovery_completed",reclaimed_leases:reclaimed,orphaned_runs:orphans,resumed_agents:resumed,failed_agents:failed,daemon_id:daemonId}),failed>0)deps.log({timestamp:deps.now().toISOString(),level:"info",event:"recovery_retry_scheduled",daemon_id:daemonId,failed_agents:failed,delay_ms:RECOVERY_RETRY_DELAY_MS}),scheduleRecoveryRetry(deps,daemonId,config)}function scheduleRecoveryRetry(deps,daemonId,config){setTimeout(async()=>{try{let retry=await runAgentRecoveryPass(deps,daemonId,config);deps.log({timestamp:deps.now().toISOString(),level:"info",event:"recovery_retry_completed",daemon_id:daemonId,resumed_agents:retry.resumed,failed_agents:retry.failed})}catch(err){let message=err instanceof Error?err.message:String(err);deps.log({timestamp:deps.now().toISOString(),level:"error",event:"recovery_retry_error",daemon_id:daemonId,error:message})}},RECOVERY_RETRY_DELAY_MS).unref?.()}async function runAgentRecoveryPass(deps,daemonId,config){let resolvedConfig=config??resolveConfig(),resumable=(await deps.listWorkers()).filter((w)=>w.state!=="suspended"&&w.state!=="done"&&w.claudeSessionId),resumed=0,failed=0;for(let worker of resumable)try{if(!await deps.isPaneAlive(worker.paneId)){if(await attemptAgentResume(deps,resolvedConfig,worker)==="resumed")resumed++}}catch(err){failed++;let message=err instanceof Error?err.message:String(err);deps.log({timestamp:deps.now().toISOString(),level:"warn",event:"recovery_worker_failed",daemon_id:daemonId,worker_id:worker.id,error:message})}return{resumed,failed}}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}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";if(!agent.claudeSessionId)return deps.log({timestamp:now.toISOString(),level:"debug",event:"agent_resume_skipped",agent_id:agentId,reason:"no_session_id"}),"skipped";let maxAttempts=agent.maxResumeAttempts??DEFAULT_MAX_RESUME_ATTEMPTS,attempts=agent.resumeAttempts??0;if(attempts>=maxAttempts)return 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;if(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}),await deps.resumeAgent(agentId))return deps.log({timestamp:now.toISOString(),level:"info",event:"agent_resume_succeeded",agent_id:agentId,resume_attempts:newAttempts}),"resumed";if(deps.log({timestamp:now.toISOString(),level:"warn",event:"agent_resume_failed",agent_id:agentId,resume_attempts:newAttempts,max_resume_attempts:maxAttempts}),newAttempts>=maxAttempts)return 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`
1756
1766
  SELECT id, worker_id, status, trigger_id FROM runs WHERE status = 'running'
1757
1767
  `,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`
1758
1768
  INSERT INTO heartbeats (id, worker_id, run_id, status, context, last_seen_at, created_at)
@@ -1773,7 +1783,7 @@ Stopped following`),process.exit(0)}),await new Promise(()=>{});return}let conte
1773
1783
  `,failedCount++,deps.log({timestamp:now.toISOString(),level:"warn",event:"orphan_run_failed",run_id:run.id,worker_id:run.worker_id,dead_heartbeats:threshold})}if(failedCount>0)deps.log({timestamp:now.toISOString(),level:"info",event:"orphan_reconciliation_completed",failed_count:failedCount});return failedCount}async function collectMachineSnapshot(deps){let sql=await deps.getConnection(),now=deps.now(),snapshotId=deps.generateId(),workers=await deps.listWorkers(),activeWorkers=workers.filter((w)=>!["done","error","suspended"].includes(w.state)).length,teams=new Set(workers.filter((w)=>w.team).map((w)=>w.team)),tmuxSessions=await deps.countTmuxSessions(),cpuPercent=null,memoryMb=null;try{let mem=process.memoryUsage();memoryMb=Math.round(mem.rss/1024/1024)}catch{}try{let cpus=(await import("os")).cpus();if(cpus.length>0){let total=cpus.reduce((acc,cpu)=>{let t=Object.values(cpu.times).reduce((a,b2)=>a+b2,0);return acc+t-cpu.times.idle},0),totalAll=cpus.reduce((acc,cpu)=>acc+Object.values(cpu.times).reduce((a,b2)=>a+b2,0),0);cpuPercent=totalAll>0?Math.round(total/totalAll*100):null}}catch{}await sql`
1774
1784
  INSERT INTO machine_snapshots (id, active_workers, active_teams, tmux_sessions, cpu_percent, memory_mb, created_at)
1775
1785
  VALUES (${snapshotId}, ${activeWorkers}, ${teams.size}, ${tmuxSessions}, ${cpuPercent}, ${memoryMb}, ${now})
1776
- `,deps.log({timestamp:now.toISOString(),level:"debug",event:"machine_snapshot",active_workers:activeWorkers,active_teams:teams.size,tmux_sessions:tmuxSessions,cpu_percent:cpuPercent,memory_mb:memoryMb})}async function emitWorkerEvents(deps){let workers=await deps.listWorkers(),now=deps.now().toISOString(),currentIds=new Set;for(let worker of workers){currentIds.add(worker.id);let prev=previousWorkerStates.get(worker.id),repoPath=worker.repoPath??process.cwd();if(!prev)await deps.publishEvent(`genie.agent.${worker.id}.spawned`,{timestamp:now,kind:"state",agent:worker.id,team:worker.team,text:`Agent ${worker.id} spawned`,data:{state:worker.state},source:"registry"},repoPath);else if(prev.state!==worker.state){if(await deps.publishEvent(`genie.agent.${worker.id}.state`,{timestamp:now,kind:"state",agent:worker.id,team:worker.team,text:`Agent ${worker.id} state: ${prev.state} \u2192 ${worker.state}`,data:{previousState:prev.state,state:worker.state},source:"registry"},repoPath),worker.state==="done"&&worker.wishSlug&&worker.groupNumber!=null)await deps.publishEvent(`genie.wish.${worker.wishSlug}.group.${worker.groupNumber}.done`,{timestamp:now,kind:"system",agent:worker.id,team:worker.team,text:`Wish ${worker.wishSlug} group ${worker.groupNumber} completed by ${worker.id}`,data:{wishSlug:worker.wishSlug,groupNumber:worker.groupNumber},source:"registry"},repoPath)}previousWorkerStates.set(worker.id,{...worker})}for(let[id,prev]of previousWorkerStates)if(!currentIds.has(id))await deps.publishEvent(`genie.agent.${id}.killed`,{timestamp:now,kind:"state",agent:id,team:prev.team,text:`Agent ${id} killed`,data:{lastState:prev.state},source:"registry"},prev.repoPath??process.cwd()),previousWorkerStates.delete(id)}function _resetWorkerStatesForTesting(){previousWorkerStates.clear()}function startInboxWatcherIfEnabled(deps){let pollMs=getInboxPollIntervalMs();if(pollMs===0)return deps.log({timestamp:deps.now().toISOString(),level:"info",event:"inbox_watcher_disabled"}),null;return deps.log({timestamp:deps.now().toISOString(),level:"info",event:"inbox_watcher_started",poll_interval_ms:pollMs}),startInboxWatcher()}function startDaemon(configOverrides,depsOverrides){let config=resolveConfig(configOverrides),deps={...createDefaultDeps(),...depsOverrides},daemonId=deps.generateId(),running2=!0,pollTimeout=null,pollResolve=null,listenConnection=null,heartbeatTimer=null,orphanTimer=null,leaseRecoveryTimer=null,inboxWatcherHandle=null,captureFallbackTimer=null,eventRouterHandle=null,deliveryUnsub=null,deliveryRetryTimer=null,stop=()=>{if(running2=!1,pollTimeout)clearTimeout(pollTimeout),pollTimeout=null;if(pollResolve)pollResolve(),pollResolve=null;if(heartbeatTimer)clearInterval(heartbeatTimer),heartbeatTimer=null;if(orphanTimer)clearInterval(orphanTimer),orphanTimer=null;if(leaseRecoveryTimer)clearInterval(leaseRecoveryTimer),leaseRecoveryTimer=null;if(inboxWatcherHandle)stopInboxWatcher(inboxWatcherHandle),inboxWatcherHandle=null;if(listenConnection)listenConnection.end().catch(()=>{}),listenConnection=null;if(captureFallbackTimer)clearInterval(captureFallbackTimer),captureFallbackTimer=null;if(eventRouterHandle?.stop().catch(()=>{}),eventRouterHandle=null,deliveryRetryTimer)clearInterval(deliveryRetryTimer),deliveryRetryTimer=null;if(deliveryUnsub)deliveryUnsub().catch(()=>{}),deliveryUnsub=null;Promise.resolve().then(() => (init_session_filewatch(),exports_session_filewatch)).then((m)=>m.stopFilewatch()).catch(()=>{}),Promise.resolve().then(() => (init_session_backfill(),exports_session_backfill)).then((m)=>m.stopBackfill()).catch(()=>{}),Promise.resolve().then(() => (init_db(),exports_db)).then(({getLockfilePath:getLockfilePath2})=>{try{__require("fs").unlinkSync(getLockfilePath2())}catch{}}).catch(()=>{})},processTriggers=async()=>{try{let claimed=await claimDueTriggers(deps,config,daemonId);if(claimed.length===0)return;if(claimed.length>config.jitterThreshold){let jitterMs=deps.jitter(config.maxJitterMs);deps.log({timestamp:deps.now().toISOString(),level:"info",event:"jitter_applied",count:claimed.length,jitter_ms:jitterMs}),await deps.sleep(jitterMs)}for(let trigger of claimed){if(!running2)break;await fireTrigger(deps,trigger,daemonId)}}catch(err){let message=err instanceof Error?err.message:String(err);deps.log({timestamp:deps.now().toISOString(),level:"error",event:"process_cycle_error",error:message})}};async function setupListenNotify(d,onTrigger){try{let sql=await d.getConnection();return await sql.listen("genie_trigger_due",async()=>{if(!running2)return;await onTrigger()}),d.log({timestamp:d.now().toISOString(),level:"info",event:"listen_started",channel:"genie_trigger_due"}),sql}catch(err){let message=err instanceof Error?err.message:String(err);return d.log({timestamp:d.now().toISOString(),level:"warn",event:"listen_failed",error:message}),null}}function startLeaseRecoveryTimer(d,cfg,dId){return setInterval(async()=>{if(!running2)return;try{await reclaimExpiredLeases(d,dId)}catch(err){let message=err instanceof Error?err.message:String(err);d.log({timestamp:d.now().toISOString(),level:"error",event:"lease_recovery_error",error:message})}},cfg.leaseRecoveryIntervalMs)}function startOrphanTimer(d,cfg){return setInterval(async()=>{if(!running2)return;try{await reconcileOrphans(d,cfg)}catch(err){let message=err instanceof Error?err.message:String(err);d.log({timestamp:d.now().toISOString(),level:"error",event:"orphan_reconciliation_error",error:message})}},cfg.orphanCheckIntervalMs)}async function startEventRouterSafe(d){try{let handle=await startEventRouter();return d.log({timestamp:d.now().toISOString(),level:"info",event:"event_router_started"}),handle}catch(err){let message=err instanceof Error?err.message:String(err);return d.log({timestamp:d.now().toISOString(),level:"warn",event:"event_router_start_failed",error:message}),null}}async function initSessionCapture(d,cfg){try{let captureSql=await d.getConnection(),{startFilewatch:startFilewatch2}=await Promise.resolve().then(() => (init_session_filewatch(),exports_session_filewatch)),{startBackfill:startBackfill2}=await Promise.resolve().then(() => (init_session_backfill(),exports_session_backfill));if(!await startFilewatch2(captureSql)){let{ingestFileFull:ingestFileFull2,discoverAllJsonlFiles:discoverAllJsonlFiles2,buildWorkerMap:buildWorkerMap2}=await Promise.resolve().then(() => (init_session_capture(),exports_session_capture));d.log({timestamp:d.now().toISOString(),level:"warn",event:"filewatch_failed_fallback_polling"});let timer2=setInterval(async()=>{if(!running2)return;try{let files=await discoverAllJsonlFiles2(),workerMap=await buildWorkerMap2(captureSql);for(let f of files)await ingestFileFull2(captureSql,f.sessionId,f.jsonlPath,f.projectPath,0,{parentSessionId:f.parentSessionId,isSubagent:f.isSubagent,workerMap})}catch{}},cfg.heartbeatIntervalMs);return startBackfill2(captureSql).catch((err)=>{let msg=err instanceof Error?err.message:String(err);d.log({timestamp:d.now().toISOString(),level:"error",event:"backfill_error",error:msg})}),timer2}return startBackfill2(captureSql).catch((err)=>{let msg=err instanceof Error?err.message:String(err);d.log({timestamp:d.now().toISOString(),level:"error",event:"backfill_error",error:msg})}),null}catch(err){let message=err instanceof Error?err.message:String(err);return d.log({timestamp:d.now().toISOString(),level:"warn",event:"session_capture_init_failed",error:message}),null}}async function runHeartbeat(d){if(!running2)return;try{await collectHeartbeats(d),await collectMachineSnapshot(d),await emitWorkerEvents(d);try{let retSql=await d.getConnection();await retSql`DELETE FROM heartbeats WHERE created_at < now() - interval '7 days'`,await retSql`DELETE FROM machine_snapshots WHERE created_at < now() - interval '30 days'`,await retSql`DELETE FROM audit_events WHERE entity_type LIKE 'otel_%' AND created_at < now() - interval '30 days'`}catch{}}catch(err){let message=err instanceof Error?err.message:String(err);d.log({timestamp:d.now().toISOString(),level:"error",event:"heartbeat_error",error:message})}}let done=(async()=>{deps.log({timestamp:deps.now().toISOString(),level:"info",event:"daemon_started",daemon_id:daemonId,max_concurrent:config.maxConcurrent,poll_interval_ms:config.pollIntervalMs});try{await recoverOnStartup(deps,daemonId,config)}catch(err){let message=err instanceof Error?err.message:String(err);deps.log({timestamp:deps.now().toISOString(),level:"error",event:"recovery_error",error:message})}listenConnection=await setupListenNotify(deps,processTriggers),heartbeatTimer=setInterval(()=>runHeartbeat(deps),config.heartbeatIntervalMs),orphanTimer=startOrphanTimer(deps,config),leaseRecoveryTimer=startLeaseRecoveryTimer(deps,config,daemonId),inboxWatcherHandle=startInboxWatcherIfEnabled(deps),eventRouterHandle=await startEventRouterSafe(deps);try{deliveryUnsub=await subscribeDelivery(async(toWorker,messageId)=>{try{let{deliverToPane:deliverToPane2}=await Promise.resolve().then(() => (init_protocol_router(),exports_protocol_router));await deliverToPane2(toWorker,messageId)}catch{}}),deps.log({timestamp:deps.now().toISOString(),level:"info",event:"mailbox_delivery_listen_started"})}catch{}let MAX_DELIVERY_ATTEMPTS=3;deliveryRetryTimer=setInterval(async()=>{try{let retryable=await getRetryable(MAX_DELIVERY_ATTEMPTS);for(let msg of retryable)try{let{deliverToPane:deliverToPane2}=await Promise.resolve().then(() => (init_protocol_router(),exports_protocol_router));if(await deliverToPane2(msg.to,msg.id)){deps.log({timestamp:deps.now().toISOString(),level:"info",event:"mailbox_delivery_retried",messageId:msg.id,to:msg.to});continue}let rows=await(await deps.getConnection())`SELECT delivery_attempts, repo_path FROM mailbox WHERE id = ${msg.id} LIMIT 1`,attempts=rows[0]?.delivery_attempts??0;if(attempts>=MAX_DELIVERY_ATTEMPTS){await markEscalated(msg.id);let repoPath=rows[0]?.repo_path;if(repoPath){let{send:send2}=await Promise.resolve().then(() => (init_mailbox(),exports_mailbox));await send2(repoPath,"scheduler","team-lead",`[escalation] Message ${msg.id} from "${msg.from}" to "${msg.to}" failed delivery after ${MAX_DELIVERY_ATTEMPTS} attempts. Body: "${msg.body.slice(0,200)}"`)}deps.log({timestamp:deps.now().toISOString(),level:"warn",event:"mailbox_delivery_escalated",messageId:msg.id,to:msg.to,attempts})}}catch{}}catch(err){let message=err instanceof Error?err.message:String(err);deps.log({timestamp:deps.now().toISOString(),level:"error",event:"mailbox_retry_error",error:message})}},60000),captureFallbackTimer=await initSessionCapture(deps,config),await processTriggers();while(running2){if(await new Promise((resolve5)=>{pollResolve=resolve5,pollTimeout=setTimeout(resolve5,config.pollIntervalMs)}),pollResolve=null,!running2)break;await processTriggers()}deps.log({timestamp:deps.now().toISOString(),level:"info",event:"daemon_stopped",daemon_id:daemonId})})();return{stop,done,daemonId}}var RECOVERY_RETRY_DELAY_MS=60000,RESUME_COOLDOWN_MS=60000,DEFAULT_MAX_RESUME_ATTEMPTS=3,previousWorkerStates;var init_scheduler_daemon=__esm(()=>{init_cron();init_event_router();init_inbox_watcher();init_mailbox();init_run_spec();previousWorkerStates=new Map});var exports_omni_approval_handler={};__export(exports_omni_approval_handler,{startOmniApprovalHandler:()=>startOmniApprovalHandler});class OmniApprovalHandler{nc=null;subs=[];sc=import_nats2.StringCodec();permissions;natsUrl;approveTokens;denyTokens;constructor(config){this.permissions=config.permissions,this.natsUrl=config.natsUrl??"localhost:4222",this.approveTokens=(config.permissions.approveTokens??DEFAULT_APPROVE_TOKENS).map((t)=>t.toLowerCase()),this.denyTokens=(config.permissions.denyTokens??DEFAULT_DENY_TOKENS).map((t)=>t.toLowerCase())}async start(){let{omniChat,omniInstance}=this.permissions;if(!omniChat||!omniInstance)return;this.nc=await import_nats2.connect({servers:this.natsUrl});let messageTopic=`omni.message.${omniInstance}.>`,msgSub=this.nc.subscribe(messageTopic);this.subs.push(msgSub),this.processMessages(msgSub);let eventSub=this.nc.subscribe("omni.event.>");this.subs.push(eventSub),this.processEvents(eventSub),handlerInstance=this,console.log(`[omni-approval] Listening for approval replies on ${messageTopic}`)}async stop(){for(let sub of this.subs)sub.unsubscribe();if(this.subs=[],this.nc)await this.nc.close(),this.nc=null;if(handlerInstance===this)handlerInstance=null}async processMessages(sub){for await(let msg of sub)try{let data=JSON.parse(this.sc.decode(msg.data));if((data.chatId??this.extractChatIdFromSubject(msg.subject))!==this.permissions.omniChat)continue;if(data.content)await this.handleTextReply(data.content,data.sender??"whatsapp-user")}catch{}}async processEvents(sub){for await(let msg of sub)try{let data=JSON.parse(this.sc.decode(msg.data));if(data.type!=="reaction")continue;if(data.chatId!==this.permissions.omniChat||data.instanceId!==this.permissions.omniInstance)continue;if(data.emoji&&data.messageId)await this.handleReaction(data.emoji,data.messageId,data.sender??"whatsapp-user")}catch{}}extractChatIdFromSubject(subject){let parts=subject.split(".");if(parts.length>=4)return parts.slice(3).join(".");return}async handleTextReply(content,sender){let normalized=content.trim().toLowerCase();if(!normalized)return!1;let decision=null;if(this.approveTokens.includes(normalized))decision="allow";else if(this.denyTokens.includes(normalized))decision="deny";if(!decision)return!1;let pending=await listPendingApprovals();if(pending.length===0)return!1;let oldest=pending[0],resolved=await resolveApproval(oldest.id,decision,sender);if(resolved)console.log(`[omni-approval] Resolved ${oldest.id} as ${decision} by ${sender} (text: "${normalized}")`);return resolved}async handleReaction(emoji,messageId,sender){let decision=null;if(DEFAULT_APPROVE_REACTIONS.includes(emoji))decision="allow";else if(DEFAULT_DENY_REACTIONS.includes(emoji))decision="deny";if(!decision)return!1;try{let sql=await getConnection(),[approval]=await sql`
1786
+ `,deps.log({timestamp:now.toISOString(),level:"debug",event:"machine_snapshot",active_workers:activeWorkers,active_teams:teams.size,tmux_sessions:tmuxSessions,cpu_percent:cpuPercent,memory_mb:memoryMb})}async function emitWorkerEvents(deps){let workers=await deps.listWorkers(),now=deps.now().toISOString(),currentIds=new Set;for(let worker of workers){currentIds.add(worker.id);let prev=previousWorkerStates.get(worker.id),repoPath=worker.repoPath??process.cwd();if(!prev)await deps.publishEvent(`genie.agent.${worker.id}.spawned`,{timestamp:now,kind:"state",agent:worker.id,team:worker.team,text:`Agent ${worker.id} spawned`,data:{state:worker.state},source:"registry"},repoPath);else if(prev.state!==worker.state){if(await deps.publishEvent(`genie.agent.${worker.id}.state`,{timestamp:now,kind:"state",agent:worker.id,team:worker.team,text:`Agent ${worker.id} state: ${prev.state} \u2192 ${worker.state}`,data:{previousState:prev.state,state:worker.state},source:"registry"},repoPath),worker.state==="done"&&worker.wishSlug&&worker.groupNumber!=null)await deps.publishEvent(`genie.wish.${worker.wishSlug}.group.${worker.groupNumber}.done`,{timestamp:now,kind:"system",agent:worker.id,team:worker.team,text:`Wish ${worker.wishSlug} group ${worker.groupNumber} completed by ${worker.id}`,data:{wishSlug:worker.wishSlug,groupNumber:worker.groupNumber},source:"registry"},repoPath)}previousWorkerStates.set(worker.id,{...worker})}for(let[id,prev]of previousWorkerStates)if(!currentIds.has(id))await deps.publishEvent(`genie.agent.${id}.killed`,{timestamp:now,kind:"state",agent:id,team:prev.team,text:`Agent ${id} killed`,data:{lastState:prev.state},source:"registry"},prev.repoPath??process.cwd()),previousWorkerStates.delete(id)}function _resetWorkerStatesForTesting(){previousWorkerStates.clear()}function startInboxWatcherIfEnabled(deps){let pollMs=getInboxPollIntervalMs();if(pollMs===0)return deps.log({timestamp:deps.now().toISOString(),level:"info",event:"inbox_watcher_disabled"}),null;return deps.log({timestamp:deps.now().toISOString(),level:"info",event:"inbox_watcher_started",poll_interval_ms:pollMs}),startInboxWatcher()}function startDaemon(configOverrides,depsOverrides){let config=resolveConfig(configOverrides),deps={...createDefaultDeps(),...depsOverrides},daemonId=deps.generateId(),running2=!0,pollTimeout=null,pollResolve=null,listenConnection=null,heartbeatTimer=null,orphanTimer=null,leaseRecoveryTimer=null,agentResumeTimer=null,inboxWatcherHandle=null,captureFallbackTimer=null,eventRouterHandle=null,deliveryUnsub=null,deliveryRetryTimer=null,stop=()=>{if(running2=!1,pollTimeout)clearTimeout(pollTimeout),pollTimeout=null;if(pollResolve)pollResolve(),pollResolve=null;if(heartbeatTimer)clearInterval(heartbeatTimer),heartbeatTimer=null;if(orphanTimer)clearInterval(orphanTimer),orphanTimer=null;if(leaseRecoveryTimer)clearInterval(leaseRecoveryTimer),leaseRecoveryTimer=null;if(agentResumeTimer)clearInterval(agentResumeTimer),agentResumeTimer=null;if(inboxWatcherHandle)stopInboxWatcher(inboxWatcherHandle),inboxWatcherHandle=null;if(listenConnection)listenConnection.end().catch(()=>{}),listenConnection=null;if(captureFallbackTimer)clearInterval(captureFallbackTimer),captureFallbackTimer=null;if(eventRouterHandle?.stop().catch(()=>{}),eventRouterHandle=null,deliveryRetryTimer)clearInterval(deliveryRetryTimer),deliveryRetryTimer=null;if(deliveryUnsub)deliveryUnsub().catch(()=>{}),deliveryUnsub=null;Promise.resolve().then(() => (init_session_filewatch(),exports_session_filewatch)).then((m)=>m.stopFilewatch()).catch(()=>{}),Promise.resolve().then(() => (init_session_backfill(),exports_session_backfill)).then((m)=>m.stopBackfill()).catch(()=>{}),Promise.resolve().then(() => (init_db(),exports_db)).then(({getLockfilePath:getLockfilePath2})=>{try{__require("fs").unlinkSync(getLockfilePath2())}catch{}}).catch(()=>{})},processTriggers=async()=>{try{let claimed=await claimDueTriggers(deps,config,daemonId);if(claimed.length===0)return;if(claimed.length>config.jitterThreshold){let jitterMs=deps.jitter(config.maxJitterMs);deps.log({timestamp:deps.now().toISOString(),level:"info",event:"jitter_applied",count:claimed.length,jitter_ms:jitterMs}),await deps.sleep(jitterMs)}for(let trigger of claimed){if(!running2)break;await fireTrigger(deps,trigger,daemonId)}}catch(err){let message=err instanceof Error?err.message:String(err);deps.log({timestamp:deps.now().toISOString(),level:"error",event:"process_cycle_error",error:message})}};async function setupListenNotify(d,onTrigger){try{let sql=await d.getConnection();return await sql.listen("genie_trigger_due",async()=>{if(!running2)return;await onTrigger()}),d.log({timestamp:d.now().toISOString(),level:"info",event:"listen_started",channel:"genie_trigger_due"}),sql}catch(err){let message=err instanceof Error?err.message:String(err);return d.log({timestamp:d.now().toISOString(),level:"warn",event:"listen_failed",error:message}),null}}function startLeaseRecoveryTimer(d,cfg,dId){return setInterval(async()=>{if(!running2)return;try{await reclaimExpiredLeases(d,dId)}catch(err){let message=err instanceof Error?err.message:String(err);d.log({timestamp:d.now().toISOString(),level:"error",event:"lease_recovery_error",error:message})}},cfg.leaseRecoveryIntervalMs)}function startOrphanTimer(d,cfg){return setInterval(async()=>{if(!running2)return;try{await reconcileOrphans(d,cfg)}catch(err){let message=err instanceof Error?err.message:String(err);d.log({timestamp:d.now().toISOString(),level:"error",event:"orphan_reconciliation_error",error:message})}},cfg.orphanCheckIntervalMs)}async function reconcileDeadPaneZombies(d){try{let{reconcileStaleSpawns:reconcileStaleSpawns2}=await Promise.resolve().then(() => (init_agent_registry(),exports_agent_registry));await reconcileStaleSpawns2()}catch(err){let message=err instanceof Error?err.message:String(err);d.log({timestamp:d.now().toISOString(),level:"warn",event:"reconcile_stale_spawns_error",error:message})}}function startAgentResumeTimer(d,cfg,dId){return setInterval(async()=>{if(!running2)return;try{await reconcileDeadPaneZombies(d),await runAgentRecoveryPass(d,dId,cfg)}catch(err){let message=err instanceof Error?err.message:String(err);d.log({timestamp:d.now().toISOString(),level:"error",event:"agent_resume_timer_error",error:message})}},cfg.leaseRecoveryIntervalMs)}async function startEventRouterSafe(d){try{let handle=await startEventRouter();return d.log({timestamp:d.now().toISOString(),level:"info",event:"event_router_started"}),handle}catch(err){let message=err instanceof Error?err.message:String(err);return d.log({timestamp:d.now().toISOString(),level:"warn",event:"event_router_start_failed",error:message}),null}}async function initSessionCapture(d,cfg){try{let captureSql=await d.getConnection(),{startFilewatch:startFilewatch2}=await Promise.resolve().then(() => (init_session_filewatch(),exports_session_filewatch)),{startBackfill:startBackfill2}=await Promise.resolve().then(() => (init_session_backfill(),exports_session_backfill));if(!await startFilewatch2(captureSql)){let{ingestFileFull:ingestFileFull2,discoverAllJsonlFiles:discoverAllJsonlFiles2,buildWorkerMap:buildWorkerMap2}=await Promise.resolve().then(() => (init_session_capture(),exports_session_capture));d.log({timestamp:d.now().toISOString(),level:"warn",event:"filewatch_failed_fallback_polling"});let timer2=setInterval(async()=>{if(!running2)return;try{let files=await discoverAllJsonlFiles2(),workerMap=await buildWorkerMap2(captureSql);for(let f of files)await ingestFileFull2(captureSql,f.sessionId,f.jsonlPath,f.projectPath,0,{parentSessionId:f.parentSessionId,isSubagent:f.isSubagent,workerMap})}catch{}},cfg.heartbeatIntervalMs);return startBackfill2(captureSql).catch((err)=>{let msg=err instanceof Error?err.message:String(err);d.log({timestamp:d.now().toISOString(),level:"error",event:"backfill_error",error:msg})}),timer2}return startBackfill2(captureSql).catch((err)=>{let msg=err instanceof Error?err.message:String(err);d.log({timestamp:d.now().toISOString(),level:"error",event:"backfill_error",error:msg})}),null}catch(err){let message=err instanceof Error?err.message:String(err);return d.log({timestamp:d.now().toISOString(),level:"warn",event:"session_capture_init_failed",error:message}),null}}async function runHeartbeat(d){if(!running2)return;try{await collectHeartbeats(d),await collectMachineSnapshot(d),await emitWorkerEvents(d);try{let retSql=await d.getConnection();await retSql`DELETE FROM heartbeats WHERE created_at < now() - interval '7 days'`,await retSql`DELETE FROM machine_snapshots WHERE created_at < now() - interval '30 days'`,await retSql`DELETE FROM audit_events WHERE entity_type LIKE 'otel_%' AND created_at < now() - interval '30 days'`}catch{}}catch(err){let message=err instanceof Error?err.message:String(err);d.log({timestamp:d.now().toISOString(),level:"error",event:"heartbeat_error",error:message})}}let done=(async()=>{deps.log({timestamp:deps.now().toISOString(),level:"info",event:"daemon_started",daemon_id:daemonId,max_concurrent:config.maxConcurrent,poll_interval_ms:config.pollIntervalMs});try{await recoverOnStartup(deps,daemonId,config)}catch(err){let message=err instanceof Error?err.message:String(err);deps.log({timestamp:deps.now().toISOString(),level:"error",event:"recovery_error",error:message})}listenConnection=await setupListenNotify(deps,processTriggers),heartbeatTimer=setInterval(()=>runHeartbeat(deps),config.heartbeatIntervalMs),orphanTimer=startOrphanTimer(deps,config),leaseRecoveryTimer=startLeaseRecoveryTimer(deps,config,daemonId),agentResumeTimer=startAgentResumeTimer(deps,config,daemonId),inboxWatcherHandle=startInboxWatcherIfEnabled(deps),eventRouterHandle=await startEventRouterSafe(deps);try{deliveryUnsub=await subscribeDelivery(async(toWorker,messageId)=>{try{let{deliverToPane:deliverToPane2}=await Promise.resolve().then(() => (init_protocol_router(),exports_protocol_router));await deliverToPane2(toWorker,messageId)}catch{}}),deps.log({timestamp:deps.now().toISOString(),level:"info",event:"mailbox_delivery_listen_started"})}catch{}let MAX_DELIVERY_ATTEMPTS=3;deliveryRetryTimer=setInterval(async()=>{try{let retryable=await getRetryable(MAX_DELIVERY_ATTEMPTS);for(let msg of retryable)try{let{deliverToPane:deliverToPane2}=await Promise.resolve().then(() => (init_protocol_router(),exports_protocol_router));if(await deliverToPane2(msg.to,msg.id)){deps.log({timestamp:deps.now().toISOString(),level:"info",event:"mailbox_delivery_retried",messageId:msg.id,to:msg.to});continue}let rows=await(await deps.getConnection())`SELECT delivery_attempts, repo_path FROM mailbox WHERE id = ${msg.id} LIMIT 1`,attempts=rows[0]?.delivery_attempts??0;if(attempts>=MAX_DELIVERY_ATTEMPTS){await markEscalated(msg.id);let repoPath=rows[0]?.repo_path;if(repoPath){let{send:send2}=await Promise.resolve().then(() => (init_mailbox(),exports_mailbox));await send2(repoPath,"scheduler","team-lead",`[escalation] Message ${msg.id} from "${msg.from}" to "${msg.to}" failed delivery after ${MAX_DELIVERY_ATTEMPTS} attempts. Body: "${msg.body.slice(0,200)}"`)}deps.log({timestamp:deps.now().toISOString(),level:"warn",event:"mailbox_delivery_escalated",messageId:msg.id,to:msg.to,attempts})}}catch{}}catch(err){let message=err instanceof Error?err.message:String(err);deps.log({timestamp:deps.now().toISOString(),level:"error",event:"mailbox_retry_error",error:message})}},60000),captureFallbackTimer=await initSessionCapture(deps,config),await processTriggers();while(running2){if(await new Promise((resolve5)=>{pollResolve=resolve5,pollTimeout=setTimeout(resolve5,config.pollIntervalMs)}),pollResolve=null,!running2)break;await processTriggers()}deps.log({timestamp:deps.now().toISOString(),level:"info",event:"daemon_stopped",daemon_id:daemonId})})();return{stop,done,daemonId}}var RECOVERY_RETRY_DELAY_MS=60000,RESUME_COOLDOWN_MS=60000,DEFAULT_MAX_RESUME_ATTEMPTS=3,INACTIVE_WORKER_STATES,previousWorkerStates;var init_scheduler_daemon=__esm(()=>{init_cron();init_event_router();init_inbox_watcher();init_mailbox();init_run_spec();INACTIVE_WORKER_STATES=new Set(["done","error","suspended","spawning"]);previousWorkerStates=new Map});var exports_omni_approval_handler={};__export(exports_omni_approval_handler,{startOmniApprovalHandler:()=>startOmniApprovalHandler});class OmniApprovalHandler{nc=null;subs=[];sc=import_nats2.StringCodec();permissions;natsUrl;approveTokens;denyTokens;constructor(config){this.permissions=config.permissions,this.natsUrl=config.natsUrl??"localhost:4222",this.approveTokens=(config.permissions.approveTokens??DEFAULT_APPROVE_TOKENS).map((t)=>t.toLowerCase()),this.denyTokens=(config.permissions.denyTokens??DEFAULT_DENY_TOKENS).map((t)=>t.toLowerCase())}async start(){let{omniChat,omniInstance}=this.permissions;if(!omniChat||!omniInstance)return;this.nc=await import_nats2.connect({servers:this.natsUrl});let messageTopic=`omni.message.${omniInstance}.>`,msgSub=this.nc.subscribe(messageTopic);this.subs.push(msgSub),this.processMessages(msgSub);let eventSub=this.nc.subscribe("omni.event.>");this.subs.push(eventSub),this.processEvents(eventSub),handlerInstance=this,console.log(`[omni-approval] Listening for approval replies on ${messageTopic}`)}async stop(){for(let sub of this.subs)sub.unsubscribe();if(this.subs=[],this.nc)await this.nc.close(),this.nc=null;if(handlerInstance===this)handlerInstance=null}async processMessages(sub){for await(let msg of sub)try{let data=JSON.parse(this.sc.decode(msg.data));if((data.chatId??this.extractChatIdFromSubject(msg.subject))!==this.permissions.omniChat)continue;if(data.content)await this.handleTextReply(data.content,data.sender??"whatsapp-user")}catch{}}async processEvents(sub){for await(let msg of sub)try{let data=JSON.parse(this.sc.decode(msg.data));if(data.type!=="reaction")continue;if(data.chatId!==this.permissions.omniChat||data.instanceId!==this.permissions.omniInstance)continue;if(data.emoji&&data.messageId)await this.handleReaction(data.emoji,data.messageId,data.sender??"whatsapp-user")}catch{}}extractChatIdFromSubject(subject){let parts=subject.split(".");if(parts.length>=4)return parts.slice(3).join(".");return}async handleTextReply(content,sender){let normalized=content.trim().toLowerCase();if(!normalized)return!1;let decision=null;if(this.approveTokens.includes(normalized))decision="allow";else if(this.denyTokens.includes(normalized))decision="deny";if(!decision)return!1;let pending=await listPendingApprovals();if(pending.length===0)return!1;let oldest=pending[0],resolved=await resolveApproval(oldest.id,decision,sender);if(resolved)console.log(`[omni-approval] Resolved ${oldest.id} as ${decision} by ${sender} (text: "${normalized}")`);return resolved}async handleReaction(emoji,messageId,sender){let decision=null;if(DEFAULT_APPROVE_REACTIONS.includes(emoji))decision="allow";else if(DEFAULT_DENY_REACTIONS.includes(emoji))decision="deny";if(!decision)return!1;try{let sql=await getConnection(),[approval]=await sql`
1777
1787
  SELECT id FROM approvals
1778
1788
  WHERE omni_message_id = ${messageId} AND decision = 'pending'
1779
1789
  `;if(approval){let resolved2=await resolveApproval(approval.id,decision,sender);if(resolved2)console.log(`[omni-approval] Resolved ${approval.id} via reaction ${emoji} by ${sender}`);return resolved2}}catch{}let pending=await listPendingApprovals();if(pending.length===0)return!1;let resolved=await resolveApproval(pending[0].id,decision,sender);if(resolved)console.log(`[omni-approval] Resolved ${pending[0].id} via reaction ${emoji} by ${sender} (fallback)`);return resolved}}async function startOmniApprovalHandler(natsUrl){let ws=findWorkspace();if(!ws)return null;let config=getWorkspaceConfig(ws.root);if(!config.permissions?.omniChat||!config.permissions?.omniInstance)return null;let handler=new OmniApprovalHandler({natsUrl,permissions:config.permissions});return await handler.start(),handler}var import_nats2,DEFAULT_APPROVE_TOKENS,DEFAULT_DENY_TOKENS,DEFAULT_APPROVE_REACTIONS,DEFAULT_DENY_REACTIONS,handlerInstance=null;var init_omni_approval_handler=__esm(()=>{init_db();init_claude_sdk_remote_approval();init_workspace();import_nats2=__toESM(require_mod4(),1),DEFAULT_APPROVE_TOKENS=["y","yes","approve","sim"],DEFAULT_DENY_TOKENS=["n","no","deny","nao"],DEFAULT_APPROVE_REACTIONS=["\uD83D\uDC4D","\u2705","\uD83D\uDC4C"],DEFAULT_DENY_REACTIONS=["\uD83D\uDC4E","\u274C","\uD83D\uDEAB"]});function isValid2(value){return typeof value==="string"&&VALID.has(value)}function resolveExecutorType(override){if(isValid2(override))return override;let env=process.env.GENIE_EXECUTOR;if(isValid2(env))return env;try{let persisted=loadGenieConfigSync().omni?.executor;if(isValid2(persisted))return persisted}catch{}return"tmux"}var VALID;var init_executor_config=__esm(()=>{init_genie_config2();VALID=new Set(["tmux","sdk"])});class BridgeSessionStore{sql;constructor(sql){this.sql=sql}async create(opts){let[row]=await this.sql`
@@ -3194,7 +3204,7 @@ ${indented}`}function formatHumanOutput(events,label){let lines=[];if(lines.push
3194
3204
  WHERE c.content ILIKE ${`%${query2}%`}
3195
3205
  ORDER BY c.timestamp DESC
3196
3206
  LIMIT ${limit}
3197
- `;if(options.json){console.log(JSON.stringify(rows,null,2));return}if(rows.length===0){console.log(`No results for "${query2}".`);return}console.log(""),console.log(`Search: "${query2}" (${rows.length} results)`),console.log("\u2500".repeat(60));for(let r of rows){let preview=String(r.content).replace(/\n/g," ").slice(0,100),agent=r.agent_id??"(unknown)",time=r.timestamp?new Date(r.timestamp).toLocaleTimeString():"??:??";console.log(` [${time}] ${agent} (${r.role}): ${preview}`)}console.log("")}init_agent_directory();init_genie_config2();import{resolve as resolvePath2}from"path";init_audit();init_genie_config2();async function resolveOmniApiUrl(){let envUrl=process.env.OMNI_API_URL;if(envUrl)return envUrl;return(await loadGenieConfig()).omni?.apiUrl??null}async function resolveOmniApiKey(){let envKey=process.env.OMNI_API_KEY;if(envKey)return envKey;return(await loadGenieConfig()).omni?.apiKey}async function registerAgentInOmni(agentName,options){let apiUrl=await resolveOmniApiUrl();if(!apiUrl)return null;let apiKey=await resolveOmniApiKey(),body={name:agentName,provider:"claude",model:options?.model,agentType:"assistant",capabilities:options?.roles??[],metadata:{source:"genie",sessionIsolation:{perPerson:!0,perChannel:!0},registeredAt:new Date().toISOString()}},traceId=generateTraceId();try{let headers={"Content-Type":"application/json","X-Trace-Id":traceId};if(apiKey)headers.Authorization=`Bearer ${apiKey}`;let response=await fetch(`${apiUrl}/api/v2/agents`,{method:"POST",headers,body:JSON.stringify(body),signal:AbortSignal.timeout(1e4)});if(!response.ok){let text=await response.text().catch(()=>"");return console.warn(`Warning: Omni registration failed (HTTP ${response.status}): ${text}`),recordAuditEvent("omni",agentName,"registration_error",getActor(),{traceId,status:response.status,error:text.slice(0,200)}).catch(()=>{}),null}let result2=await response.json();return recordAuditEvent("omni",agentName,"registration_success",getActor(),{traceId,omniAgentId:result2.data.id}).catch(()=>{}),result2.data.id}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);return console.warn(`Warning: Omni registration failed: ${message}`),recordAuditEvent("omni",agentName,"registration_error",getActor(),{traceId,error:message.slice(0,200)}).catch(()=>{}),null}}async function findOmniAgent(agentName){let apiUrl=await resolveOmniApiUrl();if(!apiUrl)return null;let apiKey=await resolveOmniApiKey(),traceId=generateTraceId();try{let headers={"X-Trace-Id":traceId};if(apiKey)headers.Authorization=`Bearer ${apiKey}`;let response=await fetch(`${apiUrl}/api/v2/agents?name=${encodeURIComponent(agentName)}`,{method:"GET",headers,signal:AbortSignal.timeout(1e4)});if(!response.ok)return null;return(await response.json()).data?.find((a)=>a.name===agentName&&a.isActive)?.id??null}catch{return null}}init_agent_directory();init_agent_sync();init_audit();init_builtin_agents();init_defaults();init_frontmatter();init_genie_config2();init_workspace();import{resolve as resolvePath}from"path";function registerDirNamespace(program2){let dir=program2.command("dir").description("Agent directory management"),addCmd=dir.command("add <name>").description("Register an agent in the directory").requiredOption("--dir <path>","Agent folder (CWD + AGENTS.md)").option("--repo <path>","Default git repo (overridden by team)").option("--prompt-mode <mode>","Prompt mode: append or system","append").option("--model <model>","Default model (sonnet, opus, codex)").option("--roles <roles...>","Built-in roles this agent can orchestrate").option("--permission-preset <preset>","Permission preset: full, read-only, chat-only").option("--allow <tools>",'Comma-separated tool allow list (e.g. "Read,Glob,Grep,Bash")').option("--bash-allow <patterns>","Comma-separated regex patterns for allowed bash commands").option("--global","Write to global directory instead of project");registerSdkFlags(addCmd),addCmd.action(async(name,options)=>{try{await handleDirAdd(name,options)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),dir.command("rm <name>").description("Remove an agent from the directory").option("--global","Remove from global directory instead of project").action(async(name,options)=>{try{let removed=await rm3(name,{global:options.global});if(recordAuditEvent("item",name,"item_removed",getActor(),{type:"agent",source:"dir_rm"}).catch(()=>{}),removed){let scope=options.global?"global":"project";console.log(`Agent "${name}" removed from ${scope} directory.`)}else console.error(`Agent "${name}" not found in directory.`),process.exit(1)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),dir.command("ls [name]").description("List all agents or show single entry details").option("--json","Output as JSON").option("--builtins","Include built-in roles and council members").option("--all","Include archived agents").action(async(name,options)=>{try{if(name)await showEntry2(name,options.json);else await listEntries2(options.json,options.builtins,options.all)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}});let editCmd=dir.command("edit <name>").description("Update an agent directory entry").option("--dir <path>","Agent folder (CWD + AGENTS.md)").option("--repo <path>","Default git repo").option("--prompt-mode <mode>","Prompt mode: append or system").option("--model <model>","Default model").option("--provider <provider>","AI provider: claude or codex").option("--color <color>","Display color for TUI").option("--description <desc>","Agent description").option("--roles <roles...>","Built-in roles this agent can orchestrate").option("--permission-preset <preset>","Permission preset: full, read-only, chat-only").option("--allow <tools>",'Comma-separated tool allow list (e.g. "Read,Glob,Grep,Bash")').option("--bash-allow <patterns>","Comma-separated regex patterns for allowed bash commands").option("--global","Edit in global directory instead of project");registerSdkFlags(editCmd),editCmd.action(async(name,options)=>{try{await handleEdit(name,options)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),dir.command("sync").description("Sync agents from workspace agents/ directory").action(async()=>{try{await handleDirSync()}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),dir.command("export <name>").description("Print full AGENTS.md frontmatter for an agent from PG state").option("--stdout","Print to stdout as raw YAML (default)").option("--json","Print resolved fields as nested JSON with declared/resolved/source").action(async(name,options)=>{try{await handleDirExport(name,options)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}})}async function handleDirAdd(name,options){let promptMode=validatePromptMode(options.promptMode),resolvedDir=resolvePath(options.dir);if(options.repo)validateRepoPath(options.repo);let permissions=buildPermissions(options.permissionPreset,options.allow,options.bashAllow),sdk=buildSdkConfig(options),entry=await add({name,dir:resolvedDir,repo:options.repo?resolvePath(options.repo):void 0,promptMode,model:options.model,roles:normalizeRoles(options.roles),...permissions&&{permissions},...sdk&&{sdk}},{global:options.global});recordAuditEvent("item",name,"item_registered",getActor(),{type:"agent",source:"dir_add"}).catch(()=>{});let scope=options.global?"global":"project";console.log(`Agent "${entry.name}" registered (${scope}).`),printEntry(entry)}async function handleEdit(name,options){let updates={};if(options.dir)updates.dir=resolvePath(options.dir);if(options.repo)updates.repo=resolvePath(options.repo);if(options.promptMode)updates.promptMode=validatePromptMode(options.promptMode);if(options.model)updates.model=options.model;if(options.provider)updates.provider=options.provider;if(options.color)updates.color=options.color;if(options.description)updates.description=options.description;if(options.roles)updates.roles=normalizeRoles(options.roles);let permissions=buildPermissions(options.permissionPreset,options.allow,options.bashAllow);if(permissions)updates.permissions=permissions;let sdk=buildSdkConfig(options);if(sdk)updates.sdk=sdk;if(Object.keys(updates).length===0)console.error("No fields to update. Provide at least one of: --dir, --repo, --prompt-mode, --model, --provider, --color, --description, --roles, --permission-preset, --allow, --bash-allow, --sdk-*"),process.exit(1);let entry=await edit(name,updates,{global:options.global});syncFrontmatterToDisk(entry,updates),recordAuditEvent("item",name,"item_updated",getActor(),{type:"agent",source:"dir_edit"}).catch(()=>{});let scope=options.global?"global":"project";console.log(`Agent "${name}" updated (${scope}).`),printEntry(entry)}async function handleDirSync(){let{findWorkspace:findWorkspace2}=await Promise.resolve().then(() => (init_workspace(),exports_workspace)),ws=findWorkspace2();if(!ws)console.error("Not in a genie workspace. Run `genie init` first."),process.exit(1);console.log(`Syncing agents from ${ws.root}/agents/...`);let result2=await syncAgentDirectory(ws.root);printSyncResult(result2)}async function handleDirExport(name,options){let entry=await get2(name);if(!entry)console.error(`Agent "${name}" not found in directory.`),process.exit(1);if(options.json){let ctx=buildDirResolveContext(name),output={name:entry.name};for(let field of RESOLVED_FIELDS){let declared=entry[field]??null,result2=resolveFieldWithSource(entry,field,ctx);output[field]={declared:declared??null,resolved:result2.value,source:result2.source}}console.log(JSON.stringify(output,null,2));return}let fm={};if(entry.name)fm.name=entry.name;if(entry.description)fm.description=entry.description;if(entry.model)fm.model=entry.model;if(entry.color)fm.color=entry.color;if(entry.promptMode)fm.promptMode=entry.promptMode;if(entry.provider)fm.provider=entry.provider;if(entry.sdk&&Object.keys(entry.sdk).length>0){let{serializeSdkConfig:serializeSdkConfig2}=await Promise.resolve().then(() => (init_frontmatter_writer(),exports_frontmatter_writer));fm.sdk=serializeSdkConfig2(entry.sdk)}let yamlStr=(await Promise.resolve().then(() => (init_js_yaml(),exports_js_yaml))).dump(fm,{lineWidth:-1,noRefs:!0,sortKeys:!1,quotingType:'"'});console.log(`---
3207
+ `;if(options.json){console.log(JSON.stringify(rows,null,2));return}if(rows.length===0){console.log(`No results for "${query2}".`);return}console.log(""),console.log(`Search: "${query2}" (${rows.length} results)`),console.log("\u2500".repeat(60));for(let r of rows){let preview=String(r.content).replace(/\n/g," ").slice(0,100),agent=r.agent_id??"(unknown)",time=r.timestamp?new Date(r.timestamp).toLocaleTimeString():"??:??";console.log(` [${time}] ${agent} (${r.role}): ${preview}`)}console.log("")}init_agent_directory();init_genie_config2();import{resolve as resolvePath2}from"path";init_audit();init_genie_config2();async function resolveOmniApiUrl(){let envUrl=process.env.OMNI_API_URL;if(envUrl)return envUrl;return(await loadGenieConfig()).omni?.apiUrl??null}async function resolveOmniApiKey(){let envKey=process.env.OMNI_API_KEY;if(envKey)return envKey;return(await loadGenieConfig()).omni?.apiKey}async function registerAgentInOmni(agentName,options){let apiUrl=await resolveOmniApiUrl();if(!apiUrl)return null;let apiKey=await resolveOmniApiKey(),body={name:agentName,provider:"claude",model:options?.model,agentType:"assistant",capabilities:options?.roles??[],metadata:{source:"genie",sessionIsolation:{perPerson:!0,perChannel:!0},registeredAt:new Date().toISOString()}},traceId=generateTraceId();try{let headers={"Content-Type":"application/json","X-Trace-Id":traceId};if(apiKey)headers.Authorization=`Bearer ${apiKey}`;let response=await fetch(`${apiUrl}/api/v2/agents`,{method:"POST",headers,body:JSON.stringify(body),signal:AbortSignal.timeout(1e4)});if(!response.ok){let text=await response.text().catch(()=>"");return console.warn(`Warning: Omni registration failed (HTTP ${response.status}): ${text}`),recordAuditEvent("omni",agentName,"registration_error",getActor(),{traceId,status:response.status,error:text.slice(0,200)}).catch(()=>{}),null}let result2=await response.json();return recordAuditEvent("omni",agentName,"registration_success",getActor(),{traceId,omniAgentId:result2.data.id}).catch(()=>{}),result2.data.id}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);return console.warn(`Warning: Omni registration failed: ${message}`),recordAuditEvent("omni",agentName,"registration_error",getActor(),{traceId,error:message.slice(0,200)}).catch(()=>{}),null}}async function findOmniAgent(agentName){let apiUrl=await resolveOmniApiUrl();if(!apiUrl)return null;let apiKey=await resolveOmniApiKey(),traceId=generateTraceId();try{let headers={"X-Trace-Id":traceId};if(apiKey)headers.Authorization=`Bearer ${apiKey}`;let response=await fetch(`${apiUrl}/api/v2/agents?name=${encodeURIComponent(agentName)}`,{method:"GET",headers,signal:AbortSignal.timeout(1e4)});if(!response.ok)return null;return(await response.json()).data?.find((a)=>a.name===agentName&&a.isActive)?.id??null}catch{return null}}init_agent_directory();init_agent_sync();init_audit();init_builtin_agents();init_defaults();init_frontmatter();init_genie_config2();init_workspace();import{resolve as resolvePath}from"path";function registerDirNamespace(program2){let dir=program2.command("dir").description("Agent directory management"),addCmd=dir.command("add <name>").description("Register an agent in the directory").requiredOption("--dir <path>","Agent folder (CWD + AGENTS.md)").option("--repo <path>","Default git repo (overridden by team)").option("--prompt-mode <mode>","Prompt mode: append or system","append").option("--model <model>","Default model (sonnet, opus, codex)").option("--roles <roles...>","Built-in roles this agent can orchestrate").option("--permission-preset <preset>","Permission preset: full, read-only, chat-only").option("--allow <tools>",'Comma-separated tool allow list (e.g. "Read,Glob,Grep,Bash")').option("--bash-allow <patterns>","Comma-separated regex patterns for allowed bash commands").option("--global","Write to global directory instead of project");registerSdkFlags(addCmd),addCmd.action(async(name,options)=>{try{await handleDirAdd(name,options)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),dir.command("rm <name>").description("Remove an agent from the directory").option("--global","Remove from global directory instead of project").option("--force","Also remove runtime/spawn rows sharing this role (id shapes: <team>-<role>, UUID)").action(async(name,options)=>{try{let result2=await rm3(name,{global:options.global,force:options.force});if(result2.removed){let scope=options.global?"global":"project";console.log(`Agent "${name}" removed from ${scope} directory.`),recordAuditEvent("item",name,"item_removed",getActor(),{type:"agent",source:"dir_rm"}).catch(()=>{})}else if(result2.message)console.error(result2.message),process.exit(1);else console.error(`Agent "${name}" not found in directory.`),process.exit(1)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),dir.command("ls [name]").description("List all agents or show single entry details").option("--json","Output as JSON").option("--builtins","Include built-in roles and council members").option("--all","Include archived agents").action(async(name,options)=>{try{if(name)await showEntry2(name,options.json);else await listEntries2(options.json,options.builtins,options.all)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}});let editCmd=dir.command("edit <name>").description("Update an agent directory entry").option("--dir <path>","Agent folder (CWD + AGENTS.md)").option("--repo <path>","Default git repo").option("--prompt-mode <mode>","Prompt mode: append or system").option("--model <model>","Default model").option("--provider <provider>","AI provider: claude or codex").option("--color <color>","Display color for TUI").option("--description <desc>","Agent description").option("--roles <roles...>","Built-in roles this agent can orchestrate").option("--permission-preset <preset>","Permission preset: full, read-only, chat-only").option("--allow <tools>",'Comma-separated tool allow list (e.g. "Read,Glob,Grep,Bash")').option("--bash-allow <patterns>","Comma-separated regex patterns for allowed bash commands").option("--global","Edit in global directory instead of project");registerSdkFlags(editCmd),editCmd.action(async(name,options)=>{try{await handleEdit(name,options)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),dir.command("sync").description("Sync agents from workspace agents/ directory").action(async()=>{try{await handleDirSync()}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),dir.command("export <name>").description("Print full AGENTS.md frontmatter for an agent from PG state").option("--stdout","Print to stdout as raw YAML (default)").option("--json","Print resolved fields as nested JSON with declared/resolved/source").action(async(name,options)=>{try{await handleDirExport(name,options)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}})}async function handleDirAdd(name,options){let promptMode=validatePromptMode(options.promptMode),resolvedDir=resolvePath(options.dir);if(options.repo)validateRepoPath(options.repo);let permissions=buildPermissions(options.permissionPreset,options.allow,options.bashAllow),sdk=buildSdkConfig(options),entry=await add({name,dir:resolvedDir,repo:options.repo?resolvePath(options.repo):void 0,promptMode,model:options.model,roles:normalizeRoles(options.roles),...permissions&&{permissions},...sdk&&{sdk}},{global:options.global});recordAuditEvent("item",name,"item_registered",getActor(),{type:"agent",source:"dir_add"}).catch(()=>{});let scope=options.global?"global":"project";console.log(`Agent "${entry.name}" registered (${scope}).`),printEntry(entry)}async function handleEdit(name,options){let updates={};if(options.dir)updates.dir=resolvePath(options.dir);if(options.repo)updates.repo=resolvePath(options.repo);if(options.promptMode)updates.promptMode=validatePromptMode(options.promptMode);if(options.model)updates.model=options.model;if(options.provider)updates.provider=options.provider;if(options.color)updates.color=options.color;if(options.description)updates.description=options.description;if(options.roles)updates.roles=normalizeRoles(options.roles);let permissions=buildPermissions(options.permissionPreset,options.allow,options.bashAllow);if(permissions)updates.permissions=permissions;let sdk=buildSdkConfig(options);if(sdk)updates.sdk=sdk;if(Object.keys(updates).length===0)console.error("No fields to update. Provide at least one of: --dir, --repo, --prompt-mode, --model, --provider, --color, --description, --roles, --permission-preset, --allow, --bash-allow, --sdk-*"),process.exit(1);let entry=await edit(name,updates,{global:options.global});syncFrontmatterToDisk(entry,updates),recordAuditEvent("item",name,"item_updated",getActor(),{type:"agent",source:"dir_edit"}).catch(()=>{});let scope=options.global?"global":"project";console.log(`Agent "${name}" updated (${scope}).`),printEntry(entry)}async function handleDirSync(){let{findWorkspace:findWorkspace2}=await Promise.resolve().then(() => (init_workspace(),exports_workspace)),ws=findWorkspace2();if(!ws)console.error("Not in a genie workspace. Run `genie init` first."),process.exit(1);console.log(`Syncing agents from ${ws.root}/agents/...`);let result2=await syncAgentDirectory(ws.root);printSyncResult(result2)}async function handleDirExport(name,options){let entry=await get2(name);if(!entry)console.error(`Agent "${name}" not found in directory.`),process.exit(1);if(options.json){let ctx=buildDirResolveContext(name),output={name:entry.name};for(let field of RESOLVED_FIELDS){let declared=entry[field]??null,result2=resolveFieldWithSource(entry,field,ctx);output[field]={declared:declared??null,resolved:result2.value,source:result2.source}}console.log(JSON.stringify(output,null,2));return}let fm={};if(entry.name)fm.name=entry.name;if(entry.description)fm.description=entry.description;if(entry.model)fm.model=entry.model;if(entry.color)fm.color=entry.color;if(entry.promptMode)fm.promptMode=entry.promptMode;if(entry.provider)fm.provider=entry.provider;if(entry.sdk&&Object.keys(entry.sdk).length>0){let{serializeSdkConfig:serializeSdkConfig2}=await Promise.resolve().then(() => (init_frontmatter_writer(),exports_frontmatter_writer));fm.sdk=serializeSdkConfig2(entry.sdk)}let yamlStr=(await Promise.resolve().then(() => (init_js_yaml(),exports_js_yaml))).dump(fm,{lineWidth:-1,noRefs:!0,sortKeys:!1,quotingType:'"'});console.log(`---
3198
3208
  ${yamlStr}---`)}function buildDirResolveContext(agentName){let ctx={};try{let ws=findWorkspace();if(ws){let wsConfig=getWorkspaceConfig(ws.root);if(ctx.workspaceDefaults=wsConfig.agents?.defaults,agentName.includes("/")){let parentName=agentName.split("/")[0],{existsSync:existsSync27,readFileSync:readFileSync17}=__require("fs"),{join:join33}=__require("path"),parentAgentsMd=join33(ws.root,"agents",parentName,"AGENTS.md");if(existsSync27(parentAgentsMd)){let parentFm=parseFrontmatter(readFileSync17(parentAgentsMd,"utf-8"));ctx.parent={name:parentName,fields:parentFm}}}}}catch{}return ctx}function validateRepoPath(repo){if(repo.startsWith("/")||repo.startsWith("~/")||repo.startsWith("./")||repo.startsWith("../"))return;throw Error(`Invalid --repo value "${repo}". Must be a path (absolute "/...", home-relative "~/...", or dot-relative "./..." / "../..."). Got a bare word instead.`)}function validatePromptMode(mode){if(mode!=="system"&&mode!=="append")throw Error(`Invalid prompt mode "${mode}". Must be "append" or "system".`);return mode}function printEntry(entry){if(console.log(` Name: ${entry.name}`),console.log(` Dir: ${contractPath(entry.dir)}`),entry.repo)console.log(` Repo: ${contractPath(entry.repo)}`);if(console.log(` PromptMode: ${entry.promptMode}`),entry.model)console.log(` Model: ${entry.model}`);if(entry.provider)console.log(` Provider: ${entry.provider}`);if(entry.color)console.log(` Color: ${entry.color}`);if(entry.description)console.log(` Description: ${entry.description}`);if(entry.roles?.length)console.log(` Roles: ${entry.roles.join(", ")}`);if(entry.permissions?.preset)console.log(` Permissions: preset=${entry.permissions.preset}`);else if(entry.permissions?.allow){if(console.log(` Permissions: allow=${entry.permissions.allow.join(",")}`),entry.permissions.bashAllowPatterns?.length)console.log(` Bash Allow: ${entry.permissions.bashAllowPatterns.join(", ")}`)}if(entry.sdk)printSdkConfig(entry.sdk);console.log(` Registered: ${entry.registeredAt}`)}async function showEntry2(name,json2){let resolved=await resolve3(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(`
3199
3209
  (built-in ${resolved.entry.registeredAt==="(built-in)"?"agent":"agent"})`);console.log(""),printEntry(resolved.entry),console.log("")}async function listEntries2(json2,includeBuiltins,_includeArchived){let entries=await ls();if(json2){listEntriesJson(entries,includeBuiltins);return}if(entries.length===0&&!includeBuiltins){console.log(`
3200
3210
  No agents registered. Add one with: genie dir add <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.260418.5",
3
+ "version": "4.260418.7",
4
4
  "description": "Collaborative terminal toolkit for human + AI workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genie",
3
- "version": "4.260418.5",
3
+ "version": "4.260418.7",
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.260418.5",
3
+ "version": "4.260418.7",
4
4
  "private": true,
5
5
  "description": "Runtime dependencies for genie bundled CLIs",
6
6
  "type": "module",