@automagik/genie 4.260420.18 → 4.260421.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/genie.js CHANGED
@@ -1820,7 +1820,7 @@ ${body}`;writeFileSync12(filePath,output,"utf-8")}function serializeSdkConfig(sd
1820
1820
  `);if(nlPos===-1)return{newOffset:fileSize,contentRowsInserted:0,toolEventsInserted:0};return{newOffset:effectiveOffset+Buffer.byteLength(skipStr.slice(0,nlPos+1),"utf-8"),contentRowsInserted:0,toolEventsInserted:0}}safeEnd=lastNewline+1}let safeData=raw.slice(0,safeEnd),newOffset=effectiveOffset+Buffer.byteLength(safeData,"utf-8"),{contentRows,toolEvents,turnCount}=parseJsonlChunk(safeData,sessionId,session.totalTurns,{agentId:session.agentId,team:session.team,wishSlug:session.wishSlug,taskId:session.taskId});return await sql.begin(async(tx)=>{await batchInsertContent(tx,contentRows),await batchInsertToolEvents(tx,toolEvents),await tx`
1821
1821
  UPDATE sessions SET last_ingested_offset = ${newOffset}, total_turns = ${session.totalTurns+turnCount}, updated_at = now()
1822
1822
  WHERE id = ${sessionId}
1823
- `}),{newOffset,contentRowsInserted:contentRows.length,toolEventsInserted:toolEvents.length}}finally{await fh.close()}}async function ingestFileFull(sql,sessionId,jsonlPath,projectPath,fromOffset,opts){return ingestFile(sql,sessionId,jsonlPath,projectPath,fromOffset,{...opts,chunkSize:Number.MAX_SAFE_INTEGER})}var liveWorkPending=!1,workerMapCache=null,WORKER_MAP_TTL_MS=300000,DEFAULT_CHUNK_SIZE=65536;var init_session_capture=()=>{};var exports_session_filewatch={};__export(exports_session_filewatch,{stopFilewatch:()=>stopFilewatch,startFilewatch:()=>startFilewatch,resetUnrecoverableSessions:()=>resetUnrecoverableSessions,isForeignKeyViolation:()=>isForeignKeyViolation,handleFileChange:()=>handleFileChange});import{watch}from"fs";import{homedir as homedir25}from"os";import{basename as basename7,join as join39}from"path";function resetUnrecoverableSessions(){unrecoverableSessions.clear(),offsetCache.clear()}function isForeignKeyViolation(err){if(!err||typeof err!=="object")return!1;let code=err.code;if(typeof code==="string"&&code==="23503")return!0;return(err instanceof Error?err.message:String(err)).toLowerCase().includes("foreign key constraint")}async function loadOffsets(sql){try{let rows=await sql`SELECT id, last_ingested_offset FROM sessions WHERE last_ingested_offset > 0`;for(let row of rows)offsetCache.set(row.id,row.last_ingested_offset)}catch{}}function extractSessionInfo(filePath){if(!filePath.endsWith(".jsonl"))return null;let sessionId=basename7(filePath,".jsonl"),parts=filePath.split("/"),sessionsIdx=parts.lastIndexOf("sessions"),subagentsIdx=parts.lastIndexOf("subagents");if(subagentsIdx>0&&parts[subagentsIdx-1]){let parentSessionId=parts[subagentsIdx-1],projectIdx=parts.indexOf("projects"),projectPath=projectIdx>=0?parts.slice(0,projectIdx+2).join("/"):"";return{sessionId,projectPath,parentSessionId,isSubagent:!0}}if(sessionsIdx>0){let projectPath=parts.slice(0,sessionsIdx).join("/");return{sessionId,projectPath,parentSessionId:null,isSubagent:!1}}return null}async function handleFileChange(filePath,sql,deps=defaultDeps3){let info=extractSessionInfo(filePath);if(!info)return;if(unrecoverableSessions.has(info.sessionId))return;let storedOffset=offsetCache.get(info.sessionId)??0;try{deps.setLiveWorkPending(!0);let workerMap=await deps.buildWorkerMap(sql),result2=await deps.ingestFileFull(sql,info.sessionId,filePath,info.projectPath,storedOffset,{parentSessionId:info.parentSessionId,isSubagent:info.isSubagent,workerMap});offsetCache.set(info.sessionId,result2.newOffset)}catch(err){let message=err instanceof Error?err.message:String(err);if(isForeignKeyViolation(err))unrecoverableSessions.add(info.sessionId),offsetCache.set(info.sessionId,Number.POSITIVE_INFINITY),deps.logError(`[filewatch] skipping ${filePath} \u2014 FK constraint violation (orphan session, parent not registered): ${message}`);else deps.logError(`[filewatch] error ingesting ${filePath} at offset ${storedOffset}: ${message}`)}finally{deps.setLiveWorkPending(!1)}}async function startFilewatch(sql){if(watcher)return!0;let claudeDir=join39(process.env.CLAUDE_CONFIG_DIR??join39(homedir25(),".claude"),"projects");await loadOffsets(sql);try{return watcher=watch(claudeDir,{recursive:!0},(_eventType,filename)=>{if(!filename||!filename.endsWith(".jsonl"))return;let fullPath=join39(claudeDir,filename),existing=debounceTimers.get(fullPath);if(existing)clearTimeout(existing);debounceTimers.set(fullPath,setTimeout(()=>{debounceTimers.delete(fullPath),handleFileChange(fullPath,sql).catch((err)=>{let message=err instanceof Error?err.message:String(err);console.error(`[filewatch] unhandled error for ${fullPath}: ${message}`)})},DEBOUNCE_MS))}),watcher.on("error",(err)=>{console.error("[filewatch] watcher error:",err.message)}),console.log(`[filewatch] watching ${claudeDir} (${offsetCache.size} sessions cached)`),!0}catch(err){let message=err instanceof Error?err.message:String(err);return console.error(`[filewatch] failed to start: ${message}`),!1}}function stopFilewatch(){if(watcher)watcher.close(),watcher=null;for(let timer2 of debounceTimers.values())clearTimeout(timer2);debounceTimers.clear()}var watcher=null,offsetCache,debounceTimers,DEBOUNCE_MS=500,unrecoverableSessions,defaultDeps3;var init_session_filewatch=__esm(()=>{init_session_capture();offsetCache=new Map,debounceTimers=new Map,unrecoverableSessions=new Set;defaultDeps3={buildWorkerMap,ingestFileFull,setLiveWorkPending,logError:(msg)=>console.error(msg)}});var exports_session_backfill={};__export(exports_session_backfill,{stopBackfill:()=>stopBackfill,startBackfill:()=>startBackfill,getBackfillStatus:()=>getBackfillStatus});function sleep2(ms){return new Promise((resolve5)=>setTimeout(resolve5,ms))}async function updateSyncState(sql,progress){await sql`
1823
+ `}),{newOffset,contentRowsInserted:contentRows.length,toolEventsInserted:toolEvents.length}}finally{await fh.close()}}async function ingestFileFull(sql,sessionId,jsonlPath,projectPath,fromOffset,opts){return ingestFile(sql,sessionId,jsonlPath,projectPath,fromOffset,{...opts,chunkSize:Number.MAX_SAFE_INTEGER})}var liveWorkPending=!1,workerMapCache=null,WORKER_MAP_TTL_MS=300000,DEFAULT_CHUNK_SIZE=65536;var init_session_capture=()=>{};var exports_session_filewatch={};__export(exports_session_filewatch,{stopFilewatch:()=>stopFilewatch,startFilewatch:()=>startFilewatch,resetUnrecoverableSessions:()=>resetUnrecoverableSessions,isForeignKeyViolation:()=>isForeignKeyViolation,handleFileChange:()=>handleFileChange});import{watch}from"fs";import{homedir as homedir25}from"os";import{basename as basename7,join as join39}from"path";function resetUnrecoverableSessions(){unrecoverableSessions.clear(),offsetCache.clear()}function isForeignKeyViolation(err){if(!err||typeof err!=="object")return!1;let code=err.code;if(typeof code==="string"&&code==="23503")return!0;return(err instanceof Error?err.message:String(err)).toLowerCase().includes("foreign key constraint")}async function loadOffsets(sql){try{let rows=await sql`SELECT id, last_ingested_offset FROM sessions WHERE last_ingested_offset > 0`;for(let row of rows)offsetCache.set(row.id,row.last_ingested_offset)}catch{}}function extractSessionInfo(filePath){if(!filePath.endsWith(".jsonl"))return null;let sessionId=basename7(filePath,".jsonl"),parts=filePath.split("/"),sessionsIdx=parts.lastIndexOf("sessions"),subagentsIdx=parts.lastIndexOf("subagents");if(subagentsIdx>0&&parts[subagentsIdx-1]){let parentSessionId=parts[subagentsIdx-1],projectIdx=parts.indexOf("projects"),projectPath=projectIdx>=0?parts.slice(0,projectIdx+2).join("/"):"";return{sessionId,projectPath,parentSessionId,isSubagent:!0}}if(sessionsIdx>0){let projectPath=parts.slice(0,sessionsIdx).join("/");return{sessionId,projectPath,parentSessionId:null,isSubagent:!1}}return null}async function handleFileChange(filePath,sql,deps=defaultDeps3){let info=extractSessionInfo(filePath);if(!info)return;if(unrecoverableSessions.has(info.sessionId))return;let storedOffset=offsetCache.get(info.sessionId)??0;try{deps.setLiveWorkPending(!0);let workerMap=await deps.buildWorkerMap(sql),result2=await deps.ingestFileFull(sql,info.sessionId,filePath,info.projectPath,storedOffset,{parentSessionId:info.parentSessionId,isSubagent:info.isSubagent,workerMap});offsetCache.set(info.sessionId,result2.newOffset)}catch(err){let message=err instanceof Error?err.message:String(err);if(isForeignKeyViolation(err))unrecoverableSessions.add(info.sessionId),offsetCache.set(info.sessionId,Number.POSITIVE_INFINITY),deps.logError(`[filewatch] skipping ${filePath} \u2014 FK constraint violation (orphan session, parent not registered): ${message}`);else deps.logError(`[filewatch] error ingesting ${filePath} at offset ${storedOffset}: ${message}`)}finally{deps.setLiveWorkPending(!1)}}async function startFilewatch(sql){if(watcher)return!0;let claudeDir=join39(process.env.CLAUDE_CONFIG_DIR??join39(homedir25(),".claude"),"projects");await loadOffsets(sql);try{return watcher=watch(claudeDir,{recursive:!0},(_eventType,filename)=>{if(!filename||!filename.endsWith(".jsonl"))return;let fullPath=join39(claudeDir,filename),existing=debounceTimers.get(fullPath);if(existing)clearTimeout(existing);debounceTimers.set(fullPath,setTimeout(()=>{debounceTimers.delete(fullPath),handleFileChange(fullPath,sql).catch((err)=>{let message=err instanceof Error?err.message:String(err);console.error(`[filewatch] unhandled error for ${fullPath}: ${message}`)})},DEBOUNCE_MS))}),watcher.on("error",(err)=>{console.error("[filewatch] watcher error:",err.message)}),console.log(`[filewatch] watching ${claudeDir} (${offsetCache.size} sessions cached)`),!0}catch(err){let message=err instanceof Error?err.message:String(err);return console.error(`[filewatch] failed to start: ${message}`),!1}}function stopFilewatch(){if(watcher)watcher.close(),watcher=null;for(let timer2 of debounceTimers.values())clearTimeout(timer2);debounceTimers.clear()}var watcher=null,offsetCache,debounceTimers,DEBOUNCE_MS=500,unrecoverableSessions,defaultDeps3;var init_session_filewatch=__esm(()=>{init_session_capture();offsetCache=new Map,debounceTimers=new Map,unrecoverableSessions=new Set;defaultDeps3={buildWorkerMap,ingestFileFull,setLiveWorkPending,logError:(msg)=>console.error(msg)}});var exports_session_backfill={};__export(exports_session_backfill,{stopBackfill:()=>stopBackfill,startBackfill:()=>startBackfill,getBackfillStatus:()=>getBackfillStatus,compareBackfillFiles:()=>compareBackfillFiles});function sleep2(ms){return new Promise((resolve5)=>setTimeout(resolve5,ms))}function compareBackfillFiles(a,b2){if(a.isSubagent!==b2.isSubagent)return a.isSubagent?1:-1;return b2.mtime-a.mtime}async function updateSyncState(sql,progress){await sql`
1824
1824
  INSERT INTO session_sync (id, status, total_files, processed_files, total_bytes, processed_bytes, errors, updated_at)
1825
1825
  VALUES ('backfill', ${progress.status}, ${progress.totalFiles}, ${progress.processedFiles}, ${progress.totalBytes}, ${progress.processedBytes}, ${progress.errors}, now())
1826
1826
  ON CONFLICT (id) DO UPDATE SET
@@ -1831,7 +1831,7 @@ ${body}`;writeFileSync12(filePath,output,"utf-8")}function serializeSdkConfig(sd
1831
1831
  processed_bytes = ${progress.processedBytes},
1832
1832
  errors = ${progress.errors},
1833
1833
  updated_at = now()
1834
- `}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,{terminalizeCleanExitUnverified:()=>terminalizeCleanExitUnverified,startDaemon:()=>startDaemon,runAgentRecoveryPass:()=>runAgentRecoveryPass,recoverOnStartup:()=>recoverOnStartup,reconcileUnresumable:()=>reconcileUnresumable,reconcileOrphans:()=>reconcileOrphans,reconcileOrphanedRuns:()=>reconcileOrphanedRuns,reclaimExpiredLeases:()=>reclaimExpiredLeases,processMailboxRetryMessage:()=>processMailboxRetryMessage,logToFile:()=>logToFile,logReconcilerMode:()=>logReconcilerMode,isTurnAwareReconcilerEnabled:()=>isTurnAwareReconcilerEnabled,fireTrigger:()=>fireTrigger,emitWorkerEvents:()=>emitWorkerEvents,collectMachineSnapshot:()=>collectMachineSnapshot,collectHeartbeats:()=>collectHeartbeats,claimDueTriggers:()=>claimDueTriggers,attemptAgentResume:()=>attemptAgentResume,_resetWorkerStatesForTesting:()=>_resetWorkerStatesForTesting,TURN_AWARE_RECONCILER_FLAG:()=>TURN_AWARE_RECONCILER_FLAG,MAX_DELIVERY_ATTEMPTS:()=>MAX_DELIVERY_ATTEMPTS,ESCALATION_RECIPIENT:()=>ESCALATION_RECIPIENT});import{randomUUID as randomUUID9}from"crypto";import{appendFileSync as appendFileSync3,mkdirSync as mkdirSync12}from"fs";import{homedir as homedir26}from"os";import{join as join40}from"path";function isTurnAwareReconcilerEnabled(env=process.env){let raw=env[TURN_AWARE_RECONCILER_FLAG];if(raw===void 0)return!0;let v=raw.trim().toLowerCase();if(v==="")return!0;if(v==="0"||v==="false"||v==="no")return!1;if(v==="1"||v==="true"||v==="yes")return!0;return!0}function logReconcilerMode(deps,daemonId){let enabled=isTurnAwareReconcilerEnabled();deps.log({timestamp:deps.now().toISOString(),level:"info",event:enabled?"reconciler_mode_turn_aware":"reconciler_mode_legacy",daemon_id:daemonId,flag:TURN_AWARE_RECONCILER_FLAG,enabled,message:enabled?"turn-aware reconciler enabled":"flag off, using legacy reconciler"})}function getLogDir2(){return join40(process.env.GENIE_HOME??join40(homedir26(),".genie"),"logs")}function getLogFile(){return join40(getLogDir2(),"scheduler.log")}function logToFile(entry2){let logDir=getLogDir2();mkdirSync12(logDir,{recursive:!0});let enriched=entry2.trace_id?entry2:withAmbientTraceId(entry2);appendFileSync3(getLogFile(),`${JSON.stringify(enriched)}
1834
+ `}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(compareBackfillFiles);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,{terminalizeCleanExitUnverified:()=>terminalizeCleanExitUnverified,startDaemon:()=>startDaemon,runAgentRecoveryPass:()=>runAgentRecoveryPass,recoverOnStartup:()=>recoverOnStartup,reconcileUnresumable:()=>reconcileUnresumable,reconcileOrphans:()=>reconcileOrphans,reconcileOrphanedRuns:()=>reconcileOrphanedRuns,reclaimExpiredLeases:()=>reclaimExpiredLeases,processMailboxRetryMessage:()=>processMailboxRetryMessage,logToFile:()=>logToFile,logReconcilerMode:()=>logReconcilerMode,isTurnAwareReconcilerEnabled:()=>isTurnAwareReconcilerEnabled,fireTrigger:()=>fireTrigger,emitWorkerEvents:()=>emitWorkerEvents,collectMachineSnapshot:()=>collectMachineSnapshot,collectHeartbeats:()=>collectHeartbeats,claimDueTriggers:()=>claimDueTriggers,attemptAgentResume:()=>attemptAgentResume,_resetWorkerStatesForTesting:()=>_resetWorkerStatesForTesting,TURN_AWARE_RECONCILER_FLAG:()=>TURN_AWARE_RECONCILER_FLAG,MAX_DELIVERY_ATTEMPTS:()=>MAX_DELIVERY_ATTEMPTS,ESCALATION_RECIPIENT:()=>ESCALATION_RECIPIENT});import{randomUUID as randomUUID9}from"crypto";import{appendFileSync as appendFileSync3,mkdirSync as mkdirSync12}from"fs";import{homedir as homedir26}from"os";import{join as join40}from"path";function isTurnAwareReconcilerEnabled(env=process.env){let raw=env[TURN_AWARE_RECONCILER_FLAG];if(raw===void 0)return!0;let v=raw.trim().toLowerCase();if(v==="")return!0;if(v==="0"||v==="false"||v==="no")return!1;if(v==="1"||v==="true"||v==="yes")return!0;return!0}function logReconcilerMode(deps,daemonId){let enabled=isTurnAwareReconcilerEnabled();deps.log({timestamp:deps.now().toISOString(),level:"info",event:enabled?"reconciler_mode_turn_aware":"reconciler_mode_legacy",daemon_id:daemonId,flag:TURN_AWARE_RECONCILER_FLAG,enabled,message:enabled?"turn-aware reconciler enabled":"flag off, using legacy reconciler"})}function getLogDir2(){return join40(process.env.GENIE_HOME??join40(homedir26(),".genie"),"logs")}function getLogFile(){return join40(getLogDir2(),"scheduler.log")}function logToFile(entry2){let logDir=getLogDir2();mkdirSync12(logDir,{recursive:!0});let enriched=entry2.trace_id?entry2:withAmbientTraceId(entry2);appendFileSync3(getLogFile(),`${JSON.stringify(enriched)}
1835
1835
  `)}function withAmbientTraceId(entry2){let ctx=getAmbient();if(!ctx)return entry2;return{...entry2,trace_id:ctx.trace_id}}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:execSync10}=await import("child_process"),{genieTmuxCmd:genieTmuxCmd2}=await Promise.resolve().then(() => (init_tmux_wrapper(),exports_tmux_wrapper));return execSync10(`${genieTmuxCmd2("list-sessions")} 2>/dev/null`,{encoding:"utf-8"}).trim().split(`
1836
1836
  `).filter(Boolean).length}catch{return 0}}async function defaultResumeAgent(agentId){try{let{execSync:execSync10}=await import("child_process");return execSync10(`genie agent resume ${agentId} --no-reset-attempts`,{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:randomUUID9,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`
1837
1837
  SELECT count(*)::int AS cnt FROM runs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/genie",
3
- "version": "4.260420.18",
3
+ "version": "4.260421.1",
4
4
  "description": "Collaborative terminal toolkit for human + AI workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genie",
3
- "version": "4.260420.18",
3
+ "version": "4.260421.1",
4
4
  "description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, turn them into wishes, execute with /work, validate with /review, and ship as one team.",
5
5
  "author": {
6
6
  "name": "Namastex Labs"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genie-plugin",
3
- "version": "4.260420.18",
3
+ "version": "4.260421.1",
4
4
  "private": true,
5
5
  "description": "Runtime dependencies for genie bundled CLIs",
6
6
  "type": "module",