@automagik/genie 4.260505.3 → 4.260505.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/genie.js
CHANGED
|
@@ -1109,7 +1109,7 @@ Next steps:`),console.log(" 1. Reload tmux: tmux source ~/.tmux.conf"),console.
|
|
|
1109
1109
|
`:"";return writeFileSync12(filePath,newContent),!0}async function promptUninstallFrom(filePath,marker,label){if(!existsSync25(filePath))return;if(!contentExists(filePath,marker)){console.log(`\u2713 ${label} has no genie shortcuts`);return}if(await prompt(`Remove shortcuts from ${filePath}? [Y/n] `)==="n"){console.log(`\u23ED\uFE0F Skipped ${label}`);return}if(removeMarkedContent(filePath,marker))console.log(`\u2705 Removed from ${filePath}`)}async function uninstallShortcuts(){let home=homedir24(),marker="generated by genie-cli";console.log(`Uninstalling Warp-like shortcuts...
|
|
1110
1110
|
`),await promptUninstallFrom(join30(home,".tmux.conf"),"generated by genie-cli","tmux.conf");for(let shellRc of[join30(home,".zshrc"),join30(home,".bashrc")])await promptUninstallFrom(shellRc,"generated by genie-cli",shellRc);let termuxDir=join30(home,".termux"),isTermux=existsSync25(termuxDir)||process.env.TERMUX_VERSION;if(isTermux){let termuxProps=join30(termuxDir,"termux.properties");if(await promptUninstallFrom(termuxProps,"generated by genie-cli","termux.properties"),!contentExists(termuxProps,"generated by genie-cli"))console.log(" Run: termux-reload-settings")}if(console.log(`
|
|
1111
1111
|
\u2705 Uninstallation complete!`),console.log(`
|
|
1112
|
-
Next steps:`),console.log(" 1. Reload tmux: tmux source ~/.tmux.conf"),console.log(" 2. Restart your shell or run: source ~/.bashrc"),isTermux)console.log(" 3. Reload Termux: termux-reload-settings")}var GENIE_CONTENT_MARKERS;var init_shortcuts=__esm(()=>{GENIE_CONTENT_MARKERS=["genie","Ctrl+","split-window","new-window","stty -ixon","Warp-like","bind-key -n","extra-keys","F1=","bind -x"]});var exports_setup={};__export(exports_setup,{setupCommand:()=>setupCommand});import{homedir as homedir25}from"os";import{join as join31}from"path";function printHeader(){console.log(),console.log(`\x1B[1m\x1B[36m${"=".repeat(64)}\x1B[0m`),console.log("\x1B[1m\x1B[36m Genie Setup Wizard\x1B[0m"),console.log(`\x1B[1m\x1B[36m${"=".repeat(64)}\x1B[0m`),console.log()}function printSection(title,description){if(console.log(),console.log(`\x1B[1m${title}\x1B[0m`),description)console.log(`\x1B[2m${description}\x1B[0m`);console.log()}async function configureSession(config,quick){if(printSection("2. Session Configuration","Configure tmux session settings"),quick)return console.log(` Using defaults: session="${config.session.name}", window="${config.session.defaultWindow}"`),config;let sessionName=await esm_default5({message:"Session name:",default:config.session.name}),defaultWindow=await esm_default5({message:"Default window name:",default:config.session.defaultWindow}),autoCreate=await esm_default4({message:"Auto-create session on connect?",default:config.session.autoCreate});return config.session={name:sessionName,defaultWindow,autoCreate},config}async function configureTerminal(config,quick){if(printSection("3. Terminal Defaults","Configure default values for term commands"),quick)return console.log(` Using defaults: timeout=${config.terminal.execTimeout}ms, lines=${config.terminal.readLines}`),config;let timeoutStr=await esm_default5({message:"Exec timeout (milliseconds):",default:String(config.terminal.execTimeout),validate:(v)=>{let n=Number.parseInt(v,10);return!Number.isNaN(n)&&n>0?!0:"Must be a positive number"}}),linesStr=await esm_default5({message:"Read lines (default for genie agent read):",default:String(config.terminal.readLines),validate:(v)=>{let n=Number.parseInt(v,10);return!Number.isNaN(n)&&n>0?!0:"Must be a positive number"}}),worktreeBase=await esm_default5({message:"Worktree base directory (leave empty for ~/.genie/worktrees/<project>/):",default:config.terminal.worktreeBase??""});return config.terminal={execTimeout:Number.parseInt(timeoutStr,10),readLines:Number.parseInt(linesStr,10),...worktreeBase?{worktreeBase}:{}},config}async function configureShortcuts(config,quick){printSection("4. Keyboard Shortcuts","Warp-like tmux shortcuts for quick navigation");let home=homedir25(),tmuxConf=join31(home,".tmux.conf");if(isShortcutsInstalled(tmuxConf))return console.log(" \x1B[32m\u2713\x1B[0m Tmux shortcuts already installed"),config.shortcuts.tmuxInstalled=!0,config;if(console.log(" Available shortcuts:"),console.log(" \x1B[36mCtrl+T\x1B[0m \u2192 New tab (window)"),console.log(" \x1B[36mCtrl+S\x1B[0m \u2192 Vertical split"),console.log(" \x1B[36mCtrl+H\x1B[0m \u2192 Horizontal split"),console.log(),quick)return console.log(" Skipped in quick mode. Run \x1B[36mgenie setup --shortcuts\x1B[0m to install."),config;if(await esm_default4({message:"Install tmux keyboard shortcuts?",default:!1}))console.log(),await installShortcuts(),config.shortcuts.tmuxInstalled=!0,await updateShortcutsConfig({tmuxInstalled:!0});else console.log(" Skipped. Run \x1B[36mgenie shortcuts install\x1B[0m later.");return config}function printCodexResult(result2){if(result2==="changed")console.log(" \x1B[32m\u2713\x1B[0m Codex config updated");else if(result2==="unchanged")console.log(" \x1B[32m\u2713\x1B[0m Codex config already up to date");else console.log(" \x1B[31m\u2717\x1B[0m Failed to update codex config")}async function configureCodex(config,quick){printSection("5. Codex Integration","Configure OpenAI Codex for genie agents");let codexCheck=await checkCommand("codex");if(!codexCheck.exists)return console.log(" \x1B[33m!\x1B[0m Codex CLI not found. Skipping codex integration."),config;if(console.log(` \x1B[32m\u2713\x1B[0m Codex CLI found (${codexCheck.version??"unknown version"})`),isCodexConfigured())return console.log(" \x1B[32m\u2713\x1B[0m Codex config already configured"),config.codex={configured:!0},config;if(console.log(),console.log(" Genie needs to configure codex for agent communication:"),console.log(" \x1B[36mdisable_paste_burst\x1B[0m \u2192 Reliable tmux command injection"),console.log(" \x1B[36mOTel exporter\x1B[0m \u2192 Telemetry relay for state detection"),console.log(` Config: \x1B[2m${contractPath(getCodexConfigPath())}\x1B[0m`),console.log(),quick){let result2=ensureCodexOtelConfig();return printCodexResult(result2),config.codex={configured:result2!=="error"},config}if(await esm_default4({message:"Configure Codex for genie agent integration?",default:!0})){let result2=ensureCodexOtelConfig();printCodexResult(result2),config.codex={configured:result2!=="error"}}else console.log(" Skipped. Run \x1B[36mgenie setup --codex\x1B[0m later.");return config}async function configureDebug(config,quick){if(printSection("6. Debug Options","Logging and debugging settings"),quick)return console.log(" Using defaults: tmuxDebug=false, verbose=false"),config;let tmuxDebug=await esm_default4({message:"Enable tmux debug logging?",default:config.logging.tmuxDebug}),verbose=await esm_default4({message:"Enable verbose mode?",default:config.logging.verbose});return config.logging={tmuxDebug,verbose},config}async function configurePromptMode(config,quick){if(printSection("7. Prompt Mode","Controls how genie injects system prompts into Claude Code"),quick)return console.log(` Using default: promptMode="${config.promptMode}"`),config;console.log(" append \u2014 Uses --append-system-prompt-file (preserves Claude Code default system prompt)"),console.log(" system \u2014 Uses --system-prompt-file (replaces Claude Code default system prompt)"),console.log();let promptMode=await esm_default11({message:"Prompt mode:",choices:[{name:"append (recommended \u2014 preserves CC default)",value:"append"},{name:"system (replaces CC default)",value:"system"}],default:config.promptMode});return config.promptMode=promptMode,config}async function showSummaryAndSave(config){printSection("Summary",`Configuration will be saved to ${contractPath(getGenieConfigPath())}`),console.log(` Session: \x1B[36m${config.session.name}\x1B[0m (window: ${config.session.defaultWindow})`),console.log(` Terminal: timeout=${config.terminal.execTimeout}ms, lines=${config.terminal.readLines}`),console.log(` Shortcuts: ${config.shortcuts.tmuxInstalled?"\x1B[32minstalled\x1B[0m":"\x1B[2mnot installed\x1B[0m"}`),console.log(` Codex: ${config.codex?.configured?"\x1B[32mconfigured\x1B[0m":"\x1B[2mnot configured\x1B[0m"}`),console.log(` Debug: tmux=${config.logging.tmuxDebug}, verbose=${config.logging.verbose}`),console.log(` Prompt mode: \x1B[36m${config.promptMode}\x1B[0m`),console.log(),config.setupComplete=!0,config.lastSetupAt=new Date().toISOString(),await saveGenieConfig(config),console.log("\x1B[32m\u2713 Configuration saved!\x1B[0m")}async function showCurrentConfig(){let config=await loadGenieConfig();console.log(),console.log("\x1B[1mCurrent Genie Configuration\x1B[0m"),console.log(`\x1B[2m${contractPath(getGenieConfigPath())}\x1B[0m`),console.log(),console.log(JSON.stringify(config,null,2)),console.log()}function printNextSteps(){console.log(),console.log("\x1B[1mNext Steps:\x1B[0m"),console.log(),console.log(" Start a session: \x1B[36mgenie\x1B[0m"),console.log(" Watch AI work: \x1B[36mtmux attach -t genie\x1B[0m"),console.log(" Check health: \x1B[36mgenie doctor\x1B[0m"),console.log()}async function setupCommand(options={}){if(options.show){await showCurrentConfig();return}if(options.reset){await resetConfig(),console.log("\x1B[32m\u2713 Configuration reset to defaults.\x1B[0m"),console.log();return}let config=await loadGenieConfig();if(options.shortcuts){printHeader(),await configureShortcuts(config,!1),await markSetupComplete();return}if(options.terminal){printHeader(),config=await configureTerminal(config,!1),await saveGenieConfig(config),console.log("\x1B[32m\u2713 Terminal configuration saved.\x1B[0m");return}if(options.session){printHeader(),config=await configureSession(config,!1),await saveGenieConfig(config),console.log("\x1B[32m\u2713 Session configuration saved.\x1B[0m");return}if(options.codex){if(printHeader(),config=await configureCodex(config,!1),await saveGenieConfig(config),config.codex?.configured)console.log("\x1B[32m\u2713 Codex configuration saved.\x1B[0m");return}let quick=options.quick??!1;if(printHeader(),quick)console.log("\x1B[2mQuick mode: accepting all defaults\x1B[0m");config=await configureSession(config,quick),config=await configureTerminal(config,quick),config=await configureShortcuts(config,quick),config=await configureCodex(config,quick),config=await configureDebug(config,quick),config=await configurePromptMode(config,quick),await showSummaryAndSave(config),installGenieTmuxConf(),printNextSteps()}function installGenieTmuxConf(){let{existsSync:existsSync26,copyFileSync:copyFileSync3,mkdirSync:mkdirSync15,chmodSync:chmodSync2}=__require("fs"),{resolve:resolve4,dirname:dirname12}=__require("path"),genieHome3=process.env.GENIE_HOME??join31(homedir25(),".genie"),dest=join31(genieHome3,"tmux.conf");if(existsSync26(dest))return;let src=[resolve4(__dirname,"..","..","scripts","tmux","genie.tmux.conf"),resolve4(__dirname,"..","scripts","tmux","genie.tmux.conf")].find((p)=>existsSync26(p));if(!src)return;try{mkdirSync15(genieHome3,{recursive:!0}),copyFileSync3(src,dest),console.log(`\x1B[32m\u2713\x1B[0m Installed genie tmux config to ${dest}`)}catch{}let osc52Src=join31(dirname12(src),"osc52-copy.sh"),osc52Dest=join31(genieHome3,"osc52-copy.sh");if(existsSync26(osc52Src))try{copyFileSync3(osc52Src,osc52Dest),chmodSync2(osc52Dest,493)}catch{}}var __dirname="/home/runner/_work/genie/genie/src/genie-commands";var init_setup=__esm(()=>{init_esm14();init_codex_config();init_genie_config2();init_system_detect();init_shortcuts()});var exports_version={};__export(exports_version,{VERSION:()=>VERSION});import{existsSync as existsSync29,readFileSync as readFileSync20}from"fs";import{dirname as dirname12,resolve as resolve4}from"path";function readPackageJson(path3){try{if(!existsSync29(path3))return null;return JSON.parse(readFileSync20(path3,"utf-8"))}catch{return null}}function readVersionFromPackageJson(){let startDir=dirname12(import.meta.dir??__dirname),current=startDir;for(let depth=0;depth<MAX_WALK_DEPTH;depth++){let candidate=resolve4(current,"package.json"),pkg=readPackageJson(candidate);if(pkg?.name===PACKAGE_NAME&&pkg.version)return pkg.version;let parent=dirname12(current);if(parent===current)break;current=parent}current=startDir;for(let depth=0;depth<MAX_WALK_DEPTH;depth++){let candidate=resolve4(current,"package.json"),pkg=readPackageJson(candidate);if(pkg?.version)return pkg.version;let parent=dirname12(current);if(parent===current)break;current=parent}return FALLBACK_VERSION}var __dirname="/home/runner/_work/genie/genie/src/lib",FALLBACK_VERSION="0.0.0-unknown",PACKAGE_NAME="@automagik/genie",MAX_WALK_DEPTH=10,VERSION;var init_version=__esm(()=>{VERSION=readVersionFromPackageJson()});import{createHash as createHash3}from"crypto";import{existsSync as existsSync30,readFileSync as readFileSync21}from"fs";import{homedir as homedir29}from"os";import{join as join35}from"path";function defaultTrustPath(){let home=process.env.GENIE_HOME??join35(homedir29(),".genie");return join35(home,"hooks","trusted.json")}function sha256OfFile(path3){let hash=createHash3("sha256");return hash.update(readFileSync21(path3)),hash.digest("hex")}function readTrustFile(path3=defaultTrustPath()){if(!existsSync30(path3))return{version:1,entries:[]};let raw=readFileSync21(path3,"utf-8");if(raw.trim().length===0)return{version:1,entries:[]};let parsed=JSON.parse(raw);if(parsed.version!==1)throw Error(`Unsupported trust file version: ${parsed.version} (expected 1)`);if(!Array.isArray(parsed.entries))throw Error("Malformed trust file: entries must be an array");return parsed}function verifyTrust(filePath,trustFile,options={}){if(!existsSync30(filePath))return{trusted:!1,reason:"file_missing"};let entry2=trustFile.entries.find((e)=>e.path===filePath);if(!entry2)return{trusted:!1,reason:"not_in_trust_file"};if(sha256OfFile(filePath)!==entry2.sha256)return{trusted:!1,reason:"sha256_mismatch"};if(entry2.scope==="repo"){if(!entry2.repoRemoteUrl)return{trusted:!1,reason:"missing_repo_remote"};if(options.currentRepoRemoteUrl!==entry2.repoRemoteUrl)return{trusted:!1,reason:"repo_remote_mismatch"}}return{trusted:!0,entry:entry2}}function parseCapabilities(source){let match=source.match(/^\/\/\s*@capabilities:\s*(.+)$/m);if(!match)return[];return match[1].split(",").map((c)=>c.trim()).filter((c)=>c.length>0)}var init_trust=()=>{};import{execSync as execSync5}from"child_process";function getRecentGitHistory(filePath,cwd){try{let trimmed=execSync5(`git log --oneline -n ${MAX_COMMITS} -- ${JSON.stringify(filePath)}`,{encoding:"utf-8",timeout:5000,cwd,stdio:["pipe","pipe","pipe"]}).trim();if(!trimmed)return null;return trimmed}catch{return null}}async function auditContext(payload){let input=payload.tool_input;if(!input)return;let filePath=input.file_path;if(!filePath)return;let cwd=payload.cwd??process.cwd(),history=getRecentGitHistory(filePath,cwd);if(!history)return;return{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:`[audit-context] Recent git history for ${filePath}:
|
|
1112
|
+
Next steps:`),console.log(" 1. Reload tmux: tmux source ~/.tmux.conf"),console.log(" 2. Restart your shell or run: source ~/.bashrc"),isTermux)console.log(" 3. Reload Termux: termux-reload-settings")}var GENIE_CONTENT_MARKERS;var init_shortcuts=__esm(()=>{GENIE_CONTENT_MARKERS=["genie","Ctrl+","split-window","new-window","stty -ixon","Warp-like","bind-key -n","extra-keys","F1=","bind -x"]});var exports_setup={};__export(exports_setup,{setupCommand:()=>setupCommand});import{homedir as homedir25}from"os";import{join as join31}from"path";function printHeader(){console.log(),console.log(`\x1B[1m\x1B[36m${"=".repeat(64)}\x1B[0m`),console.log("\x1B[1m\x1B[36m Genie Setup Wizard\x1B[0m"),console.log(`\x1B[1m\x1B[36m${"=".repeat(64)}\x1B[0m`),console.log()}function printSection(title,description){if(console.log(),console.log(`\x1B[1m${title}\x1B[0m`),description)console.log(`\x1B[2m${description}\x1B[0m`);console.log()}async function configureSession(config,quick){if(printSection("2. Session Configuration","Configure tmux session settings"),quick)return console.log(` Using defaults: session="${config.session.name}", window="${config.session.defaultWindow}"`),config;let sessionName=await esm_default5({message:"Session name:",default:config.session.name}),defaultWindow=await esm_default5({message:"Default window name:",default:config.session.defaultWindow}),autoCreate=await esm_default4({message:"Auto-create session on connect?",default:config.session.autoCreate});return config.session={name:sessionName,defaultWindow,autoCreate},config}async function configureTerminal(config,quick){if(printSection("3. Terminal Defaults","Configure default values for term commands"),quick)return console.log(` Using defaults: timeout=${config.terminal.execTimeout}ms, lines=${config.terminal.readLines}`),config;let timeoutStr=await esm_default5({message:"Exec timeout (milliseconds):",default:String(config.terminal.execTimeout),validate:(v)=>{let n=Number.parseInt(v,10);return!Number.isNaN(n)&&n>0?!0:"Must be a positive number"}}),linesStr=await esm_default5({message:"Read lines (default for genie agent read):",default:String(config.terminal.readLines),validate:(v)=>{let n=Number.parseInt(v,10);return!Number.isNaN(n)&&n>0?!0:"Must be a positive number"}}),worktreeBase=await esm_default5({message:"Worktree base directory (leave empty for ~/.genie/worktrees/<project>/):",default:config.terminal.worktreeBase??""});return config.terminal={execTimeout:Number.parseInt(timeoutStr,10),readLines:Number.parseInt(linesStr,10),...worktreeBase?{worktreeBase}:{}},config}async function configureShortcuts(config,quick){printSection("4. Keyboard Shortcuts","Warp-like tmux shortcuts for quick navigation");let home=homedir25(),tmuxConf=join31(home,".tmux.conf");if(isShortcutsInstalled(tmuxConf))return console.log(" \x1B[32m\u2713\x1B[0m Tmux shortcuts already installed"),config.shortcuts.tmuxInstalled=!0,config;if(console.log(" Available shortcuts:"),console.log(" \x1B[36mCtrl+T\x1B[0m \u2192 New tab (window)"),console.log(" \x1B[36mCtrl+S\x1B[0m \u2192 Vertical split"),console.log(" \x1B[36mCtrl+H\x1B[0m \u2192 Horizontal split"),console.log(),quick)return console.log(" Skipped in quick mode. Run \x1B[36mgenie setup --shortcuts\x1B[0m to install."),config;if(await esm_default4({message:"Install tmux keyboard shortcuts?",default:!1}))console.log(),await installShortcuts(),config.shortcuts.tmuxInstalled=!0,await updateShortcutsConfig({tmuxInstalled:!0});else console.log(" Skipped. Run \x1B[36mgenie shortcuts install\x1B[0m later.");return config}function printCodexResult(result2){if(result2==="changed")console.log(" \x1B[32m\u2713\x1B[0m Codex config updated");else if(result2==="unchanged")console.log(" \x1B[32m\u2713\x1B[0m Codex config already up to date");else console.log(" \x1B[31m\u2717\x1B[0m Failed to update codex config")}async function configureCodex(config,quick){printSection("5. Codex Integration","Configure OpenAI Codex for genie agents");let codexCheck=await checkCommand("codex");if(!codexCheck.exists)return console.log(" \x1B[33m!\x1B[0m Codex CLI not found. Skipping codex integration."),config;if(console.log(` \x1B[32m\u2713\x1B[0m Codex CLI found (${codexCheck.version??"unknown version"})`),isCodexConfigured())return console.log(" \x1B[32m\u2713\x1B[0m Codex config already configured"),config.codex={configured:!0},config;if(console.log(),console.log(" Genie needs to configure codex for agent communication:"),console.log(" \x1B[36mdisable_paste_burst\x1B[0m \u2192 Reliable tmux command injection"),console.log(" \x1B[36mOTel exporter\x1B[0m \u2192 Telemetry relay for state detection"),console.log(` Config: \x1B[2m${contractPath(getCodexConfigPath())}\x1B[0m`),console.log(),quick){let result2=ensureCodexOtelConfig();return printCodexResult(result2),config.codex={configured:result2!=="error"},config}if(await esm_default4({message:"Configure Codex for genie agent integration?",default:!0})){let result2=ensureCodexOtelConfig();printCodexResult(result2),config.codex={configured:result2!=="error"}}else console.log(" Skipped. Run \x1B[36mgenie setup --codex\x1B[0m later.");return config}async function configureDebug(config,quick){if(printSection("6. Debug Options","Logging and debugging settings"),quick)return console.log(" Using defaults: tmuxDebug=false, verbose=false"),config;let tmuxDebug=await esm_default4({message:"Enable tmux debug logging?",default:config.logging.tmuxDebug}),verbose=await esm_default4({message:"Enable verbose mode?",default:config.logging.verbose});return config.logging={tmuxDebug,verbose},config}async function configurePromptMode(config,quick){if(printSection("7. Prompt Mode","Controls how genie injects system prompts into Claude Code"),quick)return console.log(` Using default: promptMode="${config.promptMode}"`),config;console.log(" append \u2014 Uses --append-system-prompt-file (preserves Claude Code default system prompt)"),console.log(" system \u2014 Uses --system-prompt-file (replaces Claude Code default system prompt)"),console.log();let promptMode=await esm_default11({message:"Prompt mode:",choices:[{name:"append (recommended \u2014 preserves CC default)",value:"append"},{name:"system (replaces CC default)",value:"system"}],default:config.promptMode});return config.promptMode=promptMode,config}async function showSummaryAndSave(config){printSection("Summary",`Configuration will be saved to ${contractPath(getGenieConfigPath())}`),console.log(` Session: \x1B[36m${config.session.name}\x1B[0m (window: ${config.session.defaultWindow})`),console.log(` Terminal: timeout=${config.terminal.execTimeout}ms, lines=${config.terminal.readLines}`),console.log(` Shortcuts: ${config.shortcuts.tmuxInstalled?"\x1B[32minstalled\x1B[0m":"\x1B[2mnot installed\x1B[0m"}`),console.log(` Codex: ${config.codex?.configured?"\x1B[32mconfigured\x1B[0m":"\x1B[2mnot configured\x1B[0m"}`),console.log(` Debug: tmux=${config.logging.tmuxDebug}, verbose=${config.logging.verbose}`),console.log(` Prompt mode: \x1B[36m${config.promptMode}\x1B[0m`),console.log(),config.setupComplete=!0,config.lastSetupAt=new Date().toISOString(),await saveGenieConfig(config),console.log("\x1B[32m\u2713 Configuration saved!\x1B[0m")}async function showCurrentConfig(){let config=await loadGenieConfig();console.log(),console.log("\x1B[1mCurrent Genie Configuration\x1B[0m"),console.log(`\x1B[2m${contractPath(getGenieConfigPath())}\x1B[0m`),console.log(),console.log(JSON.stringify(config,null,2)),console.log()}function printNextSteps(){console.log(),console.log("\x1B[1mNext Steps:\x1B[0m"),console.log(),console.log(" Start a session: \x1B[36mgenie\x1B[0m"),console.log(" Watch AI work: \x1B[36mtmux attach -t genie\x1B[0m"),console.log(" Check health: \x1B[36mgenie doctor\x1B[0m"),console.log()}async function setupCommand(options={}){if(options.show){await showCurrentConfig();return}if(options.reset){await resetConfig(),console.log("\x1B[32m\u2713 Configuration reset to defaults.\x1B[0m"),console.log();return}let config=await loadGenieConfig();if(options.shortcuts){printHeader(),await configureShortcuts(config,!1),await markSetupComplete();return}if(options.terminal){printHeader(),config=await configureTerminal(config,!1),await saveGenieConfig(config),console.log("\x1B[32m\u2713 Terminal configuration saved.\x1B[0m");return}if(options.session){printHeader(),config=await configureSession(config,!1),await saveGenieConfig(config),console.log("\x1B[32m\u2713 Session configuration saved.\x1B[0m");return}if(options.codex){if(printHeader(),config=await configureCodex(config,!1),await saveGenieConfig(config),config.codex?.configured)console.log("\x1B[32m\u2713 Codex configuration saved.\x1B[0m");return}let quick=options.quick??!1;if(printHeader(),quick)console.log("\x1B[2mQuick mode: accepting all defaults\x1B[0m");config=await configureSession(config,quick),config=await configureTerminal(config,quick),config=await configureShortcuts(config,quick),config=await configureCodex(config,quick),config=await configureDebug(config,quick),config=await configurePromptMode(config,quick),await showSummaryAndSave(config),installGenieTmuxConf(),printNextSteps()}function installGenieTmuxConf(){let{existsSync:existsSync26,copyFileSync:copyFileSync3,mkdirSync:mkdirSync15,chmodSync:chmodSync2}=__require("fs"),{resolve:resolve4,dirname:dirname12}=__require("path"),genieHome3=process.env.GENIE_HOME??join31(homedir25(),".genie"),dest=join31(genieHome3,"tmux.conf");if(existsSync26(dest))return;let src=[resolve4(__dirname,"..","..","scripts","tmux","genie.tmux.conf"),resolve4(__dirname,"..","scripts","tmux","genie.tmux.conf")].find((p)=>existsSync26(p));if(!src)return;try{mkdirSync15(genieHome3,{recursive:!0}),copyFileSync3(src,dest),console.log(`\x1B[32m\u2713\x1B[0m Installed genie tmux config to ${dest}`)}catch{}let osc52Src=join31(dirname12(src),"osc52-copy.sh"),osc52Dest=join31(genieHome3,"osc52-copy.sh");if(existsSync26(osc52Src))try{copyFileSync3(osc52Src,osc52Dest),chmodSync2(osc52Dest,493)}catch{}}var __dirname="/home/runner/_work/genie/genie/src/genie-commands";var init_setup=__esm(()=>{init_esm14();init_codex_config();init_genie_config2();init_system_detect();init_shortcuts()});var exports_version={};__export(exports_version,{VERSION:()=>VERSION});import{existsSync as existsSync28,readFileSync as readFileSync19}from"fs";import{dirname as dirname12,resolve as resolve4}from"path";function readPackageJson(path3){try{if(!existsSync28(path3))return null;return JSON.parse(readFileSync19(path3,"utf-8"))}catch{return null}}function readVersionFromPackageJson(){let startDir=dirname12(import.meta.dir??__dirname),current=startDir;for(let depth=0;depth<MAX_WALK_DEPTH;depth++){let candidate=resolve4(current,"package.json"),pkg=readPackageJson(candidate);if(pkg?.name===PACKAGE_NAME&&pkg.version)return pkg.version;let parent=dirname12(current);if(parent===current)break;current=parent}current=startDir;for(let depth=0;depth<MAX_WALK_DEPTH;depth++){let candidate=resolve4(current,"package.json"),pkg=readPackageJson(candidate);if(pkg?.version)return pkg.version;let parent=dirname12(current);if(parent===current)break;current=parent}return FALLBACK_VERSION}var __dirname="/home/runner/_work/genie/genie/src/lib",FALLBACK_VERSION="0.0.0-unknown",PACKAGE_NAME="@automagik/genie",MAX_WALK_DEPTH=10,VERSION;var init_version=__esm(()=>{VERSION=readVersionFromPackageJson()});import{createHash as createHash3}from"crypto";import{existsSync as existsSync30,readFileSync as readFileSync21}from"fs";import{homedir as homedir29}from"os";import{join as join35}from"path";function defaultTrustPath(){let home=process.env.GENIE_HOME??join35(homedir29(),".genie");return join35(home,"hooks","trusted.json")}function sha256OfFile(path3){let hash=createHash3("sha256");return hash.update(readFileSync21(path3)),hash.digest("hex")}function readTrustFile(path3=defaultTrustPath()){if(!existsSync30(path3))return{version:1,entries:[]};let raw=readFileSync21(path3,"utf-8");if(raw.trim().length===0)return{version:1,entries:[]};let parsed=JSON.parse(raw);if(parsed.version!==1)throw Error(`Unsupported trust file version: ${parsed.version} (expected 1)`);if(!Array.isArray(parsed.entries))throw Error("Malformed trust file: entries must be an array");return parsed}function verifyTrust(filePath,trustFile,options={}){if(!existsSync30(filePath))return{trusted:!1,reason:"file_missing"};let entry2=trustFile.entries.find((e)=>e.path===filePath);if(!entry2)return{trusted:!1,reason:"not_in_trust_file"};if(sha256OfFile(filePath)!==entry2.sha256)return{trusted:!1,reason:"sha256_mismatch"};if(entry2.scope==="repo"){if(!entry2.repoRemoteUrl)return{trusted:!1,reason:"missing_repo_remote"};if(options.currentRepoRemoteUrl!==entry2.repoRemoteUrl)return{trusted:!1,reason:"repo_remote_mismatch"}}return{trusted:!0,entry:entry2}}function parseCapabilities(source){let match=source.match(/^\/\/\s*@capabilities:\s*(.+)$/m);if(!match)return[];return match[1].split(",").map((c)=>c.trim()).filter((c)=>c.length>0)}var init_trust=()=>{};import{execSync as execSync5}from"child_process";function getRecentGitHistory(filePath,cwd){try{let trimmed=execSync5(`git log --oneline -n ${MAX_COMMITS} -- ${JSON.stringify(filePath)}`,{encoding:"utf-8",timeout:5000,cwd,stdio:["pipe","pipe","pipe"]}).trim();if(!trimmed)return null;return trimmed}catch{return null}}async function auditContext(payload){let input=payload.tool_input;if(!input)return;let filePath=input.file_path;if(!filePath)return;let cwd=payload.cwd??process.cwd(),history=getRecentGitHistory(filePath,cwd);if(!history)return;return{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:`[audit-context] Recent git history for ${filePath}:
|
|
1113
1113
|
${history}`}}}var MAX_COMMITS=5;var init_audit_context=()=>{};var exports_agent_directory={};__export(exports_agent_directory,{rm:()=>rm2,resolve:()=>resolve6,ls:()=>ls,loadIdentity:()=>loadIdentity,getProjectRoot:()=>getProjectRoot,get:()=>get2,findSessionByRepo:()=>findSessionByRepo,edit:()=>edit,add:()=>add});import{existsSync as existsSync32,lstatSync as lstatSync2}from"fs";import{join as join38}from"path";function validateAgentsMd(dir,allowSymlink){let agentsPath=join38(dir,"AGENTS.md");if(!existsSync32(agentsPath))throw Error(`AGENTS.md not found in ${dir}. Each agent directory must contain an AGENTS.md file.`);if(allowSymlink)return;let stat4=lstatSync2(agentsPath);if(!stat4)throw Error(`AGENTS.md in ${dir} disappeared between exists check and stat.`);if(stat4.isSymbolicLink())throw Error(`AGENTS.md in ${dir} is a symlink. Refusing to register: a symlinked AGENTS.md usually means --dir was pointed at a containing folder rather than the agent's real home (the cwd will be wrong and the agent's brain/runbooks won't be visible). Pass --allow-symlink to override if this is intentional.`);if(!stat4.isFile())throw Error(`AGENTS.md in ${dir} is not a regular file (got ${describeFileType(stat4)}).`)}function describeFileType(stat4){if(stat4.isDirectory())return"directory";if(stat4.isBlockDevice())return"block device";if(stat4.isCharacterDevice())return"character device";if(stat4.isFIFO())return"FIFO";if(stat4.isSocket())return"socket";return"unknown special file"}function getProjectRoot(){if(process.env.GENIE_PROJECT_ROOT)return process.env.GENIE_PROJECT_ROOT;try{let{execSync:execSync6}=__require("child_process");return execSync6("git rev-parse --show-toplevel",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return process.cwd()}}async function add(entry2,options){if(!entry2.name||entry2.name.trim()==="")throw Error("Agent name is required.");if(!entry2.dir||entry2.dir.trim()==="")throw Error("Agent directory (--dir) is required.");if(!existsSync32(entry2.dir))throw Error(`Directory does not exist: ${entry2.dir}`);validateAgentsMd(entry2.dir,options?.allowSymlink??!1);let full={...entry2,promptMode:entry2.promptMode??"append",registeredAt:new Date().toISOString()},existing=await resolve6(entry2.name);if(existing&&!existing.builtin)throw Error(`Agent "${entry2.name}" already exists. Use "genie dir edit" to update or "genie dir rm" first.`);let metadata=buildMetadata(full),team=entry2.team??entry2.bridgeTmuxSession??null,{getConnection:getConnection2}=await Promise.resolve().then(() => (init_db(),exports_db)),sql=await getConnection2();return await sql`
|
|
1114
1114
|
INSERT INTO agents (id, role, custom_name, team, repo_path, started_at, state, metadata)
|
|
1115
1115
|
VALUES (
|
|
@@ -3983,8 +3983,8 @@ module.exports = {
|
|
|
3983
3983
|
`);return}process.stdout.write(`id status appliedAt from
|
|
3984
3984
|
`),process.stdout.write(`------------------------------- ---------- ------------------------ ------------
|
|
3985
3985
|
`);for(let r of rows){let id=r.id.padEnd(31),st=r.status.padEnd(10),at=(r.appliedAt||"-").padEnd(24),from=r.appliedFrom||"-";process.stdout.write(`${id} ${st} ${at} ${from}
|
|
3986
|
-
`)}return}let result2=await migrate({quiet:options.quiet,dryRun:options.dryRun});process.exit(result2.ok?0:1)}init_setup();init_shortcuts();import{existsSync as existsSync26}from"fs";import{homedir as homedir26}from"os";import{join as join32}from"path";async function shortcutsShowCommand(){displayShortcuts();let home=homedir26(),tmuxConf=join32(home,".tmux.conf"),zshrc=join32(home,".zshrc"),bashrc=join32(home,".bashrc");if(console.log("Installation status:"),isShortcutsInstalled(tmuxConf))console.log(" \x1B[32m\u2713\x1B[0m tmux.conf");else console.log(" \x1B[33m-\x1B[0m tmux.conf");let shellRc=existsSync26(zshrc)?zshrc:bashrc;if(isShortcutsInstalled(shellRc))console.log(` \x1B[32m\u2713\x1B[0m ${shellRc.replace(home,"~")}`);else console.log(` \x1B[33m-\x1B[0m ${shellRc.replace(home,"~")}`);console.log(),console.log("Run \x1B[36mgenie shortcuts install\x1B[0m to install shortcuts."),console.log("Run \x1B[36mgenie shortcuts uninstall\x1B[0m to remove shortcuts."),console.log()}async function shortcutsInstallCommand(){await installShortcuts()}async function shortcutsUninstallCommand(){await uninstallShortcuts()}init_esm14();init_claude_settings();init_genie_config2();import{existsSync as existsSync27,lstatSync,rmSync as rmSync2,unlinkSync as unlinkSync8}from"fs";import{homedir as homedir27}from"os";import{join as join33}from"path";var ORCHESTRATION_RULES_PATH=join33(homedir27(),".claude","rules","genie-orchestration.md"),LOCAL_BIN=join33(homedir27(),".local","bin"),SYMLINKS=["genie","term"];function isGenieSymlink(path3){try{if(!existsSync27(path3))return!1;if(!lstatSync(path3).isSymbolicLink())return!1;return!0}catch{return!1}}function removeSymlinks(){let removed=[];for(let name of SYMLINKS){let symlinkPath=join33(LOCAL_BIN,name);if(isGenieSymlink(symlinkPath))try{unlinkSync8(symlinkPath),removed.push(name)}catch{}}return removed}function tryRemoveStep(label,successMsg,fn){console.log(`\x1B[2m${label}\x1B[0m`);try{fn(),console.log(` \x1B[32m+\x1B[0m ${successMsg}`)}catch(error){let message=error instanceof Error?error.message:String(error);console.log(` \x1B[33m!\x1B[0m ${label.replace("...","")} failed: ${message}`)}}function performUninstall(hasHookScript,existingSymlinks,genieDir,hasGenieDir){if(hasHookScript)tryRemoveStep("Removing hook script...","Hook script removed",()=>removeHookScript());if(existingSymlinks.length>0){console.log("\x1B[2mRemoving symlinks...\x1B[0m");let removed=removeSymlinks();if(removed.length>0)console.log(` \x1B[32m+\x1B[0m Removed: ${removed.join(", ")}`)}if(existsSync27(ORCHESTRATION_RULES_PATH))tryRemoveStep("Removing orchestration rules...","Orchestration rules removed (~/.claude/rules/genie-orchestration.md)",()=>unlinkSync8(ORCHESTRATION_RULES_PATH));if(hasGenieDir)tryRemoveStep("Removing genie directory...","Directory removed",()=>rmSync2(genieDir,{recursive:!0,force:!0}))}async function uninstallCommand(){console.log(),console.log("\x1B[1m\x1B[33m Uninstall Genie CLI\x1B[0m"),console.log();let genieDir=getGenieDir(),hasGenieDir=existsSync27(genieDir),hasHookScript=hookScriptExists(),hasOrchestrationRules=existsSync27(ORCHESTRATION_RULES_PATH),existingSymlinks=SYMLINKS.filter((name)=>isGenieSymlink(join33(LOCAL_BIN,name)));if(console.log("\x1B[2mThis will remove:\x1B[0m"),hasHookScript)console.log(" \x1B[31m-\x1B[0m Hook script (~/.claude/hooks/genie-bash-hook.sh)");if(hasOrchestrationRules)console.log(" \x1B[31m-\x1B[0m Orchestration rules (~/.claude/rules/genie-orchestration.md)");if(hasGenieDir)console.log(` \x1B[31m-\x1B[0m Genie directory (${contractPath(genieDir)})`);if(existingSymlinks.length>0)console.log(` \x1B[31m-\x1B[0m Symlinks from ~/.local/bin: ${existingSymlinks.join(", ")}`);if(console.log(),!hasGenieDir&&!hasHookScript&&!hasOrchestrationRules&&existingSymlinks.length===0){console.log("\x1B[33mNothing to uninstall.\x1B[0m"),console.log();return}if(!await esm_default4({message:"Are you sure you want to uninstall Genie CLI?",default:!1})){console.log(),console.log("\x1B[2mUninstall cancelled.\x1B[0m"),console.log();return}console.log(),performUninstall(hasHookScript,existingSymlinks,genieDir,hasGenieDir),console.log(),console.log("\x1B[32m+\x1B[0m Genie CLI uninstalled."),console.log(),console.log("\x1B[2mNote: If you installed via npm/bun, also run:\x1B[0m"),console.log(" \x1B[36mbun remove -g @automagik/genie\x1B[0m"),console.log(" \x1B[2mor\x1B[0m"),console.log(" \x1B[36mnpm uninstall -g @automagik/genie\x1B[0m"),console.log()}init_genie_config2();import{execSync as execSync3,spawn as spawn3}from"child_process";import{chmodSync as chmodSync2,closeSync as closeSync3,copyFileSync as copyFileSync3,existsSync as existsSync28,mkdirSync as mkdirSync15,openSync as openSync3,readFileSync as readFileSync19,readSync as readSync2,readdirSync as readdirSync9,rmSync as rmSync3,statSync as statSync7,writeFileSync as writeFileSync13}from"fs";import{chmod,copyFile,mkdir as mkdir5,unlink as unlink2}from"fs/promises";import{homedir as homedir28}from"os";import{join as join34}from"path";var GENIE_HOME2=process.env.GENIE_HOME||join34(homedir28(),".genie"),GENIE_SRC=join34(GENIE_HOME2,"src"),GENIE_BIN=join34(GENIE_HOME2,"bin"),LOCAL_BIN2=join34(homedir28(),".local","bin"),TRUTHY=new Set(["1","true","yes","on"]),UPDATE_DIAGNOSTIC_SCHEMA_VERSION=1;function log(message){console.log(`\x1B[32m\u25B8\x1B[0m ${message}`)}function success(message){console.log(`\x1B[32m\u2714\x1B[0m ${message}`)}function error(message){console.log(`\x1B[31m\u2716\x1B[0m ${message}`)}function formatDuration2(ms){if(ms<1000)return`${ms}ms`;return`${(ms/1000).toFixed(1)}s`}function isTruthyEnv(value){return value!==void 0&&TRUTHY.has(value.trim().toLowerCase())}async function withTemporaryEnv(key,value,fn){let previous=process.env[key];process.env[key]=value;try{return await fn()}finally{if(previous===void 0)delete process.env[key];else process.env[key]=previous}}function safeExec(command,timeoutMs=1500){try{return execSync3(command,{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:timeoutMs}).trim()}catch(err){let stdout=err.stdout;if(typeof stdout==="string"&&stdout.trim())return stdout.trim();return""}}function safeRead(path3,maxChars=4000){try{let value=readFileSync19(path3,"utf-8");if(value.length<=maxChars)return value;return value.slice(value.length-maxChars)}catch{return null}}function tailLines(path3,maxBytes=64000,maxLines=200){let fd=null;try{let stat4=statSync7(path3),bytesToRead=Math.min(stat4.size,maxBytes),buffer2=Buffer.alloc(bytesToRead);return fd=openSync3(path3,"r"),readSync2(fd,buffer2,0,bytesToRead,Math.max(0,stat4.size-bytesToRead)),buffer2.toString("utf-8").split(/\r?\n/).map((line)=>line.trim()).filter(Boolean).slice(-maxLines)}catch{return[]}finally{if(fd!==null)try{closeSync3(fd)}catch{}}}function summarizeJsonlSignals(path3){let signals2=new Map;for(let line of tailLines(path3))try{let event=JSON.parse(line),level=typeof event.level==="string"?event.level:"unknown";if(level!=="error"&&level!=="warn")continue;let name=typeof event.event==="string"?event.event:"unknown",key=`${level}:${name}`,existing=signals2.get(key)??{level,event:name,count:0};if(existing.count++,typeof event.timestamp==="string")existing.lastTimestamp=event.timestamp;if(typeof event.error==="string")existing.lastError=event.error;signals2.set(key,existing)}catch{}return[...signals2.values()].sort((a,b2)=>b2.count-a.count).slice(0,10)}async function collectUpdateDiagnostics(ctx,maintenance){let logsDir=join34(GENIE_HOME2,"logs");mkdirSync15(logsDir,{recursive:!0});let generatedAt=new Date().toISOString(),safeStamp=generatedAt.replace(/[:.]/g,"-"),path3=join34(logsDir,`update-diagnostics-${safeStamp}.json`),schedulerLog=join34(logsDir,"scheduler.log"),tuiCrashLog=join34(logsDir,"tui-crash.log"),signals2=summarizeJsonlSignals(schedulerLog),diagnostics={schemaVersion:UPDATE_DIAGNOSTIC_SCHEMA_VERSION,generatedAt,update:ctx,runtime:{platform:process.platform,arch:process.arch,cwd:process.cwd(),node:process.version,bun:(await runCommandSilent("bun",["--version"])).output.trim()||null,npm:(await runCommandSilent("npm",["--version"])).output.trim()||null,genie:{which:(await runCommandSilent("which",["genie"])).output.trim()||null,tuiDisabled:isTruthyEnv(process.env.GENIE_TUI_DISABLE),updateSkipMaintenance:isTruthyEnv(process.env.GENIE_UPDATE_SKIP_MAINTENANCE)}},paths:{genieHome:GENIE_HOME2,logsDir,servePid:safeRead(join34(GENIE_HOME2,"serve.pid"),200),pgservePort:safeRead(join34(GENIE_HOME2,"pgserve.port"),200),schedulerLog,tuiCrashLog},processSnapshot:{genie:safeExec("ps -axo pid,ppid,pgid,stat,pcpu,pmem,etime,command -r | rg -i 'dist/genie.js|/src/genie.ts|pgserve|postgres -D .*\\.genie/data/pgserve|tmux -L genie-tui|bun' || true",2000)||null,tuiTmux:safeExec("tmux -L genie-tui ls 2>/dev/null || true",1000)||null},maintenance:{...maintenance,pgAutostartDisabled:!0,legend:{"[ok]":"healthy","[fix]":"fixed during maintenance","[--]":"skipped/non-blocking","[!!]":"operator action needed; update still completed"}},recentLogSignals:{scheduler:signals2,schedulerTail:tailLines(schedulerLog,32000,80),tuiCrashTail:tailLines(tuiCrashLog,32000,80)}};return writeFileSync13(path3,`${JSON.stringify(diagnostics,null,2)}
|
|
3987
|
-
`),{path:path3,signals:signals2}}async function runCommand(command,args,cwd){return new Promise((resolve4)=>{let output=[],child=spawn3(command,args,{cwd,stdio:["inherit","pipe","pipe"],env:{...process.env,FORCE_COLOR:"1"}});child.stdout?.on("data",(data)=>{let str2=data.toString();output.push(str2),process.stdout.write(str2)}),child.stderr?.on("data",(data)=>{let str2=data.toString();output.push(str2),process.stderr.write(str2)}),child.on("close",(code)=>{resolve4({success:code===0,output:output.join("")})}),child.on("error",(err)=>{error(err.message),resolve4({success:!1,output:err.message})})})}async function getGitInfo(cwd){try{let branchResult=await runCommandSilent("git",["rev-parse","--abbrev-ref","HEAD"],cwd),commitResult=await runCommandSilent("git",["rev-parse","--short","HEAD"],cwd),dateResult=await runCommandSilent("git",["log","-1","--format=%ci"],cwd);if(branchResult.success&&commitResult.success&&dateResult.success)return{branch:branchResult.output.trim(),commit:commitResult.output.trim(),commitDate:dateResult.output.trim().split(" ")[0]}}catch{}return null}async function runCommandSilent(command,args,cwd,timeoutMs=4000){return new Promise((resolve4)=>{let output=[],settled=!1,child=spawn3(command,args,{cwd,stdio:["inherit","pipe","pipe"]}),timer2=setTimeout(()=>{if(settled)return;settled=!0,child.kill("SIGTERM"),resolve4({success:!1,output:`Timed out after ${timeoutMs}ms`})},timeoutMs);child.stdout?.on("data",(data)=>{output.push(data.toString())}),child.stderr?.on("data",(data)=>{output.push(data.toString())}),child.on("close",(code)=>{if(settled)return;settled=!0,clearTimeout(timer2),resolve4({success:code===0,output:output.join("")})}),child.on("error",(err)=>{if(settled)return;settled=!0,clearTimeout(timer2),resolve4({success:!1,output:err.message})})})}function detectFromBinaryPath(path3){let resolved=path3;try{resolved=__require("fs").realpathSync(path3)}catch{}if(resolved.includes(".bun"))return"bun";if(resolved.includes("node_modules"))return"npm";if(path3===join34(LOCAL_BIN2,"genie")||resolved.startsWith(GENIE_BIN))return"source";return null}async function detectInstallationType(){let whichResult=await runCommandSilent("which",["genie"]);if(whichResult.success){let detected=detectFromBinaryPath(whichResult.output.trim());if(detected)return detected}if(genieConfigExists())try{let config=await loadGenieConfig();if(config.installMethod)return config.installMethod}catch{}if(existsSync28(join34(GENIE_SRC,".git")))return"source";return(await runCommandSilent("which",["bun"])).success?"bun":"npm"}async function updateViaBun(channel){try{__require("fs").unlinkSync(join34(homedir28(),".bun","install","global","bun.lock"))}catch{}if(log(`Updating via bun (channel: ${channel})...`),!(await runCommand("bun",["add","-g",`@automagik/genie@${channel}`])).success)return error("Failed to update via bun"),!1;return console.log(),success(`Genie CLI updated via bun (${channel})!`),!0}async function updateViaNpm(channel){if(log(`Updating via npm (channel: ${channel})...`),!(await runCommand("npm",["install","-g",`@automagik/genie@${channel}`])).success)return error("Failed to update via npm"),!1;return console.log(),success(`Genie CLI updated via npm (${channel})!`),!0}async function detectGlobalInstalls(){let found=new Set,[npmResult,bunResult]=await Promise.all([runCommandSilent("npm",["list","-g","@automagik/genie"]),runCommandSilent("bun",["pm","ls","-g"])]);if(npmResult.success&&!npmResult.output.includes("(empty)"))found.add("npm");if(bunResult.success&&bunResult.output.includes("@automagik/genie"))found.add("bun");return found}async function updateSource(){if(!existsSync28(GENIE_SRC))error(`Source install path not found: ${GENIE_SRC}`),console.error(" Detection picked the source-install path, but the directory does not exist."),console.error(" This usually means a stale install hint (config or ~/.genie/src/.git) is"),console.error(" pointing somewhere genuine. Either:"),console.error(` 1. Re-clone the source: git clone https://github.com/automagik-dev/genie ${GENIE_SRC}`),console.error(" 2. Update via package manager instead: genie update --next --via bun"),console.error(" 3. Inspect detection: genie doctor --update-detection"),process.exit(1);if(!existsSync28(join34(GENIE_SRC,".git")))error(`Source install path is not a git checkout: ${GENIE_SRC}`),console.error(` ${GENIE_SRC} exists but has no .git/. Cannot run \`git fetch\` from it.`),console.error(` Either delete ${GENIE_SRC} and re-clone, or update via package manager:`),console.error(" genie update --next --via bun"),process.exit(1);let beforeInfo=await getGitInfo(GENIE_SRC);if(beforeInfo)console.log(`Current: \x1B[2m${beforeInfo.branch}@${beforeInfo.commit} (${beforeInfo.commitDate})\x1B[0m`),console.log();if(log("Fetching latest changes..."),!(await runCommand("git",["fetch","origin"],GENIE_SRC)).success)error("Failed to fetch from origin"),process.exit(1);if(log("Resetting to origin/main..."),!(await runCommand("git",["reset","--hard","origin/main"],GENIE_SRC)).success)error("Failed to reset to origin/main"),process.exit(1);console.log();let afterInfo=await getGitInfo(GENIE_SRC);if(beforeInfo&&afterInfo&&beforeInfo.commit===afterInfo.commit){success("Already up to date!"),console.log();return}if(log("Installing dependencies..."),!(await runCommand("bun",["install"],GENIE_SRC)).success)error("Failed to install dependencies"),process.exit(1);if(console.log(),log("Building..."),!(await runCommand("bun",["run","build"],GENIE_SRC)).success)error("Failed to build"),process.exit(1);console.log(),log("Installing binaries...");try{await mkdir5(GENIE_BIN,{recursive:!0}),await mkdir5(LOCAL_BIN2,{recursive:!0});let binaries=["genie.js","term.js"],names=["genie","term"];for(let i2=0;i2<binaries.length;i2++){let src=join34(GENIE_SRC,"dist",binaries[i2]),binDest=join34(GENIE_BIN,binaries[i2]),linkDest=join34(LOCAL_BIN2,names[i2]);await copyFile(src,binDest),await chmod(binDest,493),await symlinkOrCopy(binDest,linkDest)}for(let legacy of["claudio.js","claudio"]){let legacyBin=join34(GENIE_BIN,legacy),legacyLink=join34(LOCAL_BIN2,legacy);try{await unlink2(legacyBin)}catch{}try{await unlink2(legacyLink)}catch{}}success("Binaries installed")}catch(err){error(`Failed to install binaries: ${err}`),process.exit(1)}if(console.log(),console.log("\x1B[2m\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m"),success("Genie CLI updated successfully!"),console.log(),afterInfo)console.log(`Version: \x1B[36m${afterInfo.branch}@${afterInfo.commit}\x1B[0m (${afterInfo.commitDate})`),console.log()}async function symlinkOrCopy(src,dest){let{symlink:symlink2,unlink:unlink3}=await import("fs/promises");try{if(existsSync28(dest))await unlink3(dest);await symlink2(src,dest)}catch{await copyFile(src,dest)}}function copyDirSync(src,dest){mkdirSync15(dest,{recursive:!0});for(let entry2 of readdirSync9(src,{withFileTypes:!0})){let srcPath=join34(src,entry2.name),destPath=join34(dest,entry2.name);if(entry2.isDirectory())copyDirSync(srcPath,destPath);else copyFileSync3(srcPath,destPath)}}async function resolveGlobalPkgDir(installType){if(installType==="bun"){let bunPath=join34(homedir28(),".bun","install","global","node_modules","@automagik","genie");if(existsSync28(bunPath))return bunPath}if(installType==="npm"){let npmRootResult=await runCommandSilent("npm",["root","-g"]);if(npmRootResult.success){let npmPath=join34(npmRootResult.output.trim(),"@automagik","genie");if(existsSync28(npmPath))return npmPath}}let bunFallback=join34(homedir28(),".bun","install","global","node_modules","@automagik","genie");if(existsSync28(bunFallback))return bunFallback;let npmRootFallback=await runCommandSilent("npm",["root","-g"]);if(npmRootFallback.success){let npmPath=join34(npmRootFallback.output.trim(),"@automagik","genie");if(existsSync28(npmPath))return npmPath}return null}function updatePluginRegistry(claudePlugins,cacheDir,version){let registryPath=join34(claudePlugins,"installed_plugins.json");try{if(!existsSync28(registryPath))return;let registry=JSON.parse(readFileSync19(registryPath,"utf-8")),entries=registry.plugins?.["genie@automagik"];if(!Array.isArray(entries))return;for(let entry2 of entries)if(entry2.scope==="user")entry2.installPath=cacheDir,entry2.version=version,entry2.lastUpdated=new Date().toISOString();writeFileSync13(registryPath,JSON.stringify(registry,null,2))}catch(err){log(`Registry update failed (non-fatal): ${err}`)}}function syncTmuxConf(tmuxScriptsSrc){mkdirSync15(GENIE_HOME2,{recursive:!0});let tmuxConfSrc=join34(tmuxScriptsSrc,"genie.tmux.conf"),tmuxConfDest=join34(GENIE_HOME2,"tmux.conf");if(existsSync28(tmuxConfSrc))try{copyFileSync3(tmuxConfSrc,tmuxConfDest),success(`Installed tmux config to ${tmuxConfDest}`);try{let{tmuxBin:tmuxBin2}=(init_ensure_tmux(),__toCommonJS(exports_ensure_tmux));execSync3(`${tmuxBin2()} -L genie source-file '${tmuxConfDest}'`,{stdio:"ignore"}),success("Reloaded genie tmux server configuration")}catch{}}catch{}let tuiConfSrc=join34(tmuxScriptsSrc,"tui-tmux.conf"),tuiConfDest=join34(GENIE_HOME2,"tui-tmux.conf");if(existsSync28(tuiConfSrc))try{copyFileSync3(tuiConfSrc,tuiConfDest),success(`Installed TUI tmux config to ${tuiConfDest}`)}catch{}let themeSrc=join34(tmuxScriptsSrc,".generated.theme.conf"),themeDest=join34(GENIE_HOME2,".generated.theme.conf");if(existsSync28(themeSrc))try{copyFileSync3(themeSrc,themeDest),success(`Installed tmux theme to ${themeDest}`)}catch{}let osc52Src=join34(tmuxScriptsSrc,"osc52-copy.sh"),osc52Dest=join34(GENIE_HOME2,"scripts","osc52-copy.sh");if(existsSync28(osc52Src))try{copyFileSync3(osc52Src,osc52Dest),chmodSync2(osc52Dest,493),success(`Installed OSC 52 clipboard helper to ${osc52Dest}`)}catch{}}function syncTmuxScripts(globalPkgDir){let tmuxScriptsSrc=join34(globalPkgDir,"scripts","tmux");if(!existsSync28(tmuxScriptsSrc))return;let scriptsDir=join34(GENIE_HOME2,"scripts");mkdirSync15(scriptsDir,{recursive:!0});let scriptCount=0;for(let entry2 of readdirSync9(tmuxScriptsSrc))if(entry2.endsWith(".sh")||entry2==="genie.tmux.conf"||entry2==="tui-tmux.conf"||entry2===".generated.theme.conf"){let src=join34(tmuxScriptsSrc,entry2),dest=join34(scriptsDir,entry2);copyFileSync3(src,dest);try{chmodSync2(dest,entry2.endsWith(".sh")?493:420)}catch{}scriptCount++}if(scriptCount>0)success(`Refreshed ${scriptCount} tmux scripts at ${scriptsDir}`);syncTmuxConf(tmuxScriptsSrc)}function syncMarketplaceVersion(claudePlugins,version){let marketplacePath=join34(claudePlugins,"marketplaces","automagik",".claude-plugin","marketplace.json");try{if(!existsSync28(marketplacePath))return;let data=JSON.parse(readFileSync19(marketplacePath,"utf-8"));if(Array.isArray(data.plugins)){for(let plugin of data.plugins)if(plugin.name==="genie")plugin.version=version}writeFileSync13(marketplacePath,JSON.stringify(data,null,2)),success(`Updated marketplace.json to v${version}`)}catch(err){log(`Marketplace version update failed (non-fatal): ${err}`)}}function syncPluginPackageVersion(claudePlugins,version){let pkgPath=join34(claudePlugins,"marketplaces","automagik","plugins","genie","package.json");try{if(!existsSync28(pkgPath))return;let data=JSON.parse(readFileSync19(pkgPath,"utf-8"));data.version=version,writeFileSync13(pkgPath,JSON.stringify(data,null,2)),success(`Updated plugin package.json to v${version}`)}catch(err){log(`Plugin package.json update failed (non-fatal): ${err}`)}}function syncSkillsSymlink(claudePlugins,version){let skillsLink=join34(claudePlugins,"marketplaces","automagik","plugins","genie","skills"),cacheSkills=join34("..","..","..","..","cache","automagik","genie",version,"skills");try{let{symlinkSync,unlinkSync:unlinkSync9,lstatSync:lstatSync2}=__require("fs");try{lstatSync2(skillsLink),unlinkSync9(skillsLink)}catch{}symlinkSync(cacheSkills,skillsLink),success(`Skills symlink \u2192 cache/${version}/skills`)}catch(err){log(`Skills symlink update failed (non-fatal): ${err}`)}}async function syncPlugin(installType){log("Syncing Claude Code plugin...");let globalPkgDir=await resolveGlobalPkgDir(installType);if(!globalPkgDir)return log("Could not find installed package \u2014 skipping plugin sync"),{skippedReason:"installed package not found"};let pluginSrc=join34(globalPkgDir,"plugins","genie");if(!existsSync28(pluginSrc))return log("Plugin source not found in package \u2014 skipping plugin sync"),{globalPkgDir,skippedReason:"plugin source not found in package"};let version;try{version=JSON.parse(readFileSync19(join34(globalPkgDir,"package.json"),"utf-8")).version}catch{return log("Could not read package version \u2014 skipping plugin sync"),{globalPkgDir,skippedReason:"could not read package version"}}let claudePlugins=join34(homedir28(),".claude","plugins"),cacheDir=join34(claudePlugins,"cache","automagik","genie",version);try{if(existsSync28(cacheDir))rmSync3(cacheDir,{recursive:!0,force:!0});copyDirSync(pluginSrc,cacheDir);let skillsSrc=join34(globalPkgDir,"skills");if(existsSync28(skillsSrc)&&!existsSync28(join34(cacheDir,"skills")))copyDirSync(skillsSrc,join34(cacheDir,"skills"))}catch(err){return error(`Failed to copy plugin: ${err}`),{version,globalPkgDir,cacheDir,skippedReason:`failed to copy plugin: ${err}`}}return updatePluginRegistry(claudePlugins,cacheDir,version),syncMarketplaceVersion(claudePlugins,version),syncPluginPackageVersion(claudePlugins,version),syncSkillsSymlink(claudePlugins,version),syncTmuxScripts(globalPkgDir),success(`Plugin synced to v${version}`),{version,globalPkgDir,cacheDir}}async function resolveChannel(options){if(options.next)return"next";if(options.stable)return"latest";if(genieConfigExists())try{let config=await loadGenieConfig();if(config.updateChannel)return config.updateChannel}catch{}return"latest"}async function persistChannel(channel){try{let config=await loadGenieConfig();config.updateChannel=channel,await saveGenieConfig(config)}catch{}}async function updateCommand(options={}){console.log(),console.log("\x1B[1m\uD83E\uDDDE Genie CLI Update\x1B[0m"),console.log("\x1B[2m\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m"),console.log();let channel=await resolveChannel(options);if(options.next||options.stable)await persistChannel(channel);let installType=await detectInstallationType();if(log(`Detected installation: ${installType}`),log(`Channel: ${channel}${channel==="next"?" (dev builds)":" (stable)"}`),console.log(),installType==="unknown")error("No Genie CLI installation found"),console.log(),console.log("Install method not configured. Please reinstall genie:"),console.log("\x1B[36m curl -fsSL https://raw.githubusercontent.com/automagik-dev/genie/main/install.sh | bash\x1B[0m"),console.log(),process.exit(1);if(installType==="source"){await updateSource();return}let globalInstalls=await detectGlobalInstalls(),primaryMethod=installType;if(!(primaryMethod==="bun"?await updateViaBun(channel):await updateViaNpm(channel)))process.exit(1);let secondaryMethod=primaryMethod==="bun"?"npm":"bun";if(globalInstalls.has(secondaryMethod)){if(console.log(),log(`Also updating ${secondaryMethod}-global install...`),!(secondaryMethod==="bun"?await updateViaBun(channel):await updateViaNpm(channel)))error(`Secondary update via ${secondaryMethod} failed (non-blocking)`)}let plugin=await syncPlugin(installType);await runPostUpdateMaintenanceSafe(options,{channel,installType,primaryMethod,globalInstalls:[...globalInstalls].sort(),plugin})}function printPostUpdateMaintenanceIntro(){console.log(),log("Running post-update maintenance..."),console.log(" Purpose: make first launch after update fast and collect upgrade health signals."),console.log(" Checks: runtime partitions, watchdog status, session backfill drift, zombie rows, team config orphans."),console.log(" PG policy: read-only; uses an already-running pgserve when available and will not auto-start it."),console.log(" Legend: [ok]=healthy, [fix]=fixed, [--]=skipped/non-blocking, [!!]=operator action needed.")}async function runMaintenanceWithCapturedLines(maintenanceLines){let{runPostUpdateMaintenance:runPostUpdateMaintenance2}=await Promise.resolve().then(() => (init_doctor(),exports_doctor));await withTemporaryEnv("GENIE_PG_NO_AUTOSTART","1",()=>runPostUpdateMaintenance2({log:(line)=>{maintenanceLines.push(line),console.log(line)}}))}function printDiagnosticsSummary(diagnostics){if(log("Post-update diagnostics captured."),console.log(` Report: ${diagnostics.path}`),console.log(" Include this file when opening a GitHub issue; it contains install metadata, step output,"),console.log(" local process state, and recent scheduler/TUI log signals."),diagnostics.signals.length===0)return;console.log(" Recent scheduler signals:");for(let signal of diagnostics.signals.slice(0,3)){let errorDetail=signal.lastError?` \u2014 ${signal.lastError}`:"";console.log(` ${signal.level}:${signal.event} \xD7${signal.count}${errorDetail}`)}}async function capturePostUpdateDiagnostics(diagnosticsCtx,maintenance){if(!diagnosticsCtx)return;try{let diagnostics=await collectUpdateDiagnostics(diagnosticsCtx,maintenance);printDiagnosticsSummary(diagnostics)}catch(err){let msg=err instanceof Error?err.message:String(err);log(`Post-update diagnostics capture failed (non-fatal): ${msg}`)}}async function runPostUpdateMaintenanceSafe(options={},diagnosticsCtx){if(options.skipMaintenance||isTruthyEnv(process.env.GENIE_UPDATE_SKIP_MAINTENANCE)){log("Skipping post-update maintenance (requested).");return}let startedAt=Date.now(),maintenanceLines=[],outcome="completed",maintenanceError;try{printPostUpdateMaintenanceIntro(),await runMaintenanceWithCapturedLines(maintenanceLines),success(`Post-update maintenance complete (${formatDuration2(Date.now()-startedAt)}).`)}catch(err){outcome="failed",maintenanceError=err instanceof Error?err.message:String(err),error(`Post-update maintenance skipped: ${maintenanceError}`)}await capturePostUpdateDiagnostics(diagnosticsCtx,{outcome,durationMs:Date.now()-startedAt,lines:maintenanceLines,error:maintenanceError})}init_version();init_trust();init_trust();init_trust();import{execSync as execSync4}from"child_process";import{existsSync as existsSync31,mkdirSync as mkdirSync16,readFileSync as readFileSync22,renameSync as renameSync6,writeFileSync as writeFileSync14}from"fs";import{dirname as dirname13,isAbsolute,join as join36,resolve as resolve5}from"path";function resolveOriginUrl(repoRoot){try{return execSync4("git config --get remote.origin.url",{cwd:repoRoot,encoding:"utf-8"}).trim()||null}catch{return null}}function findRepoRoot(start){let current=start;while(current!=="/"){if(existsSync31(join36(current,".git")))return current;current=dirname13(current)}return null}function writeTrustFile(path3,file){let dir=dirname13(path3);if(!existsSync31(dir))mkdirSync16(dir,{recursive:!0});let sorted={version:1,entries:[...file.entries].sort((a,b2)=>a.path.localeCompare(b2.path))},serialized=`${JSON.stringify(sorted,null,2)}
|
|
3986
|
+
`)}return}let result2=await migrate({quiet:options.quiet,dryRun:options.dryRun});process.exit(result2.ok?0:1)}init_setup();init_shortcuts();import{existsSync as existsSync26}from"fs";import{homedir as homedir26}from"os";import{join as join32}from"path";async function shortcutsShowCommand(){displayShortcuts();let home=homedir26(),tmuxConf=join32(home,".tmux.conf"),zshrc=join32(home,".zshrc"),bashrc=join32(home,".bashrc");if(console.log("Installation status:"),isShortcutsInstalled(tmuxConf))console.log(" \x1B[32m\u2713\x1B[0m tmux.conf");else console.log(" \x1B[33m-\x1B[0m tmux.conf");let shellRc=existsSync26(zshrc)?zshrc:bashrc;if(isShortcutsInstalled(shellRc))console.log(` \x1B[32m\u2713\x1B[0m ${shellRc.replace(home,"~")}`);else console.log(` \x1B[33m-\x1B[0m ${shellRc.replace(home,"~")}`);console.log(),console.log("Run \x1B[36mgenie shortcuts install\x1B[0m to install shortcuts."),console.log("Run \x1B[36mgenie shortcuts uninstall\x1B[0m to remove shortcuts."),console.log()}async function shortcutsInstallCommand(){await installShortcuts()}async function shortcutsUninstallCommand(){await uninstallShortcuts()}init_esm14();init_claude_settings();init_genie_config2();import{existsSync as existsSync27,lstatSync,rmSync as rmSync2,unlinkSync as unlinkSync8}from"fs";import{homedir as homedir27}from"os";import{join as join33}from"path";var ORCHESTRATION_RULES_PATH=join33(homedir27(),".claude","rules","genie-orchestration.md"),LOCAL_BIN=join33(homedir27(),".local","bin"),SYMLINKS=["genie","term"];function isGenieSymlink(path3){try{if(!existsSync27(path3))return!1;if(!lstatSync(path3).isSymbolicLink())return!1;return!0}catch{return!1}}function removeSymlinks(){let removed=[];for(let name of SYMLINKS){let symlinkPath=join33(LOCAL_BIN,name);if(isGenieSymlink(symlinkPath))try{unlinkSync8(symlinkPath),removed.push(name)}catch{}}return removed}function tryRemoveStep(label,successMsg,fn){console.log(`\x1B[2m${label}\x1B[0m`);try{fn(),console.log(` \x1B[32m+\x1B[0m ${successMsg}`)}catch(error){let message=error instanceof Error?error.message:String(error);console.log(` \x1B[33m!\x1B[0m ${label.replace("...","")} failed: ${message}`)}}function performUninstall(hasHookScript,existingSymlinks,genieDir,hasGenieDir){if(hasHookScript)tryRemoveStep("Removing hook script...","Hook script removed",()=>removeHookScript());if(existingSymlinks.length>0){console.log("\x1B[2mRemoving symlinks...\x1B[0m");let removed=removeSymlinks();if(removed.length>0)console.log(` \x1B[32m+\x1B[0m Removed: ${removed.join(", ")}`)}if(existsSync27(ORCHESTRATION_RULES_PATH))tryRemoveStep("Removing orchestration rules...","Orchestration rules removed (~/.claude/rules/genie-orchestration.md)",()=>unlinkSync8(ORCHESTRATION_RULES_PATH));if(hasGenieDir)tryRemoveStep("Removing genie directory...","Directory removed",()=>rmSync2(genieDir,{recursive:!0,force:!0}))}async function uninstallCommand(){console.log(),console.log("\x1B[1m\x1B[33m Uninstall Genie CLI\x1B[0m"),console.log();let genieDir=getGenieDir(),hasGenieDir=existsSync27(genieDir),hasHookScript=hookScriptExists(),hasOrchestrationRules=existsSync27(ORCHESTRATION_RULES_PATH),existingSymlinks=SYMLINKS.filter((name)=>isGenieSymlink(join33(LOCAL_BIN,name)));if(console.log("\x1B[2mThis will remove:\x1B[0m"),hasHookScript)console.log(" \x1B[31m-\x1B[0m Hook script (~/.claude/hooks/genie-bash-hook.sh)");if(hasOrchestrationRules)console.log(" \x1B[31m-\x1B[0m Orchestration rules (~/.claude/rules/genie-orchestration.md)");if(hasGenieDir)console.log(` \x1B[31m-\x1B[0m Genie directory (${contractPath(genieDir)})`);if(existingSymlinks.length>0)console.log(` \x1B[31m-\x1B[0m Symlinks from ~/.local/bin: ${existingSymlinks.join(", ")}`);if(console.log(),!hasGenieDir&&!hasHookScript&&!hasOrchestrationRules&&existingSymlinks.length===0){console.log("\x1B[33mNothing to uninstall.\x1B[0m"),console.log();return}if(!await esm_default4({message:"Are you sure you want to uninstall Genie CLI?",default:!1})){console.log(),console.log("\x1B[2mUninstall cancelled.\x1B[0m"),console.log();return}console.log(),performUninstall(hasHookScript,existingSymlinks,genieDir,hasGenieDir),console.log(),console.log("\x1B[32m+\x1B[0m Genie CLI uninstalled."),console.log(),console.log("\x1B[2mNote: If you installed via npm/bun, also run:\x1B[0m"),console.log(" \x1B[36mbun remove -g @automagik/genie\x1B[0m"),console.log(" \x1B[2mor\x1B[0m"),console.log(" \x1B[36mnpm uninstall -g @automagik/genie\x1B[0m"),console.log()}init_genie_config2();init_version();import{execSync as execSync3,spawn as spawn3}from"child_process";import{chmodSync as chmodSync2,closeSync as closeSync3,copyFileSync as copyFileSync3,existsSync as existsSync29,mkdirSync as mkdirSync15,openSync as openSync3,readFileSync as readFileSync20,readSync as readSync2,readdirSync as readdirSync9,rmSync as rmSync3,statSync as statSync7,writeFileSync as writeFileSync13}from"fs";import{chmod,copyFile,mkdir as mkdir5,unlink as unlink2}from"fs/promises";import{homedir as homedir28}from"os";import{join as join34}from"path";var REGISTRY=[];async function cleanupLegacyArtifacts(skipList,registry=REGISTRY){let entries=[];for(let artifact of registry){if(skipList.has(artifact.name)){entries.push({name:artifact.name,outcome:"skipped",removed:[],warnings:[]});continue}if(!await artifact.detect()){entries.push({name:artifact.name,outcome:"absent",removed:[],warnings:[]});continue}let result2=await artifact.cleanup();entries.push({name:artifact.name,outcome:"cleaned",removed:result2.removed,warnings:result2.warnings})}return{entries}}function parseSkipCleanupFlag(value){let skip=new Set;if(!value)return skip;for(let part of value.split(",")){let name=part.trim();if(name)skip.add(name)}return skip}var GENIE_HOME2=process.env.GENIE_HOME||join34(homedir28(),".genie"),GENIE_SRC=join34(GENIE_HOME2,"src"),GENIE_BIN=join34(GENIE_HOME2,"bin"),LOCAL_BIN2=join34(homedir28(),".local","bin"),TRUTHY=new Set(["1","true","yes","on"]),UPDATE_DIAGNOSTIC_SCHEMA_VERSION=2,VERIFY_PROBE_DEADLINE_MS=15000,VERIFY_PROBE_POLL_INTERVAL_MS=500,FETCH_LATEST_TIMEOUT_MS=5000;function normalizeVersion(value){let trimmed=value.trim(),plusIdx=trimmed.indexOf("+");return plusIdx===-1?trimmed:trimmed.slice(0,plusIdx)}function decideVerify(args){if(args.skipReason)return{kind:"skipped",reason:args.skipReason};if(args.serverHealthBody===null)return{kind:"health-unreachable",endpoint:args.endpoint};let cliVersion=normalizeVersion(args.cliVersion),rawServerVersion=args.serverHealthBody.version??null,serverVersion=rawServerVersion===null?null:normalizeVersion(rawServerVersion);if(serverVersion===null||serverVersion!==cliVersion)return{kind:"version-mismatch",cliVersion,serverVersion};return{kind:"ok",cliVersion,serverVersion}}function shortCircuitIfCurrent(currentVersion,latestVersion){if(!latestVersion)return!1;return normalizeVersion(currentVersion)===normalizeVersion(latestVersion)}async function fetchLatestVersion(channel){let candidates=[{cmd:"npm",args:["view",`@automagik/genie@${channel}`,"version"]},{cmd:"bunx",args:["npm","view",`@automagik/genie@${channel}`,"version"]}];for(let{cmd,args}of candidates){let result2=await runCommandSilent(cmd,args,void 0,FETCH_LATEST_TIMEOUT_MS);if(!result2.success)continue;let trimmed=result2.output.trim();if(!trimmed)continue;let lines=trimmed.split(/\r?\n/).filter(Boolean),tokens2=lines[lines.length-1].split(/\s+/),candidate=tokens2[tokens2.length-1].replace(/^['"]|['"]$/g,"");if(/^\d+\.\d+/.test(candidate))return candidate}return null}async function promptConfirm(question){if(!process.stdin.isTTY||!process.stdout.isTTY)return!0;return process.stdout.write(`${question} [Y/n] `),new Promise((resolve5)=>{let onData=(chunk)=>{process.stdin.removeListener("data",onData),process.stdin.pause();let answer=chunk.toString("utf-8").trim().toLowerCase();if(answer===""||answer==="y"||answer==="yes")resolve5(!0);else resolve5(!1)};process.stdin.resume(),process.stdin.once("data",onData)})}function shouldAutoConfirm(opts){if(opts.yes)return!0;return isTruthyEnv(process.env.GENIE_UPDATE_YES)}var VERIFY_PROBE_ENDPOINT="pgserve status --json + ~/.genie/serve.pid";async function readServerHealth(){if(!(await runCommandSilent("pgserve",["status","--json"],void 0,3000)).success)return null;let pidPath=join34(GENIE_HOME2,"serve.pid"),rawPid=safeRead(pidPath,32);if(!rawPid)return null;let pid=Number.parseInt(rawPid.trim(),10);if(!Number.isFinite(pid)||pid<=0)return null;try{process.kill(pid,0)}catch{return null}return{version:VERSION}}async function pollHealth(readHealth,deadlineMs,intervalMs){let startedAt=Date.now();while(Date.now()-startedAt<deadlineMs){let body=null;try{body=await readHealth()}catch{}if(body!==null)return body;await new Promise((r)=>setTimeout(r,intervalMs))}return null}async function runVerifyProbe(opts){if(opts.skipReason)return decideVerify({cliVersion:opts.cliVersion,serverHealthBody:null,endpoint:VERIFY_PROBE_ENDPOINT,skipReason:opts.skipReason});let reader=opts.readHealth??readServerHealth,deadline=opts.deadlineMs??VERIFY_PROBE_DEADLINE_MS,interval=opts.intervalMs??VERIFY_PROBE_POLL_INTERVAL_MS,body=await pollHealth(reader,deadline,interval);return decideVerify({cliVersion:opts.cliVersion,serverHealthBody:body,endpoint:VERIFY_PROBE_ENDPOINT})}function formatVerifyBanner(result2){let lines=[];switch(result2.kind){case"ok":lines.push(`${colorize("\x1B[32m","\x1B[0m","\u2714")} CLI: v${result2.cliVersion}`),lines.push(`${colorize("\x1B[32m","\x1B[0m","\u2714")} Server: v${result2.serverVersion} (healthy)`);break;case"health-unreachable":lines.push(`${colorize("\x1B[33m","\x1B[0m","!")} CLI: v${VERSION}`),lines.push(`${colorize("\x1B[31m","\x1B[0m","\u2716")} Server: unreachable (probe: ${result2.endpoint})`);break;case"version-mismatch":lines.push(`${colorize("\x1B[32m","\x1B[0m","\u2714")} CLI: v${result2.cliVersion}`),lines.push(`${colorize("\x1B[31m","\x1B[0m","\u2716")} Server: v${result2.serverVersion??"unknown"} (mismatch)`);break;case"auth-invalid":lines.push(`${colorize("\x1B[31m","\x1B[0m","\u2716")} Auth: invalid`);break;case"skipped":lines.push(`${colorize("\x1B[32m","\x1B[0m","\u2714")} CLI: v${VERSION}`),lines.push(`${colorize("\x1B[2m","\x1B[0m",`\xB7 Server: v\u2026 (skipped: ${result2.reason})`)}`);break}return lines}function colorEnabled(){if(process.env.NO_COLOR)return!1;if(process.env.FORCE_COLOR&&process.env.FORCE_COLOR!=="0")return!0;return Boolean(process.stdout.isTTY)}function colorize(open4,close,text){return colorEnabled()?`${open4}${text}${close}`:text}function log(message){console.log(`${colorize("\x1B[32m","\x1B[0m","\u25B8")} ${message}`)}function success(message){console.log(`${colorize("\x1B[32m","\x1B[0m","\u2714")} ${message}`)}function error(message){console.log(`${colorize("\x1B[31m","\x1B[0m","\u2716")} ${message}`)}function formatDuration2(ms){if(ms<1000)return`${ms}ms`;return`${(ms/1000).toFixed(1)}s`}function isTruthyEnv(value){return value!==void 0&&TRUTHY.has(value.trim().toLowerCase())}async function withTemporaryEnv(key,value,fn){let previous=process.env[key];process.env[key]=value;try{return await fn()}finally{if(previous===void 0)delete process.env[key];else process.env[key]=previous}}function safeExec(command,timeoutMs=1500){try{return execSync3(command,{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:timeoutMs}).trim()}catch(err){let stdout=err.stdout;if(typeof stdout==="string"&&stdout.trim())return stdout.trim();return""}}function safeRead(path3,maxChars=4000){try{let value=readFileSync20(path3,"utf-8");if(value.length<=maxChars)return value;return value.slice(value.length-maxChars)}catch{return null}}function tailLines(path3,maxBytes=64000,maxLines=200){let fd=null;try{let stat4=statSync7(path3),bytesToRead=Math.min(stat4.size,maxBytes),buffer2=Buffer.alloc(bytesToRead);return fd=openSync3(path3,"r"),readSync2(fd,buffer2,0,bytesToRead,Math.max(0,stat4.size-bytesToRead)),buffer2.toString("utf-8").split(/\r?\n/).map((line)=>line.trim()).filter(Boolean).slice(-maxLines)}catch{return[]}finally{if(fd!==null)try{closeSync3(fd)}catch{}}}function summarizeJsonlSignals(path3){let signals2=new Map;for(let line of tailLines(path3))try{let event=JSON.parse(line),level=typeof event.level==="string"?event.level:"unknown";if(level!=="error"&&level!=="warn")continue;let name=typeof event.event==="string"?event.event:"unknown",key=`${level}:${name}`,existing=signals2.get(key)??{level,event:name,count:0};if(existing.count++,typeof event.timestamp==="string")existing.lastTimestamp=event.timestamp;if(typeof event.error==="string")existing.lastError=event.error;signals2.set(key,existing)}catch{}return[...signals2.values()].sort((a,b2)=>b2.count-a.count).slice(0,10)}async function collectUpdateDiagnostics(ctx,maintenance,extras){let logsDir=join34(GENIE_HOME2,"logs");mkdirSync15(logsDir,{recursive:!0});let generatedAt=new Date().toISOString(),safeStamp=generatedAt.replace(/[:.]/g,"-"),path3=join34(logsDir,`update-diagnostics-${safeStamp}.json`),schedulerLog=join34(logsDir,"scheduler.log"),tuiCrashLog=join34(logsDir,"tui-crash.log"),signals2=summarizeJsonlSignals(schedulerLog),diagnostics={schemaVersion:UPDATE_DIAGNOSTIC_SCHEMA_VERSION,cli:"genie",generatedAt,verify:extras.verify,cleanups:extras.cleanups,update:ctx,runtime:{platform:process.platform,arch:process.arch,cwd:process.cwd(),node:process.version,bun:(await runCommandSilent("bun",["--version"])).output.trim()||null,npm:(await runCommandSilent("npm",["--version"])).output.trim()||null,genie:{which:(await runCommandSilent("which",["genie"])).output.trim()||null,tuiDisabled:isTruthyEnv(process.env.GENIE_TUI_DISABLE),updateSkipMaintenance:isTruthyEnv(process.env.GENIE_UPDATE_SKIP_MAINTENANCE)}},paths:{genieHome:GENIE_HOME2,logsDir,servePid:safeRead(join34(GENIE_HOME2,"serve.pid"),200),pgservePort:safeRead(join34(GENIE_HOME2,"pgserve.port"),200),schedulerLog,tuiCrashLog},processSnapshot:{genie:safeExec("ps -axo pid,ppid,pgid,stat,pcpu,pmem,etime,command -r | rg -i 'dist/genie.js|/src/genie.ts|pgserve|postgres -D .*\\.genie/data/pgserve|tmux -L genie-tui|bun' || true",2000)||null,tuiTmux:safeExec("tmux -L genie-tui ls 2>/dev/null || true",1000)||null},maintenance:{...maintenance,pgAutostartDisabled:!0,legend:{"[ok]":"healthy","[fix]":"fixed during maintenance","[--]":"skipped/non-blocking","[!!]":"operator action needed; update still completed"}},recentLogSignals:{scheduler:signals2,schedulerTail:tailLines(schedulerLog,32000,80),tuiCrashTail:tailLines(tuiCrashLog,32000,80)}};return writeFileSync13(path3,`${JSON.stringify(diagnostics,null,2)}
|
|
3987
|
+
`),{path:path3,signals:signals2}}async function runCommand(command,args,cwd){return new Promise((resolve5)=>{let output=[],child=spawn3(command,args,{cwd,stdio:["inherit","pipe","pipe"],env:{...process.env,FORCE_COLOR:"1"}});child.stdout?.on("data",(data)=>{let str2=data.toString();output.push(str2),process.stdout.write(str2)}),child.stderr?.on("data",(data)=>{let str2=data.toString();output.push(str2),process.stderr.write(str2)}),child.on("close",(code)=>{resolve5({success:code===0,output:output.join("")})}),child.on("error",(err)=>{error(err.message),resolve5({success:!1,output:err.message})})})}async function getGitInfo(cwd){try{let branchResult=await runCommandSilent("git",["rev-parse","--abbrev-ref","HEAD"],cwd),commitResult=await runCommandSilent("git",["rev-parse","--short","HEAD"],cwd),dateResult=await runCommandSilent("git",["log","-1","--format=%ci"],cwd);if(branchResult.success&&commitResult.success&&dateResult.success)return{branch:branchResult.output.trim(),commit:commitResult.output.trim(),commitDate:dateResult.output.trim().split(" ")[0]}}catch{}return null}async function runCommandSilent(command,args,cwd,timeoutMs=4000){return new Promise((resolve5)=>{let output=[],settled=!1,child=spawn3(command,args,{cwd,stdio:["inherit","pipe","pipe"]}),timer2=setTimeout(()=>{if(settled)return;settled=!0,child.kill("SIGTERM"),resolve5({success:!1,output:`Timed out after ${timeoutMs}ms`})},timeoutMs);child.stdout?.on("data",(data)=>{output.push(data.toString())}),child.stderr?.on("data",(data)=>{output.push(data.toString())}),child.on("close",(code)=>{if(settled)return;settled=!0,clearTimeout(timer2),resolve5({success:code===0,output:output.join("")})}),child.on("error",(err)=>{if(settled)return;settled=!0,clearTimeout(timer2),resolve5({success:!1,output:err.message})})})}function detectFromBinaryPath(path3){let resolved=path3;try{resolved=__require("fs").realpathSync(path3)}catch{}if(resolved.includes(".bun"))return"bun";if(resolved.includes("node_modules"))return"npm";if(path3===join34(LOCAL_BIN2,"genie")||resolved.startsWith(GENIE_BIN))return"source";return null}async function detectInstallationType(){let whichResult=await runCommandSilent("which",["genie"]);if(whichResult.success){let detected=detectFromBinaryPath(whichResult.output.trim());if(detected)return detected}if(genieConfigExists())try{let config=await loadGenieConfig();if(config.installMethod)return config.installMethod}catch{}if(existsSync29(join34(GENIE_SRC,".git")))return"source";return(await runCommandSilent("which",["bun"])).success?"bun":"npm"}async function updateViaBun(channel){try{__require("fs").unlinkSync(join34(homedir28(),".bun","install","global","bun.lock"))}catch{}if(log(`Updating via bun (channel: ${channel})...`),!(await runCommand("bun",["add","-g",`@automagik/genie@${channel}`])).success)return error("Failed to update via bun"),!1;return console.log(),success(`Genie CLI updated via bun (${channel})!`),!0}async function updateViaNpm(channel){if(log(`Updating via npm (channel: ${channel})...`),!(await runCommand("npm",["install","-g",`@automagik/genie@${channel}`])).success)return error("Failed to update via npm"),!1;return console.log(),success(`Genie CLI updated via npm (${channel})!`),!0}async function detectGlobalInstalls(){let found=new Set,[npmResult,bunResult]=await Promise.all([runCommandSilent("npm",["list","-g","@automagik/genie"]),runCommandSilent("bun",["pm","ls","-g"])]);if(npmResult.success&&!npmResult.output.includes("(empty)"))found.add("npm");if(bunResult.success&&bunResult.output.includes("@automagik/genie"))found.add("bun");return found}async function updateSource(){if(!existsSync29(GENIE_SRC))error(`Source install path not found: ${GENIE_SRC}`),console.error(" Detection picked the source-install path, but the directory does not exist."),console.error(" This usually means a stale install hint (config or ~/.genie/src/.git) is"),console.error(" pointing somewhere genuine. Either:"),console.error(` 1. Re-clone the source: git clone https://github.com/automagik-dev/genie ${GENIE_SRC}`),console.error(" 2. Update via package manager instead: genie update --next --via bun"),console.error(" 3. Inspect detection: genie doctor --update-detection"),process.exit(1);if(!existsSync29(join34(GENIE_SRC,".git")))error(`Source install path is not a git checkout: ${GENIE_SRC}`),console.error(` ${GENIE_SRC} exists but has no .git/. Cannot run \`git fetch\` from it.`),console.error(` Either delete ${GENIE_SRC} and re-clone, or update via package manager:`),console.error(" genie update --next --via bun"),process.exit(1);let beforeInfo=await getGitInfo(GENIE_SRC);if(beforeInfo)console.log(`Current: \x1B[2m${beforeInfo.branch}@${beforeInfo.commit} (${beforeInfo.commitDate})\x1B[0m`),console.log();if(log("Fetching latest changes..."),!(await runCommand("git",["fetch","origin"],GENIE_SRC)).success)error("Failed to fetch from origin"),process.exit(1);if(log("Resetting to origin/main..."),!(await runCommand("git",["reset","--hard","origin/main"],GENIE_SRC)).success)error("Failed to reset to origin/main"),process.exit(1);console.log();let afterInfo=await getGitInfo(GENIE_SRC);if(beforeInfo&&afterInfo&&beforeInfo.commit===afterInfo.commit){success("Already up to date!"),console.log();return}if(log("Installing dependencies..."),!(await runCommand("bun",["install"],GENIE_SRC)).success)error("Failed to install dependencies"),process.exit(1);if(console.log(),log("Building..."),!(await runCommand("bun",["run","build"],GENIE_SRC)).success)error("Failed to build"),process.exit(1);console.log(),log("Installing binaries...");try{await mkdir5(GENIE_BIN,{recursive:!0}),await mkdir5(LOCAL_BIN2,{recursive:!0});let binaries=["genie.js","term.js"],names=["genie","term"];for(let i2=0;i2<binaries.length;i2++){let src=join34(GENIE_SRC,"dist",binaries[i2]),binDest=join34(GENIE_BIN,binaries[i2]),linkDest=join34(LOCAL_BIN2,names[i2]);await copyFile(src,binDest),await chmod(binDest,493),await symlinkOrCopy(binDest,linkDest)}for(let legacy of["claudio.js","claudio"]){let legacyBin=join34(GENIE_BIN,legacy),legacyLink=join34(LOCAL_BIN2,legacy);try{await unlink2(legacyBin)}catch{}try{await unlink2(legacyLink)}catch{}}success("Binaries installed")}catch(err){error(`Failed to install binaries: ${err}`),process.exit(1)}if(console.log(),console.log("\x1B[2m\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m"),success("Genie CLI updated successfully!"),console.log(),afterInfo)console.log(`Version: \x1B[36m${afterInfo.branch}@${afterInfo.commit}\x1B[0m (${afterInfo.commitDate})`),console.log()}async function symlinkOrCopy(src,dest){let{symlink:symlink2,unlink:unlink3}=await import("fs/promises");try{if(existsSync29(dest))await unlink3(dest);await symlink2(src,dest)}catch{await copyFile(src,dest)}}function copyDirSync(src,dest){mkdirSync15(dest,{recursive:!0});for(let entry2 of readdirSync9(src,{withFileTypes:!0})){let srcPath=join34(src,entry2.name),destPath=join34(dest,entry2.name);if(entry2.isDirectory())copyDirSync(srcPath,destPath);else copyFileSync3(srcPath,destPath)}}async function resolveGlobalPkgDir(installType){if(installType==="bun"){let bunPath=join34(homedir28(),".bun","install","global","node_modules","@automagik","genie");if(existsSync29(bunPath))return bunPath}if(installType==="npm"){let npmRootResult=await runCommandSilent("npm",["root","-g"]);if(npmRootResult.success){let npmPath=join34(npmRootResult.output.trim(),"@automagik","genie");if(existsSync29(npmPath))return npmPath}}let bunFallback=join34(homedir28(),".bun","install","global","node_modules","@automagik","genie");if(existsSync29(bunFallback))return bunFallback;let npmRootFallback=await runCommandSilent("npm",["root","-g"]);if(npmRootFallback.success){let npmPath=join34(npmRootFallback.output.trim(),"@automagik","genie");if(existsSync29(npmPath))return npmPath}return null}function updatePluginRegistry(claudePlugins,cacheDir,version){let registryPath=join34(claudePlugins,"installed_plugins.json");try{if(!existsSync29(registryPath))return;let registry=JSON.parse(readFileSync20(registryPath,"utf-8")),entries=registry.plugins?.["genie@automagik"];if(!Array.isArray(entries))return;for(let entry2 of entries)if(entry2.scope==="user")entry2.installPath=cacheDir,entry2.version=version,entry2.lastUpdated=new Date().toISOString();writeFileSync13(registryPath,JSON.stringify(registry,null,2))}catch(err){log(`Registry update failed (non-fatal): ${err}`)}}function syncTmuxConf(tmuxScriptsSrc){mkdirSync15(GENIE_HOME2,{recursive:!0});let tmuxConfSrc=join34(tmuxScriptsSrc,"genie.tmux.conf"),tmuxConfDest=join34(GENIE_HOME2,"tmux.conf");if(existsSync29(tmuxConfSrc))try{copyFileSync3(tmuxConfSrc,tmuxConfDest),success(`Installed tmux config to ${tmuxConfDest}`);try{let{tmuxBin:tmuxBin2}=(init_ensure_tmux(),__toCommonJS(exports_ensure_tmux));execSync3(`${tmuxBin2()} -L genie source-file '${tmuxConfDest}'`,{stdio:"ignore"}),success("Reloaded genie tmux server configuration")}catch{}}catch{}let tuiConfSrc=join34(tmuxScriptsSrc,"tui-tmux.conf"),tuiConfDest=join34(GENIE_HOME2,"tui-tmux.conf");if(existsSync29(tuiConfSrc))try{copyFileSync3(tuiConfSrc,tuiConfDest),success(`Installed TUI tmux config to ${tuiConfDest}`)}catch{}let themeSrc=join34(tmuxScriptsSrc,".generated.theme.conf"),themeDest=join34(GENIE_HOME2,".generated.theme.conf");if(existsSync29(themeSrc))try{copyFileSync3(themeSrc,themeDest),success(`Installed tmux theme to ${themeDest}`)}catch{}let osc52Src=join34(tmuxScriptsSrc,"osc52-copy.sh"),osc52Dest=join34(GENIE_HOME2,"scripts","osc52-copy.sh");if(existsSync29(osc52Src))try{copyFileSync3(osc52Src,osc52Dest),chmodSync2(osc52Dest,493),success(`Installed OSC 52 clipboard helper to ${osc52Dest}`)}catch{}}function syncTmuxScripts(globalPkgDir){let tmuxScriptsSrc=join34(globalPkgDir,"scripts","tmux");if(!existsSync29(tmuxScriptsSrc))return;let scriptsDir=join34(GENIE_HOME2,"scripts");mkdirSync15(scriptsDir,{recursive:!0});let scriptCount=0;for(let entry2 of readdirSync9(tmuxScriptsSrc))if(entry2.endsWith(".sh")||entry2==="genie.tmux.conf"||entry2==="tui-tmux.conf"||entry2===".generated.theme.conf"){let src=join34(tmuxScriptsSrc,entry2),dest=join34(scriptsDir,entry2);copyFileSync3(src,dest);try{chmodSync2(dest,entry2.endsWith(".sh")?493:420)}catch{}scriptCount++}if(scriptCount>0)success(`Refreshed ${scriptCount} tmux scripts at ${scriptsDir}`);syncTmuxConf(tmuxScriptsSrc)}function syncMarketplaceVersion(claudePlugins,version){let marketplacePath=join34(claudePlugins,"marketplaces","automagik",".claude-plugin","marketplace.json");try{if(!existsSync29(marketplacePath))return;let data=JSON.parse(readFileSync20(marketplacePath,"utf-8"));if(Array.isArray(data.plugins)){for(let plugin of data.plugins)if(plugin.name==="genie")plugin.version=version}writeFileSync13(marketplacePath,JSON.stringify(data,null,2)),success(`Updated marketplace.json to v${version}`)}catch(err){log(`Marketplace version update failed (non-fatal): ${err}`)}}function syncPluginPackageVersion(claudePlugins,version){let pkgPath=join34(claudePlugins,"marketplaces","automagik","plugins","genie","package.json");try{if(!existsSync29(pkgPath))return;let data=JSON.parse(readFileSync20(pkgPath,"utf-8"));data.version=version,writeFileSync13(pkgPath,JSON.stringify(data,null,2)),success(`Updated plugin package.json to v${version}`)}catch(err){log(`Plugin package.json update failed (non-fatal): ${err}`)}}function syncSkillsSymlink(claudePlugins,version){let skillsLink=join34(claudePlugins,"marketplaces","automagik","plugins","genie","skills"),cacheSkills=join34("..","..","..","..","cache","automagik","genie",version,"skills");try{let{symlinkSync,unlinkSync:unlinkSync9,lstatSync:lstatSync2}=__require("fs");try{lstatSync2(skillsLink),unlinkSync9(skillsLink)}catch{}symlinkSync(cacheSkills,skillsLink),success(`Skills symlink \u2192 cache/${version}/skills`)}catch(err){log(`Skills symlink update failed (non-fatal): ${err}`)}}async function syncPlugin(installType){log("Syncing Claude Code plugin...");let globalPkgDir=await resolveGlobalPkgDir(installType);if(!globalPkgDir)return log("Could not find installed package \u2014 skipping plugin sync"),{skippedReason:"installed package not found"};let pluginSrc=join34(globalPkgDir,"plugins","genie");if(!existsSync29(pluginSrc))return log("Plugin source not found in package \u2014 skipping plugin sync"),{globalPkgDir,skippedReason:"plugin source not found in package"};let version;try{version=JSON.parse(readFileSync20(join34(globalPkgDir,"package.json"),"utf-8")).version}catch{return log("Could not read package version \u2014 skipping plugin sync"),{globalPkgDir,skippedReason:"could not read package version"}}let claudePlugins=join34(homedir28(),".claude","plugins"),cacheDir=join34(claudePlugins,"cache","automagik","genie",version);try{if(existsSync29(cacheDir))rmSync3(cacheDir,{recursive:!0,force:!0});copyDirSync(pluginSrc,cacheDir);let skillsSrc=join34(globalPkgDir,"skills");if(existsSync29(skillsSrc)&&!existsSync29(join34(cacheDir,"skills")))copyDirSync(skillsSrc,join34(cacheDir,"skills"))}catch(err){return error(`Failed to copy plugin: ${err}`),{version,globalPkgDir,cacheDir,skippedReason:`failed to copy plugin: ${err}`}}return updatePluginRegistry(claudePlugins,cacheDir,version),syncMarketplaceVersion(claudePlugins,version),syncPluginPackageVersion(claudePlugins,version),syncSkillsSymlink(claudePlugins,version),syncTmuxScripts(globalPkgDir),success(`Plugin synced to v${version}`),{version,globalPkgDir,cacheDir}}async function resolveChannel(options){if(options.next)return"next";if(options.stable)return"latest";if(genieConfigExists())try{let config=await loadGenieConfig();if(config.updateChannel)return config.updateChannel}catch{}return"latest"}async function persistChannel(channel){try{let config=await loadGenieConfig();config.updateChannel=channel,await saveGenieConfig(config)}catch{}}async function updateCommand(options={}){console.log(),console.log(`${colorize("\x1B[1m","\x1B[0m","\uD83E\uDDDE Genie CLI Update")}`),console.log(`${colorize("\x1B[2m","\x1B[0m","\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}`),console.log();let cleanupSkipList=buildCleanupSkipList(options),noRestart=options.restart===!1||isTruthyEnv(process.env.GENIE_UPDATE_NO_RESTART),noVerify=options.verify===!1||isTruthyEnv(process.env.GENIE_UPDATE_NO_VERIFY),channel=await resolveChannel(options);if(options.next||options.stable)await persistChannel(channel);let latestVersion=await fetchLatestVersion(channel);if(shortCircuitIfCurrent(VERSION,latestVersion)){success(`Already up to date (v${normalizeVersion(VERSION)}, channel ${channel})`),console.log();return}let installType=await detectInstallationType();if(log(`Detected installation: ${installType}`),log(`Channel: ${channel}${channel==="next"?" (dev builds)":" (stable)"}`),latestVersion)log(`Update available: ${normalizeVersion(VERSION)} \u2192 ${normalizeVersion(latestVersion)}`);else log(`Registry version unavailable (proceeding with reinstall of channel ${channel})`);if(console.log(),installType==="unknown")error("No Genie CLI installation found"),console.log(),console.log("Install method not configured. Please reinstall genie:"),console.log(`${colorize("\x1B[36m","\x1B[0m"," curl -fsSL https://raw.githubusercontent.com/automagik-dev/genie/main/install.sh | bash")}`),console.log(),process.exit(1);if(!shouldAutoConfirm(options)){let proceedQuestion=latestVersion?`Update v${normalizeVersion(VERSION)} \u2192 v${normalizeVersion(latestVersion)}?`:`Reinstall channel "${channel}"?`;if(!await promptConfirm(proceedQuestion)){console.log(),log("Update declined."),console.log();return}}if(installType==="source"){await updateSource();return}let globalInstalls=await detectGlobalInstalls(),primaryMethod=installType;if(!(primaryMethod==="bun"?await updateViaBun(channel):await updateViaNpm(channel)))process.exit(1);let secondaryMethod=primaryMethod==="bun"?"npm":"bun";if(globalInstalls.has(secondaryMethod)){if(console.log(),log(`Also updating ${secondaryMethod}-global install...`),!(secondaryMethod==="bun"?await updateViaBun(channel):await updateViaNpm(channel)))error(`Secondary update via ${secondaryMethod} failed (non-blocking)`)}let plugin=await syncPlugin(installType),cleanupReport=await runLegacyCleanupSafe(cleanupSkipList);await runPostUpdateMaintenanceSafe({...options,noRestart,noVerify},{channel,installType,primaryMethod,globalInstalls:[...globalInstalls].sort(),plugin,latestVersion,cliVersion:VERSION},cleanupReport)}function buildCleanupSkipList(options){let skipList=parseSkipCleanupFlag(options.skipCleanup);if(options.sidecarCleanup===!1)skipList.add("nats-reply-sidecar"),log("--no-sidecar-cleanup (no-op for genie, retained for cross-CLI portability)");return skipList}async function runLegacyCleanupSafe(skipList){try{return await cleanupLegacyArtifacts(skipList)}catch(err){let msg=err instanceof Error?err.message:String(err);return log(`Legacy artifact cleanup failed (non-fatal): ${msg}`),{entries:[]}}}function printPostUpdateMaintenanceIntro(){console.log(),log("Running post-update maintenance..."),console.log(" Purpose: make first launch after update fast and collect upgrade health signals."),console.log(" Checks: runtime partitions, watchdog status, session backfill drift, zombie rows, team config orphans."),console.log(" PG policy: read-only; uses an already-running pgserve when available and will not auto-start it."),console.log(" Legend: [ok]=healthy, [fix]=fixed, [--]=skipped/non-blocking, [!!]=operator action needed.")}async function runMaintenanceWithCapturedLines(maintenanceLines){let{runPostUpdateMaintenance:runPostUpdateMaintenance2}=await Promise.resolve().then(() => (init_doctor(),exports_doctor));await withTemporaryEnv("GENIE_PG_NO_AUTOSTART","1",()=>runPostUpdateMaintenance2({log:(line)=>{maintenanceLines.push(line),console.log(line)}}))}function printDiagnosticsSummary(diagnostics){if(log("Post-update diagnostics captured."),console.log(` Report: ${diagnostics.path}`),console.log(" Include this file when opening a GitHub issue; it contains install metadata, step output,"),console.log(" local process state, and recent scheduler/TUI log signals."),diagnostics.signals.length===0)return;console.log(" Recent scheduler signals:");for(let signal of diagnostics.signals.slice(0,3)){let errorDetail=signal.lastError?` \u2014 ${signal.lastError}`:"";console.log(` ${signal.level}:${signal.event} \xD7${signal.count}${errorDetail}`)}}async function capturePostUpdateDiagnostics(diagnosticsCtx,maintenance,extras){if(!diagnosticsCtx)return;try{let diagnostics=await collectUpdateDiagnostics(diagnosticsCtx,maintenance,extras);printDiagnosticsSummary(diagnostics)}catch(err){let msg=err instanceof Error?err.message:String(err);log(`Post-update diagnostics capture failed (non-fatal): ${msg}`)}}function printVerifyBanner(result2){console.log();for(let line of formatVerifyBanner(result2))console.log(` ${line}`);console.log()}async function runPostUpdateMaintenanceSafe(options,diagnosticsCtx,cleanupReport){if(options.noRestart){log("--no-restart: skipping maintenance and verify probe.");let verify2=await runVerifyProbe({cliVersion:VERSION,skipReason:"no-restart"});printVerifyBanner(verify2),await capturePostUpdateDiagnostics(diagnosticsCtx,{outcome:"completed",durationMs:0,lines:[]},{verify:verify2,cleanups:cleanupReport});return}if(options.skipMaintenance||isTruthyEnv(process.env.GENIE_UPDATE_SKIP_MAINTENANCE)){log("Skipping post-update maintenance (requested).");let verify2=await runVerifyProbe({cliVersion:VERSION,skipReason:"no-restart"});printVerifyBanner(verify2),await capturePostUpdateDiagnostics(diagnosticsCtx,{outcome:"completed",durationMs:0,lines:[]},{verify:verify2,cleanups:cleanupReport});return}let startedAt=Date.now(),maintenanceLines=[],outcome="completed",maintenanceError;try{printPostUpdateMaintenanceIntro(),await runMaintenanceWithCapturedLines(maintenanceLines),success(`Post-update maintenance complete (${formatDuration2(Date.now()-startedAt)}).`)}catch(err){outcome="failed",maintenanceError=err instanceof Error?err.message:String(err),error(`Post-update maintenance skipped: ${maintenanceError}`)}let verify=options.noVerify?await runVerifyProbe({cliVersion:VERSION,skipReason:"no-verify-flag"}):await runVerifyProbe({cliVersion:VERSION});if(printVerifyBanner(verify),await capturePostUpdateDiagnostics(diagnosticsCtx,{outcome,durationMs:Date.now()-startedAt,lines:maintenanceLines,error:maintenanceError},{verify,cleanups:cleanupReport}),verify.kind==="health-unreachable"&&!options.noVerify)process.exitCode=1}init_version();init_trust();init_trust();init_trust();import{execSync as execSync4}from"child_process";import{existsSync as existsSync31,mkdirSync as mkdirSync16,readFileSync as readFileSync22,renameSync as renameSync6,writeFileSync as writeFileSync14}from"fs";import{dirname as dirname13,isAbsolute,join as join36,resolve as resolve5}from"path";function resolveOriginUrl(repoRoot){try{return execSync4("git config --get remote.origin.url",{cwd:repoRoot,encoding:"utf-8"}).trim()||null}catch{return null}}function findRepoRoot(start){let current=start;while(current!=="/"){if(existsSync31(join36(current,".git")))return current;current=dirname13(current)}return null}function writeTrustFile(path3,file){let dir=dirname13(path3);if(!existsSync31(dir))mkdirSync16(dir,{recursive:!0});let sorted={version:1,entries:[...file.entries].sort((a,b2)=>a.path.localeCompare(b2.path))},serialized=`${JSON.stringify(sorted,null,2)}
|
|
3988
3988
|
`,tmpPath=`${path3}.tmp.${process.pid}`;writeFileSync14(tmpPath,serialized,"utf-8"),renameSync6(tmpPath,path3)}function runTrustList(trustPath){let current=readTrustFile(trustPath);if(current.entries.length===0){console.log(`(trust file empty: ${trustPath})`);return}console.log(`Trusted hooks (${current.entries.length}, from ${trustPath}):`);for(let entry2 of current.entries){let scope=entry2.scope==="repo"?`repo:${entry2.repoRemoteUrl??"?"}`:entry2.scope;if(console.log(` ${entry2.path}`),console.log(` scope: ${scope}`),console.log(` sha256: ${entry2.sha256}`),console.log(` trusted: ${entry2.trustedAt}`),entry2.capabilities&&entry2.capabilities.length>0)console.log(` caps: ${entry2.capabilities.join(", ")}`);if(entry2.note)console.log(` note: ${entry2.note}`)}}function resolveTrustScope(filePath,options){if(options.repo){let repoRoot=findRepoRoot(dirname13(filePath));if(!repoRoot)console.error(`Error: --repo passed but no .git directory found above ${filePath}`),process.exit(1);let remote=resolveOriginUrl(repoRoot);if(!remote)console.error(`Error: --repo passed but ${repoRoot} has no remote.origin.url`),process.exit(1);return{scope:"repo",repoRemoteUrl:remote}}if(options.team)return{scope:"team"};return{scope:"global"}}async function confirmTrustOrAbort(yes){if(yes||!process.stdin.isTTY)return;process.stdout.write("Confirm? (y/N) ");let buf=Buffer.alloc(8),read=0;try{read=(await import("fs")).readSync(0,buf,0,buf.length,null)}catch{console.error("Error: cannot read confirmation; pass --yes to trust non-interactively"),process.exit(1)}let answer=buf.subarray(0,read).toString().trim().toLowerCase();if(answer!=="y"&&answer!=="yes")console.log("Aborted."),process.exit(1)}async function runTrustAdd(target,options,trustPath){let filePath=isAbsolute(target)?target:resolve5(process.cwd(),target);if(!existsSync31(filePath))console.error(`Error: file not found: ${filePath}`),process.exit(1);if(!filePath.endsWith(".ts"))console.error(`Error: trust target must be a .ts file: ${filePath}`),process.exit(1);let{scope,repoRemoteUrl}=resolveTrustScope(filePath,options),sha=sha256OfFile(filePath),source=readFileSync22(filePath,"utf-8"),capabilities=parseCapabilities(source);if(console.log(`About to trust: ${filePath}`),console.log(` scope: ${scope==="repo"?`repo:${repoRemoteUrl}`:scope}`),console.log(` sha256: ${sha}`),capabilities.length>0)console.log(` caps: ${capabilities.join(", ")}`);if(options.note)console.log(` note: ${options.note}`);await confirmTrustOrAbort(options.yes??!1);let current=readTrustFile(trustPath),newEntry={path:filePath,sha256:sha,scope,repoRemoteUrl,trustedAt:new Date().toISOString(),note:options.note,capabilities:capabilities.length>0?capabilities:void 0},next={version:1,entries:[...current.entries.filter((e)=>e.path!==filePath),newEntry]};writeTrustFile(trustPath,next),console.log(`Trusted ${filePath} \u2192 ${trustPath}`)}async function trustAction(target,options){let trustPath=defaultTrustPath();if(!target)return runTrustList(trustPath);await runTrustAdd(target,options,trustPath)}function registerHookTrustCommand(parent){parent.command("trust [path]").description("Add a .ts hook file to the trust allowlist (or list current entries when [path] is omitted)").option("--repo","Scope to current repo (pinned to remote.origin.url)").option("--global","Scope globally (default)").option("--team <name>","Scope to a specific team directory").option("--note <text>","Free-form note saved with the entry").option("--yes","Skip the interactive confirmation prompt").action(trustAction)}import{appendFileSync as appendFileSync3,chmodSync as chmodSync3,mkdirSync as mkdirSync17,statSync as statSync8}from"fs";import{connect as connect2}from"net";import{homedir as homedir30}from"os";import{dirname as dirname14,join as join37}from"path";var PATTERNS=[{kind:"gh-token",re:/gh[ps]_[A-Za-z0-9]{30,}/g},{kind:"sk-token",re:/sk-[A-Za-z0-9-]{20,}/g},{kind:"glpat",re:/glpat-[A-Za-z0-9_-]{20,}/g},{kind:"hex",re:/\b[a-f0-9]{40,}\b/g}];function redactTokenShapes(text){if(text==null)return null;if(process.env.GENIE_HOOK_REDACTION==="off")return String(text);let out=String(text);for(let{kind,re}of PATTERNS)out=out.replace(re,`[REDACTED:${kind}]`);return out}function defaultSocketPath(){if(process.env.GENIE_HOOK_SOCK)return process.env.GENIE_HOOK_SOCK;let home=process.env.GENIE_HOME??join37(homedir30(),".genie");return join37(home,"hook.sock")}function fallbackLogPath2(){let home=process.env.GENIE_HOME??join37(homedir30(),".genie");return join37(home,"hook-fallback.log")}var MAX_FRAME_BYTES=1048576,FALLBACK_LOG_MAX_BYTES=104857600,DEFAULT_TIMEOUT_MS=5000;function readStdinSync(){let chunks=[],total=0,fd=0,buf=Buffer.alloc(65536);while(!0){let n;try{n=__require("fs").readSync(fd,buf,0,buf.length,null)}catch{break}if(n===0)break;if(chunks.push(Buffer.from(buf.subarray(0,n))),total+=n,total>MAX_FRAME_BYTES)break}return Buffer.concat(chunks,Math.min(total,MAX_FRAME_BYTES))}function summarizePayload(payload){try{let obj=JSON.parse(payload.toString("utf-8")),event=typeof obj.hook_event_name==="string"?obj.hook_event_name:null,tool=typeof obj.tool_name==="string"?obj.tool_name:null,command=null,ti=obj.tool_input;if(ti&&typeof ti.command==="string")command=ti.command.split(`
|
|
3989
3989
|
`)[0].slice(0,256);return{event,tool,command}}catch{return{event:null,tool:null,command:null}}}function ensureLogPermissions(path3){let st;try{st=statSync8(path3)}catch{return}let mode=st.mode&511;if(mode===384)return;try{chmodSync3(path3,384),process.stderr.write(`[genie-hook] tightened ${path3} permissions ${mode.toString(8)} -> 600
|
|
3990
3990
|
`)}catch{}}function appendFallback(record){let path3=fallbackLogPath2();try{mkdirSync17(dirname14(path3),{recursive:!0}),ensureLogPermissions(path3);let safe={...record,command:redactTokenShapes(record.command)},writeFresh=!1;try{if(statSync8(path3).size>=FALLBACK_LOG_MAX_BYTES)writeFresh=!0}catch{}let line=`${JSON.stringify(safe)}
|
|
@@ -4796,7 +4796,7 @@ Run with --dry-run to inspect, or pass --force to override.`};return{blocked:!1,
|
|
|
4796
4796
|
)
|
|
4797
4797
|
`,result2={sessionsLinked:linkResult.count??0,toolEventsBackfilled:teResult.count??0,ambiguousCount:0,forced:force,driftDetected:!1}}),result2}function renderDryRun(diag,sample,ambiguous,json2){if(json2){console.log(JSON.stringify({diagnostics:diag,sample,ambiguous},null,2));return}if(console.log("repair-links --dry-run (no rows mutated)"),console.log("-----------------------------------------"),printRepairDiagnostics(diag,sample,ambiguous),diag.linkableOrphanSessions===0&&diag.toolEventsLinkableMissingAttribution===0)console.log(`
|
|
4798
4798
|
Nothing to repair.`);else console.log(`
|
|
4799
|
-
Run with --apply to repair ${diag.linkableOrphanSessions} session(s) and up to ${diag.toolEventsLinkableMissingAttribution} tool_event(s).`)}function renderApplyResult(result2,json2){if(json2){console.log(JSON.stringify(result2,null,2));return}if(console.log("repair-links --apply complete"),console.log(` sessions linked: ${result2.sessionsLinked}`),console.log(` tool_events backfilled: ${result2.toolEventsBackfilled}`),result2.forced)console.log(" --force was used")}async function sessionsRepairLinksCommand(options){if(!await isAvailable())console.error("Database not available."),process.exit(1);let sql=await getConnection(),diag=await diagnoseSessionLinks(sql),sample=await sampleLinkableOrphanSessions(sql,10),ambiguous=await findAmbiguousExecutorSessions(sql);if(options.apply!==!0){renderDryRun(diag,sample,ambiguous,options.json===!0);return}let force=options.force===!0,ambiguityGate=evaluateAmbiguityGate(ambiguous.length,force);if(ambiguityGate.blocked)console.error(ambiguityGate.message),process.exit(2);let noWorkResult=buildNoWorkResultIfApplicable(diag,ambiguous.length,force);if(noWorkResult){if(options.json)console.log(JSON.stringify(noWorkResult,null,2));else console.log("repair-links: nothing to repair (0 candidates).");return}let result2;try{result2=await applyRepairTransaction(sql,diag.linkableOrphanSessions,options.force===!0)}catch(err){console.error(err.message),process.exit(2)}renderApplyResult(result2,options.json===!0)}async function sessionsSyncStatusCommand(){if(!await isAvailable())console.error("Database not available."),process.exit(1);let sql=await getConnection(),status2=await getBackfillStatus(sql);if(!status2){console.log("No backfill has been started. It runs automatically on first daemon start.");return}let pct=status2.totalFiles>0?(status2.processedFiles/status2.totalFiles*100).toFixed(1):"0.0",mbRead=(status2.processedBytes/1024/1024).toFixed(1),mbTotal=(status2.totalBytes/1024/1024).toFixed(1);console.log(`Session backfill: ${status2.processedFiles} / ${status2.totalFiles} files (${pct}%)`),console.log(`Bytes read: ${mbRead} MB / ${mbTotal} MB`),console.log(`Errors: ${status2.errors}`),console.log(`Status: ${status2.status}`)}function registerSessionsCommands(program2){let sessions2=program2.command("sessions").description("Session history \u2014 list, replay, search");sessions2.command("list",{isDefault:!0}).description("List Claude Code sessions").option("--active","Show only active sessions").option("--orphaned","Show only orphaned sessions").option("--agent <name>","Filter by agent").option("--source <name>","Filter by executor metadata source (e.g. omni)").option("--limit <n>","Max number of sessions to return (default: 50)").option("--json","Output as JSON").action(async(options)=>{await sessionsListCommand(options)}),sessions2.command("replay <session-id>").description("Replay a session \u2014 interleave content + events").option("--json","Output as JSON").action(async(sessionId,options)=>{await sessionsReplayCommand(sessionId,options)}),sessions2.command("search <query>").description("Full-text search across session content").option("--json","Output as JSON").option("--limit <n>","Max results","20").action(async(query2,options)=>{await sessionsSearchCommand(query2,options)}),sessions2.command("sync").description("Check session backfill progress").action(async()=>{await sessionsSyncStatusCommand()}),sessions2.command("repair-links").description("Diagnose and (with --apply) repair linkable orphan sessions + tool_events attribution").option("--dry-run","Preview only \u2014 never mutates rows (default)").option("--apply","Run the repair transaction").option("--force","Override the candidate-count drift gate and ambiguity gate").option("--json","Output as JSON").action(async(options)=>{await sessionsRepairLinksCommand(options)})}init_state();init_observability_health();init_agent_observability();init_agent_registry();init_agent_registry();init_derived_signals();init_derived_signals();init_executor_registry();init_should_resume();init_term_format();var ANSI2={reset:"\x1B[0m",dim:"\x1B[2m",bold:"\x1B[1m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",cyan:"\x1B[36m",magenta:"\x1B[35m"};function colorize(text,color2){if(process.env.NO_COLOR||!process.stdout.isTTY)return text;return`${ANSI2[color2]}${text}${ANSI2.reset}`}async function aggregateAgentDecisions(includeArchived){let agents=await listAgentsForRender({includeArchived}),results=Array(agents.length),cursor=0,cap=Math.min(BOOT_PASS_CONCURRENCY_CAP,Math.max(1,agents.length)),workers=Array.from({length:cap},async()=>{while(cursor<agents.length){let i2=cursor++;if(i2>=agents.length)return;let a=agents[i2],decision=await shouldResume(a.id).catch(()=>({resume:!1,reason:"no_session_id",rehydrate:"lazy"})),name=a.customName??a.role??a.id,sessionPreview=decision.sessionId?decision.sessionId.slice(0,8):null,lastWriteAt=null;if(a.currentExecutorId){let exec3=await getExecutor(a.currentExecutorId).catch(()=>null);lastWriteAt=exec3?.updatedAt??exec3?.startedAt??null}results[i2]={agentId:a.id,name,kind:a.kind??null,decision,sessionPreview,lastWriteAt}}});return await Promise.all(workers),results}async function collectHealthChecks(){let report2=await collectObservabilityHealth();return[{name:"partition",status:report2.partition_health,message:report2.next_rotation_at?`next rotation: ${report2.next_rotation_at}`:void 0},{name:"watchdog",status:report2.watchdog,message:report2.watchdog_detail},{name:"spill journal",status:report2.spill_journal==="pending"?"warn":report2.spill_journal==="unknown"?"unknown":"ok",message:report2.spill_path},{name:"watcher metrics",status:report2.watcher_metrics,message:report2.watcher_metrics==="ok"?"all six recently seen":"one or more meta-events missing"}]}function statusIcon(status2){switch(status2){case"ok":return colorize("\u2713","green");case"warn":return colorize("!","yellow");case"fail":return colorize("\u2717","red");default:return colorize("?","dim")}}function severityBadge(sev){if(sev==="critical")return colorize("[CRITICAL]","red");if(sev==="warn")return colorize("[WARN]","yellow");return colorize("[INFO]","dim")}function formatAgentLine(line){let kindTag=line.kind==="permanent"?colorize("p","magenta"):colorize("t","cyan"),session=line.sessionPreview?colorize(line.sessionPreview,"dim"):colorize("no-session","yellow"),lastWrite=line.lastWriteAt?formatRelativeTimestamp(line.lastWriteAt):"-",reason=line.decision.reason==="ok"?colorize("resume ready","green"):colorize(line.decision.reason,"yellow");return` [${kindTag}] ${line.name.padEnd(28).slice(0,28)} ${session.padEnd(8)} last:${lastWrite.padEnd(10)} ${reason}`}function renderResumableSection(lines){let resumable=lines.filter((l)=>l.decision.resume);if(resumable.length===0){console.log(colorize(" (no in-flight agents \u2014 every prior anchor is closed or paused)","dim"));return}for(let line of resumable)console.log(formatAgentLine(line))}function renderStuckSection(lines){let stuck=lines.filter((l)=>!l.decision.resume&&l.decision.reason!=="assignment_closed"&&l.decision.reason!=="unknown_agent");if(stuck.length===0)return;console.log(""),console.log(colorize("STUCK / NEEDS ATTENTION","bold")),console.log("-".repeat(60));for(let line of stuck)if(console.log(formatAgentLine(line)),line.decision.reason==="auto_resume_disabled")console.log(colorize(` \u2192 genie agent resume ${line.name}`,"dim"));else if(line.decision.reason==="no_session_id")console.log(colorize(` \u2192 genie agent show ${line.name} # inspect; consider archive`,"dim"))}function renderArchivedSection(lines){let done=lines.filter((l)=>l.decision.reason==="assignment_closed");if(done.length===0)return;console.log(""),console.log(colorize("DONE / ARCHIVED","bold")),console.log("-".repeat(60));for(let line of done)console.log(formatAgentLine(line))}function renderSignalsSection(signals2){if(signals2.length===0){console.log(colorize(" (no active alerts)","dim"));return}for(let sig of signals2){console.log(` ${severityBadge(sig.severity)} ${colorize(sig.type,"bold")} on ${sig.subject}`);let drilldown=SIGNAL_DRILLDOWN[sig.type];if(drilldown)console.log(colorize(` \u2192 ${drilldown}`,"dim"));if(sig.triggeredAt)console.log(colorize(` ${formatRelativeTimestamp(sig.triggeredAt)}`,"dim"))}}function renderHealthSection(checks){for(let check2 of checks){let detail=check2.message?colorize(` ${check2.message}`,"dim"):"";console.log(` ${statusIcon(check2.status)} ${check2.name.padEnd(18)} ${detail}`)}}async function renderDebugSection(){let audit=await auditAgentKind();if(console.log(""),console.log(colorize("DEBUG \u2014 kind audit","bold")),console.log("-".repeat(60)),console.log(` rows scanned: ${audit.total}`),console.log(` drift count : ${audit.drifted.length}`),audit.drifted.length>0)for(let d of audit.drifted.slice(0,10))console.log(colorize(` drift: ${d.id} stored=${d.kind??"null"} expected=${d.expected}`,"yellow"))}function summarizeObservability(snaps){let flagCounts={},degraded=0;for(let snap of snaps){if(snap.health.degraded)degraded++;for(let flag of snap.health.flags)flagCounts[flag]=(flagCounts[flag]??0)+1}return{schemaVersion:AGENT_OBSERVABILITY_SCHEMA_VERSION,view:"v_agent_observability",total:snaps.length,degraded,flagCounts}}async function buildReport(opts){let includeArchived=opts.all===!0,[agents,signals2,observabilitySnaps]=await Promise.all([aggregateAgentDecisions(includeArchived),listActiveDerivedSignals(),listAgentObservability().catch(()=>[])]),partitionSignal=await detectPartitionMissing().catch(()=>null);if(partitionSignal)await recordDerivedSignal(partitionSignal).catch(()=>{}),signals2.unshift(partitionSignal);let report2={agents,signals:signals2,observability:summarizeObservability(observabilitySnaps)};if(opts.health)report2.health=await collectHealthChecks();return report2}async function statusCommand2(opts={}){let t0=Date.now(),report2=await buildReport(opts);if(opts.json){console.log(JSON.stringify(report2,null,2));return}if(console.log(""),console.log(colorize("IN-FLIGHT \u2014 should resume","bold")),console.log("-".repeat(60)),renderResumableSection(report2.agents),renderStuckSection(report2.agents),opts.all)renderArchivedSection(report2.agents);if(console.log(""),console.log(colorize("ACTIVE SIGNALS","bold")),console.log("-".repeat(60)),renderSignalsSection(report2.signals),report2.health)console.log(""),console.log(colorize("HEALTH","bold")),console.log("-".repeat(60)),renderHealthSection(report2.health);if(opts.debug)await renderDebugSection();renderObservabilitySection(report2.observability),console.log(""),console.log(colorize(` rendered in ${Date.now()-t0}ms \u2014 ${report2.agents.length} agents, ${report2.signals.length} signals \u2014 observability schema v${report2.observability.schemaVersion}`,"dim")),console.log("")}function renderObservabilitySection(summary){console.log(""),console.log(colorize(`OBSERVABILITY (v_agent_observability v${summary.schemaVersion})`,"bold")),console.log("-".repeat(60)),console.log(` ${summary.total} snapshots, ${summary.degraded} degraded`);let flags=Object.entries(summary.flagCounts).sort((a,b2)=>b2[1]-a[1]);if(flags.length===0){console.log(colorize(" (no health flags raised)","dim"));return}for(let[flag,count]of flags)console.log(` ${colorize("!","yellow")} ${flag.padEnd(22)} ${count}`)}init_genie_tokens();init_term_format();var _taskService7;async function getTaskService7(){if(!_taskService7)_taskService7=await Promise.resolve().then(() => (init_task_service(),exports_task_service));return _taskService7}function registerTagCommands(program2){let tag=program2.command("tag").description("Tag management");tag.command("list").description("List all tags").option("--type <typeId>","Filter by task type").option("--json","Output as JSON").action(async(options)=>{try{let tags=await(await getTaskService7()).listTags(options.type);if(options.json){console.log(JSON.stringify(tags,null,2));return}console.log(` ${padRight("ID",20)} ${padRight("NAME",20)} ${padRight("COLOR",10)} TYPE`),console.log(` ${"\u2500".repeat(55)}`);for(let t of tags)console.log(` ${padRight(t.id,20)} ${padRight(t.name,20)} ${padRight(t.color,10)} ${t.typeId??"-"}`);console.log(`
|
|
4799
|
+
Run with --apply to repair ${diag.linkableOrphanSessions} session(s) and up to ${diag.toolEventsLinkableMissingAttribution} tool_event(s).`)}function renderApplyResult(result2,json2){if(json2){console.log(JSON.stringify(result2,null,2));return}if(console.log("repair-links --apply complete"),console.log(` sessions linked: ${result2.sessionsLinked}`),console.log(` tool_events backfilled: ${result2.toolEventsBackfilled}`),result2.forced)console.log(" --force was used")}async function sessionsRepairLinksCommand(options){if(!await isAvailable())console.error("Database not available."),process.exit(1);let sql=await getConnection(),diag=await diagnoseSessionLinks(sql),sample=await sampleLinkableOrphanSessions(sql,10),ambiguous=await findAmbiguousExecutorSessions(sql);if(options.apply!==!0){renderDryRun(diag,sample,ambiguous,options.json===!0);return}let force=options.force===!0,ambiguityGate=evaluateAmbiguityGate(ambiguous.length,force);if(ambiguityGate.blocked)console.error(ambiguityGate.message),process.exit(2);let noWorkResult=buildNoWorkResultIfApplicable(diag,ambiguous.length,force);if(noWorkResult){if(options.json)console.log(JSON.stringify(noWorkResult,null,2));else console.log("repair-links: nothing to repair (0 candidates).");return}let result2;try{result2=await applyRepairTransaction(sql,diag.linkableOrphanSessions,options.force===!0)}catch(err){console.error(err.message),process.exit(2)}renderApplyResult(result2,options.json===!0)}async function sessionsSyncStatusCommand(){if(!await isAvailable())console.error("Database not available."),process.exit(1);let sql=await getConnection(),status2=await getBackfillStatus(sql);if(!status2){console.log("No backfill has been started. It runs automatically on first daemon start.");return}let pct=status2.totalFiles>0?(status2.processedFiles/status2.totalFiles*100).toFixed(1):"0.0",mbRead=(status2.processedBytes/1024/1024).toFixed(1),mbTotal=(status2.totalBytes/1024/1024).toFixed(1);console.log(`Session backfill: ${status2.processedFiles} / ${status2.totalFiles} files (${pct}%)`),console.log(`Bytes read: ${mbRead} MB / ${mbTotal} MB`),console.log(`Errors: ${status2.errors}`),console.log(`Status: ${status2.status}`)}function registerSessionsCommands(program2){let sessions2=program2.command("sessions").description("Session history \u2014 list, replay, search");sessions2.command("list",{isDefault:!0}).description("List Claude Code sessions").option("--active","Show only active sessions").option("--orphaned","Show only orphaned sessions").option("--agent <name>","Filter by agent").option("--source <name>","Filter by executor metadata source (e.g. omni)").option("--limit <n>","Max number of sessions to return (default: 50)").option("--json","Output as JSON").action(async(options)=>{await sessionsListCommand(options)}),sessions2.command("replay <session-id>").description("Replay a session \u2014 interleave content + events").option("--json","Output as JSON").action(async(sessionId,options)=>{await sessionsReplayCommand(sessionId,options)}),sessions2.command("search <query>").description("Full-text search across session content").option("--json","Output as JSON").option("--limit <n>","Max results","20").action(async(query2,options)=>{await sessionsSearchCommand(query2,options)}),sessions2.command("sync").description("Check session backfill progress").action(async()=>{await sessionsSyncStatusCommand()}),sessions2.command("repair-links").description("Diagnose and (with --apply) repair linkable orphan sessions + tool_events attribution").option("--dry-run","Preview only \u2014 never mutates rows (default)").option("--apply","Run the repair transaction").option("--force","Override the candidate-count drift gate and ambiguity gate").option("--json","Output as JSON").action(async(options)=>{await sessionsRepairLinksCommand(options)})}init_state();init_observability_health();init_agent_observability();init_agent_registry();init_agent_registry();init_derived_signals();init_derived_signals();init_executor_registry();init_should_resume();init_term_format();var ANSI2={reset:"\x1B[0m",dim:"\x1B[2m",bold:"\x1B[1m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",cyan:"\x1B[36m",magenta:"\x1B[35m"};function colorize2(text,color2){if(process.env.NO_COLOR||!process.stdout.isTTY)return text;return`${ANSI2[color2]}${text}${ANSI2.reset}`}async function aggregateAgentDecisions(includeArchived){let agents=await listAgentsForRender({includeArchived}),results=Array(agents.length),cursor=0,cap=Math.min(BOOT_PASS_CONCURRENCY_CAP,Math.max(1,agents.length)),workers=Array.from({length:cap},async()=>{while(cursor<agents.length){let i2=cursor++;if(i2>=agents.length)return;let a=agents[i2],decision=await shouldResume(a.id).catch(()=>({resume:!1,reason:"no_session_id",rehydrate:"lazy"})),name=a.customName??a.role??a.id,sessionPreview=decision.sessionId?decision.sessionId.slice(0,8):null,lastWriteAt=null;if(a.currentExecutorId){let exec3=await getExecutor(a.currentExecutorId).catch(()=>null);lastWriteAt=exec3?.updatedAt??exec3?.startedAt??null}results[i2]={agentId:a.id,name,kind:a.kind??null,decision,sessionPreview,lastWriteAt}}});return await Promise.all(workers),results}async function collectHealthChecks(){let report2=await collectObservabilityHealth();return[{name:"partition",status:report2.partition_health,message:report2.next_rotation_at?`next rotation: ${report2.next_rotation_at}`:void 0},{name:"watchdog",status:report2.watchdog,message:report2.watchdog_detail},{name:"spill journal",status:report2.spill_journal==="pending"?"warn":report2.spill_journal==="unknown"?"unknown":"ok",message:report2.spill_path},{name:"watcher metrics",status:report2.watcher_metrics,message:report2.watcher_metrics==="ok"?"all six recently seen":"one or more meta-events missing"}]}function statusIcon(status2){switch(status2){case"ok":return colorize2("\u2713","green");case"warn":return colorize2("!","yellow");case"fail":return colorize2("\u2717","red");default:return colorize2("?","dim")}}function severityBadge(sev){if(sev==="critical")return colorize2("[CRITICAL]","red");if(sev==="warn")return colorize2("[WARN]","yellow");return colorize2("[INFO]","dim")}function formatAgentLine(line){let kindTag=line.kind==="permanent"?colorize2("p","magenta"):colorize2("t","cyan"),session=line.sessionPreview?colorize2(line.sessionPreview,"dim"):colorize2("no-session","yellow"),lastWrite=line.lastWriteAt?formatRelativeTimestamp(line.lastWriteAt):"-",reason=line.decision.reason==="ok"?colorize2("resume ready","green"):colorize2(line.decision.reason,"yellow");return` [${kindTag}] ${line.name.padEnd(28).slice(0,28)} ${session.padEnd(8)} last:${lastWrite.padEnd(10)} ${reason}`}function renderResumableSection(lines){let resumable=lines.filter((l)=>l.decision.resume);if(resumable.length===0){console.log(colorize2(" (no in-flight agents \u2014 every prior anchor is closed or paused)","dim"));return}for(let line of resumable)console.log(formatAgentLine(line))}function renderStuckSection(lines){let stuck=lines.filter((l)=>!l.decision.resume&&l.decision.reason!=="assignment_closed"&&l.decision.reason!=="unknown_agent");if(stuck.length===0)return;console.log(""),console.log(colorize2("STUCK / NEEDS ATTENTION","bold")),console.log("-".repeat(60));for(let line of stuck)if(console.log(formatAgentLine(line)),line.decision.reason==="auto_resume_disabled")console.log(colorize2(` \u2192 genie agent resume ${line.name}`,"dim"));else if(line.decision.reason==="no_session_id")console.log(colorize2(` \u2192 genie agent show ${line.name} # inspect; consider archive`,"dim"))}function renderArchivedSection(lines){let done=lines.filter((l)=>l.decision.reason==="assignment_closed");if(done.length===0)return;console.log(""),console.log(colorize2("DONE / ARCHIVED","bold")),console.log("-".repeat(60));for(let line of done)console.log(formatAgentLine(line))}function renderSignalsSection(signals2){if(signals2.length===0){console.log(colorize2(" (no active alerts)","dim"));return}for(let sig of signals2){console.log(` ${severityBadge(sig.severity)} ${colorize2(sig.type,"bold")} on ${sig.subject}`);let drilldown=SIGNAL_DRILLDOWN[sig.type];if(drilldown)console.log(colorize2(` \u2192 ${drilldown}`,"dim"));if(sig.triggeredAt)console.log(colorize2(` ${formatRelativeTimestamp(sig.triggeredAt)}`,"dim"))}}function renderHealthSection(checks){for(let check2 of checks){let detail=check2.message?colorize2(` ${check2.message}`,"dim"):"";console.log(` ${statusIcon(check2.status)} ${check2.name.padEnd(18)} ${detail}`)}}async function renderDebugSection(){let audit=await auditAgentKind();if(console.log(""),console.log(colorize2("DEBUG \u2014 kind audit","bold")),console.log("-".repeat(60)),console.log(` rows scanned: ${audit.total}`),console.log(` drift count : ${audit.drifted.length}`),audit.drifted.length>0)for(let d of audit.drifted.slice(0,10))console.log(colorize2(` drift: ${d.id} stored=${d.kind??"null"} expected=${d.expected}`,"yellow"))}function summarizeObservability(snaps){let flagCounts={},degraded=0;for(let snap of snaps){if(snap.health.degraded)degraded++;for(let flag of snap.health.flags)flagCounts[flag]=(flagCounts[flag]??0)+1}return{schemaVersion:AGENT_OBSERVABILITY_SCHEMA_VERSION,view:"v_agent_observability",total:snaps.length,degraded,flagCounts}}async function buildReport(opts){let includeArchived=opts.all===!0,[agents,signals2,observabilitySnaps]=await Promise.all([aggregateAgentDecisions(includeArchived),listActiveDerivedSignals(),listAgentObservability().catch(()=>[])]),partitionSignal=await detectPartitionMissing().catch(()=>null);if(partitionSignal)await recordDerivedSignal(partitionSignal).catch(()=>{}),signals2.unshift(partitionSignal);let report2={agents,signals:signals2,observability:summarizeObservability(observabilitySnaps)};if(opts.health)report2.health=await collectHealthChecks();return report2}async function statusCommand2(opts={}){let t0=Date.now(),report2=await buildReport(opts);if(opts.json){console.log(JSON.stringify(report2,null,2));return}if(console.log(""),console.log(colorize2("IN-FLIGHT \u2014 should resume","bold")),console.log("-".repeat(60)),renderResumableSection(report2.agents),renderStuckSection(report2.agents),opts.all)renderArchivedSection(report2.agents);if(console.log(""),console.log(colorize2("ACTIVE SIGNALS","bold")),console.log("-".repeat(60)),renderSignalsSection(report2.signals),report2.health)console.log(""),console.log(colorize2("HEALTH","bold")),console.log("-".repeat(60)),renderHealthSection(report2.health);if(opts.debug)await renderDebugSection();renderObservabilitySection(report2.observability),console.log(""),console.log(colorize2(` rendered in ${Date.now()-t0}ms \u2014 ${report2.agents.length} agents, ${report2.signals.length} signals \u2014 observability schema v${report2.observability.schemaVersion}`,"dim")),console.log("")}function renderObservabilitySection(summary){console.log(""),console.log(colorize2(`OBSERVABILITY (v_agent_observability v${summary.schemaVersion})`,"bold")),console.log("-".repeat(60)),console.log(` ${summary.total} snapshots, ${summary.degraded} degraded`);let flags=Object.entries(summary.flagCounts).sort((a,b2)=>b2[1]-a[1]);if(flags.length===0){console.log(colorize2(" (no health flags raised)","dim"));return}for(let[flag,count]of flags)console.log(` ${colorize2("!","yellow")} ${flag.padEnd(22)} ${count}`)}init_genie_tokens();init_term_format();var _taskService7;async function getTaskService7(){if(!_taskService7)_taskService7=await Promise.resolve().then(() => (init_task_service(),exports_task_service));return _taskService7}function registerTagCommands(program2){let tag=program2.command("tag").description("Tag management");tag.command("list").description("List all tags").option("--type <typeId>","Filter by task type").option("--json","Output as JSON").action(async(options)=>{try{let tags=await(await getTaskService7()).listTags(options.type);if(options.json){console.log(JSON.stringify(tags,null,2));return}console.log(` ${padRight("ID",20)} ${padRight("NAME",20)} ${padRight("COLOR",10)} TYPE`),console.log(` ${"\u2500".repeat(55)}`);for(let t of tags)console.log(` ${padRight(t.id,20)} ${padRight(t.name,20)} ${padRight(t.color,10)} ${t.typeId??"-"}`);console.log(`
|
|
4800
4800
|
${tags.length} tag${tags.length===1?"":"s"}`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),tag.command("create <name>").description("Create a custom tag").option("--color <hex>","Tag color (hex)",palette.textDim).option("--type <typeId>","Associate with a task type").action(async(name,options)=>{try{let ts3=await getTaskService7(),id=name.toLowerCase().replace(/\s+/g,"-"),t=await ts3.createTag({id,name,color:options.color,typeId:options.type});console.log(`Created tag "${t.name}" (${t.id}) with color ${t.color}.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}})}init_term_format();var _taskService8;async function getTaskService8(){if(!_taskService8)_taskService8=await Promise.resolve().then(() => (init_task_service(),exports_task_service));return _taskService8}var _boardService2;async function getBoardService2(){if(!_boardService2)_boardService2=await Promise.resolve().then(() => (init_board_service(),exports_board_service));return _boardService2}var _closeMergedService;async function getCloseMergedService(){if(!_closeMergedService)_closeMergedService=await Promise.resolve().then(() => (init_task_close_merged(),exports_task_close_merged));return _closeMergedService}function localActor2(name){return{actorType:"local",actorId:name}}function currentActor3(){let name=process.env.GENIE_AGENT_NAME??"cli";return localActor2(name)}function getRunId(){return process.env.GENIE_RUN_ID??`run-${Date.now()}`}var PRIORITY_COLORS={urgent:"\x1B[31m",high:"\x1B[33m",normal:"\x1B[0m",low:"\x1B[90m"},RESET2="\x1B[0m";async function resolveDefaultBoardId(){try{let{execSync:execSync17}=await import("child_process"),repoRoot=execSync17("git rev-parse --show-toplevel",{encoding:"utf-8"}).trim(),{join:join87}=await import("path"),configPath2=join87(repoRoot,".genie","config.json"),{existsSync:existsSync72,readFileSync:readFileSync47}=await import("fs");if(existsSync72(configPath2)){let config=JSON.parse(readFileSync47(configPath2,"utf-8"));if(config.activeBoard)return config.activeBoard}}catch{}return null}async function handleInvalidStageError(taskId,message){try{let task=await(await getTaskService8()).getTask(taskId);if(!task?.boardId)return;let board=await(await getBoardService2()).getBoard(task.boardId);if(!board)return;let validCols=board.columns.sort((a,b2)=>a.position-b2.position).map((c)=>c.name).join(" \u2192 ");console.error(`Error: ${message}
|
|
4801
4801
|
Valid columns for board "${board.name}": ${validCols}`),process.exit(1)}catch{}}async function resolveBoardOption(boardName){if(boardName){let board2=await(await getBoardService2()).getBoard(boardName);if(!board2)console.error(`Error: Board not found: ${boardName}`),process.exit(1);return board2.id}let defaultId=await resolveDefaultBoardId();if(!defaultId)return;let board=await(await getBoardService2()).getBoard(defaultId);if(!board)console.error(`Error: configured activeBoard "${defaultId}" no longer exists.
|
|
4802
4802
|
Run \`genie board list\` to see available boards, then either:
|
|
@@ -4885,7 +4885,7 @@ Stage Pipeline:`);let stages=t.stages;for(let i2=0;i2<stages.length;i2++){let s2
|
|
|
4885
4885
|
No fixable violations to apply.`);process.exit(report2.summary.total>0?1:0)}function handleDryRunFix(report2,markdown,fixed,wishPath,jsonMode){if(jsonMode)console.log(JSON.stringify({...report2,dryRun:!0,diff:renderDiff(markdown,fixed)}));else console.log(formatLintReport(report2,{color:process.stdout.isTTY??!1,path:wishPath})),console.log(`
|
|
4886
4886
|
--- Dry-run diff (${wishPath}) ---`),console.log(renderDiff(markdown,fixed)),console.log(`
|
|
4887
4887
|
File not modified (--dry-run).`);process.exit(report2.summary.total>0?1:0)}async function applyAndReportFix(report2,fixed,wishPath,slug,lintOpts,jsonMode){await writeFile11(wishPath,fixed,"utf-8");let docOrError2=parseWishOrError(fixed),report22={...lintWish(docOrError2,fixed,lintOpts),wish:slug,file:wishPath},fixedCount=report2.summary.fixable;if(jsonMode)console.log(JSON.stringify({...report22,fixedViolations:fixedCount}));else console.log(`\u2705 Applied ${fixedCount} fix(es) to ${wishPath}`),console.log(""),console.log(formatLintReport(report22,{color:process.stdout.isTTY??!1,path:wishPath}));let remainingErrors=report22.violations.filter((v)=>v.severity==="error").length;process.exit(remainingErrors>0?1:0)}async function runLintFix(report2,markdown,wishPath,slug,lintOpts,options){let{applyFixes:applyFixes2}=await Promise.resolve().then(() => (init_wish_lint(),exports_wish_lint)),fixed=applyFixes2(markdown,report2),jsonMode=options.json??!1;if(fixed===markdown)handleNoFixableViolations(report2,wishPath,jsonMode);if(options.dryRun)handleDryRunFix(report2,markdown,fixed,wishPath,jsonMode);return applyAndReportFix(report2,fixed,wishPath,slug,lintOpts,jsonMode)}async function wishLintCommand(slug,options){let wishPath=join88(process.cwd(),".genie","wishes",slug,"WISH.md"),jsonMode=options.json??!1;if(!existsSync73(wishPath))reportWishFileMissing(slug,wishPath,jsonMode);let markdown=await readFile17(wishPath,"utf-8"),lintOpts={allowTodoPlaceholders:options.allowTodoPlaceholders},docOrError=parseWishOrError(markdown),report2={...lintWish(docOrError,markdown,lintOpts),wish:slug,file:wishPath};if(options.fix){await runLintFix(report2,markdown,wishPath,slug,lintOpts,options);return}emitLintReport(report2,wishPath,jsonMode),exitWithErrorCount(report2)}function reportWishParseError(error2,jsonMode){let payload={error:error2.message,rule:error2.rule,line:error2.line,column:error2.column??null,file:error2.file??null};if(jsonMode){console.log(JSON.stringify(payload));return}if(console.error(`\u274C Parse failed (${payload.rule}): ${payload.error}`),payload.file)console.error(` File: ${payload.file}`);if(payload.line)console.error(` Line: ${payload.line}`)}async function wishParseCommand(slug,options){try{let doc=parseWishFile(slug);console.log(options.json?JSON.stringify(doc):JSON.stringify(doc,null,2));return}catch(error2){if(error2 instanceof WishParseError)reportWishParseError(error2,options.json??!1),process.exit(1);let message=error2 instanceof Error?error2.message:String(error2);console.error(`\u274C ${message}`),process.exit(1)}}async function isWishFile(wishPath){try{return(await stat11(wishPath)).isFile()}catch{return!1}}function parseWishSummary(slug){try{let doc=parseWishFile(slug);return{status:doc.metadata.status??"-",groupCount:String(doc.executionGroups.length)}}catch(error2){return{status:error2 instanceof WishParseError?"malformed":"error",groupCount:"-"}}}async function loadStateCounts(slug){try{let state=await(await Promise.resolve().then(() => (init_wish_state(),exports_wish_state))).getState(slug);if(!state)return{ready:0,inProgress:0,done:0};let ready=0,inProgress=0,done=0;for(let g of Object.values(state.groups))if(g.status==="ready")ready++;else if(g.status==="in_progress")inProgress++;else if(g.status==="done")done++;return{ready,inProgress,done}}catch{return{ready:0,inProgress:0,done:0}}}async function wishListCommand(){let wishesRoot=join88(process.cwd(),".genie","wishes");if(!existsSync73(wishesRoot))console.error(`\u274C Wishes directory not found: ${wishesRoot}`),process.exit(1);let entries=await readdir11(wishesRoot),rows=[];for(let entry2 of entries.sort()){if(entry2.startsWith("_")||entry2.startsWith("."))continue;if(!await isWishFile(join88(wishesRoot,entry2,"WISH.md")))continue;let{status:status2,groupCount}=parseWishSummary(entry2),{ready,inProgress,done}=await loadStateCounts(entry2);rows.push({slug:entry2,status:status2,groupCount,ready,inProgress,done})}if(rows.length===0){console.log("No wishes found under .genie/wishes/");return}let slugW=Math.max(4,...rows.map((r)=>r.slug.length)),statusW=Math.max(6,...rows.map((r)=>r.status.length)),pad=(s2,n)=>s2+" ".repeat(Math.max(0,n-s2.length));console.log(` ${pad("SLUG",slugW)} ${pad("STATUS",statusW)} GROUPS READY IN-PROG DONE`),console.log(` ${"\u2500".repeat(slugW+statusW+32)}`);for(let r of rows)console.log(` ${pad(r.slug,slugW)} ${pad(r.status,statusW)} ${pad(r.groupCount,6)} ${pad(String(r.ready),5)} ${pad(String(r.inProgress),7)} ${r.done}`);console.log(""),console.log(` Total: ${rows.length} wishes`)}function registerWishCommands(program2){let wish=program2.command("wish").description("Wish lifecycle management");wish.command("new <slug>").description("Scaffold a new WISH.md from templates/wish-template.md").option("--force","Overwrite an existing wish directory").action(async(slug,options)=>{await wishNewCommand(slug,options)}),wish.command("lint <slug>").description("Structural health check (stub \u2014 full implementation in Group 3)").option("--json","Emit machine-readable JSON output").option("--fix","Auto-repair deterministic violations").option("--dry-run","With --fix: print diff without writing").option("--allow-todo-placeholders","Pass <TODO> placeholders without emitting todo-placeholder-remaining").action(async(slug,options)=>{await wishLintCommand(slug,options)}),wish.command("parse <slug>").description("Parse WISH.md and emit the WishDocument as JSON").option("--json","One-line JSON output (default: pretty-printed)").action(async(slug,options)=>{await wishParseCommand(slug,options)}),wish.command("status <slug>").description("Show wish state overview for all groups").action(async(slug)=>{await statusCommand(slug)}),wish.command("done <ref>").description("Mark a wish group as done (format: <slug>#<group>)").action(async(ref)=>{await doneCommand(ref)}),wish.command("reset <ref>").option("-y, --yes","Skip confirmation prompt (required in non-interactive mode)").description("Reset wish state. <slug>#<group> resets one in-progress group; bare <slug> wipes the wish and recreates from current WISH.md").action(async(ref,options)=>{await resetAction(ref,options)}),wish.command("list").description("Enumerate all wishes with status, group counts, and progress").action(async()=>{await wishListCommand()})}var _T_BOOT=Date.now();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{}function parseNumericFlag2(flagName){return(value)=>{let n=Number(value);if(Number.isNaN(n))throw Error(`${flagName} must be a number, got: ${value}`);return n}}if(process.env.GENIE_PROFILE_DB)console.error(`[profile] imports=${Date.now()-_T_BOOT}ms`);var program2=new Command;program2.name("genie").description("Genie CLI - AI-assisted development").version(VERSION);program2.option("--no-interactive","Disable interactive prompts (exit 2 instead of prompting)");program2.option("--no-tui","Skip TUI bootstrap (or set GENIE_TUI_DISABLE=1)");program2.configureHelp({sortSubcommands:!0,showGlobalOptions:!0});program2.configureOutput({outputError:(str5,write)=>{let cmd=program2.commands.find((c)=>process.argv.slice(2,6).includes(c.name())),prefix=cmd?`genie ${cmd.name()}`:"genie";write(`\x1B[31mError (${prefix}): ${str5}\x1B[0m
|
|
4888
|
-
`)}});async function startNamedSession(name){let{randomUUID:randomUUID15}=await import("crypto"),{buildTeamLeadCommand:buildTeamLeadCommand2}=await Promise.resolve().then(() => (init_team_lead_command(),exports_team_lead_command)),{getAgentsFilePath:getAgentsFilePath2}=await Promise.resolve().then(() => (init_session(),exports_session)),systemPromptFile=getAgentsFilePath2(),sessionId=randomUUID15(),cmd=buildTeamLeadCommand2(name,{systemPromptFile:systemPromptFile??void 0,sessionId});console.log(`Starting new session: ${name}`);let{spawnSync:spawnSync11}=await import("child_process"),result2=spawnSync11("sh",["-c",cmd],{stdio:"inherit"});if(result2.status)process.exit(result2.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("install").description("Register genie-serve under pm2 with hardened defaults (canonical-pgserve-pm2-supervision wave 2)").option("--skip-pgserve","Don't run `pgserve install` first (operators who manage pgserve themselves)").action(async(options)=>{await installCommand(options)});program2.command("doctor").description("Run diagnostic checks on genie installation").option("--fix","Auto-fix: kill zombie postgres, clean shared memory, restart daemon").option("--observability","Report partition health + GENIE_WIDE_EMIT flag state").option("--perf","Report rolling per-handler P50/P99 from hook_perf_baseline + flag P99 regressions and recent fallback-log entries").option("--fix-team-orphans","Archive stale Claude-team config dirs missing config.json (paired with invincible-genie wish migration 050)").option("--dry-run","Pair with --fix-team-orphans to preview archive moves without mutating").option("--json","Emit JSON instead of human output (pairs with --observability)").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)").option("--skip-maintenance","Skip post-update maintenance (or set GENIE_UPDATE_SKIP_MAINTENANCE=1)").action(updateCommand);program2.command("migrate").description("Apply pending genie host-migrations (auto-runs on install)").option("--dry-run","List pending migrations without executing").option("--quiet","Suppress per-step OK lines (used by postinstall)").option("--status","Show applied / pending / failed table").action(async(opts)=>{await migrateCommand({dryRun:opts.dryRun,quiet:opts.quiet,status:opts.status})});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);registerServeCommands(program2);registerAppCommand(program2);registerInitCommands(program2);registerTeamNamespace(program2);registerDirNamespace(program2);registerAgentCommands(program2);registerObserveCommands(program2);registerOmniNamespace(program2);registerSendInboxCommands(program2);registerStateCommands(program2);registerDispatchCommands(program2);registerDispatchGroupCommands(program2);registerWishCommands(program2);registerHookNamespace(program2);registerDbCommands(program2);registerScheduleCommands(program2);registerDaemonCommands(program2);registerTaskCommands(program2);registerTypeCommands(program2);registerBoardCommands(program2);registerTagCommands(program2);registerReleaseCommands(program2);registerSecCommands(program2);registerProjectCommands(program2);registerPruneCommands(program2);registerNotifyCommands(program2);registerEventsCommands(program2);registerSessionsCommands(program2);registerMetricsCommands(program2);registerExportCommands(program2);registerImportCommands(program2);registerTemplateCommands(program2);registerBrainCommands(program2);registerBriefCommands(program2);registerApprovalCommands(program2);program2.command("done [ref]").description("Close the current turn (inside an agent session) or mark a wish group done (team-lead, <slug>#<group>)").action(async(ref)=>{let{doneAction:doneAction2}=await Promise.resolve().then(() => (init_done(),exports_done));await doneAction2(ref)});program2.command("blocked").description("Close the current turn with outcome=blocked").requiredOption("--reason <message>","Why the turn is blocked").action(async(options)=>{let{blockedAction:blockedAction2}=await Promise.resolve().then(() => (init_blocked(),exports_blocked));await blockedAction2(options)});program2.command("failed").description("Close the current turn with outcome=failed").requiredOption("--reason <message>","Why the turn failed").action(async(options)=>{let{failedAction:failedAction2}=await Promise.resolve().then(() => (init_failed(),exports_failed));await failedAction2(options)});program2.command("pane-trap").description("Internal: write clean_exit_unverified outcome for a dying pane/shell. Invoked by the tmux pane-died hook and the inline shell EXIT trap.").option("--pane-id <id>","tmux pane id (%N) \u2014 resolved to executor via executors.tmux_pane_id").option("--executor-id <id>","explicit executor UUID (preferred when available)").option("--reason <reason>","trap source: pane_died or shell_exit","pane_died").action(async(options)=>{let{paneTrapAction:paneTrapAction2}=await Promise.resolve().then(() => (init_pane_trap2(),exports_pane_trap));await paneTrapAction2(options)});installWorkspaceCheck(program2);var auditTimers=new Map,auditSpans=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(()=>{}),(async()=>{try{let{isWideEmitEnabled:isWideEmitEnabled2}=await Promise.resolve().then(() => exports_observability_flag);if(!isWideEmitEnabled2())return;let{startSpan:startSpan2}=await Promise.resolve().then(() => (init_emit(),exports_emit)),{getAmbient:getAmbient2}=await Promise.resolve().then(() => (init_trace_context(),exports_trace_context)),handle=startSpan2("cli.command",{command:name,args:actionCommand.args??[],cwd:process.cwd()},{severity:"debug",source_subsystem:"cli",ctx:getAmbient2()??void 0,agent:getActor()});auditSpans.set(name,handle)}catch{}})()});program2.hook("postAction",async(_thisCommand,actionCommand)=>{let name=actionCommand.name(),startMs=auditTimers.get(name),durationMs=startMs?Date.now()-startMs:void 0;auditTimers.delete(name);try{let{isConnected:isConnected2}=await Promise.resolve().then(() => (init_db(),exports_db));if(!isConnected2())return;await recordAuditEvent("command",name,"command_success",getActor(),{args:actionCommand.args,duration_ms:durationMs})}catch{}let handle=auditSpans.get(name);auditSpans.delete(name);try{if(handle){let{isWideEmitEnabled:isWideEmitEnabled2}=await Promise.resolve().then(() => exports_observability_flag);if(isWideEmitEnabled2()){let{endSpan:endSpan2}=await Promise.resolve().then(() => (init_emit(),exports_emit));endSpan2(handle,{exit_code:0,duration_ms:durationMs??0},{severity:"debug",source_subsystem:"cli",agent:getActor()})}}}catch{}try{let{flushNow:flushNow2}=await Promise.resolve().then(() => (init_emit(),exports_emit));await flushNow2()}catch{}});program2.command("spawn <name>").description("Spawn a new agent by name (resolves from directory or built-ins)").option("--provider <provider>","Provider: claude or codex","claude").option("--team <team>","Team name").option("--model <model>","Model override (e.g., sonnet, opus)").option("--skill <skill>","Skill to load (optional)").option("--layout <layout>","Layout mode: mosaic (default) or vertical").option("--color <color>","Teammate pane border color").option("--plan-mode","Start teammate in plan mode").option("--permission-mode <mode>","Permission mode (e.g., acceptEdits)").option("--extra-args <args...>","Extra CLI args forwarded to provider").option("--cwd <path>","Working directory for the agent (overrides directory entry)").option("--session <session>","Tmux session name to spawn into").option("--role <role>","Override role name for registration (avoids duplicate guard)").option("--new-window","Create a new tmux window instead of splitting").option("--window <target>","Tmux window to split into (e.g., genie:3)").option("--no-auto-resume","Disable auto-resume on pane death").option("--no-auto-sync","Disable auto-registration from workspace agents directory").option("--stream","Stream SDK messages to stdout in real-time (claude-sdk provider)").option("--stream-format <format>","Streaming output format: text, json, ndjson (default: text)","text").option("--sdk-max-turns <n>","SDK: max conversation turns",parseNumericFlag2("--sdk-max-turns")).option("--sdk-max-budget <usd>","SDK: max budget in USD",parseNumericFlag2("--sdk-max-budget")).option("--sdk-stream","SDK: enable streaming output (shortcut for --stream)").option("--sdk-effort <level>","SDK: reasoning effort level (low, medium, high, max)").option("--sdk-resume <session-id>","SDK: resume a previous session by ID").option("--prompt <text>","Initial prompt to send as the first user message").addHelpText("after",`
|
|
4888
|
+
`)}});async function startNamedSession(name){let{randomUUID:randomUUID15}=await import("crypto"),{buildTeamLeadCommand:buildTeamLeadCommand2}=await Promise.resolve().then(() => (init_team_lead_command(),exports_team_lead_command)),{getAgentsFilePath:getAgentsFilePath2}=await Promise.resolve().then(() => (init_session(),exports_session)),systemPromptFile=getAgentsFilePath2(),sessionId=randomUUID15(),cmd=buildTeamLeadCommand2(name,{systemPromptFile:systemPromptFile??void 0,sessionId});console.log(`Starting new session: ${name}`);let{spawnSync:spawnSync11}=await import("child_process"),result2=spawnSync11("sh",["-c",cmd],{stdio:"inherit"});if(result2.status)process.exit(result2.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("install").description("Register genie-serve under pm2 with hardened defaults (canonical-pgserve-pm2-supervision wave 2)").option("--skip-pgserve","Don't run `pgserve install` first (operators who manage pgserve themselves)").action(async(options)=>{await installCommand(options)});program2.command("doctor").description("Run diagnostic checks on genie installation").option("--fix","Auto-fix: kill zombie postgres, clean shared memory, restart daemon").option("--observability","Report partition health + GENIE_WIDE_EMIT flag state").option("--perf","Report rolling per-handler P50/P99 from hook_perf_baseline + flag P99 regressions and recent fallback-log entries").option("--fix-team-orphans","Archive stale Claude-team config dirs missing config.json (paired with invincible-genie wish migration 050)").option("--dry-run","Pair with --fix-team-orphans to preview archive moves without mutating").option("--json","Emit JSON instead of human output (pairs with --observability)").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)").option("-y, --yes","Skip the TTY confirmation prompt (or set GENIE_UPDATE_YES=1)").option("--no-restart","Skip post-update maintenance AND the verify probe").option("--no-verify","Run maintenance but skip the post-restart verify probe").option("--skip-maintenance","Skip post-update maintenance (or set GENIE_UPDATE_SKIP_MAINTENANCE=1)").option("--skip-cleanup <names>","Comma-separated legacy-artifact cleanup names to skip").option("--no-sidecar-cleanup","Accepted for cross-CLI portability with omni (no-op for genie)").action(updateCommand);program2.command("migrate").description("Apply pending genie host-migrations (auto-runs on install)").option("--dry-run","List pending migrations without executing").option("--quiet","Suppress per-step OK lines (used by postinstall)").option("--status","Show applied / pending / failed table").action(async(opts)=>{await migrateCommand({dryRun:opts.dryRun,quiet:opts.quiet,status:opts.status})});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);registerServeCommands(program2);registerAppCommand(program2);registerInitCommands(program2);registerTeamNamespace(program2);registerDirNamespace(program2);registerAgentCommands(program2);registerObserveCommands(program2);registerOmniNamespace(program2);registerSendInboxCommands(program2);registerStateCommands(program2);registerDispatchCommands(program2);registerDispatchGroupCommands(program2);registerWishCommands(program2);registerHookNamespace(program2);registerDbCommands(program2);registerScheduleCommands(program2);registerDaemonCommands(program2);registerTaskCommands(program2);registerTypeCommands(program2);registerBoardCommands(program2);registerTagCommands(program2);registerReleaseCommands(program2);registerSecCommands(program2);registerProjectCommands(program2);registerPruneCommands(program2);registerNotifyCommands(program2);registerEventsCommands(program2);registerSessionsCommands(program2);registerMetricsCommands(program2);registerExportCommands(program2);registerImportCommands(program2);registerTemplateCommands(program2);registerBrainCommands(program2);registerBriefCommands(program2);registerApprovalCommands(program2);program2.command("done [ref]").description("Close the current turn (inside an agent session) or mark a wish group done (team-lead, <slug>#<group>)").action(async(ref)=>{let{doneAction:doneAction2}=await Promise.resolve().then(() => (init_done(),exports_done));await doneAction2(ref)});program2.command("blocked").description("Close the current turn with outcome=blocked").requiredOption("--reason <message>","Why the turn is blocked").action(async(options)=>{let{blockedAction:blockedAction2}=await Promise.resolve().then(() => (init_blocked(),exports_blocked));await blockedAction2(options)});program2.command("failed").description("Close the current turn with outcome=failed").requiredOption("--reason <message>","Why the turn failed").action(async(options)=>{let{failedAction:failedAction2}=await Promise.resolve().then(() => (init_failed(),exports_failed));await failedAction2(options)});program2.command("pane-trap").description("Internal: write clean_exit_unverified outcome for a dying pane/shell. Invoked by the tmux pane-died hook and the inline shell EXIT trap.").option("--pane-id <id>","tmux pane id (%N) \u2014 resolved to executor via executors.tmux_pane_id").option("--executor-id <id>","explicit executor UUID (preferred when available)").option("--reason <reason>","trap source: pane_died or shell_exit","pane_died").action(async(options)=>{let{paneTrapAction:paneTrapAction2}=await Promise.resolve().then(() => (init_pane_trap2(),exports_pane_trap));await paneTrapAction2(options)});installWorkspaceCheck(program2);var auditTimers=new Map,auditSpans=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(()=>{}),(async()=>{try{let{isWideEmitEnabled:isWideEmitEnabled2}=await Promise.resolve().then(() => exports_observability_flag);if(!isWideEmitEnabled2())return;let{startSpan:startSpan2}=await Promise.resolve().then(() => (init_emit(),exports_emit)),{getAmbient:getAmbient2}=await Promise.resolve().then(() => (init_trace_context(),exports_trace_context)),handle=startSpan2("cli.command",{command:name,args:actionCommand.args??[],cwd:process.cwd()},{severity:"debug",source_subsystem:"cli",ctx:getAmbient2()??void 0,agent:getActor()});auditSpans.set(name,handle)}catch{}})()});program2.hook("postAction",async(_thisCommand,actionCommand)=>{let name=actionCommand.name(),startMs=auditTimers.get(name),durationMs=startMs?Date.now()-startMs:void 0;auditTimers.delete(name);try{let{isConnected:isConnected2}=await Promise.resolve().then(() => (init_db(),exports_db));if(!isConnected2())return;await recordAuditEvent("command",name,"command_success",getActor(),{args:actionCommand.args,duration_ms:durationMs})}catch{}let handle=auditSpans.get(name);auditSpans.delete(name);try{if(handle){let{isWideEmitEnabled:isWideEmitEnabled2}=await Promise.resolve().then(() => exports_observability_flag);if(isWideEmitEnabled2()){let{endSpan:endSpan2}=await Promise.resolve().then(() => (init_emit(),exports_emit));endSpan2(handle,{exit_code:0,duration_ms:durationMs??0},{severity:"debug",source_subsystem:"cli",agent:getActor()})}}}catch{}try{let{flushNow:flushNow2}=await Promise.resolve().then(() => (init_emit(),exports_emit));await flushNow2()}catch{}});program2.command("spawn <name>").description("Spawn a new agent by name (resolves from directory or built-ins)").option("--provider <provider>","Provider: claude or codex","claude").option("--team <team>","Team name").option("--model <model>","Model override (e.g., sonnet, opus)").option("--skill <skill>","Skill to load (optional)").option("--layout <layout>","Layout mode: mosaic (default) or vertical").option("--color <color>","Teammate pane border color").option("--plan-mode","Start teammate in plan mode").option("--permission-mode <mode>","Permission mode (e.g., acceptEdits)").option("--extra-args <args...>","Extra CLI args forwarded to provider").option("--cwd <path>","Working directory for the agent (overrides directory entry)").option("--session <session>","Tmux session name to spawn into").option("--role <role>","Override role name for registration (avoids duplicate guard)").option("--new-window","Create a new tmux window instead of splitting").option("--window <target>","Tmux window to split into (e.g., genie:3)").option("--no-auto-resume","Disable auto-resume on pane death").option("--no-auto-sync","Disable auto-registration from workspace agents directory").option("--stream","Stream SDK messages to stdout in real-time (claude-sdk provider)").option("--stream-format <format>","Streaming output format: text, json, ndjson (default: text)","text").option("--sdk-max-turns <n>","SDK: max conversation turns",parseNumericFlag2("--sdk-max-turns")).option("--sdk-max-budget <usd>","SDK: max budget in USD",parseNumericFlag2("--sdk-max-budget")).option("--sdk-stream","SDK: enable streaming output (shortcut for --stream)").option("--sdk-effort <level>","SDK: reasoning effort level (low, medium, high, max)").option("--sdk-resume <session-id>","SDK: resume a previous session by ID").option("--prompt <text>","Initial prompt to send as the first user message").addHelpText("after",`
|
|
4889
4889
|
Examples:
|
|
4890
4890
|
genie spawn engineer # Spawn built-in engineer role
|
|
4891
4891
|
genie spawn researcher --model sonnet # Spawn with model override
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automagik/genie",
|
|
3
|
-
"version": "4.260505.
|
|
3
|
+
"version": "4.260505.5",
|
|
4
4
|
"description": "Collaborative terminal toolkit for human + AI workflows. NOTE: the npm distribution is being soft-deprecated — the canonical install is `curl -fsSL https://get.automagik.dev/genie | bash` (cosign + SLSA verified). See https://automagik.dev/genie/security/distribution-sovereignty",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genie",
|
|
3
|
-
"version": "4.260505.
|
|
3
|
+
"version": "4.260505.5",
|
|
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"
|