@automagik/genie 4.260506.3 → 4.260506.4
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
|
@@ -3985,8 +3985,8 @@ module.exports = {
|
|
|
3985
3985
|
`);return}process.stdout.write(`id status appliedAt from
|
|
3986
3986
|
`),process.stdout.write(`------------------------------- ---------- ------------------------ ------------
|
|
3987
3987
|
`);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}
|
|
3988
|
-
`)}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)}
|
|
3989
|
-
`),{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)}}var FRAMEWORK_MARKER_FILES=new Set([".orphaned_at"]);function copyDirSync(src,dest){mkdirSync15(dest,{recursive:!0});for(let entry2 of readdirSync9(src,{withFileTypes:!0})){if(FRAMEWORK_MARKER_FILES.has(entry2.name))continue;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
|
+
`)}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,readlinkSync,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(args.serverHealthBody.daemonInodeStale===!0)return{kind:"daemon-stale-inode",cliVersion,diskVersion:serverVersion,pid:args.serverHealthBody.daemonPid??0,cwd:args.serverHealthBody.daemonCwd??""};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";function readDaemonCwd(pid){if(process.platform!=="linux")return null;try{let cwd=readlinkSync(`/proc/${pid}/cwd`);return{cwd,staleInode:cwd.endsWith(" (deleted)")}}catch{return null}}function readInstalledPackageVersion(){let candidates=[join34(homedir28(),".bun","install","global","node_modules","@automagik","genie","package.json")],npmPrefix=safeExec("npm prefix -g",1500);if(npmPrefix)candidates.push(join34(npmPrefix,"lib","node_modules","@automagik","genie","package.json"));for(let path3 of candidates)try{let pkg=JSON.parse(readFileSync20(path3,"utf-8"));if(typeof pkg.version==="string"&&/^\d+\.\d+/.test(pkg.version))return pkg.version}catch{}return null}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}let cwdInfo=readDaemonCwd(pid);return{version:readInstalledPackageVersion()??VERSION,daemonInodeStale:cwdInfo?.staleInode??!1,daemonPid:pid,daemonCwd:cwdInfo?.cwd}}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})}async function pm2GenieServe(){let result2=await runCommandSilent("pm2",["jlist"],void 0,3000);if(!result2.success)return null;try{let entry2=JSON.parse(result2.output).find((p)=>p.name==="genie-serve");if(!entry2||typeof entry2.pid!=="number"||entry2.pid<=0)return null;if(entry2.pm2_env?.status!=="online")return null;return{pid:entry2.pid,restartCount:entry2.pm2_env?.restart_time??0}}catch{return null}}async function restartServeIfStale(){let before=await pm2GenieServe();if(!before)return null;let cwdInfo=readDaemonCwd(before.pid);if(!cwdInfo||!cwdInfo.staleInode)return null;if(log(`Restarting pm2 genie-serve (stale inode detected: ${cwdInfo.cwd})`),!(await runCommandSilent("pm2",["restart","genie-serve","--update-env"],void 0,1e4)).success)return error("pm2 restart genie-serve failed; daemon will keep serving pre-update bytes until manually restarted"),null;let deadline=Date.now()+1e4;while(Date.now()<deadline){let after=await pm2GenieServe();if(after&&(after.pid!==before.pid||after.restartCount>before.restartCount))return success(`pm2 genie-serve restarted (pid ${before.pid} \u2192 ${after.pid})`),{oldPid:before.pid,newPid:after.pid};await new Promise((r)=>setTimeout(r,500))}return error("pm2 genie-serve restart did not produce a new pid within 10s \u2014 verify probe will surface the stale state"),null}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"daemon-stale-inode":lines.push(`${colorize("\x1B[32m","\x1B[0m","\u2714")} CLI: v${result2.cliVersion}`),lines.push(`${colorize("\x1B[31m","\x1B[0m","\u2716")} Server: stale inode (pid ${result2.pid}, on-disk v${result2.diskVersion??"unknown"})`),lines.push(`${colorize("\x1B[2m","\x1B[0m",` cwd: ${result2.cwd}`)}`),lines.push(`${colorize("\x1B[2m","\x1B[0m"," fix: pm2 restart genie-serve --update-env")}`);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)}
|
|
3989
|
+
`),{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)}}var FRAMEWORK_MARKER_FILES=new Set([".orphaned_at"]);function copyDirSync(src,dest){mkdirSync15(dest,{recursive:!0});for(let entry2 of readdirSync9(src,{withFileTypes:!0})){if(FRAMEWORK_MARKER_FILES.has(entry2.name))continue;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}`)}await restartServeIfStaleSafe();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"||verify.kind==="daemon-stale-inode")&&!options.noVerify)process.exitCode=1}async function restartServeIfStaleSafe(){try{await restartServeIfStale()}catch(err){let msg=err instanceof Error?err.message:String(err);log(`Stale-serve restart skipped (non-fatal): ${msg}`)}}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)}
|
|
3990
3990
|
`,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(`
|
|
3991
3991
|
`)[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
|
|
3992
3992
|
`)}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)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automagik/genie",
|
|
3
|
-
"version": "4.260506.
|
|
3
|
+
"version": "4.260506.4",
|
|
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.260506.
|
|
3
|
+
"version": "4.260506.4",
|
|
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"
|