@automagik/genie 4.260329.16 → 4.260329.18

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.
@@ -10,7 +10,7 @@
10
10
  "plugins": [
11
11
  {
12
12
  "name": "genie",
13
- "version": "4.260329.16",
13
+ "version": "4.260329.18",
14
14
  "source": "./plugins/genie",
15
15
  "description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, wish them into plans, make with parallel agents, ship as one team. A coding genie that grows with your project."
16
16
  }
package/dist/genie.js CHANGED
@@ -1432,7 +1432,7 @@ ${answer}
1432
1432
  ORDER BY seq
1433
1433
  `).map((r)=>({id:r.id,seq:r.seq,title:r.title,stage:r.stage,repoPath:r.repo_path}))}function getRepoPathSafe(){try{return execSync12("git rev-parse --show-toplevel",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return process.cwd()}}var init_task_close_merged=()=>{};var palette,icons,tmuxStyle;var init_theme2=__esm(()=>{palette={purple:"#a855f7",violet:"#7c3aed",cyan:"#22d3ee",emerald:"#34d399",bg:"#1a1028",bgLight:"#241838",bgLighter:"#2e2048",text:"#e2e8f0",textDim:"#94a3b8",textMuted:"#64748b",border:"#414868",borderActive:"#7c3aed",scrollTrack:"#414868",scrollThumb:"#7aa2f7",active:"#22d3ee",success:"#34d399",warning:"#fbbf24",error:"#f87171",idle:"#94a3b8"},icons={org:"\u25C6",project:"\u25B8",projectOpen:"\u25BE",board:"\u2261",boardOpen:"\u2261",column:"\u2502",task:"\u25CB",taskActive:"\u25CF",taskDone:"\u2713",agent:"\u25B6",collapsed:"\u25B8",expanded:"\u25BE"},tmuxStyle={statusBg:"#1a1028",statusFg:"#e2e8f0",activeBorder:"#7c3aed",inactiveBorder:"#414868",activeTab:"#7c3aed",inactiveTab:"#414868"}});import{execSync as execSync13,spawnSync as spawnSync2}from"child_process";function hasTmux(){try{return execSync13("which tmux",{stdio:"ignore"}),!0}catch{return!1}}function isInsideTuiSession(){return process.env.GENIE_TUI_PANE==="left"}function createTuiSession(){let cols=process.stdout.columns||120,rows=process.stdout.rows||40;try{execSync13(`tmux kill-session -t ${SESSION_NAME} 2>/dev/null`,{stdio:"ignore"})}catch{}execSync13(`tmux new-session -d -s ${SESSION_NAME} -x ${cols} -y ${rows} -e GENIE_TUI_PANE=left`,{stdio:"ignore"}),execSync13(`tmux split-window -h -t ${SESSION_NAME}:0 -l ${cols-NAV_WIDTH-1}`,{stdio:"ignore"});let panes=execSync13(`tmux list-panes -t ${SESSION_NAME}:0 -F '#{pane_id}'`,{encoding:"utf-8"}).trim().split(`
1434
1434
  `),leftPane=panes[0],rightPane=panes[1]||panes[0];return applyTmuxStyle(SESSION_NAME),setupKeybindings(SESSION_NAME),{session:SESSION_NAME,leftPane,rightPane}}function resolveRightPane(rightPane){try{return execSync13(`tmux display-message -t ${rightPane} -p ''`,{stdio:"ignore"}),rightPane}catch{try{let panes=execSync13(`tmux list-panes -t ${SESSION_NAME}:0 -F '#{pane_id}'`,{encoding:"utf-8"}).trim().split(`
1435
- `);return panes[1]||panes[0]}catch{return rightPane}}}function ensureSession3(sessionName){try{execSync13(`tmux has-session -t '${sessionName}' 2>/dev/null`,{stdio:"ignore"})}catch{try{execSync13(`tmux new-session -d -s '${sessionName}'`,{stdio:"ignore"})}catch{}}}function attachProject(rightPane,targetSession){let pane=resolveRightPane(rightPane);ensureSession3(targetSession);try{execSync13(`tmux respawn-pane -k -t ${pane} "TMUX='' tmux attach-session -t '${targetSession}'"`,{stdio:"ignore"})}catch{}}function switchRightPane(rightPane,targetSession){attachProject(rightPane,targetSession)}function attachProjectWindow(rightPane,targetSession,windowIndex){let pane=resolveRightPane(rightPane);if(ensureSession3(targetSession),windowIndex!==void 0)try{execSync13(`tmux select-window -t '${targetSession}:${windowIndex}'`,{stdio:"ignore"})}catch{}try{execSync13(`tmux respawn-pane -k -t ${pane} "TMUX='' tmux attach-session -t '${targetSession}'"`,{stdio:"ignore"})}catch{}}function setupKeybindings(session){try{execSync13(`tmux bind-key -T ${KEY_TABLE} Tab select-pane -t :.+ \\; switch-client -T ${KEY_TABLE}`,{stdio:"ignore"}),execSync13(`tmux bind-key -T ${KEY_TABLE} C-b if-shell "[ $(tmux display-message -p '#{pane_width}' -t ${session}:0.0) -gt 5 ]" "resize-pane -t ${session}:0.0 -x 0" "resize-pane -t ${session}:0.0 -x ${NAV_WIDTH}" \\; switch-client -T ${KEY_TABLE}`,{stdio:"ignore"}),execSync13(`tmux bind-key -T ${KEY_TABLE} C-t send-keys -t ${session}:0.1 C-b c \\; switch-client -T ${KEY_TABLE}`,{stdio:"ignore"}),execSync13(`tmux bind-key -T ${KEY_TABLE} 'C-\\' run-shell "tmux kill-session -t ${session}"`,{stdio:"ignore"}),execSync13(`tmux set-hook -t ${session} client-session-changed "switch-client -T ${KEY_TABLE}"`,{stdio:"ignore"}),execSync13(`tmux switch-client -T ${KEY_TABLE}`,{stdio:"ignore"})}catch{}}function applyTmuxStyle(session){try{let cmds=[`set-option -t ${session} pane-border-style 'fg=${tmuxStyle.inactiveBorder}'`,`set-option -t ${session} pane-active-border-style 'fg=${tmuxStyle.activeBorder}'`,`set-option -t ${session} status off`,`set-option -t ${session} mouse on`];for(let cmd of cmds)execSync13(`tmux ${cmd}`,{stdio:"ignore"})}catch{}}function cleanup(session=SESSION_NAME){try{execSync13(`tmux unbind-key -T ${KEY_TABLE} Tab 2>/dev/null`,{stdio:"ignore"}),execSync13(`tmux unbind-key -T ${KEY_TABLE} C-b 2>/dev/null`,{stdio:"ignore"}),execSync13(`tmux unbind-key -T ${KEY_TABLE} C-t 2>/dev/null`,{stdio:"ignore"}),execSync13(`tmux unbind-key -T ${KEY_TABLE} 'C-\\' 2>/dev/null`,{stdio:"ignore"}),execSync13(`tmux set-hook -u -t ${session} client-session-changed 2>/dev/null`,{stdio:"ignore"}),execSync13(`tmux kill-session -t ${session} 2>/dev/null`,{stdio:"ignore"})}catch{}}function attachTuiSession(){spawnSync2("tmux",["attach-session","-t",SESSION_NAME],{stdio:"inherit"})}function listSessionWindows(session){try{let output=execSync13(`tmux list-windows -t ${session} -F '#{window_name}:#{window_index}:#{?window_active,1,0}' 2>/dev/null`,{encoding:"utf-8"}).trim();if(!output)return[];return output.split(`
1435
+ `);return panes[1]||panes[0]}catch{return rightPane}}}function ensureSession3(sessionName){try{execSync13(`tmux has-session -t '${sessionName}' 2>/dev/null`,{stdio:"ignore"})}catch{try{execSync13(`tmux new-session -d -s '${sessionName}'`,{stdio:"ignore"})}catch{}}}function attachProject(rightPane,targetSession){let pane=resolveRightPane(rightPane);ensureSession3(targetSession);try{execSync13(`tmux respawn-pane -k -t ${pane} "TMUX='' tmux attach-session -t '${targetSession}'"`,{stdio:"ignore"})}catch{}}function switchRightPane(rightPane,targetSession){attachProject(rightPane,targetSession)}function attachProjectWindow(rightPane,targetSession,windowIndex){let pane=resolveRightPane(rightPane);if(ensureSession3(targetSession),windowIndex!==void 0)try{execSync13(`tmux select-window -t '${targetSession}:${windowIndex}'`,{stdio:"ignore"})}catch{}try{execSync13(`tmux respawn-pane -k -t ${pane} "TMUX='' tmux attach-session -t '${targetSession}'"`,{stdio:"ignore"})}catch{}}function setupKeybindings(session){try{execSync13(`tmux bind-key -T ${KEY_TABLE} Tab select-pane -t ${session}:0.1 \\; switch-client -T ${KEY_TABLE}`,{stdio:"ignore"}),execSync13(`tmux bind-key -T ${KEY_TABLE} C-b if-shell "[ $(tmux display-message -p '#{pane_width}' -t ${session}:0.0) -gt 5 ]" "resize-pane -t ${session}:0.0 -x 0" "resize-pane -t ${session}:0.0 -x ${NAV_WIDTH}" \\; switch-client -T ${KEY_TABLE}`,{stdio:"ignore"}),execSync13(`tmux bind-key -T ${KEY_TABLE} C-t send-keys -t ${session}:0.1 C-b c \\; switch-client -T ${KEY_TABLE}`,{stdio:"ignore"}),execSync13(`tmux bind-key -T ${KEY_TABLE} 'C-\\' run-shell "tmux kill-session -t ${session}"`,{stdio:"ignore"}),execSync13(`tmux set-hook -t ${session} client-session-changed "switch-client -T ${KEY_TABLE}"`,{stdio:"ignore"}),execSync13(`tmux switch-client -T ${KEY_TABLE}`,{stdio:"ignore"})}catch{}}function applyTmuxStyle(session){try{let cmds=[`set-option -t ${session} pane-border-style 'fg=${tmuxStyle.inactiveBorder}'`,`set-option -t ${session} pane-active-border-style 'fg=${tmuxStyle.activeBorder}'`,`set-option -t ${session} status off`,`set-option -t ${session} mouse on`];for(let cmd of cmds)execSync13(`tmux ${cmd}`,{stdio:"ignore"})}catch{}}function cleanup(session=SESSION_NAME){try{execSync13(`tmux unbind-key -T ${KEY_TABLE} Tab 2>/dev/null`,{stdio:"ignore"}),execSync13(`tmux unbind-key -T ${KEY_TABLE} C-b 2>/dev/null`,{stdio:"ignore"}),execSync13(`tmux unbind-key -T ${KEY_TABLE} C-t 2>/dev/null`,{stdio:"ignore"}),execSync13(`tmux unbind-key -T ${KEY_TABLE} 'C-\\' 2>/dev/null`,{stdio:"ignore"}),execSync13(`tmux set-hook -u -t ${session} client-session-changed 2>/dev/null`,{stdio:"ignore"}),execSync13(`tmux kill-session -t ${session} 2>/dev/null`,{stdio:"ignore"})}catch{}}function attachTuiSession(){spawnSync2("tmux",["attach-session","-t",SESSION_NAME],{stdio:"inherit"})}function listSessionWindows(session){try{let output=execSync13(`tmux list-windows -t ${session} -F '#{window_name}:#{window_index}:#{?window_active,1,0}' 2>/dev/null`,{encoding:"utf-8"}).trim();if(!output)return[];return output.split(`
1436
1436
  `).map((line)=>{let[name,idx,active]=line.split(":");return{name,index:Number.parseInt(idx,10),active:active==="1"}})}catch{return[]}}var SESSION_NAME="genie-tui",KEY_TABLE="genie-tui",NAV_WIDTH=30;var init_tmux2=__esm(()=>{init_theme2()});var highlights_default="./highlights-ghv9g403.scm";var init_highlights=()=>{};var tree_sitter_javascript_default="./tree-sitter-javascript-nd0q4pe9.wasm";var init_tree_sitter_javascript=()=>{};var highlights_default2="./highlights-eq9cgrbb.scm";var init_highlights2=()=>{};var tree_sitter_typescript_default="./tree-sitter-typescript-zxjzwt75.wasm";var init_tree_sitter_typescript=()=>{};var highlights_default3="./highlights-r812a2qc.scm";var init_highlights3=()=>{};var tree_sitter_markdown_default="./tree-sitter-markdown-411r6y9b.wasm";var init_tree_sitter_markdown=()=>{};var injections_default="./injections-73j83es3.scm";var init_injections=()=>{};var highlights_default4="./highlights-x6tmsnaa.scm";var init_highlights4=()=>{};var tree_sitter_markdown_inline_default="./tree-sitter-markdown_inline-j5349f42.wasm";var init_tree_sitter_markdown_inline=()=>{};var highlights_default5="./highlights-hk7bwhj4.scm";var init_highlights5=()=>{};var tree_sitter_zig_default="./tree-sitter-zig-e78zbjpm.wasm";var init_tree_sitter_zig=()=>{};import{EventEmitter}from"events";import{Buffer as Buffer2}from"buffer";import{Buffer as Buffer3}from"buffer";import{EventEmitter as EventEmitter2}from"events";import{resolve as resolve7,dirname as dirname9}from"path";import{fileURLToPath as fileURLToPath2}from"url";import{resolve as resolve22,isAbsolute,parse as parse2}from"path";import{existsSync as existsSync33}from"fs";import{basename as basename7,join as join44}from"path";import os2 from"os";import path2 from"path";import{EventEmitter as EventEmitter3}from"events";import path22 from"path";import{readFile as readFile22,writeFile as writeFile22,mkdir as mkdir22}from"fs/promises";import*as path4 from"path";import{mkdir as mkdir9,readFile as readFile13,writeFile as writeFile6}from"fs/promises";import*as path3 from"path";import{readdir as readdir7}from"fs/promises";import{dlopen,toArrayBuffer as toArrayBuffer4,JSCallback,ptr as ptr4}from"bun:ffi";import{existsSync as existsSync210,writeFileSync as writeFileSync11}from"fs";import{EventEmitter as EventEmitter4}from"events";import{toArrayBuffer,ptr}from"bun:ffi";import{ptr as ptr2,toArrayBuffer as toArrayBuffer2}from"bun:ffi";import{ptr as ptr3,toArrayBuffer as toArrayBuffer3}from"bun:ffi";import{EventEmitter as EventEmitter5}from"events";import util3 from"util";import{EventEmitter as EventEmitter7}from"events";import{Console}from"console";import fs2 from"fs";import path5 from"path";import util22 from"util";import{Writable}from"stream";import{EventEmitter as EventEmitter6}from"events";import{EventEmitter as EventEmitter8}from"events";function __exportSetter2(name,newValue){this[name]=__returnValue2.bind(null,newValue)}function wrapAssembly(lib){function patch(prototype,name,fn){let original=prototype[name];prototype[name]=function(){for(var _len=arguments.length,args=Array(_len),_key=0;_key<_len;_key++)args[_key]=arguments[_key];return fn.call(this,original,...args)}}for(let fnName of["setPosition","setMargin","setFlexBasis","setWidth","setHeight","setMinWidth","setMinHeight","setMaxWidth","setMaxHeight","setPadding","setGap"]){let methods={[Unit.Point]:lib.Node.prototype[fnName],[Unit.Percent]:lib.Node.prototype[`${fnName}Percent`],[Unit.Auto]:lib.Node.prototype[`${fnName}Auto`]};patch(lib.Node.prototype,fnName,function(original){for(var _len2=arguments.length,args=Array(_len2>1?_len2-1:0),_key2=1;_key2<_len2;_key2++)args[_key2-1]=arguments[_key2];let value=args.pop(),unit,asNumber;if(value==="auto")unit=Unit.Auto,asNumber=void 0;else if(typeof value==="object")unit=value.unit,asNumber=value.valueOf();else if(unit=typeof value==="string"&&value.endsWith("%")?Unit.Percent:Unit.Point,asNumber=parseFloat(value),value!==void 0&&!Number.isNaN(value)&&Number.isNaN(asNumber))throw Error(`Invalid value ${value} for ${fnName}`);if(!methods[unit])throw Error(`Failed to execute "${fnName}": Unsupported unit '${value}'`);if(asNumber!==void 0)return methods[unit].call(this,...args,asNumber);else return methods[unit].call(this,...args)})}function wrapMeasureFunction(measureFunction){return lib.MeasureCallback.implement({measure:function(){let{width,height:height2}=measureFunction(...arguments);return{width:width??NaN,height:height2??NaN}}})}patch(lib.Node.prototype,"setMeasureFunc",function(original,measureFunc){if(measureFunc)return original.call(this,wrapMeasureFunction(measureFunc));else return this.unsetMeasureFunc()});function wrapDirtiedFunc(dirtiedFunction){return lib.DirtiedCallback.implement({dirtied:dirtiedFunction})}return patch(lib.Node.prototype,"setDirtiedFunc",function(original,dirtiedFunc){original.call(this,wrapDirtiedFunc(dirtiedFunc))}),patch(lib.Config.prototype,"free",function(){lib.Config.destroy(this)}),patch(lib.Node,"create",(_,config)=>{return config?lib.Node.createWithConfig(config):lib.Node.createDefault()}),patch(lib.Node.prototype,"free",function(){lib.Node.destroy(this)}),patch(lib.Node.prototype,"freeRecursive",function(){for(let t=0,T=this.getChildCount();t<T;++t)this.getChild(0).freeRecursive();this.free()}),patch(lib.Node.prototype,"calculateLayout",function(original){let width=arguments.length>1&&arguments[1]!==void 0?arguments[1]:NaN,height2=arguments.length>2&&arguments[2]!==void 0?arguments[2]:NaN,direction=arguments.length>3&&arguments[3]!==void 0?arguments[3]:Direction.LTR;return original.call(this,width,height2,direction)}),{Config:lib.Config,Node:lib.Node,...YGEnums_default}}function isValidBorderStyle(value){return typeof value==="string"&&VALID_BORDER_STYLES.includes(value)}function parseBorderStyle(value,fallback="single"){if(isValidBorderStyle(value))return value;if(value!==void 0&&value!==null)console.warn(`Invalid borderStyle "${value}", falling back to "${fallback}". Valid values are: ${VALID_BORDER_STYLES.join(", ")}`);return fallback}function getBorderFromSides(sides){let result=[];if(sides.top)result.push("top");if(sides.right)result.push("right");if(sides.bottom)result.push("bottom");if(sides.left)result.push("left");return result.length>0?result:!1}function getBorderSides(border){return border===!0?{top:!0,right:!0,bottom:!0,left:!0}:Array.isArray(border)?{top:border.includes("top"),right:border.includes("right"),bottom:border.includes("bottom"),left:border.includes("left")}:{top:!1,right:!1,bottom:!1,left:!1}}function borderCharsToArray(chars){let array=new Uint32Array(11);return array[0]=chars.topLeft.codePointAt(0),array[1]=chars.topRight.codePointAt(0),array[2]=chars.bottomLeft.codePointAt(0),array[3]=chars.bottomRight.codePointAt(0),array[4]=chars.horizontal.codePointAt(0),array[5]=chars.vertical.codePointAt(0),array[6]=chars.topT.codePointAt(0),array[7]=chars.bottomT.codePointAt(0),array[8]=chars.leftT.codePointAt(0),array[9]=chars.rightT.codePointAt(0),array[10]=chars.cross.codePointAt(0),array}class KeyEvent{name;ctrl;meta;shift;option;sequence;number;raw;eventType;source;code;super;hyper;capsLock;numLock;baseCode;repeated;_defaultPrevented=!1;_propagationStopped=!1;constructor(key){this.name=key.name,this.ctrl=key.ctrl,this.meta=key.meta,this.shift=key.shift,this.option=key.option,this.sequence=key.sequence,this.number=key.number,this.raw=key.raw,this.eventType=key.eventType,this.source=key.source,this.code=key.code,this.super=key.super,this.hyper=key.hyper,this.capsLock=key.capsLock,this.numLock=key.numLock,this.baseCode=key.baseCode,this.repeated=key.repeated}get defaultPrevented(){return this._defaultPrevented}get propagationStopped(){return this._propagationStopped}preventDefault(){this._defaultPrevented=!0}stopPropagation(){this._propagationStopped=!0}}class PasteEvent{type="paste";bytes;metadata;_defaultPrevented=!1;_propagationStopped=!1;constructor(bytes,metadata){this.bytes=bytes,this.metadata=metadata}get defaultPrevented(){return this._defaultPrevented}get propagationStopped(){return this._propagationStopped}preventDefault(){this._defaultPrevented=!0}stopPropagation(){this._propagationStopped=!0}}class RGBA{buffer;constructor(buffer2){this.buffer=buffer2}static fromArray(array){return new RGBA(array)}static fromValues(r,g,b2,a=1){return new RGBA(new Float32Array([r,g,b2,a]))}static fromInts(r,g,b2,a=255){return new RGBA(new Float32Array([r/255,g/255,b2/255,a/255]))}static fromHex(hex){return hexToRgb(hex)}toInts(){return[Math.round(this.r*255),Math.round(this.g*255),Math.round(this.b*255),Math.round(this.a*255)]}get r(){return this.buffer[0]}set r(value){this.buffer[0]=value}get g(){return this.buffer[1]}set g(value){this.buffer[1]=value}get b(){return this.buffer[2]}set b(value){this.buffer[2]=value}get a(){return this.buffer[3]}set a(value){this.buffer[3]=value}map(fn){return[fn(this.r),fn(this.g),fn(this.b),fn(this.a)]}toString(){return`rgba(${this.r.toFixed(2)}, ${this.g.toFixed(2)}, ${this.b.toFixed(2)}, ${this.a.toFixed(2)})`}equals(other){if(!other)return!1;return this.r===other.r&&this.g===other.g&&this.b===other.b&&this.a===other.a}}function hexToRgb(hex){if(hex=hex.replace(/^#/,""),hex.length===3)hex=hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];else if(hex.length===4)hex=hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2]+hex[3]+hex[3];if(!/^[0-9A-Fa-f]{6}$/.test(hex)&&!/^[0-9A-Fa-f]{8}$/.test(hex))return console.warn(`Invalid hex color: ${hex}, defaulting to magenta`),RGBA.fromValues(1,0,1,1);let r=parseInt(hex.substring(0,2),16)/255,g=parseInt(hex.substring(2,4),16)/255,b2=parseInt(hex.substring(4,6),16)/255,a=hex.length===8?parseInt(hex.substring(6,8),16)/255:1;return RGBA.fromValues(r,g,b2,a)}function rgbToHex(rgb){return"#"+(rgb.a===1?[rgb.r,rgb.g,rgb.b]:[rgb.r,rgb.g,rgb.b,rgb.a]).map((x)=>{let hex=Math.floor(Math.max(0,Math.min(1,x)*255)).toString(16);return hex.length===1?"0"+hex:hex}).join("")}function hsvToRgb(h,s,v){let r=0,g=0,b2=0,i2=Math.floor(h/60)%6,f=h/60-Math.floor(h/60),p=v*(1-s),q=v*(1-f*s),t=v*(1-(1-f)*s);switch(i2){case 0:r=v,g=t,b2=p;break;case 1:r=q,g=v,b2=p;break;case 2:r=p,g=v,b2=t;break;case 3:r=p,g=q,b2=v;break;case 4:r=t,g=p,b2=v;break;case 5:r=v,g=p,b2=q;break}return RGBA.fromValues(r,g,b2,1)}function parseColor(color){if(typeof color==="string"){let lowerColor=color.toLowerCase();if(lowerColor==="transparent")return RGBA.fromValues(0,0,0,0);if(CSS_COLOR_NAMES[lowerColor])return hexToRgb(CSS_COLOR_NAMES[lowerColor]);return hexToRgb(color)}return color}function parseColorTags(text){let segments=[],currentIndex=0,colorTagRegex=/<c(\d+)>(.*?)<\/c\d+>/g,lastIndex=0,match;while((match=colorTagRegex.exec(text))!==null){if(match.index>lastIndex){let plainText=text.slice(lastIndex,match.index);if(plainText)segments.push({text:plainText,colorIndex:0})}let colorIndex=parseInt(match[1])-1,taggedText=match[2];segments.push({text:taggedText,colorIndex:Math.max(0,colorIndex)}),lastIndex=match.index+match[0].length}if(lastIndex<text.length){let remainingText=text.slice(lastIndex);if(remainingText)segments.push({text:remainingText,colorIndex:0})}return segments}function getParsedFont(fontKey){if(!parsedFonts[fontKey]){let fontDef=fonts[fontKey],parsedChars={};for(let[char,lines]of Object.entries(fontDef.chars))parsedChars[char]=lines.map((line)=>parseColorTags(line));parsedFonts[fontKey]={...fontDef,colors:fontDef.colors||1,chars:parsedChars}}return parsedFonts[fontKey]}function measureText({text,font="tiny"}){let fontDef=getParsedFont(font);if(!fontDef)return console.warn(`Font '${font}' not found`),{width:0,height:0};let currentX=0;for(let i2=0;i2<text.length;i2++){let char=text[i2].toUpperCase(),charDef=fontDef.chars[char];if(!charDef){let spaceChar=fontDef.chars[" "];if(spaceChar&&spaceChar[0]){let spaceWidth=0;for(let segment of spaceChar[0])spaceWidth+=segment.text.length;currentX+=spaceWidth}else currentX+=1;continue}let charWidth=0;if(charDef[0])for(let segment of charDef[0])charWidth+=segment.text.length;if(currentX+=charWidth,i2<text.length-1)currentX+=fontDef.letterspace_size}return{width:currentX,height:fontDef.lines}}function getCharacterPositions(text,font="tiny"){let fontDef=getParsedFont(font);if(!fontDef)return[0];let positions=[0],currentX=0;for(let i2=0;i2<text.length;i2++){let char=text[i2].toUpperCase(),charDef=fontDef.chars[char],charWidth=0;if(!charDef){let spaceChar=fontDef.chars[" "];if(spaceChar&&spaceChar[0])for(let segment of spaceChar[0])charWidth+=segment.text.length;else charWidth=1}else if(charDef[0])for(let segment of charDef[0])charWidth+=segment.text.length;if(currentX+=charWidth,i2<text.length-1)currentX+=fontDef.letterspace_size;positions.push(currentX)}return positions}function coordinateToCharacterIndex(x,text,font="tiny"){let positions=getCharacterPositions(text,font);if(x<0)return 0;for(let i2=0;i2<positions.length-1;i2++){let currentPos=positions[i2],nextPos=positions[i2+1];if(x>=currentPos&&x<nextPos){let charMidpoint=currentPos+(nextPos-currentPos)/2;return x<charMidpoint?i2:i2+1}}if(positions.length>0&&x>=positions[positions.length-1])return text.length;return 0}function renderFontToFrameBuffer(buffer2,{text,x=0,y=0,color=[RGBA.fromInts(255,255,255,255)],backgroundColor=RGBA.fromInts(0,0,0,255),font="tiny"}){let{width,height:height2}=buffer2,fontDef=getParsedFont(font);if(!fontDef)return console.warn(`Font '${font}' not found`),{width:0,height:0};let colors4=Array.isArray(color)?color:[color];if(y<0||y+fontDef.lines>height2)return{width:0,height:fontDef.lines};let currentX=x,startX=x;for(let i2=0;i2<text.length;i2++){let char=text[i2].toUpperCase(),charDef=fontDef.chars[char];if(!charDef){let spaceChar=fontDef.chars[" "];if(spaceChar&&spaceChar[0]){let spaceWidth=0;for(let segment of spaceChar[0])spaceWidth+=segment.text.length;currentX+=spaceWidth}else currentX+=1;continue}let charWidth=0;if(charDef[0])for(let segment of charDef[0])charWidth+=segment.text.length;if(currentX>=width)break;if(currentX+charWidth<0){currentX+=charWidth+fontDef.letterspace_size;continue}for(let lineIdx=0;lineIdx<fontDef.lines&&lineIdx<charDef.length;lineIdx++){let segments=charDef[lineIdx],renderY=y+lineIdx;if(renderY>=0&&renderY<height2){let segmentX=currentX;for(let segment of segments){let segmentColor=colors4[segment.colorIndex]||colors4[0];for(let charIdx=0;charIdx<segment.text.length;charIdx++){let renderX=segmentX+charIdx;if(renderX>=0&&renderX<width){let fontChar=segment.text[charIdx];if(fontChar!==" ")buffer2.setCellWithAlphaBlending(renderX,renderY,fontChar,parseColor(segmentColor),parseColor(backgroundColor))}}segmentX+=segment.text.length}}}if(currentX+=charWidth,i2<text.length-1)currentX+=fontDef.letterspace_size}return{width:currentX-startX,height:fontDef.lines}}function getBaseAttributes(attr){return attr&ATTRIBUTE_BASE_MASK}function createTextAttributes({bold=!1,italic=!1,underline=!1,dim=!1,blink=!1,inverse=!1,hidden=!1,strikethrough=!1}={}){let attributes=TextAttributes.NONE;if(bold)attributes|=TextAttributes.BOLD;if(italic)attributes|=TextAttributes.ITALIC;if(underline)attributes|=TextAttributes.UNDERLINE;if(dim)attributes|=TextAttributes.DIM;if(blink)attributes|=TextAttributes.BLINK;if(inverse)attributes|=TextAttributes.INVERSE;if(hidden)attributes|=TextAttributes.HIDDEN;if(strikethrough)attributes|=TextAttributes.STRIKETHROUGH;return attributes}function attributesWithLink(baseAttributes,linkId){let base=baseAttributes&ATTRIBUTE_BASE_MASK2,linkBits=(linkId&LINK_ID_PAYLOAD_MASK)<<LINK_ID_SHIFT;return base|linkBits}function getLinkId(attributes){return attributes>>>LINK_ID_SHIFT&LINK_ID_PAYLOAD_MASK}function visualizeRenderableTree(renderable,maxDepth=10){function buildTreeLines(node,prefix="",parentPrefix="",isLastChild=!0,depth=0){if(depth>=maxDepth)return[`${prefix}${node.id} ... (max depth reached)`];let lines=[],children=node.getChildren();if(lines.push(`${prefix}${node.id}`),children.length>0){let lastChildIndex=children.length-1;children.forEach((child,index)=>{let childIsLast=index===lastChildIndex,connector=childIsLast?"\u2514\u2500\u2500 ":"\u251C\u2500\u2500 ",childPrefix=parentPrefix+(isLastChild?" ":"\u2502 "),childLines=buildTreeLines(child,childPrefix+connector,childPrefix,childIsLast,depth+1);lines.push(...childLines)})}return lines}let treeLines=buildTreeLines(renderable);console.log(`Renderable Tree:
1437
1437
  `+treeLines.join(`
1438
1438
  `))}function isStyledText(obj){return obj&&obj[BrandedStyledText]}function stringToStyledText(content){return new StyledText([{__isChunk:!0,text:content}])}function applyStyle(input,style){if(typeof input==="object"&&"__isChunk"in input){let existingChunk=input,fg=style.fg?parseColor(style.fg):existingChunk.fg,bg=style.bg?parseColor(style.bg):existingChunk.bg,newAttrs=createTextAttributes(style),mergedAttrs=existingChunk.attributes?existingChunk.attributes|newAttrs:newAttrs;return{__isChunk:!0,text:existingChunk.text,fg,bg,attributes:mergedAttrs,link:existingChunk.link}}else{let plainTextStr=String(input),fg=style.fg?parseColor(style.fg):void 0,bg=style.bg?parseColor(style.bg):void 0,attributes=createTextAttributes(style);return{__isChunk:!0,text:plainTextStr,fg,bg,attributes}}}function t(strings,...values2){let chunks=[];for(let i2=0;i2<strings.length;i2++){let raw=strings[i2];if(raw)chunks.push({__isChunk:!0,text:raw,attributes:0});let val=values2[i2];if(typeof val==="object"&&"__isChunk"in val)chunks.push(val);else if(val!==void 0){let plainTextStr=String(val);chunks.push({__isChunk:!0,text:plainTextStr,attributes:0})}}return new StyledText(chunks)}function hastToTextChunks(node,syntaxStyle,parentStyles=[]){let chunks=[];if(node.type==="text"){let stylesToMerge=parentStyles.length>0?parentStyles:["default"],mergedStyle=syntaxStyle.mergeStyles(...stylesToMerge);chunks.push({__isChunk:!0,text:node.value,fg:mergedStyle.fg,bg:mergedStyle.bg,attributes:mergedStyle.attributes})}else if(node.type==="element"){let currentStyles=[...parentStyles];if(node.properties?.className){let classes=node.properties.className.split(" ");for(let cls of classes)currentStyles.push(cls)}for(let child of node.children)chunks.push(...hastToTextChunks(child,syntaxStyle,currentStyles))}return chunks}function hastToStyledText(hast,syntaxStyle){let chunks=hastToTextChunks(hast,syntaxStyle);return new StyledText(chunks)}class SystemClock{now(){if(!globalThis.performance||typeof globalThis.performance.now!=="function")throw Error("SystemClock requires globalThis.performance.now()");return globalThis.performance.now()}setTimeout(fn,delayMs){return globalThis.setTimeout(fn,delayMs)}clearTimeout(handle){globalThis.clearTimeout(handle)}setInterval(fn,delayMs){return globalThis.setInterval(fn,delayMs)}clearInterval(handle){globalThis.clearInterval(handle)}}function fromKittyMods(mod){return{shift:!!(mod&1),alt:!!(mod&2),ctrl:!!(mod&4),super:!!(mod&8),hyper:!!(mod&16),meta:!!(mod&32),capsLock:!!(mod&64),numLock:!!(mod&128)}}function parseKittySpecialKey(sequence){let match=/^\x1b\[(\d+);(\d+):(\d+)([A-Z~])$/.exec(sequence);if(!match)return null;let keyNumOrOne=match[1],modifierStr=match[2],eventTypeStr=match[3],terminator=match[4],keyName;if(terminator==="~")keyName=tildeKeyMap[keyNumOrOne];else{if(keyNumOrOne!=="1")return null;keyName=functionalKeyMap[terminator]}if(!keyName)return null;let key={name:keyName,ctrl:!1,meta:!1,shift:!1,option:!1,number:!1,sequence,raw:sequence,eventType:"press",source:"kitty",super:!1,hyper:!1,capsLock:!1,numLock:!1};if(modifierStr){let modifierMask=parseInt(modifierStr,10);if(!isNaN(modifierMask)&&modifierMask>1){let mods=fromKittyMods(modifierMask-1);key.shift=mods.shift,key.ctrl=mods.ctrl,key.meta=mods.alt||mods.meta,key.option=mods.alt,key.super=mods.super,key.hyper=mods.hyper,key.capsLock=mods.capsLock,key.numLock=mods.numLock}}if(eventTypeStr==="1"||!eventTypeStr)key.eventType="press";else if(eventTypeStr==="2")key.eventType="press",key.repeated=!0;else if(eventTypeStr==="3")key.eventType="release";return key}function parseKittyKeyboard(sequence){let specialResult=parseKittySpecialKey(sequence);if(specialResult)return specialResult;let match=/^\x1b\[([^\x1b]+)u$/.exec(sequence);if(!match)return null;let fields=match[1].split(";");if(fields.length<1)return null;let key={name:"",ctrl:!1,meta:!1,shift:!1,option:!1,number:!1,sequence,raw:sequence,eventType:"press",source:"kitty",super:!1,hyper:!1,capsLock:!1,numLock:!1},text="",field1=fields[0]?.split(":")||[],codepointStr=field1[0];if(!codepointStr)return null;let codepoint=parseInt(codepointStr,10);if(isNaN(codepoint))return null;let shiftedCodepoint,baseCodepoint;if(field1[1]){let shifted=parseInt(field1[1],10);if(!isNaN(shifted)&&shifted>0&&shifted<=1114111)shiftedCodepoint=shifted}if(field1[2]){let base=parseInt(field1[2],10);if(!isNaN(base)&&base>0&&base<=1114111)baseCodepoint=base}let knownKey=kittyKeyMap[codepoint];if(knownKey)key.name=knownKey,key.code=`[${codepoint}u`;else if(codepoint===0)key.name="";else if(codepoint>0&&codepoint<=1114111){let char=String.fromCodePoint(codepoint);if(key.name=char,baseCodepoint)key.baseCode=baseCodepoint}else return null;if(fields[1]){let field2=fields[1].split(":"),modifierStr=field2[0],eventTypeStr=field2[1];if(modifierStr){let modifierMask=parseInt(modifierStr,10);if(!isNaN(modifierMask)&&modifierMask>1){let mods=fromKittyMods(modifierMask-1);key.shift=mods.shift,key.ctrl=mods.ctrl,key.meta=mods.alt||mods.meta,key.option=mods.alt,key.super=mods.super,key.hyper=mods.hyper,key.capsLock=mods.capsLock,key.numLock=mods.numLock}}if(eventTypeStr==="1"||!eventTypeStr)key.eventType="press";else if(eventTypeStr==="2")key.eventType="press",key.repeated=!0;else if(eventTypeStr==="3")key.eventType="release";else key.eventType="press"}if(fields[2]){let codepoints=fields[2].split(":");for(let cpStr of codepoints){let cp3=parseInt(cpStr,10);if(!isNaN(cp3)&&cp3>0&&cp3<=1114111)text+=String.fromCodePoint(cp3)}}if(text===""){if(key.name.length>0&&!kittyKeyMap[codepoint])if(key.shift&&shiftedCodepoint)text=String.fromCodePoint(shiftedCodepoint);else if(key.shift&&key.name.length===1)text=key.name.toLocaleUpperCase();else text=key.name}if(key.name===" "&&key.shift&&!key.ctrl&&!key.meta)text=" ";if(text){if(codepoint===0)key.name=text;key.sequence=text}if(codepoint===0&&text==="")return null;return key}class LinearScrollAccel{tick(_now){return 1}reset(){}}class MacOSScrollAccel{opts;lastTickTime=0;velocityHistory=[];historySize=3;streakTimeout=150;minTickInterval=6;constructor(opts={}){this.opts=opts}tick(now=Date.now()){let A=this.opts.A??0.8,tau=this.opts.tau??3,maxMultiplier=this.opts.maxMultiplier??6,dt=this.lastTickTime?now-this.lastTickTime:1/0;if(dt===1/0||dt>this.streakTimeout)return this.lastTickTime=now,this.velocityHistory=[],1;if(dt<this.minTickInterval)return 1;if(this.lastTickTime=now,this.velocityHistory.push(dt),this.velocityHistory.length>this.historySize)this.velocityHistory.shift();let x=100/(this.velocityHistory.reduce((a,b2)=>a+b2,0)/this.velocityHistory.length)/tau,multiplier=1+A*(Math.exp(x)-1);return Math.min(multiplier,maxMultiplier)}reset(){this.lastTickTime=0,this.velocityHistory=[]}}function parseAlign(value){if(value==null)return Align.Auto;switch(value.toLowerCase()){case"auto":return Align.Auto;case"flex-start":return Align.FlexStart;case"center":return Align.Center;case"flex-end":return Align.FlexEnd;case"stretch":return Align.Stretch;case"baseline":return Align.Baseline;case"space-between":return Align.SpaceBetween;case"space-around":return Align.SpaceAround;case"space-evenly":return Align.SpaceEvenly;default:return Align.Auto}}function parseAlignItems(value){if(value==null)return Align.Stretch;switch(value.toLowerCase()){case"auto":return Align.Auto;case"flex-start":return Align.FlexStart;case"center":return Align.Center;case"flex-end":return Align.FlexEnd;case"stretch":return Align.Stretch;case"baseline":return Align.Baseline;case"space-between":return Align.SpaceBetween;case"space-around":return Align.SpaceAround;case"space-evenly":return Align.SpaceEvenly;default:return Align.Stretch}}function parseBoxSizing(value){if(value==null)return BoxSizing.BorderBox;switch(value.toLowerCase()){case"border-box":return BoxSizing.BorderBox;case"content-box":return BoxSizing.ContentBox;default:return BoxSizing.BorderBox}}function parseDimension(value){if(value==null)return Dimension.Width;switch(value.toLowerCase()){case"width":return Dimension.Width;case"height":return Dimension.Height;default:return Dimension.Width}}function parseDirection(value){if(value==null)return Direction.LTR;switch(value.toLowerCase()){case"inherit":return Direction.Inherit;case"ltr":return Direction.LTR;case"rtl":return Direction.RTL;default:return Direction.LTR}}function parseDisplay(value){if(value==null)return Display.Flex;switch(value.toLowerCase()){case"flex":return Display.Flex;case"none":return Display.None;case"contents":return Display.Contents;default:return Display.Flex}}function parseEdge(value){if(value==null)return Edge.All;switch(value.toLowerCase()){case"left":return Edge.Left;case"top":return Edge.Top;case"right":return Edge.Right;case"bottom":return Edge.Bottom;case"start":return Edge.Start;case"end":return Edge.End;case"horizontal":return Edge.Horizontal;case"vertical":return Edge.Vertical;case"all":return Edge.All;default:return Edge.All}}function parseFlexDirection(value){if(value==null)return FlexDirection.Column;switch(value.toLowerCase()){case"column":return FlexDirection.Column;case"column-reverse":return FlexDirection.ColumnReverse;case"row":return FlexDirection.Row;case"row-reverse":return FlexDirection.RowReverse;default:return FlexDirection.Column}}function parseGutter(value){if(value==null)return Gutter.All;switch(value.toLowerCase()){case"column":return Gutter.Column;case"row":return Gutter.Row;case"all":return Gutter.All;default:return Gutter.All}}function parseJustify(value){if(value==null)return Justify.FlexStart;switch(value.toLowerCase()){case"flex-start":return Justify.FlexStart;case"center":return Justify.Center;case"flex-end":return Justify.FlexEnd;case"space-between":return Justify.SpaceBetween;case"space-around":return Justify.SpaceAround;case"space-evenly":return Justify.SpaceEvenly;default:return Justify.FlexStart}}function parseLogLevel(value){if(value==null)return LogLevel.Info;switch(value.toLowerCase()){case"error":return LogLevel.Error;case"warn":return LogLevel.Warn;case"info":return LogLevel.Info;case"debug":return LogLevel.Debug;case"verbose":return LogLevel.Verbose;case"fatal":return LogLevel.Fatal;default:return LogLevel.Info}}function parseMeasureMode(value){if(value==null)return MeasureMode.Undefined;switch(value.toLowerCase()){case"undefined":return MeasureMode.Undefined;case"exactly":return MeasureMode.Exactly;case"at-most":return MeasureMode.AtMost;default:return MeasureMode.Undefined}}function parseOverflow(value){if(value==null)return Overflow.Visible;switch(value.toLowerCase()){case"visible":return Overflow.Visible;case"hidden":return Overflow.Hidden;case"scroll":return Overflow.Scroll;default:return Overflow.Visible}}function parsePositionType(value){if(value==null)return PositionType.Relative;switch(value.toLowerCase()){case"static":return PositionType.Static;case"relative":return PositionType.Relative;case"absolute":return PositionType.Absolute;default:return PositionType.Static}}function parseUnit(value){if(value==null)return Unit.Point;switch(value.toLowerCase()){case"undefined":return Unit.Undefined;case"point":return Unit.Point;case"percent":return Unit.Percent;case"auto":return Unit.Auto;default:return Unit.Point}}function parseWrap(value){if(value==null)return Wrap.NoWrap;switch(value.toLowerCase()){case"no-wrap":return Wrap.NoWrap;case"wrap":return Wrap.Wrap;case"wrap-reverse":return Wrap.WrapReverse;default:return Wrap.NoWrap}}class SelectionAnchor{renderable;relativeX;relativeY;constructor(renderable,absoluteX,absoluteY){this.renderable=renderable,this.relativeX=absoluteX-this.renderable.x,this.relativeY=absoluteY-this.renderable.y}get x(){return this.renderable.x+this.relativeX}get y(){return this.renderable.y+this.relativeY}}class Selection{_anchor;_focus;_selectedRenderables=[];_touchedRenderables=[];_isActive=!0;_isDragging=!0;_isStart=!1;constructor(anchorRenderable,anchor,focus){this._anchor=new SelectionAnchor(anchorRenderable,anchor.x,anchor.y),this._focus={...focus}}get isStart(){return this._isStart}set isStart(value){this._isStart=value}get anchor(){return{x:this._anchor.x,y:this._anchor.y}}get focus(){return{...this._focus}}set focus(value){this._focus={...value}}get isActive(){return this._isActive}set isActive(value){this._isActive=value}get isDragging(){return this._isDragging}set isDragging(value){this._isDragging=value}get bounds(){let minX=Math.min(this._anchor.x,this._focus.x),maxX=Math.max(this._anchor.x,this._focus.x),minY=Math.min(this._anchor.y,this._focus.y),maxY=Math.max(this._anchor.y,this._focus.y),width=maxX-minX+1,height2=maxY-minY+1;return{x:minX,y:minY,width,height:height2}}updateSelectedRenderables(selectedRenderables){this._selectedRenderables=selectedRenderables}get selectedRenderables(){return this._selectedRenderables}updateTouchedRenderables(touchedRenderables){this._touchedRenderables=touchedRenderables}get touchedRenderables(){return this._touchedRenderables}getSelectedText(){return this._selectedRenderables.sort((a,b2)=>{let aY=a.y,bY=b2.y;if(aY!==bY)return aY-bY;return a.x-b2.x}).filter((renderable)=>!renderable.isDestroyed).map((renderable)=>renderable.getSelectedText()).filter((text)=>text).join(`
@@ -1901,7 +1901,7 @@ $ bun add react-devtools-core@7 -d
1901
1901
  ORDER BY a.started_at DESC
1902
1902
  `).map(mapAssignment)}function mapOrg(row){return{id:String(row.id),name:String(row.name),slug:String(row.slug),description:row.description?String(row.description):null,leaderAgent:row.leader_agent?String(row.leader_agent):null}}function mapProject2(row){return{id:String(row.id),name:String(row.name),description:row.description?String(row.description):null,orgId:row.org_id?String(row.org_id):null,leaderAgent:row.leader_agent?String(row.leader_agent):null,tmuxSession:row.tmux_session?String(row.tmux_session):null,repoPath:row.repo_path?String(row.repo_path):null}}function mapBoard2(row){let rawCols=row.columns,columns=Array.isArray(rawCols)?rawCols.map((c,i2)=>({id:String(c.id??`col-${i2}`),name:String(c.name??""),label:String(c.label??c.name??""),color:String(c.color??"#94a3b8"),position:typeof c.position==="number"?c.position:i2})):[];return{id:String(row.id),name:String(row.name),projectId:row.project_id?String(row.project_id):null,description:row.description?String(row.description):null,columns}}function mapTask2(row){return{id:String(row.id),seq:Number(row.seq),title:String(row.title),status:String(row.status),stage:String(row.stage),priority:String(row.priority),projectId:row.project_id?String(row.project_id):null,boardId:row.board_id?String(row.board_id):null,columnId:row.column_id?String(row.column_id):null,description:row.description?String(row.description):null}}function mapAgentProject(row){return{agentName:String(row.agent_name),projectId:String(row.project_id),role:String(row.role)}}function mapExecutor(row){let meta=row.metadata;return{id:String(row.id),agentId:String(row.agent_id),agentName:row.agent_name?String(row.agent_name):null,provider:String(row.provider),transport:String(row.transport),pid:row.pid!=null?Number(row.pid):null,tmuxSession:row.tmux_session?String(row.tmux_session):null,tmuxPaneId:row.tmux_pane_id?String(row.tmux_pane_id):null,state:String(row.state),metadata:typeof meta==="string"?JSON.parse(meta):meta??{},startedAt:row.started_at instanceof Date?row.started_at.toISOString():String(row.started_at),role:row.role?String(row.role):null,team:row.team?String(row.team):null}}function mapAssignment(row){return{id:String(row.id),executorId:String(row.executor_id),taskId:row.task_id?String(row.task_id):null,taskTitle:row.task_title?String(row.task_title):null,wishSlug:row.wish_slug?String(row.wish_slug):null,groupNumber:row.group_number!=null?Number(row.group_number):null,startedAt:row.started_at instanceof Date?row.started_at.toISOString():String(row.started_at)}}function loadTmuxTree(){let output;try{output=execSync14("tmux list-windows -a -F '#{session_name}|#{window_index}|#{window_name}|#{window_active}|#{window_panes}|#{session_attached}|#{session_windows}'",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return[]}if(!output)return[];let sessionMap=new Map;for(let line of output.split(`
1903
1903
  `)){if(!line)continue;let[sessName,winIdx,winName,winActive,winPanes,sessAttached,sessWindows]=line.split("|");if(!sessionMap.has(sessName))sessionMap.set(sessName,{name:sessName,attached:sessAttached==="1",windowCount:Number.parseInt(sessWindows,10)||0,windows:[]});sessionMap.get(sessName)?.windows.push({sessionName:sessName,index:Number.parseInt(winIdx,10)||0,name:winName,active:winActive==="1",paneCount:Number.parseInt(winPanes,10)||0})}return Array.from(sessionMap.values()).sort((a,b3)=>a.name.localeCompare(b3.name))}var init_db2=()=>{};import{execSync as execSync15}from"child_process";function execQuiet(cmd){try{return execSync15(cmd,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return""}}function parsePaneLine(parts){let[sessionName,winIdxStr,winName,winActive,winPanes,paneIdxStr,paneId,panePidStr,paneCmd,paneTitle,paneSize,sessAttached,sessWindows,sessCreated,paneDead]=parts;return{sessionName,winIdxStr,session:{name:sessionName,attached:sessAttached==="1",windowCount:Number.parseInt(sessWindows,10)||0,created:Number.parseInt(sessCreated,10)||0},window:{sessionName,index:Number.parseInt(winIdxStr,10)||0,name:winName,active:winActive==="1",paneCount:Number.parseInt(winPanes,10)||0},pane:{sessionName,windowIndex:Number.parseInt(winIdxStr,10)||0,paneIndex:Number.parseInt(paneIdxStr,10)||0,paneId,pid:Number.parseInt(panePidStr,10)||0,command:paneCmd,title:paneTitle,size:paneSize,isDead:paneDead==="1"}}}function getTmuxInventory(){let paneOutput=execQuiet("tmux list-panes -a -F '#{session_name}|#{window_index}|#{window_name}|#{window_active}|#{window_panes}|#{pane_index}|#{pane_id}|#{pane_pid}|#{pane_current_command}|#{pane_title}|#{pane_width}x#{pane_height}|#{session_attached}|#{session_windows}|#{session_created}|#{pane_dead}'");if(!paneOutput)return[];let sessionMap=new Map,windowMap=new Map;for(let line of paneOutput.split(`
1904
- `)){if(!line)continue;let parts=line.split("|");if(parts.length<15)continue;let parsed=parsePaneLine(parts);if(!sessionMap.has(parsed.sessionName))sessionMap.set(parsed.sessionName,{...parsed.session,windows:[]});let winKey=`${parsed.sessionName}:${parsed.winIdxStr}`;if(!windowMap.has(winKey)){let win={...parsed.window,panes:[]};windowMap.set(winKey,win),sessionMap.get(parsed.sessionName)?.windows.push(win)}windowMap.get(winKey)?.panes.push(parsed.pane)}return Array.from(sessionMap.values()).sort((a,b3)=>a.name.localeCompare(b3.name))}function isPidAlive(pid){try{return process.kill(pid,0),!0}catch{return!1}}function allClaudePanes(sessions){return sessions.flatMap((s)=>s.windows.flatMap((w2)=>w2.panes)).filter((p)=>p.command==="claude"||p.title.includes("claude"))}function detectGaps(executors,sessions){let deadPidExecutors=executors.filter((e)=>e.pid!=null&&!isPidAlive(e.pid)),executorPaneIds=new Set(executors.map((e)=>e.tmuxPaneId).filter(Boolean)),claudePanes=allClaudePanes(sessions),orphanPanes=claudePanes.filter((p)=>!executorPaneIds.has(p.paneId)),linkedCount=executors.filter((e)=>e.tmuxPaneId&&!deadPidExecutors.some((d2)=>d2.id===e.id)).length,deadPaneCount=sessions.flatMap((s)=>s.windows.flatMap((w2)=>w2.panes)).filter((p)=>p.isDead).length;return{deadPidExecutors,orphanPanes,linkedCount,totalExecutors:executors.length,totalClaudePanes:claudePanes.length,deadPaneCount}}async function collectDiagnostics(){let{loadExecutors:loadExecutors2,loadAssignments:loadAssignments2}=await Promise.resolve().then(() => (init_db2(),exports_db2)),sessions=getTmuxInventory(),executors=await loadExecutors2(),executorIds=executors.map((e)=>e.id),assignments=await loadAssignments2(executorIds),gaps=detectGaps(executors,sessions);return{sessions,executors,assignments,gaps,timestamp:Date.now()}}var init_diagnostics=()=>{};function buildTree(data){let orgNodes=[];for(let org of data.orgs){let projectNodes=data.projects.filter((p)=>p.orgId===org.id).map((proj)=>{let boardNodes=data.boards.filter((b3)=>b3.projectId===proj.id).map((board)=>{let columnNodes=(board.columns||[]).sort((a,b3)=>a.position-b3.position).map((col)=>{let colTasks=data.tasks.filter((t2)=>t2.boardId===board.id&&t2.columnId===col.id),taskNodes=colTasks.map((task)=>({id:task.id,type:"task",label:`#${task.seq} ${task.title}`,depth:4,expanded:!1,children:[],data:task,activePanes:0}));return{id:col.id,type:"column",label:`${col.label} (${colTasks.length})`,depth:3,expanded:!1,children:taskNodes,data:col,activePanes:0}});return{id:board.id,type:"board",label:board.name,depth:2,expanded:!1,children:columnNodes,data:board,activePanes:0}});return{id:proj.id,type:"project",label:proj.name,depth:1,expanded:!1,children:boardNodes,data:proj,activePanes:0}});orgNodes.push({id:org.id,type:"org",label:org.name,depth:0,expanded:!0,children:projectNodes,data:org,activePanes:0})}return orgNodes}function flattenTree(nodes){let result=[];function walk(node,depth){if(result.push({node,depth,visible:!0}),node.expanded)for(let child of node.children)walk(child,depth+1)}for(let node of nodes)walk(node,0);return result}function toggleNode(nodes,id){return nodes.map((node)=>{if(node.id===id)return{...node,expanded:!node.expanded};return{...node,children:toggleNode(node.children,id)}})}function applyActivity(nodes,activity){return nodes.map((node)=>{let act=activity.get(node.id),updated={...node,activePanes:act?.panes??0,agentState:act?.state,children:applyActivity(node.children,activity)};if(updated.children.some((c)=>c.activePanes>0)&&updated.activePanes===0)updated.activePanes=updated.children.reduce((sum,c)=>sum+c.activePanes,0);return updated})}var import_jsx_dev_runtime2;var init_jsx_dev_runtime=__esm(()=>{import_jsx_dev_runtime2=__toESM(require_react_jsx_dev_runtime_development(),1)});function stateColor(state){return STATE_COLORS[state]??palette.textMuted}function executorDisplayName(exec3){let name=exec3.agentName?`${exec3.agentName}${exec3.team?`@${exec3.team}`:""}`:exec3.agentId;return exec3.role?`${name} (${exec3.role})`:name}function metaRow(exec3){let hasTmux2=!!exec3.tmuxPaneId,isApi=exec3.transport==="api";return{id:`meta:${exec3.id}`,depth:1,label:hasTmux2?`${exec3.tmuxSession??"?"}:${exec3.tmuxPaneId}`:isApi?"api (no tmux)":"tmux: not linked",color:hasTmux2?palette.emerald:isApi?palette.textDim:palette.error,detail:exec3.pid!=null?`pid:${exec3.pid}`:"",detailColor:palette.textMuted,isOrphan:!hasTmux2&&!isApi}}function assignmentRow(exec3,a){let taskLabel=a.taskTitle??a.taskId??"unknown",wishLabel=a.wishSlug?` [${a.wishSlug}]`:"";return{id:`assign:${exec3.id}`,depth:1,label:`\u2192 ${taskLabel}${wishLabel}`,color:palette.purple,detail:a.groupNumber!=null?`grp:${a.groupNumber}`:"",detailColor:palette.textMuted,isOrphan:!1}}function executorToRows(exec3,assignments,isDead){let rows=[{id:`exec:${exec3.id}`,depth:0,label:executorDisplayName(exec3),color:isDead?palette.error:stateColor(exec3.state),detail:isDead?`DEAD pid:${exec3.pid}`:`${exec3.state} ${exec3.provider}`,detailColor:isDead?palette.error:palette.textMuted,isOrphan:isDead},metaRow(exec3)],active=assignments.find((a)=>a.executorId===exec3.id);if(active)rows.push(assignmentRow(exec3,active));return rows}function flattenExecutors(executors,assignments,gaps){let deadIds=new Set(gaps.deadPidExecutors.map((e)=>e.id)),rows=executors.flatMap((exec3)=>executorToRows(exec3,assignments,deadIds.has(exec3.id)));if(gaps.orphanPanes.length>0){rows.push({id:"orphan-header",depth:0,label:`\u2500\u2500 Orphan Panes (${gaps.orphanPanes.length}) \u2500\u2500`,color:palette.warning,detail:"",detailColor:palette.textMuted,isOrphan:!1});for(let pane of gaps.orphanPanes)rows.push({id:`orphan:${pane.paneId}`,depth:1,label:`${pane.sessionName}:${pane.windowIndex}.${pane.paneIndex}`,color:palette.error,detail:`pid:${pane.pid} [${pane.title}]`,detailColor:palette.textMuted,isOrphan:!0})}return rows}function ClaudeView({executors,assignments,gaps,selectedIndex}){let rows=import_react13.useMemo(()=>flattenExecutors(executors,assignments,gaps),[executors,assignments,gaps]);return import_jsx_dev_runtime2.jsxDEV("box",{flexDirection:"column",width:"100%",height:"100%",children:[import_jsx_dev_runtime2.jsxDEV("box",{height:1,paddingX:1,backgroundColor:palette.bgLighter,children:import_jsx_dev_runtime2.jsxDEV("text",{children:[import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.emerald,children:[gaps.linkedCount," linked"]},void 0,!0,void 0,this),gaps.deadPidExecutors.length>0?import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.error,children:[" ",gaps.deadPidExecutors.length," dead"]},void 0,!0,void 0,this):null,gaps.orphanPanes.length>0?import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.warning,children:[" ",gaps.orphanPanes.length," unmapped"]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this),import_jsx_dev_runtime2.jsxDEV("scrollbox",{focused:!0,height:"100%",style:{scrollbarOptions:{showArrows:!1,trackOptions:{foregroundColor:palette.scrollThumb,backgroundColor:palette.scrollTrack}}},children:rows.map((row,i2)=>{let indent=" ".repeat(row.depth),icon=row.depth===0?row.isOrphan?"\u2718":"\u2713":"\u2514";return import_jsx_dev_runtime2.jsxDEV("box",{height:1,width:"100%",backgroundColor:i2===selectedIndex?palette.violet:void 0,children:import_jsx_dev_runtime2.jsxDEV("text",{children:[import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.textMuted,children:indent},void 0,!1,void 0,this),import_jsx_dev_runtime2.jsxDEV("span",{fg:row.color,children:[icon," ",row.label]},void 0,!0,void 0,this),import_jsx_dev_runtime2.jsxDEV("span",{fg:row.detailColor,children:[" ",row.detail]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},row.id,!1,void 0,this)})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function getClaudeRowCount(executors,assignments,gaps){let count=0;for(let exec3 of executors)if(count+=2,assignments.some((a)=>a.executorId===exec3.id))count++;if(gaps.orphanPanes.length>0)count+=1+gaps.orphanPanes.length;return count}var import_react13,STATE_COLORS;var init_ClaudeView=__esm(()=>{init_theme2();init_jsx_dev_runtime();import_react13=__toESM(require_react_development(),1),STATE_COLORS={working:palette.emerald,idle:palette.textDim,running:palette.cyan,spawning:palette.warning,permission:palette.warning,question:palette.warning,error:palette.error}});function tabBadge(tab,gaps){if(tab==="claude"){let total=(gaps?.orphanProcesses??0)+(gaps?.orphanPanes??0);return total>0?import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.error,children:[" ",total]},void 0,!0,void 0,this):null}if(tab==="tmux"){let dead=gaps?.deadPanes??0;return dead>0?import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.error,children:[" ",dead,"\\u2620"]},void 0,!0,void 0,this):null}return null}function TabBar({activeTab,focused,gaps}){return import_jsx_dev_runtime2.jsxDEV("box",{height:1,flexDirection:"row",width:"100%",backgroundColor:palette.bgLight,children:TAB_ORDER.map((tab)=>{let isActive=tab===activeTab,bg2=isActive?palette.violet:palette.bgLight,fg2=isActive?"#ffffff":focused?palette.textDim:palette.textMuted;return import_jsx_dev_runtime2.jsxDEV("box",{backgroundColor:bg2,paddingX:1,children:import_jsx_dev_runtime2.jsxDEV("text",{children:[import_jsx_dev_runtime2.jsxDEV("span",{fg:fg2,children:[isActive&&focused?">":" ",TAB_LABELS[tab]]},void 0,!0,void 0,this),tabBadge(tab,gaps)]},void 0,!0,void 0,this)},tab,!1,void 0,this)})},void 0,!1,void 0,this)}var TAB_ORDER,TAB_LABELS;var init_TabBar=__esm(()=>{init_theme2();init_jsx_dev_runtime();TAB_ORDER=["projects","tmux","claude"],TAB_LABELS={projects:"Projects",tmux:"tmux",claude:"Claude"}});function toPaneRow(pane,sessionName,windowIndex){let isClaude=pane.command==="claude"||pane.title.includes("claude"),color=pane.isDead?palette.textMuted:isClaude?palette.cyan:palette.textDim;return{id:`p:${pane.paneId}`,depth:2,label:pane.isDead?`${pane.paneId} [DEAD]`:`${pane.paneId} [${pane.command}]`,color,detail:`pid:${pane.pid} ${pane.size}`,detailColor:palette.textMuted,type:"pane",sessionName,windowIndex,isClaude,isDead:pane.isDead}}function flattenSessions(sessions){return sessions.flatMap((session)=>{let sessionRow={id:`s:${session.name}`,depth:0,label:session.name,color:session.attached?palette.emerald:palette.textDim,detail:`${session.windowCount}w ${session.attached?"(attached)":""}`,detailColor:session.attached?palette.emerald:palette.textMuted,type:"session",sessionName:session.name,isClaude:!1,isDead:!1},windowRows=session.windows.flatMap((window2)=>{let deadInWindow=window2.panes.filter((p)=>p.isDead).length,winRow={id:`w:${session.name}:${window2.index}`,depth:1,label:`${window2.index}:${window2.name}`,color:window2.active?palette.cyan:palette.text,detail:`${window2.paneCount}p${deadInWindow>0?` ${deadInWindow}\u2620`:""}${window2.active?" *":""}`,detailColor:window2.active?palette.cyan:palette.textMuted,type:"window",sessionName:session.name,windowIndex:window2.index,isClaude:!1,isDead:!1},paneRows=window2.panes.map((pane)=>toPaneRow(pane,session.name,window2.index));return[winRow,...paneRows]});return[sessionRow,...windowRows]})}function TmuxView({sessions,selectedIndex}){let rows=import_react14.useMemo(()=>flattenSessions(sessions),[sessions]),totalPanes=sessions.reduce((sum,s)=>sum+s.windows.reduce((ws,w2)=>ws+w2.panes.length,0),0),deadPanes=sessions.reduce((sum,s)=>sum+s.windows.reduce((ws,w2)=>ws+w2.panes.filter((p)=>p.isDead).length,0),0);return import_jsx_dev_runtime2.jsxDEV("box",{flexDirection:"column",width:"100%",height:"100%",children:[import_jsx_dev_runtime2.jsxDEV("box",{height:1,paddingX:1,backgroundColor:palette.bgLighter,children:import_jsx_dev_runtime2.jsxDEV("text",{children:[import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.textDim,children:[sessions.length,"s ",sessions.reduce((s,x2)=>s+x2.windowCount,0),"w ",totalPanes,"p"]},void 0,!0,void 0,this),deadPanes>0?import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.error,children:[" ",deadPanes," dead"]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this),import_jsx_dev_runtime2.jsxDEV("scrollbox",{focused:!0,height:"100%",style:{scrollbarOptions:{showArrows:!1,trackOptions:{foregroundColor:palette.scrollThumb,backgroundColor:palette.scrollTrack}}},children:rows.map((row,i2)=>{let indent=" ".repeat(row.depth),icon=row.type==="session"?"\u25C8":row.type==="window"?"\u25A1":row.isDead?"\u2718":"\u2500";return import_jsx_dev_runtime2.jsxDEV("box",{height:1,width:"100%",backgroundColor:i2===selectedIndex?palette.violet:void 0,children:import_jsx_dev_runtime2.jsxDEV("text",{children:[import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.textMuted,children:indent},void 0,!1,void 0,this),import_jsx_dev_runtime2.jsxDEV("span",{fg:row.color,children:[icon," ",row.label]},void 0,!0,void 0,this),import_jsx_dev_runtime2.jsxDEV("span",{fg:row.detailColor,children:[" ",row.detail]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},row.id,!1,void 0,this)})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function getTmuxRowCount(sessions){let count=0;for(let s of sessions){count++;for(let w2 of s.windows)count++,count+=w2.panes.length}return count}function getTmuxRowTarget(sessions,index){let row=flattenSessions(sessions)[index];if(!row)return null;return{sessionName:row.sessionName,windowIndex:row.windowIndex}}var import_react14;var init_TmuxView=__esm(()=>{init_theme2();init_jsx_dev_runtime();import_react14=__toESM(require_react_development(),1)});function getNodeIcon(node){switch(node.type){case"org":return icons.org;case"project":return node.expanded?icons.projectOpen:icons.project;case"board":return node.expanded?icons.boardOpen:icons.board;case"column":return icons.column;case"task":if(node.activePanes>0)return icons.taskActive;if(node.data.status==="done")return icons.taskDone;return icons.task;default:return" "}}function getNodeColor(node){switch(node.type){case"org":return palette.purple;case"project":return node.activePanes>0?palette.emerald:palette.textDim;case"board":return palette.violet;case"column":return palette.textMuted;case"task":if(node.activePanes>0)return palette.cyan;if(node.data.status==="done")return palette.emerald;return palette.text;default:return palette.text}}var import_react15,TreeNodeRow;var init_TreeNode=__esm(()=>{init_theme2();init_jsx_dev_runtime();import_react15=__toESM(require_react_development(),1),TreeNodeRow=import_react15.memo(function({node,selected,onSelect,onToggle}){let indent=" ".repeat(node.depth),hasChildren=node.children.length>0,expandIcon=hasChildren?node.expanded?icons.expanded:icons.collapsed:" ",icon=getNodeIcon(node),color=getNodeColor(node),activeIndicator=node.activePanes>0?` ${icons.agent}${node.activePanes}`:"";return import_jsx_dev_runtime2.jsxDEV("box",{height:1,width:"100%",backgroundColor:selected?palette.violet:void 0,onMouseDown:()=>{if(onSelect(node.id),hasChildren)onToggle(node.id)},children:import_jsx_dev_runtime2.jsxDEV("text",{children:[import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.textDim,children:[indent,expandIcon," "]},void 0,!0,void 0,this),import_jsx_dev_runtime2.jsxDEV("span",{fg:color,children:[icon," "]},void 0,!0,void 0,this),import_jsx_dev_runtime2.jsxDEV("span",{fg:selected?"#ffffff":palette.text,children:node.label},void 0,!1,void 0,this),activeIndicator?import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.cyan,children:activeIndicator},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this)})});function Nav({tree,onTreeChange,onProjectSelect,onTmuxSessionSelect}){let[activeTab,setActiveTab]=import_react17.useState("projects"),[tabBarFocused,setTabBarFocused]=import_react17.useState(!1),[diagnostics,setDiagnostics]=import_react17.useState(null),[projectIndex,setProjectIndex]=import_react17.useState(0),[tmuxIndex,setTmuxIndex]=import_react17.useState(0),[claudeIndex,setClaudeIndex]=import_react17.useState(0),flatNodes=import_react17.useMemo(()=>flattenTree(tree),[tree]),diagTimer=import_react17.useRef(null);import_react17.useEffect(()=>{let active=!0;async function refresh(){try{let snap=await collectDiagnostics();if(active)setDiagnostics(snap)}catch(err){console.error("TUI: diagnostics failed:",err)}}return refresh(),diagTimer.current=setInterval(refresh,2000),()=>{if(active=!1,diagTimer.current)clearInterval(diagTimer.current)}},[]);let getRowCount=import_react17.useCallback(()=>{switch(activeTab){case"projects":return flatNodes.length;case"tmux":return diagnostics?getTmuxRowCount(diagnostics.sessions):0;case"claude":return diagnostics?getClaudeRowCount(diagnostics.executors,diagnostics.assignments,diagnostics.gaps):0}},[activeTab,flatNodes,diagnostics]),getSelectedIndex=import_react17.useCallback(()=>{switch(activeTab){case"projects":return projectIndex;case"tmux":return tmuxIndex;case"claude":return claudeIndex}},[activeTab,projectIndex,tmuxIndex,claudeIndex]),setSelectedIndex=import_react17.useCallback((idx)=>{switch(activeTab){case"projects":setProjectIndex(idx);break;case"tmux":setTmuxIndex(idx);break;case"claude":setClaudeIndex(idx);break}},[activeTab]);import_react17.useEffect(()=>{if(activeTab!=="projects"||tabBarFocused)return;let current=flatNodes[projectIndex]?.node;if(!current||current.type!=="project")return;let proj=current.data;if(proj.tmuxSession)onProjectSelect(proj.id,proj.tmuxSession)},[activeTab,tabBarFocused,projectIndex,flatNodes,onProjectSelect]);let handleProjectSelect=import_react17.useCallback((id)=>{let idx=flatNodes.findIndex((n)=>n.node.id===id);if(idx>=0)setProjectIndex(idx)},[flatNodes]),handleToggle=import_react17.useCallback((id)=>{onTreeChange(toggleNode(tree,id))},[tree,onTreeChange]),handleEnter=import_react17.useCallback(()=>{if(activeTab==="projects"){let current=flatNodes[projectIndex]?.node;if(!current)return;if(current.type==="project"){let proj=current.data;onProjectSelect(proj.id,proj.tmuxSession)}else if(current.children.length>0)handleToggle(current.id)}else if(activeTab==="tmux"&&diagnostics&&onTmuxSessionSelect){let target=getTmuxRowTarget(diagnostics.sessions,tmuxIndex);if(target)onTmuxSessionSelect(target.sessionName,target.windowIndex)}},[activeTab,flatNodes,projectIndex,onProjectSelect,handleToggle,diagnostics,tmuxIndex,onTmuxSessionSelect]),handleTabBarKey=import_react17.useCallback((keyName2)=>{if(keyName2==="left"||keyName2==="h"){let idx=(TAB_ORDER.indexOf(activeTab)-1+TAB_ORDER.length)%TAB_ORDER.length;return setActiveTab(TAB_ORDER[idx]),!0}if(keyName2==="right"||keyName2==="l"){let idx=(TAB_ORDER.indexOf(activeTab)+1)%TAB_ORDER.length;return setActiveTab(TAB_ORDER[idx]),!0}if(keyName2==="down"||keyName2==="j")return setTabBarFocused(!1),setSelectedIndex(0),!0;return!1},[activeTab,setSelectedIndex]),handleVerticalNav=import_react17.useCallback((keyName2,selectedIdx,rowCount)=>{if(rowCount===0)return;if(keyName2==="up"||keyName2==="k")setSelectedIndex(selectedIdx===0?rowCount-1:selectedIdx-1);else if(keyName2==="down"||keyName2==="j")setSelectedIndex(selectedIdx>=rowCount-1?0:selectedIdx+1)},[setSelectedIndex]),handleTreeExpand=import_react17.useCallback((keyName2,selectedIdx)=>{if(activeTab!=="projects")return;let node=flatNodes[selectedIdx]?.node;if(!node)return;if((keyName2==="right"||keyName2==="l")&&node.children.length>0&&!node.expanded)handleToggle(node.id);else if((keyName2==="left"||keyName2==="h")&&node.expanded)handleToggle(node.id)},[activeTab,flatNodes,handleToggle]),handleListKey=import_react17.useCallback((keyName2,selectedIdx,rowCount)=>{if(keyName2==="enter"||keyName2==="return")handleEnter();else if(keyName2==="up"||keyName2==="k"||keyName2==="down"||keyName2==="j")handleVerticalNav(keyName2,selectedIdx,rowCount);else handleTreeExpand(keyName2,selectedIdx)},[handleEnter,handleVerticalNav,handleTreeExpand]);useKeyboard((key)=>{if(tabBarFocused){handleTabBarKey(key.name);return}handleListKey(key.name,getSelectedIndex(),getRowCount())});let gapCounts=diagnostics?{orphanProcesses:diagnostics.gaps.deadPidExecutors.length,orphanPanes:diagnostics.gaps.orphanPanes.length,deadPanes:diagnostics.gaps.deadPaneCount}:void 0;return import_jsx_dev_runtime2.jsxDEV("box",{flexDirection:"column",width:"100%",height:"100%",backgroundColor:palette.bg,children:[import_jsx_dev_runtime2.jsxDEV(TabBar,{activeTab,focused:tabBarFocused,gaps:gapCounts},void 0,!1,void 0,this),activeTab==="projects"&&import_jsx_dev_runtime2.jsxDEV("box",{flexDirection:"column",flexGrow:1,children:import_jsx_dev_runtime2.jsxDEV("scrollbox",{focused:!0,height:"100%",style:{scrollbarOptions:{showArrows:!1,trackOptions:{foregroundColor:palette.scrollThumb,backgroundColor:palette.scrollTrack}}},children:flatNodes.map((flat,i2)=>import_jsx_dev_runtime2.jsxDEV(TreeNodeRow,{node:flat.node,selected:!tabBarFocused&&i2===projectIndex,onSelect:handleProjectSelect,onToggle:handleToggle},flat.node.id,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this),activeTab==="tmux"&&diagnostics&&import_jsx_dev_runtime2.jsxDEV(TmuxView,{sessions:diagnostics.sessions,selectedIndex:tabBarFocused?-1:tmuxIndex},void 0,!1,void 0,this),activeTab==="claude"&&diagnostics&&import_jsx_dev_runtime2.jsxDEV(ClaudeView,{executors:diagnostics.executors,assignments:diagnostics.assignments,gaps:diagnostics.gaps,selectedIndex:tabBarFocused?-1:claudeIndex},void 0,!1,void 0,this),(activeTab==="tmux"||activeTab==="claude")&&!diagnostics&&import_jsx_dev_runtime2.jsxDEV("box",{flexGrow:1,justifyContent:"center",alignItems:"center",children:import_jsx_dev_runtime2.jsxDEV("text",{fg:palette.textDim,children:"Collecting..."},void 0,!1,void 0,this)},void 0,!1,void 0,this),import_jsx_dev_runtime2.jsxDEV("box",{height:1,paddingX:1,backgroundColor:palette.bgLight,children:import_jsx_dev_runtime2.jsxDEV("text",{children:import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.textMuted,children:tabBarFocused?"\u2190\u2192:tab \u2193:tree":"\u2191\u2193:nav Enter:select"},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var import_react17;var init_Nav=__esm(async()=>{init_diagnostics();init_theme2();init_ClaudeView();init_TabBar();init_TmuxView();init_TreeNode();init_jsx_dev_runtime();await init_react();import_react17=__toESM(require_react_development(),1)});function App({rightPane}){let renderer=useRenderer(),[tree,setTree]=import_react19.useState([]),[loading,setLoading]=import_react19.useState(!0),[error2,setError]=import_react19.useState(null),[currentProject,setCurrentProject]=import_react19.useState(null),dataRef=import_react19.useRef(null),subRef=import_react19.useRef(null);useKeyboard((key)=>{if(key.name==="q"||key.ctrl&&key.name==="c")renderer.destroy(),cleanup()}),import_react19.useEffect(()=>{let cancelled=!1,onEvent=async()=>{try{let freshData=await loadAll2();if(cancelled)return;dataRef.current=freshData,setTree((prev)=>mergeExpandedState(prev,buildTree(freshData)))}catch(err){console.error("TUI: data refresh failed:",err)}};async function boot(){let data=await loadAll2();if(cancelled)return;dataRef.current=data,setTree(buildTree(data)),setLoading(!1);let sub=await subscribe(onEvent);if(cancelled)return void sub.stop();subRef.current=sub}return boot().catch((err)=>{if(cancelled)return;setError(err instanceof Error?err.message:String(err)),setLoading(!1)}),()=>{cancelled=!0,subRef.current?.stop(),subRef.current=null}},[]);let executorsRef=import_react19.useRef([]),assignmentsRef=import_react19.useRef([]);import_react19.useEffect(()=>{let active=!0;async function refreshActivity(){if(!dataRef.current)return;let activity=await fetchMergedActivity(dataRef.current,executorsRef,assignmentsRef);if(active)setTree((prev)=>applyActivity(prev,activity))}let timer2=setInterval(refreshActivity,1000);return()=>{active=!1,clearInterval(timer2)}},[]);let handleTreeChange=import_react19.useCallback((newTree)=>{setTree(newTree)},[]),handleProjectSelect=import_react19.useCallback((projectId,tmuxSession)=>{if(!tmuxSession||!rightPane)return;if(currentProject===projectId)return;if(currentProject)switchRightPane(rightPane,tmuxSession);else attachProject(rightPane,tmuxSession);setCurrentProject(projectId)},[rightPane,currentProject]),handleTmuxSessionSelect=import_react19.useCallback((sessionName,windowIndex)=>{if(!rightPane)return;attachProjectWindow(rightPane,sessionName,windowIndex)},[rightPane]);if(loading)return import_jsx_dev_runtime2.jsxDEV("box",{width:"100%",height:"100%",backgroundColor:palette.bg,justifyContent:"center",alignItems:"center",children:import_jsx_dev_runtime2.jsxDEV("text",{fg:palette.purple,children:"Loading..."},void 0,!1,void 0,this)},void 0,!1,void 0,this);if(error2)return import_jsx_dev_runtime2.jsxDEV("box",{width:"100%",height:"100%",backgroundColor:palette.bg,justifyContent:"center",alignItems:"center",children:import_jsx_dev_runtime2.jsxDEV("text",{fg:palette.error,children:error2},void 0,!1,void 0,this)},void 0,!1,void 0,this);return import_jsx_dev_runtime2.jsxDEV(Nav,{tree,onTreeChange:handleTreeChange,onProjectSelect:handleProjectSelect,onTmuxSessionSelect:handleTmuxSessionSelect},void 0,!1,void 0,this)}function mergeExpandedState(oldTree,newTree){let expandedIds=new Set;function collect(nodes){for(let n of nodes){if(n.expanded)expandedIds.add(n.id);collect(n.children)}}collect(oldTree);function apply(nodes){return nodes.map((n)=>({...n,expanded:expandedIds.has(n.id)||n.expanded,children:apply(n.children)}))}return apply(newTree)}function scanTmuxActivity(data){let result=new Map;for(let proj of data.projects){if(!proj.tmuxSession)continue;let windows=getActiveWork(proj.tmuxSession);for(let[taskId,act]of matchWorkToTasks(windows,data.tasks))result.set(taskId,act)}return result}async function fetchMergedActivity(data,executorsRef,assignmentsRef){try{let execs=await loadExecutors(),execIds=execs.map((e)=>e.id),assigns=execIds.length>0?await loadAssignments(execIds):[];executorsRef.current=execs,assignmentsRef.current=assigns;let activity=getExecutorActivity(execs,assigns);for(let[taskId,act]of scanTmuxActivity(data))if(!activity.has(taskId))activity.set(taskId,act);return activity}catch{return scanTmuxActivity(data)}}var import_react19;var init_app=__esm(async()=>{init_activity();init_db2();init_theme2();init_tmux2();init_jsx_dev_runtime();await __promiseAll([init_react(),init_Nav()]);import_react19=__toESM(require_react_development(),1)});var exports_render={};__export(exports_render,{renderNav:()=>renderNav});async function renderNav(){let rightPane=process.env.GENIE_TUI_RIGHT||void 0,renderer=await createCliRenderer({exitOnCtrlC:!1,useMouse:!0});createRoot(renderer).render(import_jsx_dev_runtime2.jsxDEV(App,{rightPane},void 0,!1,void 0,this))}var init_render=__esm(async()=>{init_jsx_dev_runtime();await __promiseAll([init_core(),init_react(),init_app()])});var exports_tui={};__export(exports_tui,{launchTui:()=>launchTui});async function launchTui(options={}){if(isInsideTuiSession()){let{renderNav:renderNav2}=await init_render().then(() => exports_render);await renderNav2();return}if(!hasTmux()){console.error("Error: tmux is required for genie tui");return}let{session,leftPane,rightPane}=createTuiSession(),bunPath=process.execPath||"bun",genieBin=process.argv[1]||"genie",{execSync:execSync16}=await import("child_process");if(options.dev)execSync16(`tmux send-keys -t '${leftPane}' "GENIE_TUI_PANE=left GENIE_TUI_RIGHT=${rightPane} bun --watch ${genieBin} tui" Enter`,{stdio:"ignore"});else execSync16(`tmux send-keys -t '${leftPane}' "GENIE_TUI_PANE=left GENIE_TUI_RIGHT=${rightPane} ${bunPath} ${genieBin} tui" Enter`,{stdio:"ignore"});attachTuiSession(),cleanup(session)}var init_tui=__esm(()=>{init_tmux2()});var import__=__toESM(require_commander(),1),{program,createCommand,createArgument,createOption,CommanderError,InvalidArgumentError,InvalidOptionArgumentError,Command,Argument,Option,Help}=import__.default;import{existsSync as existsSync3,unlinkSync as unlinkSync2}from"fs";import{homedir as homedir3}from"os";import{join as join3}from"path";var{$:$2}=globalThis.Bun;import{existsSync,unlinkSync}from"fs";import{homedir}from"os";import{join}from"path";var CLAUDE_DIR=join(homedir(),".claude"),CLAUDE_HOOKS_DIR=join(CLAUDE_DIR,"hooks"),CLAUDE_SETTINGS_FILE=join(CLAUDE_DIR,"settings.json"),GENIE_HOOK_SCRIPT_NAME="genie-bash-hook.sh";function getClaudeSettingsPath(){return CLAUDE_SETTINGS_FILE}function getGenieHookScriptPath(){return join(CLAUDE_HOOKS_DIR,GENIE_HOOK_SCRIPT_NAME)}function hookScriptExists(){return existsSync(getGenieHookScriptPath())}function removeHookScript(){let scriptPath=getGenieHookScriptPath();if(existsSync(scriptPath))unlinkSync(scriptPath)}function contractClaudePath(path){let home=homedir();if(path.startsWith(`${home}/`))return`~${path.slice(home.length)}`;if(path===home)return"~";return path}init_genie_config2();var{$}=globalThis.Bun;async function checkCommand(cmd){try{let cmdPath=(await $`which ${cmd}`.quiet().text()).trim();if(!cmdPath)return{exists:!1};let version;try{let firstLine=(await $`${cmd} --version`.quiet().text()).split(`
1904
+ `)){if(!line)continue;let parts=line.split("|");if(parts.length<15)continue;let parsed=parsePaneLine(parts);if(!sessionMap.has(parsed.sessionName))sessionMap.set(parsed.sessionName,{...parsed.session,windows:[]});let winKey=`${parsed.sessionName}:${parsed.winIdxStr}`;if(!windowMap.has(winKey)){let win={...parsed.window,panes:[]};windowMap.set(winKey,win),sessionMap.get(parsed.sessionName)?.windows.push(win)}windowMap.get(winKey)?.panes.push(parsed.pane)}return Array.from(sessionMap.values()).sort((a,b3)=>a.name.localeCompare(b3.name))}function isPidAlive(pid){try{return process.kill(pid,0),!0}catch{return!1}}function allClaudePanes(sessions){return sessions.flatMap((s)=>s.windows.flatMap((w2)=>w2.panes)).filter((p)=>p.command==="claude"||p.title.includes("claude"))}function detectGaps(executors,sessions){let deadPidExecutors=executors.filter((e)=>e.pid!=null&&!isPidAlive(e.pid)),executorPaneIds=new Set(executors.map((e)=>e.tmuxPaneId).filter(Boolean)),claudePanes=allClaudePanes(sessions),orphanPanes=claudePanes.filter((p)=>!executorPaneIds.has(p.paneId)),linkedCount=executors.filter((e)=>e.tmuxPaneId&&!deadPidExecutors.some((d2)=>d2.id===e.id)).length,deadPaneCount=sessions.flatMap((s)=>s.windows.flatMap((w2)=>w2.panes)).filter((p)=>p.isDead).length;return{deadPidExecutors,orphanPanes,linkedCount,totalExecutors:executors.length,totalClaudePanes:claudePanes.length,deadPaneCount}}async function collectDiagnostics(){let{loadExecutors:loadExecutors2,loadAssignments:loadAssignments2}=await Promise.resolve().then(() => (init_db2(),exports_db2)),sessions=getTmuxInventory(),executors=await loadExecutors2(),executorIds=executors.map((e)=>e.id),assignments=await loadAssignments2(executorIds),gaps=detectGaps(executors,sessions);return{sessions,executors,assignments,gaps,timestamp:Date.now()}}var init_diagnostics=()=>{};function buildTree(data){let orgNodes=[];for(let org of data.orgs){let projectNodes=data.projects.filter((p)=>p.orgId===org.id).map((proj)=>{let boardNodes=data.boards.filter((b3)=>b3.projectId===proj.id).map((board)=>{let columnNodes=(board.columns||[]).sort((a,b3)=>a.position-b3.position).map((col)=>{let colTasks=data.tasks.filter((t2)=>t2.boardId===board.id&&t2.columnId===col.id),taskNodes=colTasks.map((task)=>({id:task.id,type:"task",label:`#${task.seq} ${task.title}`,depth:4,expanded:!1,children:[],data:task,activePanes:0}));return{id:col.id,type:"column",label:`${col.label} (${colTasks.length})`,depth:3,expanded:!1,children:taskNodes,data:col,activePanes:0}});return{id:board.id,type:"board",label:board.name,depth:2,expanded:!1,children:columnNodes,data:board,activePanes:0}});return{id:proj.id,type:"project",label:proj.name,depth:1,expanded:!1,children:boardNodes,data:proj,activePanes:0}});orgNodes.push({id:org.id,type:"org",label:org.name,depth:0,expanded:!0,children:projectNodes,data:org,activePanes:0})}return orgNodes}function flattenTree(nodes){let result=[];function walk(node,depth){if(result.push({node,depth,visible:!0}),node.expanded)for(let child of node.children)walk(child,depth+1)}for(let node of nodes)walk(node,0);return result}function toggleNode(nodes,id){return nodes.map((node)=>{if(node.id===id)return{...node,expanded:!node.expanded};return{...node,children:toggleNode(node.children,id)}})}function applyActivity(nodes,activity){return nodes.map((node)=>{let act=activity.get(node.id),updated={...node,activePanes:act?.panes??0,agentState:act?.state,children:applyActivity(node.children,activity)};if(updated.children.some((c)=>c.activePanes>0)&&updated.activePanes===0)updated.activePanes=updated.children.reduce((sum,c)=>sum+c.activePanes,0);return updated})}var import_jsx_dev_runtime2;var init_jsx_dev_runtime=__esm(()=>{import_jsx_dev_runtime2=__toESM(require_react_jsx_dev_runtime_development(),1)});function stateColor(state){return STATE_COLORS[state]??palette.textMuted}function executorDisplayName(exec3){let name=exec3.agentName?`${exec3.agentName}${exec3.team?`@${exec3.team}`:""}`:exec3.agentId;return exec3.role?`${name} (${exec3.role})`:name}function metaRow(exec3){let hasTmux2=!!exec3.tmuxPaneId,isApi=exec3.transport==="api";return{id:`meta:${exec3.id}`,depth:1,label:hasTmux2?`${exec3.tmuxSession??"?"}:${exec3.tmuxPaneId}`:isApi?"api (no tmux)":"tmux: not linked",color:hasTmux2?palette.emerald:isApi?palette.textDim:palette.error,detail:exec3.pid!=null?`pid:${exec3.pid}`:"",detailColor:palette.textMuted,isOrphan:!hasTmux2&&!isApi}}function assignmentRow(exec3,a){let taskLabel=a.taskTitle??a.taskId??"unknown",wishLabel=a.wishSlug?` [${a.wishSlug}]`:"";return{id:`assign:${exec3.id}`,depth:1,label:`\u2192 ${taskLabel}${wishLabel}`,color:palette.purple,detail:a.groupNumber!=null?`grp:${a.groupNumber}`:"",detailColor:palette.textMuted,isOrphan:!1}}function executorToRows(exec3,assignments,isDead){let rows=[{id:`exec:${exec3.id}`,depth:0,label:executorDisplayName(exec3),color:isDead?palette.error:stateColor(exec3.state),detail:isDead?`DEAD pid:${exec3.pid}`:`${exec3.state} ${exec3.provider}`,detailColor:isDead?palette.error:palette.textMuted,isOrphan:isDead},metaRow(exec3)],active=assignments.find((a)=>a.executorId===exec3.id);if(active)rows.push(assignmentRow(exec3,active));return rows}function flattenExecutors(executors,assignments,gaps){let deadIds=new Set(gaps.deadPidExecutors.map((e)=>e.id)),byProvider=new Map;for(let exec3 of executors){let key=exec3.provider;if(!byProvider.has(key))byProvider.set(key,[]);byProvider.get(key)?.push(exec3)}let rows=[];for(let[provider,group]of byProvider){rows.push({id:`provider:${provider}`,depth:0,label:`\u2500\u2500 ${provider} (${group.length}) \u2500\u2500`,color:palette.cyan,detail:"",detailColor:palette.textMuted,isOrphan:!1});for(let exec3 of group)for(let row of executorToRows(exec3,assignments,deadIds.has(exec3.id)))rows.push({...row,depth:row.depth+1})}if(gaps.orphanPanes.length>0){rows.push({id:"orphan-header",depth:0,label:`\u2500\u2500 Orphan Panes (${gaps.orphanPanes.length}) \u2500\u2500`,color:palette.warning,detail:"",detailColor:palette.textMuted,isOrphan:!1});for(let pane of gaps.orphanPanes)rows.push({id:`orphan:${pane.paneId}`,depth:1,label:`${pane.sessionName}:${pane.windowIndex}.${pane.paneIndex}`,color:palette.error,detail:`pid:${pane.pid} [${pane.title}]`,detailColor:palette.textMuted,isOrphan:!0})}return rows}function ClaudeView({executors,assignments,gaps,selectedIndex}){let rows=import_react13.useMemo(()=>flattenExecutors(executors,assignments,gaps),[executors,assignments,gaps]);return import_jsx_dev_runtime2.jsxDEV("box",{flexDirection:"column",width:"100%",height:"100%",children:[import_jsx_dev_runtime2.jsxDEV("box",{height:1,paddingX:1,backgroundColor:palette.bgLighter,children:import_jsx_dev_runtime2.jsxDEV("text",{children:[import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.emerald,children:[gaps.linkedCount," linked"]},void 0,!0,void 0,this),gaps.deadPidExecutors.length>0?import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.error,children:[" ",gaps.deadPidExecutors.length," dead"]},void 0,!0,void 0,this):null,gaps.orphanPanes.length>0?import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.warning,children:[" ",gaps.orphanPanes.length," unmapped"]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this),import_jsx_dev_runtime2.jsxDEV("scrollbox",{focused:!0,height:"100%",style:{scrollbarOptions:{showArrows:!1,trackOptions:{foregroundColor:palette.scrollThumb,backgroundColor:palette.scrollTrack}}},children:rows.map((row,i2)=>{let indent=" ".repeat(row.depth),icon=row.depth===0?row.isOrphan?"\u2718":"\u2713":"\u2514";return import_jsx_dev_runtime2.jsxDEV("box",{height:1,width:"100%",backgroundColor:i2===selectedIndex?palette.violet:void 0,children:import_jsx_dev_runtime2.jsxDEV("text",{children:[import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.textMuted,children:indent},void 0,!1,void 0,this),import_jsx_dev_runtime2.jsxDEV("span",{fg:row.color,children:[icon," ",row.label]},void 0,!0,void 0,this),import_jsx_dev_runtime2.jsxDEV("span",{fg:row.detailColor,children:[" ",row.detail]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},row.id,!1,void 0,this)})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function getClaudeRowCount(executors,assignments,gaps){let count=new Set(executors.map((e)=>e.provider)).size;for(let exec3 of executors)if(count+=2,assignments.some((a)=>a.executorId===exec3.id))count++;if(gaps.orphanPanes.length>0)count+=1+gaps.orphanPanes.length;return count}var import_react13,STATE_COLORS;var init_ClaudeView=__esm(()=>{init_theme2();init_jsx_dev_runtime();import_react13=__toESM(require_react_development(),1),STATE_COLORS={working:palette.emerald,idle:palette.textDim,running:palette.cyan,spawning:palette.warning,permission:palette.warning,question:palette.warning,error:palette.error}});function tabBadge(tab,gaps){if(tab==="claude"){let total=(gaps?.orphanProcesses??0)+(gaps?.orphanPanes??0);return total>0?import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.error,children:[" ",total]},void 0,!0,void 0,this):null}if(tab==="tmux"){let dead=gaps?.deadPanes??0;return dead>0?import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.error,children:[" ",dead,"\\u2620"]},void 0,!0,void 0,this):null}return null}function TabBar({activeTab,focused,gaps}){return import_jsx_dev_runtime2.jsxDEV("box",{height:1,flexDirection:"row",width:"100%",backgroundColor:palette.bgLight,children:TAB_ORDER.map((tab)=>{let isActive=tab===activeTab,bg2=isActive?palette.violet:palette.bgLight,fg2=isActive?"#ffffff":focused?palette.textDim:palette.textMuted;return import_jsx_dev_runtime2.jsxDEV("box",{backgroundColor:bg2,paddingX:1,children:import_jsx_dev_runtime2.jsxDEV("text",{children:[import_jsx_dev_runtime2.jsxDEV("span",{fg:fg2,children:[isActive&&focused?">":" ",TAB_LABELS[tab]]},void 0,!0,void 0,this),tabBadge(tab,gaps)]},void 0,!0,void 0,this)},tab,!1,void 0,this)})},void 0,!1,void 0,this)}var TAB_ORDER,TAB_LABELS;var init_TabBar=__esm(()=>{init_theme2();init_jsx_dev_runtime();TAB_ORDER=["tmux","claude"],TAB_LABELS={projects:"Projects",tmux:"Sessions",claude:"Executors"}});function toPaneRow(pane,sessionName,windowIndex){let isClaude=pane.command==="claude"||pane.title.includes("claude"),color=pane.isDead?palette.textMuted:isClaude?palette.cyan:palette.textDim;return{id:`p:${pane.paneId}`,depth:2,label:pane.isDead?`${pane.paneId} [DEAD]`:`${pane.paneId} [${pane.command}]`,color,detail:`pid:${pane.pid} ${pane.size}`,detailColor:palette.textMuted,type:"pane",sessionName,windowIndex,isClaude,isDead:pane.isDead}}function flattenSessions(sessions){return sessions.flatMap((session)=>{let sessionRow={id:`s:${session.name}`,depth:0,label:session.name,color:session.attached?palette.emerald:palette.textDim,detail:`${session.windowCount}w ${session.attached?"(attached)":""}`,detailColor:session.attached?palette.emerald:palette.textMuted,type:"session",sessionName:session.name,isClaude:!1,isDead:!1},windowRows=session.windows.flatMap((window2)=>{let deadInWindow=window2.panes.filter((p)=>p.isDead).length,winRow={id:`w:${session.name}:${window2.index}`,depth:1,label:`${window2.index}:${window2.name}`,color:window2.active?palette.cyan:palette.text,detail:`${window2.paneCount}p${deadInWindow>0?` ${deadInWindow}\u2620`:""}${window2.active?" *":""}`,detailColor:window2.active?palette.cyan:palette.textMuted,type:"window",sessionName:session.name,windowIndex:window2.index,isClaude:!1,isDead:!1},paneRows=window2.panes.map((pane)=>toPaneRow(pane,session.name,window2.index));return[winRow,...paneRows]});return[sessionRow,...windowRows]})}function TmuxView({sessions,selectedIndex}){let rows=import_react14.useMemo(()=>flattenSessions(sessions),[sessions]),totalPanes=sessions.reduce((sum,s)=>sum+s.windows.reduce((ws,w2)=>ws+w2.panes.length,0),0),deadPanes=sessions.reduce((sum,s)=>sum+s.windows.reduce((ws,w2)=>ws+w2.panes.filter((p)=>p.isDead).length,0),0);return import_jsx_dev_runtime2.jsxDEV("box",{flexDirection:"column",width:"100%",height:"100%",children:[import_jsx_dev_runtime2.jsxDEV("box",{height:1,paddingX:1,backgroundColor:palette.bgLighter,children:import_jsx_dev_runtime2.jsxDEV("text",{children:[import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.textDim,children:[sessions.length,"s ",sessions.reduce((s,x2)=>s+x2.windowCount,0),"w ",totalPanes,"p"]},void 0,!0,void 0,this),deadPanes>0?import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.error,children:[" ",deadPanes," dead"]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this),import_jsx_dev_runtime2.jsxDEV("scrollbox",{focused:!0,height:"100%",style:{scrollbarOptions:{showArrows:!1,trackOptions:{foregroundColor:palette.scrollThumb,backgroundColor:palette.scrollTrack}}},children:rows.map((row,i2)=>{let indent=" ".repeat(row.depth),icon=row.type==="session"?"\u25C8":row.type==="window"?"\u25A1":row.isDead?"\u2718":"\u2500";return import_jsx_dev_runtime2.jsxDEV("box",{height:1,width:"100%",backgroundColor:i2===selectedIndex?palette.violet:void 0,children:import_jsx_dev_runtime2.jsxDEV("text",{children:[import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.textMuted,children:indent},void 0,!1,void 0,this),import_jsx_dev_runtime2.jsxDEV("span",{fg:row.color,children:[icon," ",row.label]},void 0,!0,void 0,this),import_jsx_dev_runtime2.jsxDEV("span",{fg:row.detailColor,children:[" ",row.detail]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},row.id,!1,void 0,this)})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function getTmuxRowCount(sessions){let count=0;for(let s of sessions){count++;for(let w2 of s.windows)count++,count+=w2.panes.length}return count}function getTmuxRowTarget(sessions,index){let row=flattenSessions(sessions)[index];if(!row)return null;return{sessionName:row.sessionName,windowIndex:row.windowIndex}}var import_react14;var init_TmuxView=__esm(()=>{init_theme2();init_jsx_dev_runtime();import_react14=__toESM(require_react_development(),1)});function getNodeIcon(node){switch(node.type){case"org":return icons.org;case"project":return node.expanded?icons.projectOpen:icons.project;case"board":return node.expanded?icons.boardOpen:icons.board;case"column":return icons.column;case"task":if(node.activePanes>0)return icons.taskActive;if(node.data.status==="done")return icons.taskDone;return icons.task;default:return" "}}function getNodeColor(node){switch(node.type){case"org":return palette.purple;case"project":return node.activePanes>0?palette.emerald:palette.textDim;case"board":return palette.violet;case"column":return palette.textMuted;case"task":if(node.activePanes>0)return palette.cyan;if(node.data.status==="done")return palette.emerald;return palette.text;default:return palette.text}}var import_react15,TreeNodeRow;var init_TreeNode=__esm(()=>{init_theme2();init_jsx_dev_runtime();import_react15=__toESM(require_react_development(),1),TreeNodeRow=import_react15.memo(function({node,selected,onSelect,onToggle}){let indent=" ".repeat(node.depth),hasChildren=node.children.length>0,expandIcon=hasChildren?node.expanded?icons.expanded:icons.collapsed:" ",icon=getNodeIcon(node),color=getNodeColor(node),activeIndicator=node.activePanes>0?` ${icons.agent}${node.activePanes}`:"";return import_jsx_dev_runtime2.jsxDEV("box",{height:1,width:"100%",backgroundColor:selected?palette.violet:void 0,onMouseDown:()=>{if(onSelect(node.id),hasChildren)onToggle(node.id)},children:import_jsx_dev_runtime2.jsxDEV("text",{children:[import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.textDim,children:[indent,expandIcon," "]},void 0,!0,void 0,this),import_jsx_dev_runtime2.jsxDEV("span",{fg:color,children:[icon," "]},void 0,!0,void 0,this),import_jsx_dev_runtime2.jsxDEV("span",{fg:selected?"#ffffff":palette.text,children:node.label},void 0,!1,void 0,this),activeIndicator?import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.cyan,children:activeIndicator},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this)})});function Nav({tree,onTreeChange,onProjectSelect,onTmuxSessionSelect}){let[activeTab,setActiveTab]=import_react17.useState("tmux"),[tabBarFocused,setTabBarFocused]=import_react17.useState(!1),[diagnostics,setDiagnostics]=import_react17.useState(null),[projectIndex,setProjectIndex]=import_react17.useState(0),[tmuxIndex,setTmuxIndex]=import_react17.useState(0),[claudeIndex,setClaudeIndex]=import_react17.useState(0),flatNodes=import_react17.useMemo(()=>flattenTree(tree),[tree]),diagTimer=import_react17.useRef(null);import_react17.useEffect(()=>{let active=!0;async function refresh(){try{let snap=await collectDiagnostics();if(active)setDiagnostics(snap)}catch(err){console.error("TUI: diagnostics failed:",err)}}return refresh(),diagTimer.current=setInterval(refresh,2000),()=>{if(active=!1,diagTimer.current)clearInterval(diagTimer.current)}},[]);let getRowCount=import_react17.useCallback(()=>{switch(activeTab){case"projects":return flatNodes.length;case"tmux":return diagnostics?getTmuxRowCount(diagnostics.sessions):0;case"claude":return diagnostics?getClaudeRowCount(diagnostics.executors,diagnostics.assignments,diagnostics.gaps):0}},[activeTab,flatNodes,diagnostics]),getSelectedIndex=import_react17.useCallback(()=>{switch(activeTab){case"projects":return projectIndex;case"tmux":return tmuxIndex;case"claude":return claudeIndex}},[activeTab,projectIndex,tmuxIndex,claudeIndex]),setSelectedIndex=import_react17.useCallback((idx)=>{switch(activeTab){case"projects":setProjectIndex(idx);break;case"tmux":setTmuxIndex(idx);break;case"claude":setClaudeIndex(idx);break}},[activeTab]);import_react17.useEffect(()=>{if(activeTab!=="projects"||tabBarFocused)return;let current=flatNodes[projectIndex]?.node;if(!current||current.type!=="project")return;let proj=current.data;if(proj.tmuxSession)onProjectSelect(proj.id,proj.tmuxSession)},[activeTab,tabBarFocused,projectIndex,flatNodes,onProjectSelect]);let handleProjectSelect=import_react17.useCallback((id)=>{let idx=flatNodes.findIndex((n)=>n.node.id===id);if(idx>=0)setProjectIndex(idx)},[flatNodes]),handleToggle=import_react17.useCallback((id)=>{onTreeChange(toggleNode(tree,id))},[tree,onTreeChange]),handleEnter=import_react17.useCallback(()=>{if(activeTab==="projects"){let current=flatNodes[projectIndex]?.node;if(!current)return;if(current.type==="project"){let proj=current.data;onProjectSelect(proj.id,proj.tmuxSession)}else if(current.children.length>0)handleToggle(current.id)}else if(activeTab==="tmux"&&diagnostics&&onTmuxSessionSelect){let target=getTmuxRowTarget(diagnostics.sessions,tmuxIndex);if(target)onTmuxSessionSelect(target.sessionName,target.windowIndex)}},[activeTab,flatNodes,projectIndex,onProjectSelect,handleToggle,diagnostics,tmuxIndex,onTmuxSessionSelect]),handleTabBarKey=import_react17.useCallback((keyName2)=>{if(keyName2==="left"||keyName2==="h"){let idx=(TAB_ORDER.indexOf(activeTab)-1+TAB_ORDER.length)%TAB_ORDER.length;return setActiveTab(TAB_ORDER[idx]),!0}if(keyName2==="right"||keyName2==="l"){let idx=(TAB_ORDER.indexOf(activeTab)+1)%TAB_ORDER.length;return setActiveTab(TAB_ORDER[idx]),!0}if(keyName2==="down"||keyName2==="j")return setTabBarFocused(!1),setSelectedIndex(0),!0;return!1},[activeTab,setSelectedIndex]),handleVerticalNav=import_react17.useCallback((keyName2,selectedIdx,rowCount)=>{if(rowCount===0)return;if(keyName2==="up"||keyName2==="k")setSelectedIndex(selectedIdx===0?rowCount-1:selectedIdx-1);else if(keyName2==="down"||keyName2==="j")setSelectedIndex(selectedIdx>=rowCount-1?0:selectedIdx+1)},[setSelectedIndex]),handleTreeExpand=import_react17.useCallback((keyName2,selectedIdx)=>{if(activeTab!=="projects")return;let node=flatNodes[selectedIdx]?.node;if(!node)return;if((keyName2==="right"||keyName2==="l")&&node.children.length>0&&!node.expanded)handleToggle(node.id);else if((keyName2==="left"||keyName2==="h")&&node.expanded)handleToggle(node.id)},[activeTab,flatNodes,handleToggle]),handleListKey=import_react17.useCallback((keyName2,selectedIdx,rowCount)=>{if(keyName2==="enter"||keyName2==="return")handleEnter();else if(keyName2==="up"||keyName2==="k"||keyName2==="down"||keyName2==="j")handleVerticalNav(keyName2,selectedIdx,rowCount);else handleTreeExpand(keyName2,selectedIdx)},[handleEnter,handleVerticalNav,handleTreeExpand]);useKeyboard((key)=>{if(tabBarFocused){handleTabBarKey(key.name);return}handleListKey(key.name,getSelectedIndex(),getRowCount())});let gapCounts=diagnostics?{orphanProcesses:diagnostics.gaps.deadPidExecutors.length,orphanPanes:diagnostics.gaps.orphanPanes.length,deadPanes:diagnostics.gaps.deadPaneCount}:void 0;return import_jsx_dev_runtime2.jsxDEV("box",{flexDirection:"column",width:"100%",height:"100%",backgroundColor:palette.bg,children:[import_jsx_dev_runtime2.jsxDEV(TabBar,{activeTab,focused:tabBarFocused,gaps:gapCounts},void 0,!1,void 0,this),activeTab==="projects"&&import_jsx_dev_runtime2.jsxDEV("box",{flexDirection:"column",flexGrow:1,children:import_jsx_dev_runtime2.jsxDEV("scrollbox",{focused:!0,height:"100%",style:{scrollbarOptions:{showArrows:!1,trackOptions:{foregroundColor:palette.scrollThumb,backgroundColor:palette.scrollTrack}}},children:flatNodes.map((flat,i2)=>import_jsx_dev_runtime2.jsxDEV(TreeNodeRow,{node:flat.node,selected:!tabBarFocused&&i2===projectIndex,onSelect:handleProjectSelect,onToggle:handleToggle},flat.node.id,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this),activeTab==="tmux"&&diagnostics&&import_jsx_dev_runtime2.jsxDEV(TmuxView,{sessions:diagnostics.sessions,selectedIndex:tabBarFocused?-1:tmuxIndex},void 0,!1,void 0,this),activeTab==="claude"&&diagnostics&&import_jsx_dev_runtime2.jsxDEV(ClaudeView,{executors:diagnostics.executors,assignments:diagnostics.assignments,gaps:diagnostics.gaps,selectedIndex:tabBarFocused?-1:claudeIndex},void 0,!1,void 0,this),(activeTab==="tmux"||activeTab==="claude")&&!diagnostics&&import_jsx_dev_runtime2.jsxDEV("box",{flexGrow:1,justifyContent:"center",alignItems:"center",children:import_jsx_dev_runtime2.jsxDEV("text",{fg:palette.textDim,children:"Collecting..."},void 0,!1,void 0,this)},void 0,!1,void 0,this),import_jsx_dev_runtime2.jsxDEV("box",{height:1,paddingX:1,backgroundColor:palette.bgLight,children:import_jsx_dev_runtime2.jsxDEV("text",{children:import_jsx_dev_runtime2.jsxDEV("span",{fg:palette.textMuted,children:tabBarFocused?"\u2190\u2192:tab \u2193:tree":"\u2191\u2193:nav Enter:select"},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var import_react17;var init_Nav=__esm(async()=>{init_diagnostics();init_theme2();init_ClaudeView();init_TabBar();init_TmuxView();init_TreeNode();init_jsx_dev_runtime();await init_react();import_react17=__toESM(require_react_development(),1)});function App({rightPane}){let renderer=useRenderer(),[tree,setTree]=import_react19.useState([]),[loading,setLoading]=import_react19.useState(!0),[error2,setError]=import_react19.useState(null),[currentProject,setCurrentProject]=import_react19.useState(null),dataRef=import_react19.useRef(null),subRef=import_react19.useRef(null);useKeyboard((key)=>{if(key.name==="q"||key.ctrl&&key.name==="c")renderer.destroy(),cleanup()}),import_react19.useEffect(()=>{let cancelled=!1,onEvent=async()=>{try{let freshData=await loadAll2();if(cancelled)return;dataRef.current=freshData,setTree((prev)=>mergeExpandedState(prev,buildTree(freshData)))}catch(err){console.error("TUI: data refresh failed:",err)}};async function boot(){let data=await loadAll2();if(cancelled)return;dataRef.current=data,setTree(buildTree(data)),setLoading(!1);let sub=await subscribe(onEvent);if(cancelled)return void sub.stop();subRef.current=sub}return boot().catch((err)=>{if(cancelled)return;setError(err instanceof Error?err.message:String(err)),setLoading(!1)}),()=>{cancelled=!0,subRef.current?.stop(),subRef.current=null}},[]);let executorsRef=import_react19.useRef([]),assignmentsRef=import_react19.useRef([]);import_react19.useEffect(()=>{let active=!0;async function refreshActivity(){if(!dataRef.current)return;let activity=await fetchMergedActivity(dataRef.current,executorsRef,assignmentsRef);if(active)setTree((prev)=>applyActivity(prev,activity))}let timer2=setInterval(refreshActivity,1000);return()=>{active=!1,clearInterval(timer2)}},[]);let handleTreeChange=import_react19.useCallback((newTree)=>{setTree(newTree)},[]),handleProjectSelect=import_react19.useCallback((projectId,tmuxSession)=>{if(!tmuxSession||!rightPane)return;if(currentProject===projectId)return;if(currentProject)switchRightPane(rightPane,tmuxSession);else attachProject(rightPane,tmuxSession);setCurrentProject(projectId)},[rightPane,currentProject]),handleTmuxSessionSelect=import_react19.useCallback((sessionName,windowIndex)=>{if(!rightPane)return;attachProjectWindow(rightPane,sessionName,windowIndex)},[rightPane]);if(loading)return import_jsx_dev_runtime2.jsxDEV("box",{width:"100%",height:"100%",backgroundColor:palette.bg,justifyContent:"center",alignItems:"center",children:import_jsx_dev_runtime2.jsxDEV("text",{fg:palette.purple,children:"Loading..."},void 0,!1,void 0,this)},void 0,!1,void 0,this);if(error2)return import_jsx_dev_runtime2.jsxDEV("box",{width:"100%",height:"100%",backgroundColor:palette.bg,justifyContent:"center",alignItems:"center",children:import_jsx_dev_runtime2.jsxDEV("text",{fg:palette.error,children:error2},void 0,!1,void 0,this)},void 0,!1,void 0,this);return import_jsx_dev_runtime2.jsxDEV(Nav,{tree,onTreeChange:handleTreeChange,onProjectSelect:handleProjectSelect,onTmuxSessionSelect:handleTmuxSessionSelect},void 0,!1,void 0,this)}function mergeExpandedState(oldTree,newTree){let expandedIds=new Set;function collect(nodes){for(let n of nodes){if(n.expanded)expandedIds.add(n.id);collect(n.children)}}collect(oldTree);function apply(nodes){return nodes.map((n)=>({...n,expanded:expandedIds.has(n.id)||n.expanded,children:apply(n.children)}))}return apply(newTree)}function scanTmuxActivity(data){let result=new Map;for(let proj of data.projects){if(!proj.tmuxSession)continue;let windows=getActiveWork(proj.tmuxSession);for(let[taskId,act]of matchWorkToTasks(windows,data.tasks))result.set(taskId,act)}return result}async function fetchMergedActivity(data,executorsRef,assignmentsRef){try{let execs=await loadExecutors(),execIds=execs.map((e)=>e.id),assigns=execIds.length>0?await loadAssignments(execIds):[];executorsRef.current=execs,assignmentsRef.current=assigns;let activity=getExecutorActivity(execs,assigns);for(let[taskId,act]of scanTmuxActivity(data))if(!activity.has(taskId))activity.set(taskId,act);return activity}catch{return scanTmuxActivity(data)}}var import_react19;var init_app=__esm(async()=>{init_activity();init_db2();init_theme2();init_tmux2();init_jsx_dev_runtime();await __promiseAll([init_react(),init_Nav()]);import_react19=__toESM(require_react_development(),1)});var exports_render={};__export(exports_render,{renderNav:()=>renderNav});async function renderNav(){let rightPane=process.env.GENIE_TUI_RIGHT||void 0,renderer=await createCliRenderer({exitOnCtrlC:!1,useMouse:!0});createRoot(renderer).render(import_jsx_dev_runtime2.jsxDEV(App,{rightPane},void 0,!1,void 0,this))}var init_render=__esm(async()=>{init_jsx_dev_runtime();await __promiseAll([init_core(),init_react(),init_app()])});var exports_tui={};__export(exports_tui,{launchTui:()=>launchTui});async function launchTui(options={}){if(isInsideTuiSession()){let{renderNav:renderNav2}=await init_render().then(() => exports_render);await renderNav2();return}if(!hasTmux()){console.error("Error: tmux is required for genie tui");return}let{session,leftPane,rightPane}=createTuiSession(),bunPath=process.execPath||"bun",genieBin=process.argv[1]||"genie",{execSync:execSync16}=await import("child_process");if(options.dev)execSync16(`tmux send-keys -t '${leftPane}' "GENIE_TUI_PANE=left GENIE_TUI_RIGHT=${rightPane} bun --watch ${genieBin} tui" Enter`,{stdio:"ignore"});else execSync16(`tmux send-keys -t '${leftPane}' "GENIE_TUI_PANE=left GENIE_TUI_RIGHT=${rightPane} ${bunPath} ${genieBin} tui" Enter`,{stdio:"ignore"});attachTuiSession(),cleanup(session)}var init_tui=__esm(()=>{init_tmux2()});var import__=__toESM(require_commander(),1),{program,createCommand,createArgument,createOption,CommanderError,InvalidArgumentError,InvalidOptionArgumentError,Command,Argument,Option,Help}=import__.default;import{existsSync as existsSync3,unlinkSync as unlinkSync2}from"fs";import{homedir as homedir3}from"os";import{join as join3}from"path";var{$:$2}=globalThis.Bun;import{existsSync,unlinkSync}from"fs";import{homedir}from"os";import{join}from"path";var CLAUDE_DIR=join(homedir(),".claude"),CLAUDE_HOOKS_DIR=join(CLAUDE_DIR,"hooks"),CLAUDE_SETTINGS_FILE=join(CLAUDE_DIR,"settings.json"),GENIE_HOOK_SCRIPT_NAME="genie-bash-hook.sh";function getClaudeSettingsPath(){return CLAUDE_SETTINGS_FILE}function getGenieHookScriptPath(){return join(CLAUDE_HOOKS_DIR,GENIE_HOOK_SCRIPT_NAME)}function hookScriptExists(){return existsSync(getGenieHookScriptPath())}function removeHookScript(){let scriptPath=getGenieHookScriptPath();if(existsSync(scriptPath))unlinkSync(scriptPath)}function contractClaudePath(path){let home=homedir();if(path.startsWith(`${home}/`))return`~${path.slice(home.length)}`;if(path===home)return"~";return path}init_genie_config2();var{$}=globalThis.Bun;async function checkCommand(cmd){try{let cmdPath=(await $`which ${cmd}`.quiet().text()).trim();if(!cmdPath)return{exists:!1};let version;try{let firstLine=(await $`${cmd} --version`.quiet().text()).split(`
1905
1905
  `)[0].trim(),versionMatch=firstLine.match(/(\d+\.[\d.]+[a-z0-9-]*)/i);version=versionMatch?versionMatch[1]:firstLine.slice(0,50)}catch{try{let firstLine=(await $`${cmd} -v`.quiet().text()).split(`
1906
1906
  `)[0].trim(),versionMatch=firstLine.match(/(\d+\.[\d.]+[a-z0-9-]*)/i);version=versionMatch?versionMatch[1]:firstLine.slice(0,50)}catch{}}return{exists:!0,version,path:cmdPath}}catch{return{exists:!1}}}function printSectionHeader(title){console.log(),console.log(`\x1B[1m${title}:\x1B[0m`)}function printCheckResult(result){let icon={pass:"\x1B[32m\u2713\x1B[0m",fail:"\x1B[31m\u2717\x1B[0m",warn:"\x1B[33m!\x1B[0m"}[result.status],message=result.message?` ${result.message}`:"";if(console.log(` ${icon} ${result.name}${message}`),result.suggestion)console.log(` \x1B[2m${result.suggestion}\x1B[0m`)}async function checkPrerequisites(){let results=[],tmuxCheck=await checkCommand("tmux");if(tmuxCheck.exists)results.push({name:"tmux",status:"pass",message:tmuxCheck.version||""});else results.push({name:"tmux",status:"fail",suggestion:"Install with: brew install tmux (or apt install tmux)"});let jqCheck=await checkCommand("jq");if(jqCheck.exists)results.push({name:"jq",status:"pass",message:jqCheck.version||""});else results.push({name:"jq",status:"fail",suggestion:"Install with: brew install jq (or apt install jq)"});let bunCheck=await checkCommand("bun");if(bunCheck.exists)results.push({name:"bun",status:"pass",message:bunCheck.version||""});else results.push({name:"bun",status:"fail",suggestion:"Install with: curl -fsSL https://bun.sh/install | bash"});let claudeCheck=await checkCommand("claude");if(claudeCheck.exists)results.push({name:"Claude Code",status:"pass",message:claudeCheck.version||""});else results.push({name:"Claude Code",status:"warn",suggestion:"Install with: npm install -g @anthropic-ai/claude-code"});return results}async function checkConfiguration(){let results=[];if(genieConfigExists())results.push({name:"Genie config exists",status:"pass",message:contractClaudePath(getGenieConfigPath())});else results.push({name:"Genie config exists",status:"warn",message:"not found",suggestion:"Run: genie setup"});if(isSetupComplete())results.push({name:"Setup complete",status:"pass"});else results.push({name:"Setup complete",status:"warn",message:"not completed",suggestion:"Run: genie setup"});let claudeSettingsPath=getClaudeSettingsPath();if(existsSync3(claudeSettingsPath))results.push({name:"Claude settings exists",status:"pass",message:contractClaudePath(claudeSettingsPath)});else results.push({name:"Claude settings exists",status:"warn",message:"not found",suggestion:"Claude Code creates this on first run"});return results}async function checkTmux(){let results=[];try{if((await $2`tmux list-sessions 2>/dev/null`.quiet()).exitCode===0)results.push({name:"Server running",status:"pass"});else return results.push({name:"Server running",status:"warn",message:"no sessions",suggestion:"Start with: tmux new-session -d -s genie"}),results}catch{return results.push({name:"Server running",status:"warn",message:"could not check"}),results}let sessionName=(await loadGenieConfig()).session.name;try{if((await $2`tmux has-session -t ${sessionName} 2>/dev/null`.quiet()).exitCode===0)results.push({name:`Session '${sessionName}' exists`,status:"pass"});else results.push({name:`Session '${sessionName}' exists`,status:"warn",suggestion:`Start with: tmux new-session -d -s ${sessionName}`})}catch{results.push({name:`Session '${sessionName}' exists`,status:"warn",message:"could not check"})}return results}async function checkWorkerProfiles(){let results=[];if(!genieConfigExists())return results.push({name:"Worker profiles",status:"warn",message:"no genie config",suggestion:"Run: genie setup"}),results;let config=await loadGenieConfig(),profiles=config.workerProfiles;if(!profiles||Object.keys(profiles).length===0)return results.push({name:"Worker profiles",status:"pass",message:"none configured (using defaults)"}),results;let totalProfiles=Object.keys(profiles).length;results.push({name:"Profiles configured",status:"pass",message:`${totalProfiles} profile${totalProfiles===1?"":"s"}`});for(let name of Object.keys(profiles))results.push({name:`Profile '${name}'`,status:"pass",message:"claude (direct)"});if(config.defaultWorkerProfile)if(profiles[config.defaultWorkerProfile])results.push({name:"Default profile",status:"pass",message:config.defaultWorkerProfile});else results.push({name:"Default profile",status:"warn",message:`'${config.defaultWorkerProfile}' not found`,suggestion:"Run: genie profiles default <profile>"});return results}function runCheckSection(label,results,counts){printSectionHeader(label);for(let result of results){if(printCheckResult(result),result.status==="fail")counts.errors=!0;if(result.status==="warn")counts.warnings=!0}}async function doctorCommand(options){if(options?.fix){await doctorFix();return}console.log(),console.log("\x1B[1mGenie Doctor\x1B[0m"),console.log(`\x1B[2m${"\u2500".repeat(40)}\x1B[0m`);let counts={errors:!1,warnings:!1};if(runCheckSection("Prerequisites",await checkPrerequisites(),counts),runCheckSection("Configuration",await checkConfiguration(),counts),runCheckSection("Tmux",await checkTmux(),counts),runCheckSection("Worker Profiles",await checkWorkerProfiles(),counts),console.log(),console.log(`\x1B[2m${"\u2500".repeat(40)}\x1B[0m`),counts.errors)console.log("\x1B[31mSome checks failed.\x1B[0m Run \x1B[36mgenie setup\x1B[0m to fix.");else if(counts.warnings)console.log("\x1B[33mSome warnings detected.\x1B[0m Everything should still work.");else console.log("\x1B[32mAll checks passed!\x1B[0m");if(console.log(),counts.errors)process.exit(1)}async function doctorFix(){console.log(`
1907
1907
  \x1B[1mGenie Doctor \u2014 Auto Fix\x1B[0m`),console.log(`\x1B[2m${"\u2500".repeat(40)}\x1B[0m
@@ -2460,4 +2460,7 @@ Valid columns for board "${board.name}": ${validCols}`),process.exit(1)}catch{}}
2460
2460
  Board: ${board.name} (${board.id})`),console.log("\u2550".repeat(40));let columns=[...board.columns].sort((a,b2)=>a.position-b2.position);for(let col of columns)printColumnTasks(col.label,tasks.filter((t)=>t.columnId===col.id));let columnIds=new Set(columns.map((c)=>c.id)),orphaned=tasks.filter((t)=>t.columnId&&!columnIds.has(t.columnId));if(orphaned.length>0)printColumnTasks("Orphaned",orphaned,!1);console.log("")}function parseGhRef(gh){let match=gh.match(/^([^#]+)#(\d+)$/);if(!match)console.error(`Error: Invalid --gh format. Expected owner/repo#N, got: ${gh}`),process.exit(1);let[,ownerRepo,num]=match;return{externalId:`${ownerRepo}#${num}`,externalUrl:`https://github.com/${ownerRepo}/issues/${num}`}}async function handleTaskCreate(title,options){let ts3=await getTaskService8(),actor=currentActor2(),repoPath,projectId;if(options.project){let project=await ts3.getProjectByName(options.project);if(!project)project=await ts3.createProject({name:options.project});projectId=project.id,repoPath=project.repoPath??void 0}let parentId;if(options.parent){if(parentId=await ts3.resolveTaskId(options.parent,repoPath)??void 0,!parentId)console.error(`Error: Parent task not found: ${options.parent}`),process.exit(1)}let boardId=await resolveBoardOption(options.board),externalId=options.externalId,externalUrl=options.externalUrl;if(options.gh){let parsed=parseGhRef(options.gh);externalId=parsed.externalId,externalUrl=parsed.externalUrl}let task=await ts3.createTask({title,typeId:options.type,priority:options.priority,dueDate:options.due,startDate:options.start,parentId,description:options.description,estimatedEffort:options.effort,boardId,externalId,externalUrl},repoPath,projectId);if(await ts3.assignTask(task.id,actor,"creator",{},task.repoPath),options.assign)await ts3.assignTask(task.id,localActor2(options.assign),"assignee",{},task.repoPath);if(options.tags){let tagIds=options.tags.split(",").map((t)=>t.trim());await ts3.tagTask(task.id,tagIds,actor,task.repoPath)}if(options.comment)await ts3.commentOnTask(task.id,actor,options.comment,task.repoPath);if(console.log(`Created task #${task.seq}: ${task.title}`),console.log(` ID: ${task.id}`),console.log(` Stage: ${task.stage} | Priority: ${task.priority}`),options.due)console.log(` Due: ${options.due}`)}async function handleCloseMerged(options){let result=await(await getCloseMergedService()).closeMergedTasks({since:options.since,dryRun:options.dryRun,repo:options.repo});if(options.dryRun)console.log("[dry-run] Would close:");for(let d of result.details){let prefix=options.dryRun?" [dry-run]":" \u2713";console.log(`${prefix} #${d.taskSeq} "${d.taskTitle}" \u2190 PR #${d.prNumber} (${d.slug})`)}let mode=options.dryRun?"[dry-run] ":"";console.log(`
2461
2461
  ${mode}Closed ${result.closed} task${result.closed===1?"":"s"} from ${result.prsScanned} merged PR${result.prsScanned===1?"":"s"} (${result.alreadyShipped} already shipped)`)}function registerTaskCommands(program2){let task=program2.command("task").description("Task lifecycle management");task.command("create <title>").description("Create a new task").option("--type <type>","Task type","software").option("--priority <priority>","Priority: urgent, high, normal, low","normal").option("--due <date>","Due date (YYYY-MM-DD)").option("--start <date>","Start date (YYYY-MM-DD)").option("--tags <tags>","Comma-separated tag IDs").option("--parent <id>","Parent task ID or #seq").option("--assign <name>","Assign to local actor").option("--description <text>","Task description").option("--effort <effort>",'Estimated effort (e.g., "2h", "3 points")').option("--comment <msg>","Initial comment on the task").option("--project <name>","Create task in a specific project (overrides CWD)").option("--board <name>","Board name to assign task to").option("--gh <owner/repo#N>","Link to GitHub issue (sets external_id + external_url)").option("--external-id <id>","External tracker ID (e.g., JIRA-123)").option("--external-url <url>","External tracker URL").action(async(title,options)=>{try{await handleTaskCreate(title,options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("list").description("List tasks with filters").option("--stage <stage>","Filter by stage").option("--type <type>","Filter by type").option("--status <status>","Filter by status").option("--priority <priority>","Filter by priority").option("--release <release>","Filter by release").option("--due-before <date>","Filter by due date").option("--mine","Show only tasks assigned to me").option("--project <name>","Show tasks for a specific project").option("--board <name>","Filter by board name").option("--gh <owner/repo#N>","Filter by GitHub issue link").option("--by-column","Group tasks by board column (kanban view)").option("--include-done","Include done tasks in kanban view (hidden by default)").option("--all","Show tasks from ALL projects").option("--limit <n>","Max number of tasks to return","100").option("--offset <n>","Skip first N tasks (for pagination)","0").option("--json","Output as JSON").action(async(options)=>{try{let ts3=await getTaskService8(),filters={stage:options.stage,typeId:options.type,status:options.status,priority:options.priority,releaseId:options.release,dueBefore:options.dueBefore,projectName:options.project,boardName:options.board,externalId:options.gh?parseGhRef(options.gh).externalId:void 0,allProjects:options.all,limit:Number(options.limit)||100,offset:Number(options.offset)||0,...options.all?{limit:1e4}:{}},tasks;if(options.mine)tasks=await ts3.listTasksForActor(currentActor2(),filters);else tasks=await ts3.listTasks(filters);if(options.byColumn){if(!options.board)console.error("Error: --by-column requires --board"),process.exit(1);if(!options.includeDone)tasks=tasks.filter((t)=>t.status!=="done");await printByColumn(tasks,options.board);return}if(options.json){console.log(JSON.stringify(tasks,null,2));return}printTaskList(tasks,options.all)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("show <id>").description("Show task detail (accepts task-id or #seq)").option("--json","Output as JSON").action(async(id,options)=>{try{let t=await(await getTaskService8()).getTask(id);if(!t)console.error(`Error: Task not found: ${id}`),process.exit(1);if(options.json){console.log(JSON.stringify(t,null,2));return}await printTaskDetail(t)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("link <id>").description("Link task to an external tracker (GitHub, Jira, etc.)").option("--gh <owner/repo#N>","Link to GitHub issue").option("--external-id <id>","External tracker ID").option("--external-url <url>","External tracker URL").action(async(id,options)=>{try{let ts3=await getTaskService8(),externalId,externalUrl;if(options.gh){let parsed=parseGhRef(options.gh);externalId=parsed.externalId,externalUrl=parsed.externalUrl}else if(options.externalId&&options.externalUrl)externalId=options.externalId,externalUrl=options.externalUrl;else console.error("Error: Provide --gh or both --external-id and --external-url."),process.exit(1);let t=await ts3.linkTask(id,externalId,externalUrl);if(!t)console.error(`Error: Task not found: ${id}`),process.exit(1);if(console.log(`Linked task #${t.seq} to ${externalId}`),t.externalUrl)console.log(` URL: ${t.externalUrl}`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("move <id>").description("Move task to a new stage").requiredOption("--to <stage>","Target stage").option("--comment <msg>","Comment on the move").action(async(id,options)=>{try{let ts3=await getTaskService8(),actor=currentActor2(),t=await ts3.moveTask(id,options.to,actor,options.comment);console.log(`Moved task #${t.seq} to stage "${t.stage}".`)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);if(message.includes("Invalid stage"))await handleInvalidStageError(id,message);console.error(`Error: ${message}`),process.exit(1)}}),task.command("assign <id>").description("Assign an actor to a task").requiredOption("--to <name>","Actor name").option("--role <role>","Actor role","assignee").option("--comment <msg>","Comment on the assignment").action(async(id,options)=>{try{let ts3=await getTaskService8(),actor=currentActor2();if(await ts3.assignTask(id,localActor2(options.to),options.role,{}),options.comment)await ts3.commentOnTask(id,actor,options.comment);console.log(`Assigned "${options.to}" as ${options.role??"assignee"} on task ${id}.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("tag <id> <tags...>").description("Add tags to a task").action(async(id,tags)=>{try{await(await getTaskService8()).tagTask(id,tags,currentActor2()),console.log(`Tagged task ${id} with: ${tags.join(", ")}`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("comment <id> <message>").description("Add a comment to a task").option("--reply-to <msgId>","Reply to a specific message ID").action(async(id,message,options)=>{try{let ts3=await getTaskService8(),replyTo=options.replyTo?Number(options.replyTo):void 0,msg=await ts3.commentOnTask(id,currentActor2(),message,void 0,replyTo);console.log(`Comment #${msg.id} added to task ${id}.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("block <id>").description("Mark task as blocked").requiredOption("--reason <reason>","Reason for blocking").option("--comment <msg>","Additional comment").action(async(id,options)=>{try{let ts3=await getTaskService8(),actor=currentActor2(),t=await ts3.blockTask(id,options.reason,actor,options.comment);console.log(`Task #${t.seq} blocked: ${options.reason}`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("unblock <id>").description("Unblock a task").option("--comment <msg>","Comment on unblock").action(async(id,options)=>{try{let ts3=await getTaskService8(),actor=currentActor2(),t=await ts3.unblockTask(id,actor,options.comment);console.log(`Task #${t.seq} unblocked.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("done <id>").description("Mark task as done").option("--comment <msg>","Comment on completion").action(async(id,options)=>{try{let ts3=await getTaskService8(),actor=currentActor2(),t=await ts3.markDone(id,actor,options.comment);console.log(`Task #${t.seq} marked as done.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("checkout <id>").description("Atomically claim a task for execution").action(async(id)=>{try{let ts3=await getTaskService8(),runId=getRunId(),t=await ts3.checkoutTask(id,runId);console.log(`Checked out task #${t.seq} for run: ${runId}`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("release <id>").description("Release task checkout claim").action(async(id)=>{try{let ts3=await getTaskService8(),runId=getRunId(),t=await ts3.releaseTask(id,runId);console.log(`Released task #${t.seq} from run: ${runId}`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("unlock <id>").description("Force-release a stale checkout (admin override)").action(async(id)=>{try{let t=await(await getTaskService8()).forceUnlockTask(id);console.log(`Force-unlocked task #${t.seq}.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("close-merged").description("Auto-close tasks whose wish slugs match recently merged PRs").option("--since <duration>",'Time window for merged PRs (e.g., "24h", "7d")',"24h").option("--dry-run","Show what would be closed without acting").option("--repo <owner/repo>","Override GitHub remote detection").action(async(options)=>{try{await handleCloseMerged(options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("dep <id>").description("Manage task dependencies").option("--depends-on <id2>","This task depends on id2").option("--blocks <id2>","This task blocks id2").option("--relates-to <id2>","This task relates to id2").option("--remove <id2>","Remove dependency on id2").action(async(id,options)=>{try{let ts3=await getTaskService8();if(options.remove){if(await ts3.removeDependency(id,options.remove))console.log(`Removed dependency between ${id} and ${options.remove}.`);else console.log("No dependency found to remove.");return}if(options.dependsOn)await ts3.addDependency(id,options.dependsOn,"depends_on"),console.log(`${id} now depends on ${options.dependsOn}.`);if(options.blocks)await ts3.addDependency(id,options.blocks,"blocks"),console.log(`${id} now blocks ${options.blocks}.`);if(options.relatesTo)await ts3.addDependency(id,options.relatesTo,"relates_to"),console.log(`${id} now relates to ${options.relatesTo}.`);if(!options.dependsOn&&!options.blocks&&!options.relatesTo)console.error("Error: Specify --depends-on, --blocks, --relates-to, or --remove."),process.exit(1)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}})}init_team_manager();import{existsSync as existsSync32}from"fs";import{copyFile as copyFile2,cp as cp2,mkdir as mkdir8}from"fs/promises";import{join as join43,resolve as resolve6}from"path";function registerTeamNamespace(program2){let team=program2.command("team").description("Team lifecycle management");team.command("create <name>").description("Create a new team with a git worktree").requiredOption("--repo <path>","Path to the git repository").option("--branch <branch>","Base branch to create from","dev").option("--wish <slug>","Wish slug \u2014 auto-spawns a task leader with wish context").option("--session <name>","Tmux session name (avoids session explosion on parallel creates)").option("--no-spawn","Create team and copy wish without spawning the leader (useful for testing)").action(async(name,options)=>{try{await handleTeamCreate(name,options)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("hire <agent>").description('Add an agent to a team ("council" hires all 10 council members)').option("--team <name>","Team name (auto-detects from leader context if omitted)").action(async(agent,options)=>{try{let teamName=options.team??await autoDetectTeam();if(!teamName)console.error("Error: Could not detect team. Use --team <name> to specify."),process.exit(1);let added=await hireAgent(teamName,agent);if(added.length===0)console.log(`Agent "${agent}" is already a member of "${teamName}".`);else if(agent==="council"){console.log(`Hired ${added.length} council members to "${teamName}":`);for(let name of added)console.log(` + ${name}`)}else console.log(`Hired "${agent}" to team "${teamName}".`)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("fire <agent>").description("Remove an agent from a team").option("--team <name>","Team name (auto-detects from leader context if omitted)").action(async(agent,options)=>{try{let teamName=options.team??await autoDetectTeam();if(!teamName)console.error("Error: Could not detect team. Use --team <name> to specify."),process.exit(1);if(await fireAgent(teamName,agent))console.log(`Fired "${agent}" from team "${teamName}".`);else console.error(`Agent "${agent}" is not a member of "${teamName}".`),process.exit(1)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("ls [name]").alias("list").description("List teams or members of a team").option("--json","Output as JSON").action(async(name,options)=>{try{if(name)await printMembers(name,options.json);else await printTeams(options.json)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("disband <name>").description("Disband a team: kill members, remove worktree, delete config").action(async(name)=>{try{if(await disbandTeam(name))console.log(`Team "${name}" disbanded.`);else console.error(`Team "${name}" not found.`),process.exit(1)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("done <name>").description("Mark a team as done and kill all members").action(async(name)=>{try{await setTeamStatus(name,"done"),await killTeamMembers(name),console.log(`Team "${name}" marked as done. All members killed.`)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("blocked <name>").description("Mark a team as blocked and kill all members").action(async(name)=>{try{await setTeamStatus(name,"blocked"),await killTeamMembers(name),console.log(`Team "${name}" marked as blocked. All members killed.`)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}})}async function handleTeamCreate(name,options){if(options.wish){let resolvedRepo=resolve6(options.repo),wishPath=join43(resolvedRepo,".genie","wishes",options.wish,"WISH.md");if(!existsSync32(wishPath)){let cwdWishDir=join43(process.cwd(),".genie","wishes",options.wish),cwdWishPath=join43(cwdWishDir,"WISH.md");if(existsSync32(cwdWishPath)){let destDir=join43(resolvedRepo,".genie","wishes",options.wish);await mkdir8(destDir,{recursive:!0}),await cp2(cwdWishDir,destDir,{recursive:!0}),console.log(`Wish: copied ${options.wish}/WISH.md to repo`)}else console.error(`Error: Wish not found at ${wishPath}`),process.exit(1)}}let config=await createTeam(name,options.repo,options.branch),needsUpdate=!1;if(options.wish)config.wishSlug=options.wish,needsUpdate=!0;if(options.session)config.tmuxSessionName=options.session,needsUpdate=!0;if(needsUpdate)await updateTeamConfig(name,config);if(console.log(`Team "${config.name}" created.`),console.log(` Worktree: ${config.worktreePath}`),console.log(` Branch: ${config.name} (from ${config.baseBranch})`),config.tmuxSessionName)console.log(` Session: ${config.tmuxSessionName}`);if(config.nativeTeamsEnabled)console.log(" Native teams: enabled");if(options.wish&&options.spawn!==!1)await spawnLeaderWithWish(config,options.wish,options.repo,options.session)}async function spawnLeaderWithWish(config,slug,repoPath,sessionOverride){let{handleWorkerSpawn:handleWorkerSpawn2}=await Promise.resolve().then(() => (init_agents(),exports_agents)),{getCurrentSessionName:getCurrentSessionName2}=await Promise.resolve().then(() => (init_tmux(),exports_tmux)),resolvedRepo=resolve6(repoPath),tmuxSession=sessionOverride??await getCurrentSessionName2(config.name)??config.name;config.tmuxSessionName=tmuxSession,await updateTeamConfig(config.name,config);let sourceWishPath=join43(resolvedRepo,".genie","wishes",slug,"WISH.md");if(!existsSync32(sourceWishPath))console.error(`Error: Wish not found at ${sourceWishPath}`),process.exit(1);let destWishDir=join43(config.worktreePath,".genie","wishes",slug);await mkdir8(destWishDir,{recursive:!0});let destWishPath=join43(destWishDir,"WISH.md");await copyFile2(sourceWishPath,destWishPath),console.log(` Wish: copied ${slug}/WISH.md into worktree`);let standardTeam=["team-lead","engineer","reviewer","qa","fix"];for(let role of standardTeam)await hireAgent(config.name,role);console.log(` Team: hired ${standardTeam.join(", ")}`);let members=standardTeam.filter((r)=>r!=="team-lead").join(", "),kickoffPrompt=`Your team is "${config.name}". Repo: ${config.repo}. Branch: ${config.name}. Worktree: ${config.worktreePath}. Wish slug: ${slug}. Your team members are: ${members} (already hired \u2014 genie work will spawn them automatically). Read the wish at .genie/wishes/${slug}/WISH.md and execute the full lifecycle autonomously.`;await handleWorkerSpawn2("team-lead",{provider:"claude",team:config.name,cwd:config.worktreePath,session:tmuxSession,initialPrompt:kickoffPrompt});let result=await(await Promise.resolve().then(() => (init_protocol_router(),exports_protocol_router))).sendMessage(config.worktreePath,"cli","team-lead",kickoffPrompt);if(!result.delivered)console.warn(`\u26A0 Backup delivery to team-lead failed: ${result.reason??"unknown"}`);console.log(" Leader: spawned and working")}async function autoDetectTeam(){let envTeam=process.env.GENIE_TEAM;if(envTeam)return envTeam;let teams=await listTeams2();if(teams.length===1)return teams[0].name;return null}async function printMembers(name,json2){let members=await listMembers(name);if(members===null)console.error(`Team "${name}" not found.`),process.exit(1);if(json2){console.log(JSON.stringify(members,null,2));return}if(members.length===0){console.log(`Team "${name}" has no members. Hire agents with: genie team hire <agent> --team ${name}`);return}console.log(""),console.log(`MEMBERS of "${name}"`),console.log("-".repeat(60));for(let m of members)console.log(` ${m}`);console.log("")}async function printTeams(json2){let teams=await listTeams2();if(json2){console.log(JSON.stringify(teams,null,2));return}if(teams.length===0){console.log("No teams found. Create one with: genie team create <name> --repo <path>");return}console.log(""),console.log("TEAMS"),console.log("-".repeat(60));for(let t of teams)printTeamSummary(t);console.log("")}function printTeamSummary(t){let status=t.status??"in_progress";console.log(` ${t.name} [${status}]`),console.log(` Repo: ${t.repo}`),console.log(` Branch: ${t.name} (from ${t.baseBranch})`),console.log(` Worktree: ${t.worktreePath}`),console.log(` Members: ${t.members.length}`)}function registerTemplateCommands(program2){let tmpl=program2.command("template").description("Board template management");tmpl.command("list",{isDefault:!0}).description("List available templates").option("--json","Output as JSON").action(async(options)=>{let{listTemplates:listTemplates3}=await Promise.resolve().then(() => (init_template_service(),exports_template_service)),templates=await listTemplates3();if(options.json){console.log(JSON.stringify(templates,null,2));return}if(templates.length===0){console.log("No templates found.");return}let maxName=Math.max(...templates.map((t)=>t.name.length),4);for(let t of templates){let cols=t.columns?.length??0,tag=t.isBuiltin?" (builtin)":"";console.log(` ${padRight(t.name,maxName)} ${cols} columns${tag} ${t.id}`)}console.log(`
2462
2462
  ${templates.length} template${templates.length===1?"":"s"}`)}),tmpl.command("show <name>").description("Show template details").option("--json","Output as JSON").action(async(name,options)=>{let{getTemplate:getTemplate2}=await Promise.resolve().then(() => (init_template_service(),exports_template_service)),t=await getTemplate2(name);if(!t)console.error(`Template "${name}" not found.`),process.exit(1);if(options.json){console.log(JSON.stringify(t,null,2));return}if(console.log(`
2463
- Name: ${t.name}`),console.log(`ID: ${t.id}`),console.log(`Builtin: ${t.isBuiltin}`),console.log(`Description: ${t.description??"(none)"}`),t.columns&&t.columns.length>0)console.log(`Columns: ${t.columns.map((c)=>c.name).join(", ")}`);console.log("")}),tmpl.command("delete <name>").description("Delete a template").action(async(name)=>{let{deleteTemplate:deleteTemplate2,getTemplate:getTemplate2}=await Promise.resolve().then(() => (init_template_service(),exports_template_service)),t=await getTemplate2(name);if(!t)console.error(`Template "${name}" not found.`),process.exit(1);let ok=await deleteTemplate2(t.id);console.log(ok?`Deleted template "${t.name}".`:"Delete failed.")})}try{let{execSync:execSyncStartup}=__require("child_process");if(execSyncStartup("git config core.bare",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()==="true")execSyncStartup("git config core.bare false",{stdio:["pipe","pipe","pipe"]})}catch{}var program2=new Command;program2.name("genie").description("Genie CLI - AI-assisted development").version(VERSION);async function startNamedSession(name){let{buildTeamLeadCommand:buildTeamLeadCommand2,sessionExists:sessionExists2}=await Promise.resolve().then(() => (init_team_lead_command(),exports_team_lead_command)),{getAgentsFilePath:getAgentsFilePath2}=await Promise.resolve().then(() => (init_session(),exports_session)),systemPromptFile=getAgentsFilePath2(),hasPriorSession=sessionExists2(name),cmd=buildTeamLeadCommand2(name,{systemPromptFile:systemPromptFile??void 0,continueName:hasPriorSession?name:void 0});console.log(hasPriorSession?`Resuming session: ${name}`:`Starting new session: ${name}`);let{spawnSync:spawnSync3}=await import("child_process"),result=spawnSync3("sh",["-c",cmd],{stdio:"inherit"});if(result.status)process.exit(result.status)}program2.command("setup").description("Configure genie settings").option("--quick","Accept all defaults").option("--shortcuts","Only configure keyboard shortcuts").option("--codex","Only configure Codex integration").option("--terminal","Only configure terminal defaults").option("--session","Only configure session settings").option("--reset","Reset configuration to defaults").option("--show","Show current configuration").action(async(options)=>{await setupCommand(options)});program2.command("doctor").description("Run diagnostic checks on genie installation").option("--fix","Auto-fix: kill zombie postgres, clean shared memory, restart daemon").action(doctorCommand);program2.command("update").description("Update Genie CLI to the latest version").option("--next","Switch to dev builds (npm @next tag)").option("--stable","Switch to stable releases (npm @latest tag)").action(updateCommand);program2.command("uninstall").description("Remove Genie CLI and clean up hooks").action(uninstallCommand);var shortcuts=program2.command("shortcuts").description("Manage tmux keyboard shortcuts");shortcuts.action(shortcutsShowCommand);shortcuts.command("show").description("Show available shortcuts and installation status").action(shortcutsShowCommand);shortcuts.command("install").description("Install shortcuts to config files (~/.tmux.conf, shell rc)").action(shortcutsInstallCommand);shortcuts.command("uninstall").description("Remove shortcuts from config files").action(shortcutsUninstallCommand);registerAgentCommands(program2);registerTaskCommands(program2);extendTaskCommands(program2);registerTeamNamespace(program2);registerExecCommands(program2);program2.command("tui").description("Launch interactive terminal UI (OpenTUI nav + tmux Claude Code)").option("--dev","Development mode with auto-reload on file changes").action(async(options)=>{let{launchTui:launchTui2}=await Promise.resolve().then(() => (init_tui(),exports_tui));await launchTui2({dev:options.dev})});registerDispatchCommands(program2);registerHookNamespace(program2);registerDbCommands(program2);registerScheduleCommands(program2);registerDaemonCommands(program2);registerNotifyCommands(program2);registerEventsCommands(program2);registerSessionsCommands(program2);registerMetricsCommands(program2);registerExportCommands(program2);registerImportCommands(program2);registerTemplateCommands(program2);registerInstallCommand(program2);registerPublishCommand(program2);var itemCmd=program2.command("item").description("Item registry management");registerItemUninstallCommand(itemCmd);registerItemUpdateCommand(itemCmd);var auditTimers=new Map;program2.hook("preAction",(_thisCommand,actionCommand)=>{let name=actionCommand.name();auditTimers.set(name,Date.now()),Promise.resolve().then(() => (init_db(),exports_db)).then(({isConnected:isConnected2})=>{if(!isConnected2())return;recordAuditEvent("command",name,"command_start",getActor(),{args:actionCommand.args}).catch(()=>{})}).catch(()=>{})});program2.hook("postAction",(_thisCommand,actionCommand)=>{let name=actionCommand.name(),startMs=auditTimers.get(name),durationMs=startMs?Date.now()-startMs:void 0;auditTimers.delete(name),Promise.resolve().then(() => (init_db(),exports_db)).then(({isConnected:isConnected2})=>{if(!isConnected2())return;recordAuditEvent("command",name,"command_success",getActor(),{args:actionCommand.args,duration_ms:durationMs}).catch(()=>{})}).catch(()=>{})});var qaCmd=program2.command("qa").description("QA \u2014 self-testing system for genie CLI");qaCmd.command("run [target]",{isDefault:!0}).description("Run QA specs (all, a domain, or a single spec)").option("--timeout <seconds>","Max seconds per spec",(v2)=>Number(v2),3600).option("--parallel <n>","Max specs to run in parallel",(v2)=>Number(v2),5).option("--verbose","Show all collected events").option("--ndjson","Machine-readable NDJSON output").action(async(target,options)=>{await qaCommand(target,options)});qaCmd.command("status").description("Show QA dashboard with last results per spec").option("--json","Output as JSON").action(async(options)=>{await qaStatusCommand(options)});qaCmd.command("history").description("Show recent QA runs").action(async()=>{await qaHistoryCommand()});qaCmd.command("check <specFile>").description("Evaluate a QA spec against current team logs and publish qa-report").option("--team <name>","Team name (defaults to GENIE_TEAM)").option("--since <timestamp>","Only consider events after this ISO timestamp").option("--since-file <path>","Read the lower-bound timestamp from a file").action(async(specFile,options)=>{await qaCheckCommand(specFile,options)});program2.command("qa-report <json>").description("Publish QA result to the PG event log (called by QA team-lead)").action(async(json2)=>{let team=process.env.GENIE_TEAM;if(!team)console.error("Error: GENIE_TEAM not set. This command must be run by a QA team-lead agent."),process.exit(1);try{let data=JSON.parse(json2),{publishSubjectEvent:publishSubjectEvent2}=await Promise.resolve().then(() => (init_runtime_events(),exports_runtime_events));await publishSubjectEvent2(process.cwd(),`genie.qa.${team}.result`,{kind:"qa",agent:"qa",team,text:`QA result: ${String(data.result??"unknown")}`,data,source:"hook"}),console.log(`QA result published to PG event log as genie.qa.${team}.result`)}catch(err){console.error(`Failed to publish QA result: ${err}`),process.exit(1)}});function errorRedirect(oldCmd,newCmd){return()=>{let args=process.argv.slice(3).join(" "),suggestion=args?`${newCmd} ${args}`:newCmd;console.error(`Command "${oldCmd}" has moved. Did you mean: genie ${suggestion}?`),process.exit(1)}}program2.command("spawn [args...]").description("(moved) \u2192 genie agent spawn").action(errorRedirect("spawn","agent spawn"));program2.command("kill [args...]").description("(moved) \u2192 genie agent kill").action(errorRedirect("kill","agent kill"));program2.command("stop [args...]").description("(moved) \u2192 genie agent stop").action(errorRedirect("stop","agent stop"));program2.command("resume [args...]").description("(moved) \u2192 genie agent resume").action(errorRedirect("resume","agent resume"));program2.command("ls").description("(moved) \u2192 genie agent list").action(errorRedirect("ls","agent list"));program2.command("read [args...]").description("(moved) \u2192 genie agent log --raw").action(errorRedirect("read","agent log --raw"));program2.command("history [args...]").description("(moved) \u2192 genie agent log --transcript").action(errorRedirect("history","agent log --transcript"));program2.command("log [args...]").description("(moved) \u2192 genie agent log").action(errorRedirect("log","agent log"));program2.command("status [args...]").description("(moved) \u2192 genie task status").action(errorRedirect("status","task status"));program2.command("done [args...]").description("(moved) \u2192 genie task done").action(errorRedirect("done","task done"));program2.command("reset [args...]").description("(moved) \u2192 genie task reset").action(errorRedirect("reset","task reset"));program2.command("send [args...]").description("(moved) \u2192 genie agent send").action(errorRedirect("send","agent send"));program2.command("broadcast [args...]").description("(moved) \u2192 genie agent send --broadcast").action(errorRedirect("broadcast","agent send --broadcast"));program2.command("answer [args...]").description("(moved) \u2192 genie agent answer").action(errorRedirect("answer","agent answer"));program2.command("inbox [args...]").description("(moved) \u2192 genie agent inbox").action(errorRedirect("inbox","agent inbox"));program2.command("chat [args...]").description("(moved) \u2192 genie agent log --conversations").action(errorRedirect("chat","agent log --conversations"));program2.command("brief [args...]").description("(moved) \u2192 genie agent brief").action(errorRedirect("brief","agent brief"));program2.command("dir [args...]").description("(moved) \u2192 genie agent directory / genie agent register").action(errorRedirect("dir","agent directory"));program2.command("show [args...]").description("(moved) \u2192 genie task show / genie agent show").action(errorRedirect("show","agent show"));var args=process.argv.slice(2);if(args.length===0||args.every((a)=>a==="--reset")){let{sessionCommand:sessionCommand2}=await Promise.resolve().then(() => (init_session(),exports_session));await sessionCommand2({reset:args.includes("--reset")}),process.exit(0)}var sessionIdx=args.indexOf("--session");if(sessionIdx!==-1&&sessionIdx+1<args.length){let sessionName=args[sessionIdx+1];if(!args.filter((_2,i2)=>i2!==sessionIdx&&i2!==sessionIdx+1).some((a)=>!a.startsWith("-")))try{await startNamedSession(sessionName),process.exit(0)}catch(err){console.error(`Error: ${err instanceof Error?err.message:err}`),process.exit(1)}else try{await program2.parseAsync(process.argv)}finally{stopOtelReceiver(),await shutdown().catch(()=>{})}}else try{await program2.parseAsync(process.argv)}finally{stopOtelReceiver(),await shutdown().catch(()=>{})}
2463
+ Name: ${t.name}`),console.log(`ID: ${t.id}`),console.log(`Builtin: ${t.isBuiltin}`),console.log(`Description: ${t.description??"(none)"}`),t.columns&&t.columns.length>0)console.log(`Columns: ${t.columns.map((c)=>c.name).join(", ")}`);console.log("")}),tmpl.command("delete <name>").description("Delete a template").action(async(name)=>{let{deleteTemplate:deleteTemplate2,getTemplate:getTemplate2}=await Promise.resolve().then(() => (init_template_service(),exports_template_service)),t=await getTemplate2(name);if(!t)console.error(`Template "${name}" not found.`),process.exit(1);let ok=await deleteTemplate2(t.id);console.log(ok?`Deleted template "${t.name}".`:"Delete failed.")})}try{let{execSync:execSyncStartup}=__require("child_process");if(execSyncStartup("git config core.bare",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()==="true")execSyncStartup("git config core.bare false",{stdio:["pipe","pipe","pipe"]})}catch{}var program2=new Command;program2.name("genie").description("Genie CLI - AI-assisted development").version(VERSION);async function startNamedSession(name){let{buildTeamLeadCommand:buildTeamLeadCommand2,sessionExists:sessionExists2}=await Promise.resolve().then(() => (init_team_lead_command(),exports_team_lead_command)),{getAgentsFilePath:getAgentsFilePath2}=await Promise.resolve().then(() => (init_session(),exports_session)),systemPromptFile=getAgentsFilePath2(),hasPriorSession=sessionExists2(name),cmd=buildTeamLeadCommand2(name,{systemPromptFile:systemPromptFile??void 0,continueName:hasPriorSession?name:void 0});console.log(hasPriorSession?`Resuming session: ${name}`:`Starting new session: ${name}`);let{spawnSync:spawnSync3}=await import("child_process"),result=spawnSync3("sh",["-c",cmd],{stdio:"inherit"});if(result.status)process.exit(result.status)}program2.command("setup").description("Configure genie settings").option("--quick","Accept all defaults").option("--shortcuts","Only configure keyboard shortcuts").option("--codex","Only configure Codex integration").option("--terminal","Only configure terminal defaults").option("--session","Only configure session settings").option("--reset","Reset configuration to defaults").option("--show","Show current configuration").action(async(options)=>{await setupCommand(options)});program2.command("doctor").description("Run diagnostic checks on genie installation").option("--fix","Auto-fix: kill zombie postgres, clean shared memory, restart daemon").action(doctorCommand);program2.command("update").description("Update Genie CLI to the latest version").option("--next","Switch to dev builds (npm @next tag)").option("--stable","Switch to stable releases (npm @latest tag)").action(updateCommand);program2.command("uninstall").description("Remove Genie CLI and clean up hooks").action(uninstallCommand);var shortcuts=program2.command("shortcuts").description("Manage tmux keyboard shortcuts");shortcuts.action(shortcutsShowCommand);shortcuts.command("show").description("Show available shortcuts and installation status").action(shortcutsShowCommand);shortcuts.command("install").description("Install shortcuts to config files (~/.tmux.conf, shell rc)").action(shortcutsInstallCommand);shortcuts.command("uninstall").description("Remove shortcuts from config files").action(shortcutsUninstallCommand);registerAgentCommands(program2);registerTaskCommands(program2);extendTaskCommands(program2);registerTeamNamespace(program2);registerExecCommands(program2);program2.command("tui").description("Launch interactive terminal UI (OpenTUI nav + tmux Claude Code)").option("--dev","Development mode with auto-reload on file changes").action(async(options)=>{let{launchTui:launchTui2}=await Promise.resolve().then(() => (init_tui(),exports_tui));await launchTui2({dev:options.dev})});registerDispatchCommands(program2);registerHookNamespace(program2);registerDbCommands(program2);registerScheduleCommands(program2);registerDaemonCommands(program2);registerNotifyCommands(program2);registerEventsCommands(program2);registerSessionsCommands(program2);registerMetricsCommands(program2);registerExportCommands(program2);registerImportCommands(program2);registerTemplateCommands(program2);registerInstallCommand(program2);registerPublishCommand(program2);var itemCmd=program2.command("item").description("Item registry management");registerItemUninstallCommand(itemCmd);registerItemUpdateCommand(itemCmd);var auditTimers=new Map;program2.hook("preAction",(_thisCommand,actionCommand)=>{let name=actionCommand.name();auditTimers.set(name,Date.now()),Promise.resolve().then(() => (init_db(),exports_db)).then(({isConnected:isConnected2})=>{if(!isConnected2())return;recordAuditEvent("command",name,"command_start",getActor(),{args:actionCommand.args}).catch(()=>{})}).catch(()=>{})});program2.hook("postAction",(_thisCommand,actionCommand)=>{let name=actionCommand.name(),startMs=auditTimers.get(name),durationMs=startMs?Date.now()-startMs:void 0;auditTimers.delete(name),Promise.resolve().then(() => (init_db(),exports_db)).then(({isConnected:isConnected2})=>{if(!isConnected2())return;recordAuditEvent("command",name,"command_success",getActor(),{args:actionCommand.args,duration_ms:durationMs}).catch(()=>{})}).catch(()=>{})});var qaCmd=program2.command("qa").description("QA \u2014 self-testing system for genie CLI");qaCmd.command("run [target]",{isDefault:!0}).description("Run QA specs (all, a domain, or a single spec)").option("--timeout <seconds>","Max seconds per spec",(v2)=>Number(v2),3600).option("--parallel <n>","Max specs to run in parallel",(v2)=>Number(v2),5).option("--verbose","Show all collected events").option("--ndjson","Machine-readable NDJSON output").action(async(target,options)=>{await qaCommand(target,options)});qaCmd.command("status").description("Show QA dashboard with last results per spec").option("--json","Output as JSON").action(async(options)=>{await qaStatusCommand(options)});qaCmd.command("history").description("Show recent QA runs").action(async()=>{await qaHistoryCommand()});qaCmd.command("check <specFile>").description("Evaluate a QA spec against current team logs and publish qa-report").option("--team <name>","Team name (defaults to GENIE_TEAM)").option("--since <timestamp>","Only consider events after this ISO timestamp").option("--since-file <path>","Read the lower-bound timestamp from a file").action(async(specFile,options)=>{await qaCheckCommand(specFile,options)});program2.command("qa-report <json>").description("Publish QA result to the PG event log (called by QA team-lead)").action(async(json2)=>{let team=process.env.GENIE_TEAM;if(!team)console.error("Error: GENIE_TEAM not set. This command must be run by a QA team-lead agent."),process.exit(1);try{let data=JSON.parse(json2),{publishSubjectEvent:publishSubjectEvent2}=await Promise.resolve().then(() => (init_runtime_events(),exports_runtime_events));await publishSubjectEvent2(process.cwd(),`genie.qa.${team}.result`,{kind:"qa",agent:"qa",team,text:`QA result: ${String(data.result??"unknown")}`,data,source:"hook"}),console.log(`QA result published to PG event log as genie.qa.${team}.result`)}catch(err){console.error(`Failed to publish QA result: ${err}`),process.exit(1)}});function errorRedirect(oldCmd,newCmd){return()=>{let cmdIdx=process.argv.indexOf(oldCmd),args=cmdIdx>=0?process.argv.slice(cmdIdx+1).join(" "):process.argv.slice(3).join(" "),suggestion=args?`${newCmd} ${args}`:newCmd;console.error(`Command "${oldCmd}" has moved. Run:
2464
+
2465
+ genie ${suggestion}
2466
+ `),process.exit(1)}}function redirect(cmd,desc,newCmd){return program2.command(`${cmd} [args...]`).description(desc).allowUnknownOption().action(errorRedirect(cmd,newCmd))}redirect("spawn","(moved) \u2192 genie agent spawn","agent spawn");redirect("kill","(moved) \u2192 genie agent kill","agent kill");redirect("stop","(moved) \u2192 genie agent stop","agent stop");redirect("resume","(moved) \u2192 genie agent resume","agent resume");redirect("ls","(moved) \u2192 genie agent list","agent list");redirect("read","(moved) \u2192 genie agent log --raw","agent log --raw");redirect("history","(moved) \u2192 genie agent log --transcript","agent log --transcript");redirect("log","(moved) \u2192 genie agent log","agent log");redirect("status","(moved) \u2192 genie task status","task status");redirect("done","(moved) \u2192 genie task done","task done");redirect("reset","(moved) \u2192 genie task reset","task reset");redirect("send","(moved) \u2192 genie agent send","agent send");redirect("broadcast","(moved) \u2192 genie agent send --broadcast","agent send --broadcast");redirect("answer","(moved) \u2192 genie agent answer","agent answer");redirect("inbox","(moved) \u2192 genie agent inbox","agent inbox");redirect("chat","(moved) \u2192 genie agent log --conversations","agent log --conversations");redirect("brief","(moved) \u2192 genie agent brief","agent brief");redirect("dir","(moved) \u2192 genie agent directory","agent directory");program2.command("show [args...]").description("(moved) \u2192 genie task show / genie agent show").allowUnknownOption().action(errorRedirect("show","agent show"));var args=process.argv.slice(2);if(args.length===0||args.every((a)=>a==="--reset")){let{sessionCommand:sessionCommand2}=await Promise.resolve().then(() => (init_session(),exports_session));await sessionCommand2({reset:args.includes("--reset")}),process.exit(0)}var sessionIdx=args.indexOf("--session");if(sessionIdx!==-1&&sessionIdx+1<args.length){let sessionName=args[sessionIdx+1];if(!args.filter((_2,i2)=>i2!==sessionIdx&&i2!==sessionIdx+1).some((a)=>!a.startsWith("-")))try{await startNamedSession(sessionName),process.exit(0)}catch(err){console.error(`Error: ${err instanceof Error?err.message:err}`),process.exit(1)}else try{await program2.parseAsync(process.argv)}finally{stopOtelReceiver(),await shutdown().catch(()=>{})}}else try{await program2.parseAsync(process.argv)}finally{stopOtelReceiver(),await shutdown().catch(()=>{})}
@@ -2,7 +2,7 @@
2
2
  "id": "genie",
3
3
  "name": "Genie",
4
4
  "description": "Skills, agents, and hooks for the Genie CLI terminal orchestration toolkit",
5
- "version": "4.260329.16",
5
+ "version": "4.260329.18",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/genie",
3
- "version": "4.260329.16",
3
+ "version": "4.260329.18",
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.260329.16",
3
+ "version": "4.260329.18",
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.260329.16",
3
+ "version": "4.260329.18",
4
4
  "private": true,
5
5
  "description": "Runtime dependencies for genie bundled CLIs",
6
6
  "type": "module",
package/src/genie.ts CHANGED
@@ -312,70 +312,42 @@ program
312
312
 
313
313
  function errorRedirect(oldCmd: string, newCmd: string): () => void {
314
314
  return () => {
315
- const args = process.argv.slice(3).join(' ');
315
+ // Reconstruct all args after the old command name (positional + flags)
316
+ const cmdIdx = process.argv.indexOf(oldCmd);
317
+ const args = cmdIdx >= 0 ? process.argv.slice(cmdIdx + 1).join(' ') : process.argv.slice(3).join(' ');
316
318
  const suggestion = args ? `${newCmd} ${args}` : newCmd;
317
- console.error(`Command "${oldCmd}" has moved. Did you mean: genie ${suggestion}?`);
319
+ console.error(`Command "${oldCmd}" has moved. Run:\n\n genie ${suggestion}\n`);
318
320
  process.exit(1);
319
321
  };
320
322
  }
321
323
 
322
- program
323
- .command('spawn [args...]')
324
- .description('(moved) → genie agent spawn')
325
- .action(errorRedirect('spawn', 'agent spawn'));
326
- program.command('kill [args...]').description('(moved) → genie agent kill').action(errorRedirect('kill', 'agent kill'));
327
- program.command('stop [args...]').description('(moved) → genie agent stop').action(errorRedirect('stop', 'agent stop'));
328
- program
329
- .command('resume [args...]')
330
- .description('(moved) → genie agent resume')
331
- .action(errorRedirect('resume', 'agent resume'));
332
- program.command('ls').description('(moved) → genie agent list').action(errorRedirect('ls', 'agent list'));
333
- program
334
- .command('read [args...]')
335
- .description('(moved) → genie agent log --raw')
336
- .action(errorRedirect('read', 'agent log --raw'));
337
- program
338
- .command('history [args...]')
339
- .description('(moved) → genie agent log --transcript')
340
- .action(errorRedirect('history', 'agent log --transcript'));
341
- program.command('log [args...]').description('(moved) → genie agent log').action(errorRedirect('log', 'agent log'));
342
- program
343
- .command('status [args...]')
344
- .description('(moved) → genie task status')
345
- .action(errorRedirect('status', 'task status'));
346
- program.command('done [args...]').description('(moved) → genie task done').action(errorRedirect('done', 'task done'));
347
- program
348
- .command('reset [args...]')
349
- .description('(moved) → genie task reset')
350
- .action(errorRedirect('reset', 'task reset'));
351
- program.command('send [args...]').description('(moved) → genie agent send').action(errorRedirect('send', 'agent send'));
352
- program
353
- .command('broadcast [args...]')
354
- .description('(moved) → genie agent send --broadcast')
355
- .action(errorRedirect('broadcast', 'agent send --broadcast'));
356
- program
357
- .command('answer [args...]')
358
- .description('(moved) → genie agent answer')
359
- .action(errorRedirect('answer', 'agent answer'));
360
- program
361
- .command('inbox [args...]')
362
- .description('(moved) → genie agent inbox')
363
- .action(errorRedirect('inbox', 'agent inbox'));
364
- program
365
- .command('chat [args...]')
366
- .description('(moved) → genie agent log --conversations')
367
- .action(errorRedirect('chat', 'agent log --conversations'));
368
- program
369
- .command('brief [args...]')
370
- .description('(moved) → genie agent brief')
371
- .action(errorRedirect('brief', 'agent brief'));
372
- program
373
- .command('dir [args...]')
374
- .description('(moved) → genie agent directory / genie agent register')
375
- .action(errorRedirect('dir', 'agent directory'));
324
+ /** Helper: create a redirect stub that swallows unknown options so Commander doesn't choke on --flags. */
325
+ function redirect(cmd: string, desc: string, newCmd: string) {
326
+ return program.command(`${cmd} [args...]`).description(desc).allowUnknownOption().action(errorRedirect(cmd, newCmd));
327
+ }
328
+
329
+ redirect('spawn', '(moved) → genie agent spawn', 'agent spawn');
330
+ redirect('kill', '(moved) → genie agent kill', 'agent kill');
331
+ redirect('stop', '(moved) → genie agent stop', 'agent stop');
332
+ redirect('resume', '(moved) → genie agent resume', 'agent resume');
333
+ redirect('ls', '(moved) → genie agent list', 'agent list');
334
+ redirect('read', '(moved) → genie agent log --raw', 'agent log --raw');
335
+ redirect('history', '(moved) → genie agent log --transcript', 'agent log --transcript');
336
+ redirect('log', '(moved) → genie agent log', 'agent log');
337
+ redirect('status', '(moved) → genie task status', 'task status');
338
+ redirect('done', '(moved) genie task done', 'task done');
339
+ redirect('reset', '(moved) → genie task reset', 'task reset');
340
+ redirect('send', '(moved) → genie agent send', 'agent send');
341
+ redirect('broadcast', '(moved) → genie agent send --broadcast', 'agent send --broadcast');
342
+ redirect('answer', '(moved) → genie agent answer', 'agent answer');
343
+ redirect('inbox', '(moved) → genie agent inbox', 'agent inbox');
344
+ redirect('chat', '(moved) → genie agent log --conversations', 'agent log --conversations');
345
+ redirect('brief', '(moved) → genie agent brief', 'agent brief');
346
+ redirect('dir', '(moved) → genie agent directory', 'agent directory');
376
347
  program
377
348
  .command('show [args...]')
378
349
  .description('(moved) → genie task show / genie agent show')
350
+ .allowUnknownOption()
379
351
  .action(errorRedirect('show', 'agent show'));
380
352
 
381
353
  // ============================================================================
@@ -1,5 +1,5 @@
1
1
  /** @jsxImportSource @opentui/react */
2
- /** Executor list — renders executor metadata from DB with gap detection */
2
+ /** Executor list — renders executor metadata from DB grouped by provider, with gap detection */
3
3
 
4
4
  import { useMemo } from 'react';
5
5
  import type { DiagnosticGaps } from '../diagnostics.js';
@@ -96,7 +96,34 @@ function flattenExecutors(
96
96
  gaps: DiagnosticGaps,
97
97
  ): FlatClaudeRow[] {
98
98
  const deadIds = new Set(gaps.deadPidExecutors.map((e) => e.id));
99
- const rows: FlatClaudeRow[] = executors.flatMap((exec) => executorToRows(exec, assignments, deadIds.has(exec.id)));
99
+
100
+ // Group executors by provider
101
+ const byProvider = new Map<string, TuiExecutor[]>();
102
+ for (const exec of executors) {
103
+ const key = exec.provider;
104
+ if (!byProvider.has(key)) byProvider.set(key, []);
105
+ byProvider.get(key)?.push(exec);
106
+ }
107
+
108
+ const rows: FlatClaudeRow[] = [];
109
+
110
+ for (const [provider, group] of byProvider) {
111
+ // Provider header
112
+ rows.push({
113
+ id: `provider:${provider}`,
114
+ depth: 0,
115
+ label: `\u2500\u2500 ${provider} (${group.length}) \u2500\u2500`,
116
+ color: palette.cyan,
117
+ detail: '',
118
+ detailColor: palette.textMuted,
119
+ isOrphan: false,
120
+ });
121
+ for (const exec of group) {
122
+ for (const row of executorToRows(exec, assignments, deadIds.has(exec.id))) {
123
+ rows.push({ ...row, depth: row.depth + 1 });
124
+ }
125
+ }
126
+ }
100
127
 
101
128
  if (gaps.orphanPanes.length > 0) {
102
129
  rows.push({
@@ -182,7 +209,9 @@ export function getClaudeRowCount(
182
209
  assignments: TuiAssignment[],
183
210
  gaps: DiagnosticGaps,
184
211
  ): number {
185
- let count = 0;
212
+ // Count provider group headers
213
+ const providers = new Set(executors.map((e) => e.provider));
214
+ let count = providers.size;
186
215
  for (const exec of executors) {
187
216
  count += 2; // executor + meta line
188
217
  if (assignments.some((a) => a.executorId === exec.id)) count++; // assignment line
@@ -1,5 +1,5 @@
1
1
  /** @jsxImportSource @opentui/react */
2
- /** Navigation panel with 3 tabs: Projects | tmux | Claude — arrow keys navigate, left/right switch tabs */
2
+ /** Navigation panel with 2 tabs: Sessions | Executors — arrow keys navigate, left/right switch tabs */
3
3
 
4
4
  import { useKeyboard } from '@opentui/react';
5
5
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
@@ -20,7 +20,7 @@ interface NavProps {
20
20
  }
21
21
 
22
22
  export function Nav({ tree, onTreeChange, onProjectSelect, onTmuxSessionSelect }: NavProps) {
23
- const [activeTab, setActiveTab] = useState<TabId>('projects');
23
+ const [activeTab, setActiveTab] = useState<TabId>('tmux');
24
24
  const [tabBarFocused, setTabBarFocused] = useState(false);
25
25
  const [diagnostics, setDiagnostics] = useState<DiagnosticSnapshot | null>(null);
26
26
 
@@ -1,16 +1,16 @@
1
1
  /** @jsxImportSource @opentui/react */
2
- /** Horizontal tab bar: Projects | tmux | Claude — left/right to switch */
2
+ /** Horizontal tab bar: Sessions | Executors — left/right to switch */
3
3
 
4
4
  import { palette } from '../theme.js';
5
5
 
6
6
  export type TabId = 'projects' | 'tmux' | 'claude';
7
7
 
8
- export const TAB_ORDER: TabId[] = ['projects', 'tmux', 'claude'];
8
+ export const TAB_ORDER: TabId[] = ['tmux', 'claude'];
9
9
 
10
10
  const TAB_LABELS: Record<TabId, string> = {
11
11
  projects: 'Projects',
12
- tmux: 'tmux',
13
- claude: 'Claude',
12
+ tmux: 'Sessions',
13
+ claude: 'Executors',
14
14
  };
15
15
 
16
16
  interface TabBarProps {
package/src/tui/tmux.ts CHANGED
@@ -128,7 +128,7 @@ export function attachProjectWindow(rightPane: string, targetSession: string, wi
128
128
  function setupKeybindings(session: string): void {
129
129
  try {
130
130
  // Define bindings in the genie-tui key table (session-scoped, not global)
131
- execSync(`tmux bind-key -T ${KEY_TABLE} Tab select-pane -t :.+ \\; switch-client -T ${KEY_TABLE}`, {
131
+ execSync(`tmux bind-key -T ${KEY_TABLE} Tab select-pane -t ${session}:0.1 \\; switch-client -T ${KEY_TABLE}`, {
132
132
  stdio: 'ignore',
133
133
  });
134
134